unser_name writeup
根据题目提示和界面功能提示,有上传功能且反序列化,初步考虑phar
一般反序列化都需要白盒代码来构造pop链,所以先看注释有没有源代码,发现提示www.zip,下载下来。
(本地测试时代码经过修改)
猜测反序列化链子出口是$find_this指向的函数,$name1->var=$name2,再用POST传对应的函数。
由于后缀检查是白名单,不知道已知的解析漏洞情况下就不考虑绕后缀了,不过思路上也更加确定是phar,毕竟phar可以改后缀,并且有可控参数的操控文件函数file_exist触发
考虑绕过黑名单,看到这几个文件头第一时间就想到虎符杯线下的tinypng,对phar再gzip一次就可以绕过__HALT_COMPILER,但是ban了gzip bzip2 zip 所以只剩下tar了。
在php序列化和反序列化的有关源码中
1 | memcmp(entry.filename, ".phar/.metadata", sizeof(".phar/.metadata")-1 |
这一行匹配文件名是否以.phar/.metadata开头,且只匹配开头,所以绕过下面的In_array直接在后面加上无意义字符就可以了。接下来php就会使用phar_tar_process_metadata和phar_parse_metadata(&metadata)开始反序列化了。
最后payload:
制作.phar/.metadata123
生成test.tar
改名为test.png上传
通过给出的参数算出文件名cddc9385153d0b6c5c80a6a94dc9219c.gif
使用phar协议,func传phpinfo尝试发现成功
接下来爆破create_function生成的函数的函数名称
拿到结果
虎符杯线下tinypng writeup
源码分析
buuoj复现
拿到源码 laravel框架先关注路由和相对应的控制器。
‘/‘路由下存在着IndexController,跟进fileUpload方法
在laravel框架中封装了一个Request类来存放有关请求内容,这里从$req中拿出上传的file并进行有关过滤,其中过滤掉了HALT_COMPILER这一phar的标志头,接下来改名字存放到uploads中。
由于过滤内容很严格且后缀过滤是白名单,又不存在已知的解析漏洞,所以不考虑单纯的文件上传。
换’/image’路由下的ImageController审计
handle方法接受一个image参数输入,后缀必须为png,发现imgcompress类和compressimg方法,跟进一下compressimg
跟进openImage()
发现getimagesize(),该方法可以触发phar反序列化。
到这个地方思路就非常明确,只要$this->src可控,就可以通过上传的phar文件来进行反序列化操作。
发现$this->src是在构造类的时候进行的赋值。
而类的实例化时使用的对应参数为$source $source又等于input(‘image’),故可控。
接下来就是通过找gadget chain通过反序列化来进行漏洞利用了,上phpggc一把梭。
payload和poc
在buuoj上复现远程死活打不通,查询相关题解发现也有人打不通,就不死磕了,记录个脚本日后来测。
1 | # -*- coding=utf-8 -*- |
跟进一下phpggc laravel rce5的链子
这个链子实际上是Laravel框架中mockery组件的漏洞
入口在PendingBroadcast.php的__destruct
可以调用任意类的dispach方法
这里选用了dispatcher.php
我们需要的是$this->dispatchToQueue
这个方法,就要使前两个条件均成立,而后文会分析this->queueResolver可控,先跟进一下commandShouldBequeued
$command需要为实现ShouldQueue接口的实例,这里使用了BroadCastEvent.php
回到先前的需要满足两个IF条件后利用的方法dispatchToQueue
跟进一下
可以看到此处调用了call_user_func,如果两个参数都可控就可以实现命令执行。
看一下构造函数,发现$this->queueResolver可控
而$connection是$command的成员,$command可控,则$connection也可控,所以此处就可以实现命令执行
全局搜索一下eval方法,发现存在
1 | class EvalLoader implements Loader |
该EvalLoader类的load方法存在eval()
call_user_func函数在第一个参数为数组的时候,第一个参数就是我们选择的类,第二个参数是类下的方法;所以这里直接去到EvalLoader类,去执行load方法从而调用到eval函数;这里发现存在参数,而且参数必须是MockDefinition类的实例,也即是意味着我们connection需要为MockDefinition类的实例,并且要执行eval
,必须使得if
返回false
接追溯到MockDefinition类:
1 | public function __construct(MockConfiguration $config, $code) |
全局搜索getName()
方法,并且实现MockConfiguration
接口,找到了MockConfiguration.php
中:
1 | public function getName() |
因此当我们使得$this->config
为该类时,那么调用getName能够返回任意值,从而使得该任意值组成的类不存在而调用eval,而$this->code
就是拼接在eval
中的命令
phpggc laravel rce5 exp
摘自网上
1 | <?php |
由unser_name和tinypng收获的总结
生成完phar再执行gzip phar.phar或者bzip2 phar.phar
效果如下。可以过黑名单检测
将序列化的数据写入.phar/.metadataXXXX中,再回退上一级执行
1 | tar -cvf test.tar .phar/ |
再用phar协议解析对应的tar包也可以触发反序列化
Zip:
1 | $a=serialize(new a()); |
不过zip的注释里不能有00.高版本可以用大写S,16进制替换%00。注意命名空间类的\和16进制的\冲突。
解决:\替换\5c
别把不是S里的\也替换了哦。
从源码角度看phar为什么能解析这几类压缩包
深入理解Zend执行引擎(PHP5) - GongYong (gywbd.github.io)
算是前置知识,现在基本看不懂,日后再来。
从源码角度分析
从虎符线下CTF深入反序列化利用 | (guokeya.github.io)
识别文件头,识别文件名。
debug插件没整明白,暂时先不跟了。
end
- Post link: http://example.com/2021/11/28/unser_name/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.
若没有本文 Issue,您可以使用 Comment 模版新建。