Page MenuHomePhabricator

Interface links can be redirected to hostile domains by cache poisoning on some server setups
Closed, ResolvedPublic

Description

Author: ayg

Description:
Originally sent to security@wikimedia.org on September 18, 2009. I never got a response, except a bounce message saying tim@wikimedia.org didn't exist. Nikerabbit was the one who originally pointed it out to me, because it affected translatewiki.net (which has since worked around it). I haven't tested if it still happens in recent trunk, but I'm not aware of any changes that should make it not happen.

Original report text:

$wgServer is set from the request's domain in most cases. This is a problem because that domain can be injected into content which is then cached. For instance, this page:

http://translatewiki.net/w/i.php?title=Special:RecentChanges&feed=rss

At the time I'm reading it, all the RSS links point to "evil2.aryeh.name" instead of translatewiki.net. To achieve this, I just set evil2.aryeh.name to be a CNAME for translatewiki.net, then browsed to the RSS feed. Now, hypothetically, anyone viewing that RSS feed on translatewiki.net will get directed to my domain. I could harvest IP addresses; switch the domain to point to a site containing script intended to infect vulnerable browsers; or lure users into logging in on my domain, stealing their passwords.

The primary mitigation is that most server setups aren't affected. Shared hosts rely on virtual hosting, so the spoofing won't work. Only wikis that can be reached by dedicated IP addresses are affected, and only if they don't have some kind of redirect in place for unrecognized domains (like wikia.com does) and don't give an error on unrecognized domains (like Wikimedia sites do). translatewiki.net is affected, and wikileaks.org also looks vulnerable. Probably so are a lot of other mid-sized wikis.

I don't see an obvious easy fix to this, but maybe I'm not thinking hard enough.

This was pointed out to me by Nikerabbit, who asked me to file this report. I mentioned it to TIm privately on IRC, but all he said was "interesting".


Version: unspecified
Severity: minor

Details

Reference
bz28798

Event Timeline

bzimport raised the priority of this task from to Normal.Nov 21 2014, 11:32 PM
bzimport added a project: MediaWiki-General.
bzimport set Reference to bz28798.
bzimport added a subscriber: Unknown Object (MLST).
bzimport created this task.May 3 2011, 5:41 PM

We'll work on this for 1.16.6.

One option would be to just drop support for getting $wgServer from the Host header. Instead, only SERVER_NAME or SERVER_ADDR or similar would be used. The installer could use the Host header to set $wgServer in LocalSettings.php, but it wouldn't be used after that.

It wouldn't be useful to do a DNS lookup on the Host header and compare it with the SERVER_ADDR, because the DNS response could be spoofed by the attacker, based on the source address of the query.

It seems that SERVER_NAME already takes priority. The host header is only used if SERVER_NAME is unset, it's been that way since the feature was introduced in r8010.

On Apache, SERVER_NAME should always be set, judging by ap_add_common_vars(). It also appears to be set unconditionally by Lighttpd's FastCGI module, which is what translatewiki.net seems to be using. RFC 3875 specifies that SERVER_NAME must be set. So this looks like a local configuration issue, due to misuse of the host header in LocalSettings.php, rather than a problem with MediaWiki.

It's not a MediaWiki configuration issue. This happens with the default configuration where $wgServer is autodetected. If the rest of your comment is right, then it seems that the server itself sets the SERVER_NAME depending on the user request.

ayg wrote:

That seems to be the case. Compare the following:

http://www.twcenter.net/~aryeh/tmp/test.php
http://thor.twcenter.net/~aryeh/tmp/test.php
http://mjollnir.twcenter.net/~aryeh/tmp/test.php

It's the same file, consisting of "<?php var_dump($_SERVER['SERVER_NAME']);", served at three different domains. They output www.twcenter.net, mjollnir.twcenter.net, and thor.twcenter.net respectively. This is lighttpd's mod_fastcgi.

My server isn't vulnerable to this attack because I have a 301 set up from any unrecognized domain, which triggers before PHP is launched. That's the obvious workaround, and translatewiki.net should do it -- it might help for SEO too -- but it's not a fix that MediaWiki can rely on. As noted, I did actually carry out the exploit in practice against translatewiki.net back in September 2009, so it's definitely possible unless something basic has changed since then.

ayg wrote:

As far as doing a DNS lookup on the Host header, I don't think we have to worry about the attacker spoofing the DNS response -- that's nontrivial. But the attack scenario is that the attacker legitimately controls the domain name given in the Host header, and has pointed its actual A records to your wiki's address, and will later point them to some evil lookalike site that will phish your password or something once the caches are poisoned. So of course the Host header will resolve to SERVER_ADDR.

Is there any reason we should be generating absolute URLs anywhere to start with if they point to $wgServer? The exploit doesn't work if the URLs are changed to be relative, and you'd also save bytes in the output.

Also, would there be any substantial harm from just setting $wgServer to a constant string on install, namely whatever SERVER_NAME at install time? That would also prevent the aesthetic issue of mixing foo.com and www.foo.com URLs or similar, in cases where sites don't have a redirect set up from one to the other.

(In reply to comment #6)

Is there any reason we should be generating absolute URLs anywhere to start
with if they point to $wgServer? The exploit doesn't work if the URLs are
changed to be relative, and you'd also save bytes in the output.

It's required to use absolute URLs in redirects, and 301 redirects in particular are cacheable. I wouldn't be surprised if it were required in RSS also.

Also, would there be any substantial harm from just setting $wgServer to a
constant string on install, namely whatever SERVER_NAME at install time? That
would also prevent the aesthetic issue of mixing foo.com and www.foo.com URLs
or similar, in cases where sites don't have a redirect set up from one to the
other.

I don't know about substantial harm, but it would certainly be disruptive and inconvenient, especially in a minor release.

How about this: let's set $wgServer in the installer in 1.18, and remove $wgServer autodetection from DefaultSettings.php a bit later, say in 1.20. Then in the meantime, I'll post an advisory to mediawiki-announce along the lines of:

It has come to our attention that allowing MediaWiki to detect the server name automatically may be insecure. An attacker may set an incorrect Host header, and if the webserver does not properly validate this Host header, MediaWiki may cache the incorrect server name. Then when other users attempt to access the wiki, the incorrect server name may appear in links. If a user follows such a link, privacy loss may result. There is a potential for more severe consequences, depending on the configuration of the wiki.

Thus, we advise all MediaWiki users to set $wgServer in LocalSettings.php, instead of relying on it being set automatically. For example:

$wgServer = 'http://wiki.example.com';

If you set it based on the Host header, make sure you validate it properly, for example:

if ( in_array( $_SERVER['SERVER_NAME'],

array( 
    'wiki1.example.com', 
    'wiki2.example.com
) ) )

{

$wgServer = 'http://' . $_SERVER['SERVER_NAME'];

} else {

die( 'Invalid hostname' );

}

Starting in MediaWiki 1.18, the installer will generate a LocalSettings.php with $wgServer set to a fixed string. In a future release, autodetection of $wgServer will be removed, and any wikis relying on it will stop working.

[end proposed advisory]

ayg wrote:

Why do we need to remove $wgServer autodetection ever? Set it by default in new LocalSettings.php, so new sites will be secure. Post an advisory telling old sites that they should set it manually themselves. And add checks to update.php and maybe a couple of other places that will tell the administrator to set it explicitly if it's being autodetected. Maybe add the checks to Maintenance.php, so they run every time the admin runs any maintenance script.

We don't need to break existing sites. The vulnerability doesn't affect shared hosts at all, since those all use domain-based virtual hosting. The small minority of MediaWikis on dedicated servers or VPSes are only affected if no domain-based virtual hosting is used, which excludes all wiki farms; and if there are no automatic redirects to the canonical domain. And for sites that are affected, it doesn't have much potential impact.

Any security announcement should start by mentioning all the installations that *aren't* vulnerable, so that the large majority of users know they can ignore it.

Thanks for adding me, Tim. I see now that we should add $wgServer to LocalSettings. But I also agree with Aryeh that we shouln't remove autodetection support. The whole thing reminds me the r77423 issue.

I'm not as convinced about adding $wgProto to LocalSettings.php. On most sites https won't be availabl, but we could be blocking https: access to the users (at the cost of a small cache pollution) for sites which allow both http & https to the host. $_SERVER['HTTPS'] doesn't look to be spoofable.

http://web.resource.org/rss/1.0/spec doesn't mention whether the URLs must be absolute or not. There probably is some user agent that only accepts them absolute.

ayg wrote:

Who mentioned $wgProto? I can't see any reason to worry about that.

(In reply to comment #11)

Who mentioned $wgProto? I can't see any reason to worry about that.

He's reviewing r90105.

Looks like it's been fixed, but probably needs testing.

Change 524396 had a related patch set uploaded (by Legoktm; owner: Legoktm):
[mediawiki/core@master] Disable $wgServer autodetection to prevent cache poisoning attacks

https://gerrit.wikimedia.org/r/524396