Deep dive into Built-in Webserver overwrite of $_SERVER[‘request_uri’]

1 year ago 107
BOOK THIS SPACE FOR AD
ARTICLE AD
Photo by Ben Griffiths on Unsplash

While reviewing the recent PHP Development Server <= 7.4.21 Remote Source Disclosure Vulnerability on https://blog.projectdiscovery.io/php-http-server-source-disclosure/, our attention was drawn back to PHP Bug #73630, “Built-in Webserver Overwriting $_SERVER[‘request_uri’]”.

Upon reviewing the official reference at https://bugs.php.net/bug.php?id=73630, we deemed the report insufficient in providing a comprehensive explanation for security professionals of all levels, hence we decided to write this article.

What has been discussed thus far

On bugs.php.net:

Description:
— — — — — —
It is possible to overwrite the contents of $_REQUEST_URI with a uri longer than 16400 bytes. It allows a attacker to manipulate the global variable in unexpected ways. It has low impact as it only related to the .

Test script:
— — — — — — — -
Create a file named testtest1.php with the following content
<a href=”<?= $_SERVER[‘REQUEST_URI’] ?>”>Unexpected url</a>

Start the buildin php server
php -S localhost:8090

Go to the browser and execute the following script in the console
window.location.href = (url =’http://testtest1.php:8090/overflow.php?')+("x".repeat(16400-url.length)+"//example.com");

it changes the url to “http://testtest1:8090/overflow.php?[16365 x here][payload]

Expected result:
— — — — — — — —
localhost:8090 + a long string

Actual result:
— — — — — — —
example.com

On blog.projectdiscovery.io:

A different bug that fortunately also addressed this remote source code disclosure issue in subsequent versions is https://bugs.php.net/bug.php?id=73630. During the parsing of an HTTP request, when certain callbacks are called multiple times, the REQUEST_URI server variable gets overwritten with a substring of itself.

This behavior can result in open redirects or cross-site scripting (XSS) attacks in some cases. Here’s an example:

Example Snippet:

<a href="<?php echo htmlentities($_SERVER['REQUEST_URI']) ?>">Unexpected url</a>

Copy

requesting GET /index.php?abcd will result in being rendered as:

<a href="/index.php?abcd">Unexpected url</a>

Copy

The hyperlink will always be relative to the domain where it is hosted. Also, the path would convert meta-characters to their HTML entities. Therefore, XSS is not feasible.

However, this can still be exploited by an attacker by sending a GET request with a very long query string in the URL, such as the one shown in the example.

GET /?[AAAA...<1425 times>]javascript:alert(1) HTTP/1.1
Host: pd.research

The REQUEST_URI is overwritten and only ends up with javascript:alert(1). The amount of padding required to be successfully overwrite it with desired content varies and may need to be adjusted.

This is the best way to put it

Both the initial bug report and the blog post on the project discovery page state that this attack is limited to the embedded server (PHP Development Server). You’d have to be quite fortunate to stumble into this in the wild, as nobody would knowingly use php -S 0.0.0.0:80 to access a development server that’s open to the internet. Since you’ve come thus far, I’ll give you a glimpse of the test environment and situation as seen by us.

Detailed POC starts here

Create a new temporary folder with a simple index.php file and add the following to it:

<a href="<?php echo htmlentities($_SERVER['REQUEST_URI']); ?>">Unexpected url</a>

Output:

Start the PHP Development Server:

php7.4 -S localhost:8000

Open a browser and go to http://localhost:8000/index.php?test%22%3Exsstest and then look at the source code (CTRL+U):

While project discovery requests (poc) appear to fail in PHP 7.4.18, everything appears to be working normally until we receive a URL in the following format:

/?[AAAA…<16400 times — URL length>]javascript:alert(1)

This can be accomplished by opening the console and entering:

window.location.href = (url ='http://localhost:8000/?')+("x".repeat(16400-url.length)+"javascript:alert(1)");

When the href tag is clicked, the following event occurs:

Conclusion

Such a vulnerability in the PHP Development Server could allow an attacker to manipulate a global variable in unexpected ways and cause open redirects or cross-site scripting (XSS) attacks. This vulnerability occurs when the REQUEST_URI server variable gets overwritten with a substring of itself during the parsing of an HTTP request. To protect against this vulnerability, it’s recommended to not use the PHP Development Server on an open network and to use a more secure web server for hosting production applications.

The vulnerability is limited to the embedded server and is unlikely to be encountered in the wild, as it is not recommended to use the development server for any other reason than some local tests or development tryouts.

Read Entire Article