PHP代码审计之WEB安全系列基础文章(二)之任意文件上传篇

【如需转载,请详细表明来源,请勿设置原创】

嗨,大家好,我是闪石星曜CyberSecurity创始人Power7089。

欢迎大家扫描下方二维码关注 “闪石星曜CyberSecurity” 公众号,这里专注分享渗透测试,Java代码审计,PHP代码审计等内容,都是非常干的干货哦。

公众号

今天为大家带来PHP代码审计基础系列文章第二篇之任意文件上传篇

这是【炼石计划@PHP代码审计】知识星球第二阶段的原创基础系列文章,拿出部分课程分享给零基础的朋友学习。本系列原创基础文章涵盖了PHP代码审计中常见的十余种WEB漏洞,是匹夫老师精心的创作,欢迎关注我的公众号跟着一起学习。

【炼石计划@PHP代码审计】是一个系统化从入门到提升学习PHP代码审计的成长型知识星球。这里不仅注重夯实基础,更加专注实战进阶。强烈推荐加入我们,一起来实战提升PHP代码审计。

公众号

PHP代码审计之文件上传

1.文件上传原理

将Web木马插入到服务器并且服务器端可以成功解析插入的Web木马

何为上传的Web木马被解析:最简单的例子就是目标服务器后端用PHP语言,那么针对上传的文件我们就要利用PHP木马进行上传,且后缀为.PHP

是否存在上传漏洞的前提条件是:①存在上传点 ②上传点的内容可控③上传的文件可被解析

1.1 文件上传业务流程

通过前端页面上传恶意文件到后端,服务器接收到文件后先将他存储为临时文件,将临时文件移动到信的位置,然后攻击者访问该文件,恶意文件被解析后返回该恶意文件内容。

1654354608439

2.2文件上传利用条件

①Web站点具有上传功能点

②上传的目标文件可被Web服务器解析

③已知上传的目标文件路径以及文件名

④目标文件可被访问

​ 在某种情况下服务器会对上传的文件进行访问控制,也就是说即使将目标文件上传到服务器也无法对其进行访问,无法进一步利用。

1.3 文件上传示例代码

index.html

form标签中action属性定义在哪个文件实现后端文件上传功能,method属性定义上传方式,enctype属性定义上传类型,如果不写浏览器将根据上传文件,自行判断上传文件类型

input标签type属性定义input标签将内容当做什么类型来处理,name属性定义上传文件名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传小demo</title>
</head>
<body>
<form action="demo.php" method="post" enctype="multipart/form-data">
<p>请选择上传的文件:</p>
<input class="upload_file" type="file" name="uploadFile"/>
<input class="button" type="submit" name="submit" value="上传" />
</form>
</body>
</html>

demo.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
if(is_uploaded_file($_FILES["uploadFile"]["tmp_name"]))
{
$upFile = $_FILES["uploadFile"];
$name = $upFile["name"];
$type = $upFile["type"];
$size = $upFile["size"];
$tmpName = $upFile["tmp_name"];

var_dump($upFile);

$path = "./".$name;
move_uploaded_file($tmpName,$path);

echo "文件上传成功";
}else
{
echo "文件上传失败";
}

?>

上传dog.jpg作为演示文件

uploadFile就是index.htmlinput标签中name属性值,上传成功后会通过var_dump()函数以键值对的形式打印出$_FILES中保存的所有值。

值得注意的是文件被上传后,默认地会被存储为临时文件(phpBD6C.tmp),需使用move_uploaded_file()函数将临时文件进行移动存储,如果不进行移动在上传代码运行完成之后临时文件将被删除,文件将不会被保存。

1654408275498

1.3.1 PHP超全局变量以及函数介绍

$_FILES

PHP中的超全局变量,用来接收上传文件的所有内容,$_FILES是一个二维数组,数组内容如下:

1
2
3
4
5
$_FILES['uploadFile']['name']   客户端文件的原名称。 
$_FILES['uploadFile']['type'] 文件的 MIME 类型,例如"image/gif"
$_FILES['uploadFile']['size'] 已上传文件的大小,单位为字节。
$_FILES['uploadFile']['tmp_name'] 文件被上传后在服务端储存的临时文件名,一般是系统默认。可以在php.ini的upload_tmp_dir指定。
$_FILES['uploadFile']['error'] 该文件上传相关的错误代码。

var_dump()

1654407862223

is_uploaded_file()

1654407920731

move_uploaded_file()

如果移动过程中文件名重复,则会覆盖以后文件。

1654407955093

2.文件上传检测类型

文件上传最重要的是对上传文件的类型进行检测,相关检测方式如下如:

2.1 代码示例

这里代码为前端JS检测代码,上述提到的检测类型代码以及绕过方式会在Upload-Labs靶场中为大家一一讲解。

upload_index.html

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传JS检测demo</title>
</head>
<body>
<form action="demo.php" method="post" enctype="multipart/form-data" onsubmit="return checkFile()">
<p>请选择上传的文件:</p>
<input class="upload_file" type="file" name="uploadFile"/>
<input class="button" type="submit" name="submit" value="上传" />


</form>


</body>
</html>

<script type="text/javascript">
function checkFile() {
//获取数组下标为0的值,也就是上传的文件名
var file = document.getElementsByName('uploadFile')[0].value;
if (file == null || file == "") {
alert("请选择要上传的文件!");
return false;
}
//定义允许上传的文件类型
var allow_ext = ".jpg|.png|.gif";
//提取上传文件的类型
var ext_name = file.substring(file.lastIndexOf("."));
//判断上传文件类型是否允许上传
if (allow_ext.indexOf(ext_name) == -1) {
var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
alert(errMsg);
return false;
}
}
</script>

2.2 绕过方式

上传.php文件,提示不允许上传

修改后缀名为.jpg,并使用burp抓包修改将后缀修改回原来的.php绕过js检测

1654409150967

1654409373369

3.文件上传代码审计总结

1
本次只对文件上传原理以及上传代码如何进行实现进行简单介绍,目的是让大家了解文件上传中前后端代码是如何进行分工配合实现文件上传的。在文件上传代码审记中重点要关注的是上传检测部分的代码,通过审计该部分代码来绕过文件上传检测。后续在Upload-Labs靶场部分会对上述所提到的所有上传检测代码以及绕过方式进行一一介绍以及实战演示。

PHP代码审计之WEB安全系列基础文章(二)之任意文件上传篇
http://example.com/2022/10/10/PHP代码审计之WEB安全系列基础文章(二)之任意文件上传篇/
作者
Power7089
发布于
2022年10月10日
许可协议