[EIS 2019]EzPOP

[EIS 2019]EzPOP

考点

  • php://filter/write绕过“死亡exit”

wp

给了源码,返回头看到PHP版本7.3。其实这里不给源码也可以做,用arjun可以探测参数,存在参数src,传入就可以看到源码了。

给了源码,一点一点看。首先定义两个类,然后GET的src参数,上传目录uploads/,最后反序列化data

确定是反序列化,然后找__destruct()作为入口,可以锁定class A,然后$this->autosavefalse,然后不断向上调用

getForStorage()那一大块可以写成一段代码,这段代码意思举个例子解释,比如array("0"=>array("path"=>"a")),处理之后就是array("0"=>"a"),感觉有点多此一举。再json_encode一下,变成一个字符串。在getForStorage()后执行的是 $this->store->set(),由此跳转到class B

到这可以先写一下A类的序列化

然后看class B的set函数,接收的三个参数分别是$name$value$expire,分别与$a->keyjson_encode([$a->cache, "2"])$a->expire相关联。然后把$expire转化为整型,用$this->options['prefix']拼接$name,处理$filename,这里感觉也没啥用,对$filename$expire处不处理并没有多大影响,更像是从哪个项目里复制出来的。

然后看一下$value的处理,它的值应该是类似于这种[[{"path":"a"}],2],或者是这种[["a"],2],把它作为参数传给$this->serialize(),在这个函数里面可以执行任意函数,但是没有函数的参数是像$value那种,所以这里最好是保持空过,$serialize就可以是trim或者strval之类的函数

接着往后看,这里的if是是否进行数据压缩,$this->options['data_compress']置为false,跳过这一步。sprintf('%012d', $expire)是把$expire左补齐12位,如果$expire是11,那么这个结果就是000000000011。再看这两行行,就是典型的php://filter的妙用,绕过“死亡exit”。$data为要写入的shell,$filenamephp://filter/write=convert.base64-decode/resource=shell.php

$data = 那一行中,可以被base64识别的是php000000000011exit这19个字符,要在shell中补字符直到总长度符合base64解码规范

如果这样生成代码,得到的value是[["PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+"],2],前面是21个字符,中间补3个,后面补3个,最后cache是array("aaaPD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+aaa")

完整代码

小结

  1. [2020 新春红包题]1是它的增强版

最后更新于