工具&环境
工具:Seay源代码审计系统,文本编辑器一个
环境:phpstudy,网站源码是 zbzcms
步骤
1, 将zbzcms网站源码放入phpstudy,根据网站安装引导完成网站搭建;
2,打开Seay,新建项目 --> 选择网站源码 --> 自动审计,审计完成后点击 漏洞描述对审计结果进行排序,方便结果查看:
3,审计完成,关注存在文件上传这一类,对结果进行观察,一般存在文件上传的地方存在upload,include,up等关键词,然后再看,发现也有文件上传在admin目录下的,这种我们可以猜测是需要登录以后进行上传的,所以首先关注非admin目录下的文件上传点:
4,这里以/cms/cms/include/up.php这个文件为例,首先双击这条结果,进入up.php存在文件上传的地方:
可以先对这个页面进行访问:
提示参数有误,说明需要进行传参,然后观察函数,move_uploaded_file,这是一个php函数,直接查看php手册,对于函数,主要观察三个点,函数的功能是什么,函数需要传入什么参数,函数返回的结果:
move_uploaded_file( string $filename, string $destination):
功能:move_uploaded_file — 将上传的文件移动到新位置
参数:$filename 文件名, $destination 文件移动的最终位置
返回结果:true 或者 false
通过php手册可知,这个函数在这里的功能就是将文件名为 $tmp_name的文件,移动到路径为$path的路径下;
因此,对$tmp_name 和 $path 进行全文追踪,查看这两个变量从哪里来的,并且是否可控,全文追踪:选中变量 -->鼠标右键 --> 全文追踪:
通过全文追踪结果可以看到,$tmp_name 来自一个数组$arr[‘tmp_name’],进而追踪数组 arr 是在foreach 遍历赋值中,通过 $_FILES 产生的,而 $_FILES 是个全局变量,再次查看php手册:
全局变量 $_FILES 包含有所有上传的文件信息。数组的内容来自以下范例表单。我们假设文件上传字段的名称如下例所示,为 userfile。名称可随意命名。
$_FILES['userfile']['name']
客户端机器文件的原名称。
$_FILES['userfile']['type']
文件的 MIME 类型,如果浏览器提供此信息的话。一个例子是"image/gif"。不过此 MIME 类型在 PHP 端并不检查,因此不要想当然认为有这个值。
$_FILES['userfile']['size']
已上传文件的大小,单位为字节。
$_FILES['userfile']['tmp_name']
文件被上传后在服务端储存的临时文件名。
$_FILES['userfile']['error']
简单来说,$_FILES是一个全局数组,用于存放上传文件的临时文件名,文件类型,文件大小等重要字段,并且要为POST上传
通过php手册可以得知,我们可以POST以方式上传文件,对$_FILES数组产生影响,进入影响$tmp_name
接下来对$path 进行全文追踪:
通过全文追踪可以看到,$path 是通过$_GET全局变量获取的,而$_GET全局变量就是从url中get传参获取的,因此$path这个变量是可控的;
代码再往上,我们可以看到有一个if判断,只有 $run 的值为file ,才能进入文件上传,再进行全文追踪查看$run ,可以发现$run 变量是从GET传参获取的:
至此,总结审计流程,进行利用:
* move_uploaded_file() 具有文件移动功能,需要提供$tmp_name ,$path 两个参数;
* $tmp_name可以通过post方式上传文件,影响$_FILES,进而影响$tmp_name,因此需要本地构建一个POST方式的文件上传表单,可控;
* $path为 文件上传路径,通过get 传参 path获取,可控;
* $run 是通过get传参获得,并且值一定要为 file 才能执行文件上传,可控;
* 在审计过程中还发现,如果$path的值,也就是路径在目标上不存在,则会创建新的目录;
* $filename 通过get传参获得,并且它的值会影响文件上传之后的文件名,为1时不更改文件名,为 0时会将时间戳拼接进文件名,
因此还需要将 $filename的值置为 1,方便文件上传之后的访问,可控;
利用:
本地构造文件上传表单,将run置为file使得程序进入上传功能,path设置为当前文件夹,也就是上传到当前文件夹下,filename置为1不更改上传之后的文件名,提交方式为post,enctype=“multipart/form-data”上传文件一定要写:
<html>
<head>
<meta charset="utf-8">
<title>test</title>
</head>
<body>
<form action="http://zbzcms.com/cms/cms/include/up.php?run=file&filename=1&path=./" method="post" enctype="multipart/form-data">
<label for="file">文件名:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="提交">
</form>
</body>
</html>
构造完成后直接双击浏览器打开,上传一个1.php, 内容为<?php phpinfo(); ?>
:
此时访问1.php,显示出当前php版本等信息即上传成功:
(文末声明:仅供学习参考)