漏洞利用开发:模仿与调试的艺术

本文详细记录了通过分析Nessus的流量包,使用Python和Scapy工具开发一个RPC命令执行漏洞利用的过程,包括调试序列号、确认机制及数据包填充等关键技术挑战。

漏洞利用开发:模仿与调试的艺术

最近,BHIS的渗透测试员Dale Hobbs在一次内部网络渗透测试中,通过漏洞扫描结果发现了一个基于RPC的任意命令执行漏洞。
Nessus插件ID 59642
我随口提到我正在学习更多关于远程过程调用(RPC)的知识,Dale邀请我一起研究这个漏洞,我欣然接受了这个邀请。

在开始之前,先做一个快速免责声明:此漏洞的初始披露全部归功于Ron Bowes和Tenable。尽管这个漏洞已经有10年历史,但为了保护Tenable的知识产权,本博客文章不会附带漏洞利用代码。出于同样的原因,直接从数据包捕获中获取的特定漏洞利用字节也被进行了编辑。虽然我很想最终公开发布漏洞利用代码以造福其他信息安全从业者,但本文重点在于创建(更重要的是调试)漏洞利用的过程。

漏洞详情

让我们通过查看Nessus对此漏洞的描述来开始这次冒险。Nessus插件ID 59642详细说明该漏洞允许通过未经身份验证的RPC接口执行特权命令。

听起来相对简单,但在此之前,我已经无数次被简单的假设所困扰。在过于急切之前,让我们看看关于此漏洞的其他可用信息。参考资料部分中的upSploit URL看起来很有希望,所以让我们先去那里看看——

无法浏览到upSploit.com
哦。好吧,也许互联网档案馆有相关参考。输入URL后,发现只有一个页面副本,保存于2013年。

存档的漏洞披露搜索结果
好吧,让我们看看我们在处理什么。根据存档文章,典型的漏洞利用连接如下所示:

  • 选择易受攻击的接口,unidata72
  • 身份验证(操作码0x04)
  • 执行操作,例如运行操作系统命令(操作码0x06)

好的,这是一个开始,但如果能看到Nessus如何利用此漏洞,那将非常酷。根据Tenable的说法,此漏洞没有已知的漏洞利用可用。

没有已知的漏洞利用可用
也许查看他们的脚本源代码会提供一些见解,就像在测试中经常对其他发现所做的那样。查看插件文件名将告诉我们去哪里查找——

Nessus脚本文件名
啊。不酷。根据我所读到的,nbin文件是一种编译的Nessus文件格式,允许供应商提供概念验证代码,而无需向所有人披露技术细节。这是一个好主意,但在测试中遇到时令人沮丧。显然,Nessus有一些秘密配方,因为漏洞扫描显示ipconfig Windows命令已成功执行,并且收到了输出。

Nessus成功利用漏洞
所以,这里有一个价值百万美元的问题:如果我们看不到源代码,我们如何弄清楚nbin文件在做什么?在仔细考虑之后,Dale有了一个想法,这引导我们走上了最终拥有一个可工作的漏洞利用的道路。

猴子看(Nessus的数据包捕获)

Dale能够配置他的漏洞扫描器仅运行特定插件。他开始进行数据包捕获(pcap),运行有限的漏洞扫描,然后将生成的pcap文件发送给我,以便我们都可以查看结果。有了pcap文件,我们能够将其放入Wireshark,并通过在数据包字节中搜索ipconfig来查看相关流。相关的TCP流如下所示。IP地址已被编辑。在显示最后一个八位字节的情况下,“.32”代表测试主机,“.74”代表目标主机。

从Nessus拦截的TCP流
通过在Wireshark中跟踪TCP流,另一个窗口打开以显示相关对话的ASCII视图。

TCP流(ASCII)
现在我们已经查看了TCP流的ASCII表示,让我们将输出切换到Raw以查看发送到服务器的字节。

TCP流(Raw)
红色中两个 heavily redacted 的行是从客户端发送到服务器的,这就是我们将参考的内容,以开始制作我们自己的漏洞利用。但首先,也许最好更仔细地分析一下通信。下图显示了我们在监听对话时看到的注释视图:

TCP流序列图
更好地理解了漏洞,并且数据包捕获作为成功利用的模型,是时候开始编写我们自己的漏洞利用了。

猴子做(漏洞利用构建和故障排除)

在经过一次不成功但 mercifully brief 的尝试用C编写漏洞利用之后,我被BHIS的渗透测试员David Fletcher说服,转而使用Python和Scapy。在重新熟悉Scapy一段时间后,是时候开始认真构建了。第一步是构建客户端发送的所有必要数据包。

我首次天真地尝试使用Scapy构建漏洞利用 predictably went poorly,并且最初无法直接实验易受攻击的系统,这使得事情变得更加困难。相反,我依赖在我控制的机器上运行的简单HTTP服务器,只是为了在实时针对目标运行之前正确设置对话结构。根据Wireshark,看起来几件事情同时出错了。

哎呀,全是错误!
通过向漏洞利用添加一些调试输出来打印序列号和确认号,我们可以看到数字没有正确更新,因为确认号应该正在改变。

漏洞利用调试输出
此时,已经是周五傍晚,我感到想要放弃,因为我们处理此漏洞的时间框架即将结束。我起身散步以清醒头脑。散步的前几分钟,我与David messaging 关于我遇到的一些问题,他慷慨地给了我一些好的指点。显然我的序列号和确认号没有加起来,我们讨论了所需的更新逻辑,直到我终于对需要更改的内容有了粗略的理解。当我散步回来时,我确信我们需要完成这件事,于是我们做到了。

第二天下午醒来后,我打开电脑开始查看我的序列号和确认号到底出了什么问题。在调整了相关的数字更新逻辑之后,我再次检查Wireshark,观察到行为似乎好了一些。

首次修复序列号和确认号
也就是说,我仍然在Wireshark中看到很多“Destination unreachable (Communication administratively filtered)”,这让我感到困惑。在虚拟机上,我反而观察到从客户端发送到服务器的重置数据包,以响应收到的每个数据包。

虚拟机中所有数据包重置
那么,这里发生了什么?事实证明,Scapy的故障排除文档有一个关于此问题的说明。问题归结为客户端操作系统响应数据包时发送重置,因为对话并非直接源自客户端操作系统。Scapy文档指出,可以使用iptables命令规避此问题:

iptables -I OUTPUT -d xxx.xxx.xxx.74 -j DROP

根据我(和David)的理解,防火墙规则是必要的,以防止我们的主机在看到并非源自操作系统自身网络堆栈的对话中的数据包时杀死连接。操作系统看到来自服务器的响应数据包并发送重置,因为操作系统不知道Scapy是处理对话的一方。

有了防火墙规则,我能够验证从我的虚拟机到测试服务器的数据包是否被正确发送和接收。以下屏幕截图显示了我能在测试中验证功能的最接近情况,而无需Dale在其客户环境中进行测试。

最终本地测试
我将最新的漏洞利用发送给Dale,并让他运行它。从生成的pcap文件来看,我们可以看到我们大约完成了一半。从错误来看,序列号和确认号似乎仍然略有 incorrect。

漏洞利用的前半部分工作
通过从下面显示的else块中删除一个错误的+1来修复了问题。以下屏幕截图显示了最终的序列/确认号更新函数:

最终修复序列号和确认号更新逻辑
在向Dale发送修改后的漏洞利用之后,我注销以享受剩余的周六。第二天早上醒来时,我收到了Dale的一条意外消息:漏洞利用成功了。

经过一些庆祝之后,我的目光被生成输出的末尾吸引,如下所示。

首次漏洞利用成功
……我们的命令输出的其余部分在哪里?Nessus执行的漏洞利用只有一个包含所有命令输出的响应数据包。Dale提供了另一个pcap,我们能够看到命令输出响应被分成两个数据包。缺失的命令输出包含在以下屏幕截图 highlighted 的两个数据包中的第二个中。

命令输出分段
再次与David交谈,他指出数据包选项可能不正确。这促使我查看Nessus漏洞利用中使用的数据包选项:

来自Nessus漏洞利用的数据包选项
根据我所看到的,SYN数据包需要指定大窗口大小、最大段大小和窗口缩放。通过将一些Scapy选项插入数据包中,这样做相对容易。

漏洞利用代码中更新的数据包选项
在这样做的时候,我还趁机清理了输出,并添加了任意命令输出支持。

在实现指定任意命令的能力时,我审查了命令数据包中存在的填充。从Nessus观察到的原始数据包有四个字节的填充。这种填充可能很重要,但我觉得确认一下会很有趣。我从数据包中移除了大部分填充,并观察到服务器的响应中没有命令输出,如下屏幕截图所示:

无效命令填充的不成功利用
查看从客户端发送的第二个PSH ACK数据包的有效负载长度,我们可以找出最可能的填充值。有效负载长度为56字节。假设有四个字节的填充,我们可以安全地猜测填充是为了使有效负载长度成为八字节的倍数,因为52 mod 8是4,而52加4是56。考虑到这一点,我在代码中临时凑齐了必要的填充:

填充逻辑
填充修复后,我们能够向易受攻击的服务器发出命令。看到正确格式化的ipconfig输出既令人兴奋又令人宽慰。

成功的漏洞利用
之后,我们基本上完成了。Dale请求一个选项来禁用序列号和确认号输出,我通过将其作为新详细选项的一部分来满足这一要求。

演示

为了验证整个交易中任意命令执行部分是否工作,Dale运行了一些额外的命令,即简单的whoami命令和更复杂的net group ‘Domain Admins’ /domain命令。两个命令都像魔法一样工作。

成功的“whoami”命令执行
成功的“net group”命令执行

结论

至此,我的第一次成功的漏洞利用开发冒险结束了。我想我应该总结一下在这个过程中学到的一些教训,尤其是我无法发布代码:

  • 为工作选择合适的工具,如果选择错误,不要害怕转换方向。我很可能可以用C做出一些东西,但Python与Scapy显然是阻力最小的路径,帮助我们在合理的时间内完成了一些工作。
  • 不要过早放弃。如果我按照原计划在周五下午放弃,我们就不会完成这项工作(你也不会读到这篇文章)。
  • 总是接受合作的邀请。与其他测试员分享项目的最好部分是,它可能会促使他们询问他们正在处理的相关挑战。在这方面,我接受了收到的每一个邀请,并且很少失望。

我最诚挚的感谢Ron Bowes和Tenable的漏洞披露和详细信息,感谢像David Fletcher这样的渗透测试员给我指明了正确的方向(以及一般的鼓励),最后感谢Dale Hobbs邀请我与他一起进行这次冒险,测试漏洞利用代码,并在周末我完成代码时提供pcap文件。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计