2019年的Positive Hack Days
包括有史以来第一次IDS Bypass
比赛。 参与者必须研究五个主机的网段,然后利用服务漏洞或满足特定标准(例如发送某个HTTP响应)以获得flag。 找到漏洞很容易,但是IDS会让参与者和主机之间的连接变得复杂,检查每个网络数据包。 当签名阻止连接时,通过屏幕通知参与者。 以下是有关任务的详细信息以及解决这些问题的方法。
相比较来说,多个参与者解决了Struts
任务。 使用Nmap进行端口扫描后,用户可以在端口8080上找到Apache Struts。
# nmap -Pn -sV -p1-10000 100.64.0.11
631/tcp open ipp CUPS 2.1
8005/tcp open mxi?
8009/tcp open ajp13 Apache Jserv (Protocol v1.3)
8080/tcp open http Apache Tomcat/Coyote JSP engine 1.1
使用2017年的Apache Struts
漏洞,攻击者可以执行OGNL
注入以获取远程代码执行(RCE)。 可以使用漏洞(例如在GitHub上),但IDS
可以轻松检测到它:
[Drop] [**] [1:1001:1] Apache Struts2 OGNL inj in header (CVE-2017-5638) [**]
参与者无法使用签名代码。 但是日志消息清楚地说明了它是如何工作的。 在这种情况下,签名检测到OGNL
注入HTTP
:
GET /showcase.action HTTP/1.1
Accept-Encoding: identity
Host: 100.64.0.11:8080
Content-Type: %{(#_='multipart/form-data')...
研究IDS
的行为后,很明显IDS
正在对Content-Type
标头开头的组合%{
做出反应。 以下有几种方法:
1 @empty_jack
尝试使用他自己的字典分隔%{
符号进行模糊测试,使用字符串Content-Type:%$ {
进行解决。
2 模糊HTTP请求本身。@ c00lhax0r
发现标题开头的空符号也会滑过IDS:Content-Type:\ 0 $ {
。
3 CVE-2017-5638
的大多数漏洞都以百分号注入。 然而,一些研究此类Apache Struts
漏洞的研究人员声称,注入可以很容易地从$
开始。 因此组合$ {
将绕过IDS签名并在系统上执行代码。 这是我们最初想到的解决方案。
这项任务最简单:八位参与者找到了解决方案。
端口8983托管了一个Apache Solr服务器(用Java编写)。
$ nmap -Pn -sV -p1-10000 100.64.0.10
22/tcp open ssh (protocol 2.0)
8983/tcp open http Jetty
查找Apache Solr 5.3.0
的漏洞利用很简单:CVE-2019-0192。 攻击者可以欺骗集合中的RMI服务器的地址。 利用需要ysoserial框架,它生成Java对象链并以各种方式提供它们。 例如使用JRMP
服务器。
当然,继续使用漏洞而不首先使用它只会触发IDS:
[Drop] [**] [1:10002700:3001] ATTACK [PTsecurity] Java Object Deserialization RCE POP Chain (ysoserial Jdk7u21) [**]
Jdk7u21
只是30种可能的payload之一。 payload的选择取决于易受攻击的服务中使用的库。Jdk7u21
小工具链仅使用Java Development Kit(JDK)
版本7u21中的标准类,而CommonsCollections1
链包含来自广泛使用的Apache Commons Collections 3.1
的类。
攻击者可以使用其他服务器替换Solr集合中的RMI服务器地址,然后启动JRMP服务器。 Solr从攻击者指示的地址请求对象并接收恶意Java对象。 对象反序列化后,其代码在服务器上执行。
签名由序列化Java对象中的类序列触发。 从攻击者的计算机发送,以下是对象在流量中的启动方式:
这个任务的解决方案很简单。 签名明确命名为Jdk7u21
。 要绕过签名必须尝试其他工具链。例如CommonsCollections
, IDS没有其他连锁的签名。 然后参与者将获得系统上的shell并读取标志。 五名参与者成功完成了这项任务。
这是最棘手和最有趣的任务之一。 目标是具有开放端口445
的Windows
计算机。该标志分为两个用户名,因此完成任务需要枚举所有Windows用户。
当然,MS17-010和其他漏洞在这台计算机上不起作用。 可以使用脚本获取用户列表,例如来自Nmap或Impacket的脚本:
$ python samrdump.py 100.64.0.12
Impacket v0.9.15 - Copyright 2002-2016 Core Security Technologies
[*] Retrieving endpoint list from 100.64.0.12
[*] Trying protocol 445/SMB…
Found domain(s):
. SAMR
. Builtin
[*] Looking up users in domain SAMR
[-] The NETBIOS connection with the remote host timed out.
[*] No entries received.
两个脚本都在端口445上向计算机发送DCERPC
请求。但事情并非如此简单。 一些数据包被IDS阻止,不仅触发一个,而且触发两个签名:
[**] [1:2001:2] SAMR DCERPC Bind [**]
[Drop] [**] [1:2002:2] SAMR EnumDomainUsers Request [**]
第一个签名检测到与SAMR的连接并标记TCP连接。 第二个签名由SAMR EnumDomainUsers请求触发。 SAMR提供了获取用户列表的其他方法:QueryDisplayInfo,QueryDisplayInfo2和QueryDisplayInfo3。 所有这些都被签名阻止了。
DCERPC协议和Windows服务包含大量远程管理功能。 大多数着名的工具,如PsExec和BloodHound,都使用DCERPC。 SAMR(“SAM远程协议”)允许使用主机上的帐户,包括用户列表的枚举。
要发出EnumDomainUsers请求,这是Impacket的作用:
通过SMB建立到SAMR的DCERPC连接,并且在SAMR上下文中发送所有后续请求。 签名由屏幕截图中的第一个和最后一个数据包触发。
在比赛中,为此任务提供了两条线索:
尝试使IDS生成2个警报。 仔细看第一个。
我们知道该协议的哪些连接命令?
我们的想法是开始考虑DCERPC和不同的连接方法。 在用于连接和更改上下文的可用PDU列表中,我们找到了Bind和Alter Context命令。 Alter Context允许在不中断连接的情况下更改当前上下文。
要获得解决方案,我们需要重新编写samrdump脚本:
1 绑定到其他服务,例如UUID 3919286a-b10c-11d0-9ba8-00c04fd92ef5。
2 使用Alter Context切换到SAMR。
3 发出EnumDomainUsers请求。
所有改变均满足以下条件:
< dce.bind(samr.MSRPC_UUID_SAMR)
---
> dce.bind(uuid.uuidtup_to_bin(("3919286a-b10c-11d0-9ba8-00c04fd92ef5", "0.0")))
> dce.alter_ctx(samr.MSRPC_UUID_SAMR)
> dce._ctx = 1
竞赛获胜者@psih1337
还提出了另一种解决方案。 EnumDomainUsers
返回按SID
而不是按名称排序的用户列表。 但SID不是随机数。 例如,LocalSystem
帐户的SID
是S-1-5-18
。 对于手动创建的组或用户,SID为1000或更高。
因此,如果我们手动强制使用1000到2000之间的SID,很可能会找到正在寻找的帐户。 在我们的例子中,SID分别为1008和1009。
此任务需要了解DCERPC协议以及调查Windows基础结构的一些经验。 @ psih1337
是唯一一个解决这个任务的人。
端口80托管一个网页,其中包含用于输入IP地址的表单。
如果键入自己的IP地址,端口53将接收UDP,如下所示:
17:40:45.501553 IP 100.64.0.13.38730 > 100.64.0.187: 61936+ CNAME? dnscat.d2bc039ce800000000d6eae8eae3bf81fd84d1695f5888aba8dcec06d071.a73b3f0561ca4906d268214f4b70da1bdb50f75739ae0577139096732bf8.0d0a987ce23408bac15426a22e. (173)
17:40:45.501639 IP 100.64.0.187 > 100.64.0.13: ICMP 100.64.0.187 udp port domain unreachable, length 209
17:40:46.520457 IP 100.64.0.13.38730 > 100.64.0.187: 21842+ TXT? dnscat.7f4e039ce800000000d6eae8eae3bf81fd84d1695f5888aba8dcec06d071.a73b3f0561ca4906d268214f4b70da1bdb50f75739ae0577139096732bf8.0d0a987ce23408bac15426a22e. (173)
17:40:46.520546 IP 100.64.0.187 > 100.64.0.13: ICMP 100.64.0.187 udp port domain unreachable, length 209
它显然是DNSCAT,一种用于DNS隧道的工具。 在表单中键入IP地址时,DNSCAT客户端会尝试连接到该地址。 如果尝试成功,则服务器(换句话说,参与者)在竞赛计算机上获得shell并收集标志。
当然,如果我们只是尝试提升DNSCAT服务器并接受连接,那就没有这样的运气了:
[Drop] [**] [1:4001:1] 'dnscat' string found in DNS response [**]
IDS
签名由来自我们服务器的流量中的字符串“dnscat”触发 - 从消息中可以清楚地看出这一点。 模糊或加密流量将无法正常工作。
但是看一下客户端代码,我们发现检查不是太严格。 响应根本不需要包含“dnscat”字符串! 我们只需要从代码中删除字符串,或者在NetSED的帮助下即时替换它。 在运行中交换它要容易得多,但这里是服务器代码的补丁,以防万一:
diff -r dnscat2/server/libs/dnser.rb dnscat2_bypass/server/libs/dnser.rb
< segments << unpack("a#{len}")
> segments << [unpack("a#{len}")[0].upcase]
< name.split(/\./).each do |segment|
> name.upcase.split(/\./).each do |segment|
diff -r dnscat2/server/tunnel_drivers/driver_dns.rb dnscat2_bypass/server/tunnel_drivers/driver_dns.rb
< response = (response == "" ? "dnscat" : ("dnscat." + response))
> response = (response == "" ? "dnsCat" : ("dnsCat." + response))
五位参与者迎接了挑战。
没有参赛人员完成此任务。
我们看到了现在熟悉的输入IP地址的形式,邀请我们参与测试新的恶意软件。 其中一个新技巧是以某种未知的方式绕过IDS。 要获取该标志,您需要做的就是发送HTTP标头“Server:ng1nx”作为响应。
正如预期的那样,我们在我们的IP地址处获得GET请求并发送响应,该响应被IDS阻止。
[Drop] [**] [1:5002:1] 'ng1nx' Server header found. Malware shall not pass [**]
以下是给与会者的提示:
有时,看起来很难的任务是最简单的。 如果没有什么东西看起来很脆弱,也许你在鼻子底下遗漏了什么东西?
IDS就是“你的鼻子下的东西”。 在检测页面上可以看到我们正在处理未受保护的Suricata IDS。
搜索“Suricata IDS Bypass”
以及获得的第一个链接指向CVE-2018-6794
。 如果正常的TCP握手过程中断并且数据在过程完成之前发送,则此漏洞允许绕过数据包检查。 它看起来像这样:
Client -> [SYN] [Seq=0 Ack=0] -> Evil Server # 1/2
Client <- 2="" ack="1] " eq="0" evil="" font="" nbsp="" server="">
Client <- ack="1] " data="" eq="1" evil="" font="" here="" nbsp="" server="">
Client <- ack="1] " eq="83" evil="" font="" nbsp="" server="">
Client -> [ACK] [Seq=1 Ack=84] -> Evil Server # 3/2
Client -> [PSH, ACK] [Seq=1 Ack= 4] -> Evil Server
我们下载漏洞,将字符串更改为“ng1nx”
,禁用内核重置(RST)数据包,然后运行它。
如上所述,没有人能够得到这个flag,尽管一些参与者非常接近。
49人报名参加比赛,其中12人成功收集了至少一个flag。 任务可以有多个解决方案,尤其是涉及SMB和DCERPC的任务。
本文为翻译稿件,来自:http://blog.ptsecurity.com/2019/07/ids-bypass-contest-at-phdays-writeup.html