CTF中的命令执行及Bypass
- 做题时发现bash的命令执行特性都不懂…白在win下的cmd试了那么久,于是乎决定总结一下
- 准确来说应该是利用Linux下bash的特性,进行一下过滤绕过
参考1:https://mp.weixin.qq.com/s/Hm6TiLHiAygrJr-MGRq9Mw
参考2(和参考1一样):https://blog.zeddyu.info/2019/01/17/%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C/
各种符号及其作用
分号
分号;
隔开命令,从左到右依次执行,不管成功或者失败,所有命令都会执行
管道符
管道符|
上一条命令的输出作为下一条命令的参数
逻辑或
||
左边为真则右边不执行,||
左边为假则继续执行右边
逻辑与
&&
先执行左边,左边为真则继续执行右边,否则不执行右边
后台进程
&
放在启动参数里表示设置此进程为后台进程(也即不会占用shell)
若连接两条命令则表示先执行右边再执行左边(先执行右再执行左不等于执行完右再执行左!)
1 | [1] 26925 |
第一行为将左边的命令放后台执行,第2~3行为执行右边命令的效果,第4~5行为执行左边命令的效果,第6行表示执行左边命令(后台进程结束)完成
但是我如果让右边的命令sleep个5秒
会发现本应先执行的next.py居然在before后才执行,我们再继续测试一下:
- 在before里调用命令行执行了next,并给了一个命令行参数3
- 在next里,如果有命令行参数则sleep 3秒(before给的);否则sleep5秒
可以发现next确实是先执行了,但是next在sleep 5秒的期间,before也在执行,并且由于运行时间比next短,before先执行完毕
再测试一下是不是真的后面的指令先执行:
可以看到next的time确实要比before早
因此大概可以推测:&
的本质作用是将前一条命令放在后台,接着开始执行后面的命令,但是不会等后面的命令执行完才执行前面的命令,而是在后一条指令执行的同时也在执行前一条指令
{}和()
():
- 格式:(cmd1;cmd2;cmd3…)
- 重新开一个子shell执行
{}:
格式:{ cmd1;cmd2;….cmdn;}
cmd1与左边花括号要有空格,最后一条命令要分号(我不知道这是不是真的,反正kali不用….kali的花括号和括号格式一样就行了)
在当前shell执行
区别
- 当使用
()
时,可以看到他们的ppid都为28045,而pid=28045的进程zsh是pid=26745的进程zsh的子进程,也就是说,在当前shell(pid=26745)下开了一个子shell(pid=28045),再由子shell去执行命令 - 当使用
{}
时,可以看到他们的ppid都是26745,即父进程都是pid=26745的zsh本身,没有开一个子shell
- 当使用
反引
- 命令替代,将某一指令的输出作为另一指令的输入
各种读取文件的关键字
1 | cat flag // 正序输出所有内容 |
可以把这些关键字存为一个字典,当遇到正则过滤时就fuzz一下看看有没有哪个没被过滤可以用的
文件名过滤绕过
- 用于在正则过滤例如flag文件名时的绕过
通配符绕过
字符 | 解释 |
---|---|
* | 匹配任意长度任意字符 |
? | 匹配任意单个字符 |
[list] | 匹配指定范围内(list)任意单个字符,也可以是单个字符组成的集合 |
list | 匹配指定范围外的任意单个字符或字符集合 |
[!list] | 同[^list] |
{str1,str2,…} | 匹配 srt1 或者 srt2 或者更多字符串,也可以是集合 |
IFS | 由 < space > 或 < tab > 或 < enter > 三者之一组成 |
CR | 由 < enter > 产生 |
! | 执行 history 中的命令 |
通配符*绕过
通配符?绕过
[]绕过
[]为文件名通配符,用来匹配指定范围内的任意单个字符
{}绕过
{}为集合,匹配集合内的字符串
专用字符集绕过
字符 | 意义 |
---|---|
[:alnum:] | 任意数字或者字母 |
[:alpha:] | 任意字母 |
[:space:] | 空格 |
[:lower:] | 小写字母 |
[:digit:] | 任意数字 |
[:upper:] | 任意大写字母 |
[:cntrl:] | 控制符 |
[:graph:] | 图形 |
[:print:] | 可打印字符 |
[:punct:] | 标点符号 |
[:xdigit:] | 十六进制数 |
[:blank:] | 空白字符 |
关键字绕过
- 用于正则过滤例如cat关键字的绕过
命令提示符$绕过
$*
、$@
、$x
(x=1~9)、${x}
(x>9)- 在没有传参时,这些值都为空(
$0
表示shell本身的文件名,不可用)
可以插入在任意位置(关键字、文件名均可以)
反斜杠绕过
单引连接符绕过
空格绕过
<或者<>
$IFS
$IFS在bash下为分隔符,不知道为什么kali中试不出效果(好像是zsh和bash的差异之一)
后来发现可能不同的shell对IFS的默认值设定不一样,bash的话默认是空格,所以可以用
{}绕过
又是zsh和bash的差异,{cat,flag}
可以把逗号当作空格
编码绕过
base64编码
16进制编码绕过
xxd -r -p
将纯16进制转储读入$()
执行括号中语句的执行结果
命令执行
利用编码+shell
- 16进制:
echo hexString|xxd -r -p|bash
- base64:
echo base64String|base64 -d|bash
变量拼接
有一个要注意的,如果是a=l;cat f$aag
的话,他会把$aag
当作一个变量,而我们没有定义这个变量从而读不到flag
内联执行
反引号``(汗了md里怎么在行内代码打出反引….)和$()
:将其中命令的输出作为输入执行(新生赛就有一道题用了这个trick然而我不懂…在win下呆呆试了半天没绕过去)
长度限制的getshell
- 这个看了一下相关博客,当场直呼
牛b内行,放在这里讲有点糟蹋了,打算另起一篇总结一下