Page MenuHomePhabricator

<cross-domain-policy> mangling allows injection in API format=php
Closed, ResolvedPublic

Description

The <cross-domain-policy> mangling in OutputHandler.php (see bug 66776) poses a potentially severe security problem for API clients written in PHP, in that format=php is affected.

Let's look at the body of wfMangleFlashPolicy():

Avoid weird excessive memory usage in PCRE on big articles

if ( preg_match( '/\<\s*cross-domain-policy\s*\>/i', $s ) ) {

return preg_replace( '/\<\s*cross-domain-policy\s*\>/i', '<NOT-cross-domain-policy>', $s );

} else {

return $s;

}

The problem is that the regex can match strings of various lengths (different numbers of whitespace characters) yet replace them with a fixed string of constant, possibly differing length. This is done after PHP serialization and allows an attacker who can control just two string fields in an API response to inject arbitrary serialized values (including objects, for which the security concerns are well-known).

Here's an example of a serialize()'d string:
s:54:"And he said, "Are you my son Esau?"; and said, "I am":";

serialize() does not have to escape syntactically important characters, including '"' and ';', because the string's length has already been encoded in the data stream.

In the first string, the attacker would add a <cross-domain-policy> tag with enough whitespace to push the expected location of the end-of-string delimiter into the body of the second string, swallowing all bytes up until that point. Then a fake end-of-string delimiter would be added, followed by an arbitrary serialized object, and the well-known exploitation techniques for unserialization of attacker-controlled data would apply.

An example attack:

  1. The attacker makes a single edit to "Wikitest:Sandbox":

Edit summary: <cross-domain-policy[95 spaces]>
Content: ";O:3:"Foo":0:{}

  1. A bot requests the URL http://www.mediawiki.test/w/api.php?action=query&format=php&prop=revisions&rvprop=comment|content&titles=Wikitest:Sandbox.
  1. The API generates and outputs the response, which is then predictably and insecurely mangled (in the name of security!).
  1. The bot tries to unserialize the response, and Foo::wakeup() is called, followed by Foo::destruct(). With some additional work on the "Content" part of his edit, the attacker may be able to overwrite arbitrary files or execute arbitrary shell commands or PHP code.

One major limitation: if I'm not mistaken, null bytes are not allowed. That would interfere with attempts to manipulate protected and private properties.


Version: unspecified
Severity: normal

Details

Reference
bz71478

Event Timeline

bzimport raised the priority of this task from to Needs Triage.Nov 22 2014, 3:51 AM
bzimport added a project: Security-Core.
bzimport set Reference to bz71478.
bzimport changed Security from none to Software security bug.
Restricted Application changed the visibility from "Public (No Login Required)" to "acl*security (Project)". · View Herald TranscriptNov 22 2014, 3:51 AM
Restricted Application changed the edit policy from "All Users" to "acl*security (Project)". · View Herald Transcript

I already have a patch for bug 66776 that will coincidentally fix this issue, or if Chris decides we can just kill wfMangleFlashPolicy that would fix it too.

Thanks Brad. To get this taken care of for the WMF, I'm hoping to start serving a crossdomain.xml file for all domains-- I just made bug 73574 for that. We can then get stop running wfMangleFlashPolicy on our sites entirely.

For mediawiki in general, I'd like to keep wfMangleFlashPolicy in for any sites that aren't able to host a crossdomain.xml file at their root, or are stuck with one that is too permissive. For them, they should run wfMangeFlashPolicy, but with your patch from bug 66776 which will prevent this issue too. So probably a config flag in OutputHandler.

This was fixed (publicly) with:
https://gerrit.wikimedia.org/r/#/c/174289/
https://gerrit.wikimedia.org/r/#/c/174496/

I'll try to get those patched on the cluster. @Mglaser, these should be backported and added to the next security release.

Restricted Application changed the visibility from "acl*security (Project)" to "Custom Policy". · View Herald TranscriptNov 24 2014, 7:23 PM
Restricted Application changed the edit policy from "acl*security (Project)" to "Custom Policy". · View Herald Transcript
Restricted Application added a project: acl*security. · View Herald Transcript
Restricted Application changed the visibility from "Custom Policy" to "Custom Policy". · View Herald TranscriptNov 26 2014, 5:58 AM
Restricted Application changed the edit policy from "Custom Policy" to "Custom Policy". · View Herald Transcript
csteipp changed Security from Software security bug to None.Nov 26 2014, 6:09 AM

Backports are in gerrit, waiting to be merged:
REL1_24 https://gerrit.wikimedia.org/r/#/c/175708/
REL1_23 https://gerrit.wikimedia.org/r/175720
REL1_22 https://gerrit.wikimedia.org/r/175722
REL1_19 https://gerrit.wikimedia.org/r/175725

and
REL1_24 https://gerrit.wikimedia.org/r/175956
REL1_23 https://gerrit.wikimedia.org/r/175957
REL1_22 https://gerrit.wikimedia.org/r/175958
REL1_19 https://gerrit.wikimedia.org/r/175960

Please note I will update the release notes just before I publish the tarball in one go. Otherwise I'd have to rebase a lot.

@Anomie, do you think you could merge the above changes? Or at least +1 them before I merge? Thanks a lot!

Cherry picks appear to be correct, so +1 on that front. I have no idea whether anything in there is going to break on whatever old PHP version is still supported by 1.19, although it seems unlikely.

ok, all changes merged. Thanks @Anomie for your help.

csteipp triaged this task as Medium priority.
csteipp changed the visibility from "Custom Policy" to "Public (No Login Required)".
csteipp changed the edit policy from "Custom Policy" to "All Users".