While penetration testing and code reviewing a customer’s web-application I came across an interesting bug I’m going to describe in this article.
The application in question supports third party plugins which often follow their own coding-conventions.
During code review, a Cross-Site scripting vulnerability was detected in one of those plugins:
<?php echo "<a href='index.php?plugin=".$_REQUEST['plugin']."'>Link text</a>"; ?>
Here the parameter plugin
is susceptible to a Cross-site scripting vulnerability because a user supplied parameter is directly reflected back to the user’s browser. While this vulnerability is relatively obvious, actual exploitation is more complicated. This is because the core application itself validates the supplied parameter plugin
before the vulnerable code within the plugin is executed. Hence, the Cross-site scripting vulnerability cannot be exploited directly. The validation code in the core application is as follows:
<?php $plugin = $_GET['plugin']; if(!in_array($plugin, $active_plugins)) { die("Plugin is not supported"); } ?>
The validation code checks if the value of the parameter plugin
is defined in an array of active plugin names. Looking closer one can see that only the GET parameter is validated. If instead submitting a POST request containing the parameter plugin
or even setting a cookie with that name this is not validated by the above code.
Furthermore, the vulnerable code inside the plugin uses $_REQUEST
to fetch the parameter plugin
. The $_REQUEST
variable contains all the parameters passed in the request via GET ($_GET
), POST ($_POST
) and cookies ($_COOKIE
). The order of merging GET/POST/COOKIE (also the default) is determined by PHP and may be configured in its configuration. This means if there is a POST parameter named plugin
, $_REQUEST['plugin']
will return the POST parameter value instead of the GET value.
Knowing this, exploitation of the vulnerability becomes possible and is demonstrated with the following steps:
First fetch a regular request that executes the vulnerable code using a tool like Burp Suite which will be used as an example. Send it to the Repeater tab to enable making changes to the request. If this request is a GET request, change it to a POST request. The context menu item “change request method” of Burp makes this very easy. After this, ensure that there is still a GET parameter plugin
(e.g. /?plugin=thumbnails
) that will pass the validation code in the core application. After this, add an additional POST parameter named plugin
containing the exploit-code:
'><script>alert(document.cookie)</script>
The complete request then looks as follows:
POST https://no-sec.net/?plugin=thumbnails HTTP/1.1 Host: no-sec.net Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 58 plugin=thumbnails'><script>alert(document.cookie)</script>
This request passes the validation as a valid GET parameter is used while also exploiting the Cross-Site scripting because of the POST parameter is referenced in the vulnerable code inside the plugin.
Finding this vulnerability is fairly difficult without manually reviewing the source code, because most web application security scanners will not try to send a GET request as a POST request using the same parameter again. It is more likely a manual penetration test would find this, but without any indication for this behavior most penetration testers will not spend valuable time on this test case for each and every request.
Note: The above code is not the same as in the tested system. This is due to confidentiality and to simplify the example.
- Hooking Burp Suite in Client Software Communication - 6. July 2017
- PHP: Exploitation with $_REQUEST while validating $_GET - 20. May 2016
- HTTP Side-Channel Attacks with Burp Suite - 25. April 2016