代码审计---反序列化实例(Tpyecho typecho-1.1-15.5.12-beta)
第一次学习审这样的源码,主要参考两篇文章:
2、http://www.freebuf.com/column/161798.html
源码下载地址:https://github.com/typecho/typecho/archive/v1.1-15.5.12-beta.zip
漏洞发生在install.php页面
这次审计用的工具有:
1、sublime text3
2、Phpstrom
3、Phpstudy
4、Burpsuite
分析:
正常安装这个站点
漏洞点在install.php页面
这里可以看到,这里将cookie __typecho_config的值取进来,先base64解密,然后再进行反序列化
第一步就是先让代码运行到这里
看前面的限制:
输入finish=1可以绕过第一个if
第二个if判断是否有$_GET()或$_POST()
当第一个绕过,第二个就过了,然后下面有一个判断Referer,修改一下Referer: 你的站点 就可以绕过
然后下面还有页面的一些限制
我们要进入的是最后一个判断,就是说要绕过前面两个
第一个判断,如果已经安装了的话,直接可以过
第二个判断,判断cookie是否有__typecho_config值
那么输入__typecho_config=任何字符,就可以绕过
下面就到了反序列化函数了。
这里如果直接在burpsuite里面运行的话,会报错的,因为后面的有一些代码运行的出错,因为我们这里是随便输入的,后面的一些函数有可能执行不了,如果要判断是否运行正确了,可以用phpstrom单步调试一下
跟着代码往下走:
代码这里新建一个对象
可以看到这里是把 $config['adapter'] 当作字符串来用的,那么如果这里的 $config['adapter'] 不是一个字符串,而是一个对象,那么就会调用这个对象里面的__toString()函数,查一下代码中,哪个class 里面 存在 __toString()
每一个都看一下
这个返回一个序列化,没有可以继续利用的
下一个
这个是拼接数据库操作的,也没有可以利用的
下一个
在这里,第291行,$item['author']->screenName 这里可以利用,因为反序列化就是利用不同的魔术方法,如果这里的$item['author']是一个对象,如果这个对象里面没有screenName这个变量,那么就会去执行这个对象里面的__get()方法,继续查一下哪个class里面有__get()方法
查一下这些方法
直接返回,不能利用
这个也不能利用
这个也不行
这个也不行
这个也不行
下面看到Request.php页面,这个是可以利用的
分析一下这些方法
先是 __get()方法 ----》 get() 方法 ----》_applyFilter()方法
__get()方法直接调用get()方法
在get()方法里面,先判断是否存在$this->_params[$key],如果存在那么 $value = $this->_params[$key];
然后判断$value 值是否是数组,且长度是否大于0 ,如果不是数组,且大于0,返回值就等于 $value
进入到 _applyFilter()方法
可以看到这个方法里面,有两个可以执行方法的函数
array_map() 和 call_user_func() 具体使用方法查百度或google
看一下进入两个判断的限制
先判断是否有 $this->_filter
然后做foreach() 也就是说 $this->_filter要是一个数组
然后再判断$value是否是数组,前面的get() 里面判断了 $value 不是一个数组,那么这里就进入的是 call_user_func()
但是这个函数怎样执行呢
函数的用法就是
call_user_func(‘函数名’,’参数’)
例如,如果执行call_user_func(‘phpinfo’,’-1’) 就会执行phpinfo() ,那个-1不用管,因为phpinfo()是不用参数的
那么如果 call_user_func(‘assert’,’file_put_contents("test.txt","Hello World")’)
就会执行文件的写入,也就是可以写shell
理清了利用的思路,下面就是编写exp了,建议可以边理思路,边写 exp,当然如果很熟悉php 可以不用边理边写
思路:
install.php 绕过限制,输入cookie ---》 Db.php 拼接的时候,因为对象被当作字符串使用,执行__toString() ------》 __toString() 所在的class是 Typecho_Feed ,所以要构造一个 class Typecho_Feed -----》 执行__get() ,__get()方法在对象 Typecho_Request 里面,所以要构造一个 class Typecho_Request
编写exp ,不要放在和站点同个服务器,不然会调用到编写exp的class,所以我这里用的是在线的编译器 http://www.dooccn.com/php/
代码没有办法一行一行解析,如果有不懂的,再交流一下吧
发送过去会报错,但是这个是因为程序运行到后面,代码的出错,不影响利用的流程。
访问一下 http://127.0.0.1:8089/test.txt
已经写入了。