php post读图片_【学习笔记】PHP代码审计入门:代码审计实例2

第  35    

 代码审计实例之任意文件上传 

课程入口(付费)

a0266de03a74b32a6637cd5d8c28d777.png

个人背景

李,本科,电子信息工程专业,毕业一年半,有JavaScript的,PHP,Python的语言基础,目前自学网络安全中。

代码审计实例之任意文件上传

文件上传知识背景

文件上传这个功能在大部分系统中都存在,但是要做好一个文件上传和下载功能的话就非常吃经验,因为涉及到很多的边界条件. 首先,文件上传首先就要校验文件类型是否在允许范围内,而确定一个文件类型恰恰是最难的事情.

而在Web的场景里,浏览器在上传文件的时候,会提供一个Content-Type,作为后端的一个参考

       3bf183eaf323263928c3bbbc48c36ea6.png      

同时上传的文件信息会在PHP的$_FILES数组里,这个数组同时也会出现Content-Type信息,因为这个信息实在是太方便了,很多人在学习的时候就会直接把它当作是文件的类型来处理,一直延续着这个习惯.

       24761caa364cafe04a5c687cdcc61a5f.png

 81e4c01a68b76f55ba07124d80c32461.png

在文件上传之后,如何保存也是一个问题.我总结成了6个字,就是不解析,不执行.

       3df5a6fdb23794385ab404eafe461334.png      

任何逃离了这个设定的上传和下载功能,都会造成问题。

下载功能,让浏览器弹出下载.一般是在响应头中,设置一个Content-Disposition信息

Content-Disposition: attachment; filename=example.html

       54333d9e7e707073585a9a8450641450.png      

如果文件名部分,没有经过过滤,传入了一些不可见的字符例如换行符\n,会导致这一行作废,换而言之浏览器就不会弹出下载,而是依据响应头中Content-type的信息再次判断,在这里就有可能让一个下载html的行为变成了渲染html。

Content-Disposition: attachment; filename=example\n.html

所以搜索Content-Disposition: attachment;这种代码,然后查看调用的上下文,审计文件名部分是否可控,也是一个审计的技巧。

 finecms5.0.8文件上传分析 

准备的CMS是finecms 5.0.8。

首先,这套系统存在我们刚刚说的base64图片上传功能,可以通过base64,来定位看到这个函数的注释,已经很明显地发现是一个头像上传功能,根据文件所在的路径结构finecms/dayrui/controllers/member/Account.php,不难得出这个功能应该是在会员的账号相关地方有对应的入口.

       5eca08eb5e89dcd05928d2b0edf0ad12.png      

我们先接着分析,前几行根据注释都能知道是创建存放图片文件夹的代码,我们重点关注下面的上传流程.

if ($_POST['tx']) {
$file = str_replace(' ', '+', $_POST['tx']);
if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $file, $result)){
$new_file = $dir.'0x0.'.$result[2];
if (!@file_put_contents($new_file, base64_decode(str_replace($result[1], '', $file)))) {
exit(dr_json(0, '目录权限不足或磁盘已满'));
}

这里是保存文件的逻辑代码.如果你看过项目的说明,就会知道这个项目是基于CodeIgniter这个PHP框架写的.这个框架获取$_POST数组,也是有封装的,对应的是$this→input→post()

然而在这里直接出现了$_POST['tx'],这种代码,并没有按照框架的约定用$this→input→post()代替,是一个不规范的写法.就我个人的开发经验而言,当在代码中开始不遵守规范的时候,就是容易犯错的时候,所以就要对接下来的代码重点关注了。

我们看下面一行代码

preg_match('/^(data:\s*image\/(\w+);base64,)/', $file, $result)

这里有一个正则表达式,用于对base64字符串做匹配,提取信息,大家如果刚入门,可能比较怕面对正则表达式,这里我推荐一个正则表达式可视化的在线工具 https://jex.im/regulex ,可以帮助大家理解这个正则表达式。

提取一下核心的逻辑,它保存文件的核心代码只有这4行

$file = str_replace(' ', '+', $_POST['tx']);
preg_match('/^(data:\s*image\/(\w+);base64,)/', $file, $result)
$new_file = $dir.'0x0.'.$result[2];
file_put_contents($new_file, base64_decode(str_replace($result[1], '', $file)))

这4行的作用分别是:

1.替换base64字符串中的空格为加号

2.利用正则表达式提取base64字符串的信息,把匹配到的信息放入$result数组

3.拼接上传文件的路径,文件名中扩展名部分从上面正则表达式中匹配结果的第2组而来

4.把base64字符串去掉前面几个字节中和格式相关的内容,然后做base64解码,然后写入文件

       dda735e98b0dfc2b23e63fb60194874a.png      

这段代码,在保存文件的时候,文件名中的扩展名部分,只是把来自正则表达式检测base64中的结果第2组信息作为扩展名,并没有对于扩展名进行丝毫的验证,根据可视化工具的提示,第3组信息的位置是 image/的后面,;base64,的前面。第2组信息,是我们完全可控的,后面文件内容部分也是我们可控的,那么不难分析出这里可以存在一个任意文件上传的漏洞.

只需要构造一个类似base64图片的字符串,在这个正则表达式的第2组位置填入我们想要生成的文件的扩展名如php,然后在文件信息的位置写入PHP代码,然后把PHP代码base64编码一下,就可以形成一个payload了.

我们先确认这段代码的入口,在这里我就直接告诉大家对应的入口是在前台的会员的头像上传处.

       9fe93910a4abed370d1aab6338d3a6da.png

这里我选一个1kb大小的图片作为头像,上传的时候抓包

       f2a895a3f684ed9e24e89407430ae665.png       

把代表文件格式的png改成php,代表图片内容的字符串改成一个简单的PHP代码

然后用base64编码一下 PD9waHAgcGhwaW5mbygpPz4=

       f2cca831cb63870f385e2f124a2f8d7a.png      

上传之后的路径,分析代码甚至是把项目目录下文件夹一个一个打开找,就可以得出是在/uploadfile/member/用户id/0x0.扩展名这个路径下。而这个用户id非常好获取,查看浏览器cookie,或者是从刚刚数据包中cookie信息就知道我这个用户的id是3

       1ffb6f0d4c0dd3839dce60b03a1c3d94.png      

简单拼接一下就可以得到:http://finecms.com.test/uploadfile/member/3/0x0.php这个url

实际访问一下,就可以发现成功访问到我们的PHP文件,并且服务端解析了并运行了这个PHP文件

       3df69a3390588f5cc0b1da34a0b5cbf0.png      

任意文件上传的代码审计就到这里,同学们可以在课后利用github的代码搜索功能,尝试自己挖掘一个任意文件上传或者是下载文件截断导致html代码被执行的漏洞。

0

下期更新笔记内容:

PHP代码审计入门:代码审计实例3

032a6ad1e48a888cfb4717f6b4799732.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值