php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #71559 Built-in HTTP server, we can downlaod file in web by bug
Submitted: 2016-02-09 12:49 UTC Modified: 2016-02-10 22:21 UTC
Votes:3
Avg. Score:4.7 ± 0.5
Reproduced:0 of 0 (0.0%)
From: setbanned at gmail dot com Assigned: ab (profile)
Status: Closed Package: Built-in web server
PHP Version: 7.0.3 OS: Windows only
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: setbanned at gmail dot com
New email:
PHP Version: OS:

 

 [2016-02-09 12:49 UTC] setbanned at gmail dot com
Description:
------------
Built-pool HTTP Downlaod Exploit.
Exploit By : TaWaN (2600 Thailand , KissShot - Studio , Tawan Naultang , Phitchayaphong Tantikul)

Software : PHP Built-in HTTP server
Version : 5.4.x , 5.6.x , 7.0.x
Os : Windows only

How to Exploit 

put . (dot) attach type in url

example : http://locahost:8000/index.php.

we can download file in Web and look code in file.

Test script:
---------------
image1 : http://www.mx7.com/i/680/lsaMUF.png
image2 : http://www.mx7.com/i/a49/RzFIyT.png
image3 : http://www.mx7.com/i/54b/2BjHvz.png
image4 : http://www.mx7.com/i/ee5/O2YHsc.png


Actual result:
--------------
we can downlaod file of the web.

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-02-09 20:05 UTC] stas@php.net
-Type: Security +Type: Bug -Package: PHP options/info functions +Package: Built-in web server
 [2016-02-09 20:05 UTC] stas@php.net
Not a security issue since built-in server should not be used in production, but somebody may want to look at it and fix it still.
 [2016-02-10 17:01 UTC] johannes@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: ab
 [2016-02-10 17:01 UTC] johannes@php.net
Anatol, you have an idea? - This seems to be Windows-specific. 

In php_cli_server_dispatch() we see that the extension is not "php" (which is correct, as the file extension is empty) so it dispatches a static file.  In php_cli_server_begin_send_static() we do

1953    if (client->request.path_translated && strlen(client->request.path_translated) != client->request.path_translated_len) {
1954        /* can't handle paths that contain nul bytes */
1955        return php_cli_server_send_error_page(server, client, 400);
1956    }
1957
1958    fd = client->request.path_translated ? open(client->request.path_translated, O_RDONLY): -1;

Which succeeds and opens "foo.php" when "foo.php." is requested.
 [2016-02-10 22:21 UTC] ab@php.net
Johannes, oh yeah, you've spotted it very well. The win32 namespace will cut off the trailing dots and spaces. I'll prepare a patch for next RCs.

Thanks.
 [2016-02-14 19:50 UTC] ab@php.net
Automatic comment on behalf of ab
Revision: http://git.php.net/?p=php-src.git;a=commit;h=ce4a2f0fc60309f429e4c04160a71befc283338a
Log: Fixed bug #71559 Built-in HTTP server, we can downlaod file in web by bug
 [2016-02-14 19:50 UTC] ab@php.net
-Status: Assigned +Status: Closed
 [2016-06-03 14:37 UTC] cpascal dot gr at gmail dot com
Hi,
 
There is an easy way to fix the "dot" security issue. 
 
You can just make a router.php to check the REQUEST_URI before the response: 
<?php
// router.php
$rcuri = explode("?",$_SERVER["REQUEST_URI"]);
if (substr($rcuri[0],-1) != ".") {
    return false;
} else { 
header("HTTP/1.0 404 Not Found");
?>
 
This will show you a blank 404 page if there is a dot in the end of URL (if there are any params i exclude them with explode...)
 
If you want to "fake" the default 404 page, you can just echo it: 
<?php
// router.php
$rcuri = explode("?",$_SERVER["REQUEST_URI"]);
if (substr($rcuri[0],-1) != ".") {
    return false;
} else { 
header("HTTP/1.0 404 Not Found");
echo '<!doctype html><html><head><title>404 Not Found</title><style>
body { background-color: #fcfcfc; color: #333333; margin: 0; padding:0; }
h1 { font-size: 1.5em; font-weight: normal; background-color: #9999cc; min-height:2em; line-height:2em; border-bottom: 1px inset black; margin: 0; }
h1, p { padding-left: 10px; }
code.url { background-color: #eeeeee; font-family:monospace; padding:0 2px;}
</style>
</head><body><h1>Not Found</h1><p>The requested resource <code class="url">'.$_SERVER["REQUEST_URI"].'</code> was not found on this server.</p></body></html>';
}
?>
 
You can put the router.php in the same dir with php.exe and run the server with:
php.exe -S 127.0.0.1:80 router.php
 
If you want to specify the document root, you must put -t param before -S param:
php.exe -t "C:\vbserver\www_uncompress" -S 192.168.123.100:80 router.php
 
 
C. Paschalidis Software Developer / DBA
 [2016-06-03 17:46 UTC] cpascal dot gr at gmail dot com
There is something more that i didn't catch in my router.php

If server have a request like this: 
http://192.168.5.152/index.php./

or like this etc:
http://192.168.5.152/index.php..../

We can't catch the bug and client can show our source code.

So, we have to do some preg_replaces to catch all posible cases with one if.

in my router.php we have to replace this line:
if (substr($rcuri[0],-1) != ".") {

with this lines:
function str_ends_with($haystack, $needle)
{return substr_compare($haystack, $needle, -strlen($needle)) === 0;}
$rmdots = preg_replace('/\.{2,}/', '.',$rcuri[0]);
$rmdots = preg_replace('/\/{2,}/', '/',$rmdots);
$rmdots = preg_replace('/[\.\/]{2,}/', './',$rmdots);
if (!str_ends_with($rcuri[0],'.') && !str_ends_with($rmdots,'.php./')) {

Ok this is not the better way, we can make a very smart preg_match to do the same but, this code will do the job too.

So, my router.php is now:
<?php
// router.php
function str_ends_with($haystack, $needle)
{
  return substr_compare($haystack, $needle, -strlen($needle)) === 0;
}
$rcuri = explode("?",$_SERVER["REQUEST_URI"]);
$rmdots = preg_replace('/\.{2,}/', '.',$rcuri[0]);
$rmdots = preg_replace('/\/{2,}/', '/',$rmdots);
$rmdots = preg_replace('/[\.\/]{2,}/', './',$rmdots);
if (!str_ends_with($rcuri[0],'.') && !str_ends_with($rmdots,'.php./')) {
    return false;
} else { 
header("HTTP/1.0 404 Not Found");
echo '<!doctype html><html><head><title>404 Not Found</title><style>
body { background-color: #fcfcfc; color: #333333; margin: 0; padding:0; }
h1 { font-size: 1.5em; font-weight: normal; background-color: #9999cc; min-height:2em; line-height:2em; border-bottom: 1px inset black; margin: 0; }
h1, p { padding-left: 10px; }
code.url { background-color: #eeeeee; font-family:monospace; padding:0 2px;}
</style>
</head><body><h1>Not Found</h1><p>The requested resource <code class="url">'.$_SERVER["REQUEST_URI"].'</code> was not found on this server.</p></body></html>';
}
?>


 
C. Paschalidis Software Developer / DBA
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 12:01:29 2024 UTC