加油
文件上传漏洞介绍
文件上传漏洞,有别于文件包含漏洞,远程文件包含漏洞是由于在文件包含时,未设置合理的白名单,导致而已代码被服务器解析。
文件上传漏洞而是由于上传过滤不合理,导致恶意代码进入服务器中,两个我们都可以通过C刀获取服务器的shell.
过滤分析
无防护
观察源码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if (isset($_POST['Upload'])) {
$target_path = "uploads/";
$target_path = $target_path . basename( $_FILES['uploaded']['name']);
if(!move_uploaded_file($_FILES['uploaded']['tmp_name'], $target_path)) {
echo '<pre>';
echo '您的图片上传失败.';
echo '</pre>';
} else {
echo '<pre>';
echo $target_path . '文件已经成功上传!';
echo '</pre>';
}
}
这里的这一段代码,实现文件的上传,然而对文件未经过滤,所以我们可以上传一句话木马。1
2//一句话木马
eval($_GET['cmd']);
初级防护
观察源码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if( isset( $_POST[ 'Upload' ] ) ) {
$target_path = "uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
//识别文件类型
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
( $uploaded_size < 100000 ) ) {
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
echo "<pre>图片上传失败</pre>";
}
else {
echo "<pre>{$target_path} 图片上传成功!</pre>";
}
}
else {
echo "<pre>只允许上传jpg或者png格式的图片文件,且文件大小不能超过100k</pre>";
}
}
初级防护中,验证上传文件的类型,以及上传文件的大小。然而我们可以通过burp抓包修改相关的文件信息,来完成绕过
一般防护
观察源码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
if( isset( $_POST[ 'Upload' ] ) ) {
$target_path = "uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
//记录文件信息
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];
//识别文件后缀
if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
( $uploaded_size < 100000 ) &&
getimagesize( $uploaded_tmp ) ) {
if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {
echo "<pre>图片上传识别.</pre>";
}
else {
echo "<pre>{$target_path} 图片上传成功!</pre>";
}
}
else {
echo "<pre>只能上传格式为jpg和png的图片.</pre>";
}
}
个人认为,对于后缀名的验证和对文件类型的验证其实防护的安全性并无太大的差别,毕竟在安全方面的设置,黑名宕的检测,始终是比不过在白名单的验证,所以一个好的防护机制始终是需要归结到白名单的验证。
关键代码:1
2if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
( $uploaded_size < 100000 ) &&
由此获得文件的后缀名,这里我们呢可以通过后缀欺骗上传一句话木马1
2
3
4
5
6
7
8
9
10
11
12
13假设网站只能上传图片文件并在后台欧了后缀的限制
此时你要上传一个shell.php的一句话木马
将”shell.php”改为”shell.php 1.png”
使用burpsuite截断代理,拦截数据包
将”shell.php 1.png”发送至decoder模块,从text模式转换为hex编辑模式,找到”shell.php 1.png”中空格对应的hex值“20”,将20改为00
从hex模式恢复为text并将修改过的字符串替换原来报文中的”shell.php 1.png”
发送报文,操作成功后会显示文件上传成功
或者通过图片一句话木马实施绕过。
较完善的防护
1 |
|
添加了sessionToken,验证会话身份,用于防止csrf攻击
使用md5( uniqid() . $uploaded_name )函数,uniqid()函数是根据当前的时间,生成一个唯一的id,跟大多数随机函数一样,基于时间的随机函数在一定条件下也是可以差生碰撞的,因此本例中采用了md5()函数来保证生成id的唯一性,而且由于md5()函数对上传的文件名进行了重命名,因此无法使用00截断的方式来上传php或者其他恶意脚本文件。
以白名单的方式限制上传的文件后缀
限定上传的文件大小不得超过10000
通过imagecreatefromjpeg()和imagecreatefrompng()函数将上传的图片文件重新写入到一个新的图片文件中,这两个函数会自动将图片中的有害元数据抹除,因此即使黑客上传了一张图片马也会被这个函数过滤成一个纯正的图片。
imagedestroy( $img )将用户上传的源文件删除
unlink( $temp_file )删除过滤过程中产生的任何临时文件