漏洞利用开发实战:逆向Nessus的RPC命令执行漏洞

本文详细记录了如何通过分析Nessus的流量包捕获,逆向工程一个基于RPC的未授权命令执行漏洞,并最终使用Python和Scapy成功开发出可执行任意命令的漏洞利用程序的过程。

漏洞利用开发——最真诚的恭维

最近,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)

红色标记的两行被大量编辑的内容是从客户端发送到服务器的,我们将参考这些内容来开始制作我们自己的漏洞利用代码。但首先,也许我们最好更仔细地分析一下通信。下图显示了我们在监听对话时看到的带注释的视图:

TCP流序列图

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

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

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

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

糟糕,全是错误!

通过在漏洞利用代码中添加一些调试输出来打印序列号和确认号,我们可以看到数字没有正确更新,因为确认号应该发生变化。

漏洞利用调试输出

此时,已经是周五傍晚了,我感觉想要放弃,因为我们处理这个漏洞的时间窗口正在迅速关闭。我起身散步以清醒头脑。散步的前几分钟,我给David发消息讨论我遇到的一些问题,他慷慨地给了我一些好的建议。显然我的序列号和确认号对不上,我们讨论了所需的更新逻辑,直到我终于对需要更改的内容有了粗略的理解。散步回来后,我确信我们需要完成这个任务,于是我们就这样做了。

第二天下午醒来后,我打开电脑开始查看我的序列号和确认号到底出了什么问题。在调整了相关的数字更新逻辑后,我再次检查了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文件来看,我们可以看到我们大约完成了一半。从错误来看,序列号和确认号似乎仍然略有错误。

漏洞利用代码的前半部分工作

通过移除下面else块中错误的+1修复了这个问题。以下截图显示了最终的序列号/确认号更新函数:

序列号和确认号更新逻辑的最终修复

向Dale发送修改后的漏洞利用代码后,我下线享受周六的剩余时间。第二天早上醒来时,我收到了Dale的意外消息:漏洞利用代码成功了。

在庆祝之后,我的目光被结果输出的末尾吸引,如下所示。

首次漏洞利用成功

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

命令输出分段

再次与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 设计