加入收藏 | 设为首页 | 会员中心 | 我要投稿 西安站长网 (https://www.029zz.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

【学习笔记】PHP代码审计入门:代码审计实例2

发布时间:2022-12-05 13:32:44 所属栏目:PHP教程 来源:未知
导读: 第35课
代码审计实例之任意文件上传
课程入口(付费)

个人背景
李php实例,本科,电子信息工程专业,毕业一年半,有JavaScript的,PHP,Python的语言基础,目前自学网络安全中。
代码审计

第35课

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

课程入口(付费)

php实例加数据库设计_php实例_php函数实例教程

个人背景

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

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

文件上传知识背景

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

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

php函数实例教程_php实例加数据库设计_php实例

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

php实例_php实例加数据库设计_php函数实例教程

php实例_php实例加数据库设计_php函数实例教程

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

php实例_php函数实例教程_php实例加数据库设计

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

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

Content-Disposition: attachment; filename=example.html

php实例_php实例加数据库设计_php函数实例教程

如果文件名部分,没有经过过滤,传入了一些不可见的字符例如换行符\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,不难得出这个功能应该是在会员的账号相关地方有对应的入口.

php实例_php函数实例教程_php实例加数据库设计

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

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字符串做匹配,提取信息,大家如果刚入门,可能比较怕面对正则表达式,这里我推荐一个正则表达式可视化的在线工具 ,可以帮助大家理解这个正则表达式。

提取一下核心的逻辑,它保存文件的核心代码只有这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解码,然后写入文件

php实例_php实例加数据库设计_php函数实例教程

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

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

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

php实例加数据库设计_php函数实例教程_php实例

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

php函数实例教程_php实例_php实例加数据库设计

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

<?php phpinfo()?>

然后用base64编码一下 PD9waHAgcGhwaW5mbygpPz4=

php实例加数据库设计_php实例_php函数实例教程

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

php函数实例教程_php实例_php实例加数据库设计

简单拼接一下就可以得到:这个url

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

php函数实例教程_php实例_php实例加数据库设计

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

0

下期更新笔记内容:

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

php实例_php函数实例教程_php实例加数据库设计

(编辑:西安站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!