漏洞描述
开发中文件上传功能很常见,作为开发者,在完成功能的基础上我们一般也要做好安全防护。
文件处理一般包含两项功能,用户上传和展示文件,如上传头像。
文件上传攻击示例
upload.php
|
1
2
3
4
5
6
7
8
9
10
|
<?php
$uploaddir = 'uploads/';
$uploadfile = $uploaddir . basename($_files['userfile']['name']);
if (move_uploaded_file($_files['userfile']['tmp_name'], $uploadfile)){
echo "file is valid, and was successfully uploaded.\\n";
}
else {
echo "file uploading failed.\\n";
}
?>
|
upload.html
|
1
2
3
4
|
<form name="upload" action="upload1.php" method="post" enctype="multipart/formdata">
select the file to upload: <input type="file" name="userfile">
<input type="submit" name="upload" value="upload">
</form>
|
上述代码未经过任何验证,恶意用户可以上传php文件,代码如下
<?php eval($_get['command']);?>
恶意用户可以通过访问 如http://server/uploads/shell.php?command=phpinfo(); 来执行远程命令
content-type验证
upload.php
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?php
if($_files['userfile']['type'] != "image/gif") {//获取http请求头信息中contenttype
echo "sorry, we only allow uploading gif images";
exit;
}
$uploaddir = 'uploads/';
$uploadfile = $uploaddir.basename($_files['userfile']['name']);
if (move_uploaded_file($_files['userfile']['tmp_name'], $uploadfile)){
echo "file is valid, and was successfully uploaded.\\n";
} else {
echo "file uploading failed.\\n";
}
?>
|
该方式是通过http请求头信息进行验证,可通过修改content-type ==> image/jpg绕过验证,可以通过脚本或burpsuite、fiddle修改
如下
content-disposition: form-data; name="userfile"; filename="shell.php"
content-type: image/gif
图片类型验证
该方法通过读取文件头中文件类型信息,获取文件类型
备注:如jpeg/jpg文件头标识为ffd8
upload.php
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<?php
$imageinfo = getimagesize($_files['userfile']['tmp_name']);
if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg') {
echo "sorry, we only accept gif and jpeg images\\n";
exit;
}
$uploaddir = 'uploads/';
$uploadfile = $uploaddir . basename($_files['userfile']['name']);
if (move_uploaded_file($_files['userfile']['tmp_name'], $uploadfile)){
echo "file is valid, and was successfully uploaded.\\n";
} else {
echo "file uploading failed.\\n";
}
?>
|
可以通过图片添加注释来绕过此验证。
如添加注释<?php phpinfo(); ?>,保存图片后将其扩展名改为php,则可成功上传。
上传成功后访问该文件则可看到如下显示
文件扩展名验证
通过黑名单或白名单对文件扩展名进行过滤,如下代码
upload.php
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<?php
$blacklist = array(".php", ".phtml", ".php3", ".php4");
foreach ($blacklist as $item) {
if(preg_match("/$item\\$/i", $_files['userfile']['name'])) {
echo "we do not allow uploading php files\\n";
exit;
}
}
$uploaddir = 'uploads/';
$uploadfile = $uploaddir . basename($_files['userfile']['name']);
if (move_uploaded_file($_files['userfile']['tmp_name'], $uploadfile)){
echo "file is valid, and was successfully uploaded.\\n";
} else {
echo "file uploading failed.\\n";
}
?>
|
当黑名单不全,构造特殊文件名可以绕过扩展名验证
直接访问上传的文件
将上传文件保存在非web root下其他文件夹下,可以防止用户通过路径直接访问到文件。
upload.php
|
1
2
3
4
5
6
7
8
9
|
<?php
$uploaddir = 'd:/uploads/';
$uploadfile = $uploaddir . basename($_files['userfile']['name']);
if (move_uploaded_file($_files['userfile']['tmp_name'], $uploadfile)) {
echo "file is valid, and was successfully uploaded.\\n";
} else {
echo "file uploading failed.\\n";
}
?>
|
用户不可以直接通过http://localhost/uploads/ 来访问文件,必须通过view.php来访问
view.php
|
1
2
3
4
5
|
<?php
$uploaddir = 'd:/uploads/';
$name = $_get['name'];
readfile($uploaddir.$name);
?>
|
查看文件代码未验证文件名,用户可以通过例如http://localhost/view.php?name=..//php/upload.php,查看指定的文件
解决漏洞示例
upload.php
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?php
require_once 'db.php';
$uploaddir = 'd:/uploads/';
$uploadfile = tempnam($uploaddir, "upload_");
if (move_uploaded_file($_files['userfile']['tmp_name'], $uploadfile)) {
$db =& db::connect("mysql://username:password@localhost/database");
if(pear::iserror($db)) {
unlink($uploadfile);
die "error connecting to the database";
}
$res = $db->query("insert into uploads set name=?, original_name=?,mime_type=?",
array(basename($uploadfile,basename($_files['userfile']['name']),$_files['userfile']['type']));
if(pear::iserror($res)) {
unlink($uploadfile);
die "error saving data to the database. the file was not uploaded";
}
$id = $db->getone('select last_insert_id() from uploads');
echo "file is valid, and was successfully uploaded. you can view it <a href=\\"view.php?id=$id\\">here</a>\\n";
} else {
echo "file uploading failed.\\n";
}
?>
|
view.php
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<?php
require_once 'db.php';
$uploaddir = 'd:/uploads/';
$id = $_get['id'];
if(!is_numeric($id)) {
die("file id must be numeric");
}
$db =& db::connect("mysql://root@localhost/db");
if(pear::iserror($db)) {
die("error connecting to the database");
}
$file = $db->getrow('select name, mime_type from uploads where id=?',array($id), db_fetchmode_assoc);
if(pear::iserror($file)) {
die("error fetching data from the database");
}
if(is_null($file) || count($file)==0) {
die("file not found");
}
header("content-type: " . $file['mime_type']);
readfile($uploaddir.$file['name']);
?>
|
上述代码文件名随机更改,文件被存储在web root之外,用户通过id在数据库中查询文件名,读取文件,可以有效的阻止上述漏洞发生
总结
通过以上示例分析,可总结一下几点
1.文件名修改,不使用用户上传的文件名
2.用户不可以通过上传路径直接访问文件
3.文件查看采用数据库获取文件名,从而在相应文件服务器读取文件
4.文件上传限制文件大小,个人上传数量等
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持快网idc。
相关文章
- 个人网站搭建:如何挑选具有弹性扩展能力的服务器? 2025-06-10
- 个人服务器网站搭建:如何选择适合自己的建站程序或框架? 2025-06-10
- 64M VPS建站:能否支持高流量网站运行? 2025-06-10
- 64M VPS建站:怎样选择合适的域名和SSL证书? 2025-06-10
- 64M VPS建站:怎样优化以提高网站加载速度? 2025-06-10
- 2025-07-10 怎样使用阿里云的安全工具进行服务器漏洞扫描和修复?
- 2025-07-10 怎样使用命令行工具优化Linux云服务器的Ping性能?
- 2025-07-10 怎样使用Xshell连接华为云服务器,实现高效远程管理?
- 2025-07-10 怎样利用云服务器D盘搭建稳定、高效的网站托管环境?
- 2025-07-10 怎样使用阿里云的安全组功能来增强服务器防火墙的安全性?
快网idc优惠网
QQ交流群
-
2025-05-27 43
-
2025-06-04 74
-
2025-05-29 20
-
2025-05-25 74
-
2025-06-05 71



