安全代码审计TP5框架及无框架变量覆盖反序列化
Yatming的博客
Metinfo-变量覆盖
phpmydmin-无框架-反序列化
搜索反序列化关键函数:serialize()
,unserialize()
,__construct
,__destruct

$_POST['configuration']
存在,并且变量action
不等于clear
,就调用反序列化函数

php魔术方法,反序列化会触发__wakeup()
- __wakeup() : 使用
unserialize()
时触发
- __sleep() : 使用
serialize()
时触发
- __destruct() : 对象被销毁时触发
- __call() : 在对象上下文中调用不可访问的方法时触发
- __callStatic() : 在静态上下文中调用不可访问的方法时触发
- __get() : 用于从不可访问的属性读取数据
- __set() : 用于将数据写入不可访问的属性
- __isset() : 在不可访问的属性上调用
isset()
或empty()
触发
- __unset() : 在不可访问的属性上使用
unset()
时触发
- __toString() : 把类当作字符串使用时触发
- __invoke() : 当脚本尝试将对象调用为函数时触发



为什么是找wakeup,因为上面有说这里使用unserialize的时候就会触发

英文注释是:在加载完session文件后,重新初始化对象,检查配置文件的是否改变,如果必要就重新加载
简单分析:getsource获取源码,filemtime() 函数返回文件内容的上次修改时间。成功,以 Unix 时间戳形式返回文件内容的上次修改时间。如果失败,则返回 FALSE。这里是检测源码的目前时间和返回的时间戳不等。(或者是默认源码的修改)
1 2 3 4 5 6 7 8 9 10 11
| ---load方法,根据判断file_get_contents是否存在来进行代码执行
---file_get_contents()将整个文件读取为字符串
---trim() 函数移除字符串两侧的空白字符或其他预定义字符。
---implode() 函数返回由数组元素组合成的字符串
---因此,这里是代码执行getsource的文件的代码
---getsource是返回目前的配置文件(小迪说是获取源代码)
|
总结:调用反序列函数,会调用创建对象的类中的wakeup方法,进而调用代码执行getsource(注意,这个getsource是对象的方法,要构造getsource就要在对象的类里面构造)
因此,我们要利用这个漏洞有两点:1.满足调用反序列化函数的条件2.满足wakeup方法里面load的条件(从这里构造payload)



访问这个路径
在电脑中的盘符中创建一个test.txt文件,然后写入内容:woaixiaodi
,然后传入下面的值
Payload:action=1&configuration=O:10:"PMA_Config":1:{s:6:"source",s:11:"E:/test.txt";}
1
| 序列化的格式(注意这里构造payload可以不是类真实的属性):对象名称:PMA_Config;长度:10;1个属性,格式为字符串形式,名为:source,长度为6,属性的内容:d:/test.txt,长度为11
|

这里就会出现文件中的内容
如果这里的内容是恶意代码的话也会被执行


总结:这里就是先载入字符串,然后使用eval将载入的字符串当做php代码执行
Thinkphp5—有框架-搭建使用入口访问调试 SQL 等
安装,由于安装thinkphp5,官网已经没有下载了,所以去github上进行下载
https://github.com/top-think/think/
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| git clone https://github.com/top-think/think.git thinkphp5 //这里的https可能会报错,下载不了,改成http试试,thinkPHP5是安装的目录
//然后进入到thinkphp5的目录 git checkout v5.0.15
//返回上一级目录 git clone https://github.com/top-think/framework.git thinkphp
//安装好之后同样进入thinkphp目录 git checkout v5.0.15
//查看版本 git branch -a
|
参考博客:
https://www.cnblogs.com/lpxspring/p/12129136.html
https://blog.csdn.net/LingTing12116/article/details/108395121


thinkphp的目录结构
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 40 41 42 43 44 45 46
| project 应用部署目录 ├─application 应用目录(可设置) │ ├─common 公共模块目录(可更改) │ ├─index 模块目录(可更改) │ │ ├─config.php 模块配置文件 │ │ ├─common.php 模块函数文件 │ │ ├─controller 控制器目录 │ │ ├─model 模型目录 │ │ ├─view 视图目录 │ │ └─ ... 更多类库目录 │ ├─command.php 命令行工具配置文件 │ ├─common.php 应用公共(函数)文件 │ ├─config.php 应用(公共)配置文件 │ ├─database.php 数据库配置文件 │ ├─tags.php 应用行为扩展定义文件 │ └─route.php 路由配置文件 ├─extend 扩展类库目录(可定义) ├─public WEB 部署目录(对外访问目录) │ ├─static 静态资源存放目录(css,js,image) │ ├─index.php 应用入口文件 │ ├─router.php 快速测试文件 │ └─.htaccess 用于 apache 的重写 ├─runtime 应用的运行时目录(可写,可设置) ├─vendor 第三方类库目录(Composer) ├─thinkphp 框架系统目录 │ ├─lang 语言包目录 │ ├─library 框架核心类库目录 │ │ ├─think Think 类库包目录 │ │ └─traits 系统 Traits 目录 │ ├─tpl 系统模板目录 │ ├─.htaccess 用于 apache 的重写 │ ├─.travis.yml CI 定义文件 │ ├─base.php 基础定义文件 │ ├─composer.json composer 定义文件 │ ├─console.php 控制台入口文件 │ ├─convention.php 惯例配置文件 │ ├─helper.php 助手函数文件(可选) │ ├─LICENSE.txt 授权说明文件 │ ├─phpunit.xml 单元测试配置文件 │ ├─README.md README 文件 │ └─start.php 框架引导文件 ├─build.php 自动生成定义文件(参考) ├─composer.json composer 定义文件 ├─LICENSE.txt 授权说明文件 ├─README.md README 文件 ├─think 命令行入口文件
|

url访问的方法(比如上面的index.php文件就是:APPlication目录下的index目录(模块),index.php文件(控制器),index()方法(操作))

这里新建一个新的方法test


在index.php目录下创建Test.php文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php namespace app\index\controller; use think\Controller; use think\Db;
class Test extends Controller{ public function x(){ echo 'xiaodi-testhhhhh'; } public function testsqlin(){ $id = $_GET['x']; $conn = mysql_connect("127.0.0.1","root","123.com"); $sql = "select * from user where id=$id"; echo $sql; $result=mysql_query($sql,$conn); } } ?>
|

这里的文件名的首字母好像是必须要大写,不能是test,需要Test

这里沙漠里的鲸
使用的php的版本是5.6,我用的是5.4的,所以语句还是老样子:mysql_query($sql,$conn);
,这里鲸鱼哥还写了判断连接的if,我这里就没有写了


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <?php namespace app\index\controller; use think\Controller; use think\Db;
class Test extends Controller{ public function x(){ echo 'xiaodi-testhhhhh'; } public function testsqlin(){ $id = $_GET['x']; $conn = mysql_connect("127.0.0.1","root","123.com"); $sql = "select * from test.user where id=$id"; echo $sql; $result=mysql_query($sql,$conn); } public function testsqlin1(){ $id=$_GET['x']; db('user')->where('id',$id)->select(); } } ?>
|



不开启调试模式,单纯的使用审计工具的mysql监控是监控不到的,github上的那种web监控好像可以(沙漠里的鲸说可以),这里我就不做实验了。

总结:
1 2 3 4 5
| 如果发现thinkphp框架,存在以下思路:
如果按照thinkphp官方的写法去写的,那么你所面对的就是去挖掘thinkphp框架的漏洞,这里最好知道thinkphp的版本,这样就可以去百度有没有这个版本的漏洞,如果有就去验证,没有就pass了
还有一种就是使用的的确是thinkphp的框架,但是没有利用框架,和上面的两个sql查询的方法一样,那么这种就是常规的审计思路
|