网络安全漏洞深度剖析
2021年7月13日,美国微软威胁情报中心发布安全公告[1],文中指出黑客利用Serv-U 0day对极少数美国军工部门成功进行了攻击,同日Serv-U母公司solarwinds也发布安全公告[2],并针对最新大版本发布了补丁[3]。(注意:目前发布的补丁只针对最新的15.2.3大版本,且只能是付费用户才能下载安装补丁,非付费用户目前无法从官方渠道获取有效补丁。根据补丁比较和fuzzer,宁静之盾
一、漏洞背景
2021年7月13日,美国微软威胁情报中心发布安全公告[1],文中指出黑客利用Serv-U 0day对极少数美国军工部门成功进行了攻击,同日Serv-U母公司solarwinds也发布安全公告[2],并针对最新大版本发布了补丁[3]。
(注意:目前发布的补丁只针对最新的15.2.3大版本,且只能是付费用户才能下载安装补丁,非付费用户目前无法从官方渠道获取有效补丁。)
根据补丁比较和fuzzer,宁静之盾安全团队成功复现了该远程溢出漏洞,并能在实战环境下成功利用。
截至9月10日,互联网上未发现任何有关该漏洞的技术分析和POC发布,也未发现更多新闻细节公布。
该漏洞是2003年Serv-U mdtm漏洞修补后出现的第一个RCE漏洞。
二、Serv-U软件说明
该软件是全球流行的商业闭源FTP服务器端软件,官方资料显示该软件全球有超过10W用户,软件默认支持ftp(21端口)/sftp(22端口)等,出于安全性考虑现在大部分使用的是sftp端口(流量使用非对称算法加密),主要运行在windows平台,新版本为X64程序,该软件22端口默认banner信息含有详细版本号,通过zoomeye搜索显示近一年IP量为13000个(全量为6.7W多)。
其中15.2.3大版本有1100台,最新补丁版本15.2.3.742有900台,该漏洞影响范围是Serv-U 版本 < 15.2.3 HF2(即15.2.3.742)。按照近一年存活13000台,已安装此漏洞补丁900台计算,也就是说现在全网至少有90%的Serv-U处于受此漏洞威胁状态(Serv-U母公司应该是出于商业考虑未对大量存在的老版本发布补丁,老版本升级到最新版本需要再次付费)。
Banner信息
三、漏洞分析与利用说明
综述
该漏洞是一个远程内存破坏漏洞(可以稳定控制虚函数指针),针对WINDOWS版Serv-U SFTP(22端口)进行攻击,该漏洞无需任何账号和密码,输入IP和端口即可成功攻击,只要版本低于15.2.3.742,成功率接近100%(单次成功率达不到100%,但可以立即再次攻击),利用成功获取SYSTEM权限SHELL。
3.1补丁比较
下载最新版本742和上一版本723,补丁包文件如下
markdown复制代码> 15.2.3.723 hf1 5/14/2021
>
> Serv-U crashes due to incorrect OpenSSL API usage
>
> <Serv-U-InstallDir>\Serv-U.dll
>
> <Serv-U-InstallDir>\RhinoNET.dll
>
> 15.2.3.742 hf2 7/12/2021
>
> * Unauthenticated Remote Code Execution in SSH protocol
>
> * <Serv-U-InstallDir>\Serv-U-RES.dll
>
> * <Serv-U-InstallDir>\Serv-U-Tray.exe
>
> * <Serv-U-InstallDir>\Serv-U.dll
>
> * <Serv-U-InstallDir>\Serv-U.exe
可以看到主要修改了4个文件,使用Bindiff依次对这4个文件进行比较,最终可以排除掉Serv-U.exe、Serv-U-Tray.exe和Serv-U-RES.dll,因为这三个文件改动非常小,基本上不可能存在漏洞。
同时结合官方的报告,APT攻击中利用该漏洞可能会报如下错误:
ini复制代码> EXCEPTION: C0000005;
>
> CSUSSHSocket::ProcessReceive();
>
> Type: 30;
>
> puchPayLoad = 0x041ec066;
>
> nPacketLength = 76;
>
> nBytesReceived = 80;
>
> nBytesUncompressed = 156;
>
> uchPaddingLength = 5
基本可以判断该漏洞是一个SSH相关的内存型漏洞。 使用BINDIFF和IDA对主DLL的补丁情况比较如下:
左边为未补丁变化的函数地址,右边为补丁后的函数地址
对Serv-U.dll中的十余个有变化的函数逐个分析,排除掉4个比较错误的函数,一共有9个函数发生变化,发现补丁为某些函数添加了硬编码的判断与赋值,比如,判断某个值198h是否为0、1、2、3、4或5等,或者给198h赋值为0、1、2、3、4或5等。
此时,需要配合IDA尝试理解这些值的含义,首先定位到该值存储的位置,可以看到该值被存储到a1[0x198]。
然后二进制搜索0x198,找到该值被读写的所有位置。
遗憾的是,即使知道了补丁补的位置与代码,也很难揣测补丁的最终意图。于是另辟蹊径,从打过补丁的函数一直向上回溯,依次记录分析,发现函数sub_180145070会引用所有打过补丁的函数。
其它几个变化的函数主要是该函数的switch case分支里调用的函数,下面我们具体分析该函数,该函数其实是RhinoNET!CRhinoSocket::ProcessReceiveBuffer,通过命名可以猜到是用于处理收到的数据BUF,在该函数入口点下断:
180145070的调用栈如下:
RhinoNET!CRhinoSocket::OnReceive+0x170
mfc140u!CWnd::OnWndMsg+0xba9
mfc140u!CWnd::WindowProc+0x3f
mfc140u!AfxCallWndProc+0x123
mfc140u!AfxWndProc+0x54
mfc140u!AfxWndProcBase+0x49
USER32!UserCallWinProcCheckWow+0x1ad
USER32!DispatchMessageWorke+0x3b5
Serv_U_180000000!CUPnPNotifyEvent::SetTimeout+0x30d85
Serv_U_180000000!CUPnPNotifyEvent::SetTimeout+0x30dfd
ucrtbase!crt_at_quick_exit+0x7d
kernel32!BaseThreadInitThunk+0xd
ntdll!RtlUserThreadStart+0x1d
仔细观察该函数的结构,一个外部大循环加内部的switch…case,明显是某种协议的实现,配合关键字符串SSH_MSG_IGNORE,不难得出结论: 函数sub_180145070实现了部分或完整的SSH握手协议。
通过调试可知,该函数主要用于处理SSH消息,依次处理的MSG消息如下:
shell复制代码> 180145070依次处理的MSG(10进制)
>
> 20 SSH_MSG_KEXINIT
>
> 30 SSH_MSG_ECDH key exchange init ! CASE 28
>
> 21 SSH_MSG_NEWKEYS
>
> 5 SSH_MSG_SERVICE_REQUEST
>
> 50 SSH_MSG_USERAUTH_REQUEST
>
> 90 SSH_MSG_CHANNEL_OPEN
>
> 98 SSH_MSG_CHANNEL_REQUEST
>
> 94 SSH_MSG_CHANNEL_DATA
比如上图中:switch(v21)中v21就是SSH协议中的消息码,标识了消息类型。
通过此文档可查到相关SFTP协议的规范
补丁后的程序,主要修补了20,30,21三个MSG,其中在这些MSG中处理CLIENT支持的SSH加密算法处多调用了SSH库578,530和538函数做检查(EVP_aes_128_ctr,EVP_EncryptInit_ex和EVP_DecryptInit_ex)
同时通过调试可知,修补后的程序,对MSG序列的顺序做了限制!
补丁比较后基本判断该漏洞是一个SSH协议握手阶段的逻辑处理出错,进而造成的内存处理出错,那么通过补丁比较就找不到传统内存溢出型漏洞补丁一般会对COPY长度做限制的地方,要复现这个漏洞就需要对Serv-U的SSH握手过程进行FUZZER。
3.2 FUZZER SSH握手过程
有了上述的信息,便可以写一个发包FUZZ脚本(不断生成消息码去测试),通过模拟SSH握手阶段的数据交换来模糊测试Serv-U服务器15.2.3.723。
脚本运行一段时间后,得到了一个崩溃,通过分析该崩溃可以确认我们发送完20号消息后,不发送30号MSG,直接发送21号消息,是造成Serv-U崩溃的原因,打上补丁后不会产生该问题。那么说明很可能找到了漏洞点。
同时该漏洞大概率能够利用,因为Serv-U.dll没有开启ASLR,而我们拥有控制EIP的能力,所以配合ROP便可以远程执行代码了。
如下图,可以看到被调用的函数指针被覆盖为了AAAAAA……,也就是我们可以利用可控的数据覆盖一个虚函数指针,从而控制函数执行流程以执行我们的ShellCode。
崩溃时的调用栈如下:
崩溃的最终位置并不在Serv-U.dll里,而是在libeay32.dll,这个动态链接库是OpenSSL用于加解密的一个组件。通过跟踪调试,发现握手数据AAAAAA…的最后8字节数据被libeay32.dll错误地当作函数指针来调用,从而触发了崩溃。
定位崩溃时发送的数据包,发现该数据包打乱了SSH正常的通信过程(握手包乱序),所以补丁中的硬编码值0、1、2、3、4、5等是为限制了数据包的发送顺序,即发送了包MSG 20之后只能发包MSG 30,以此缓解该漏洞。
3.3 漏洞利用
通过分析发包流程和Serv-U的SSH通信处理过程便得知,该**漏洞的成因为Serv-U的SSH通信处理流程乱序导致的内存未初始化漏洞。**通过网络数据包列举漏洞触发原理及过程如下:
- SSH通信正常的处理过程为
密钥交换初始化(申请N字节内存,每个版本可能不同);
密钥协商算法交换参数,比如ECDH(填充N字节内存:在内存块内填充函数地址等);
加解密数据(调用N字节内存中的函数地址)
- 触发漏洞的过程为
密钥交换初始化(申请N字节内存);
加解密数据(调用N字节内存中的函数地址);
可以看到漏洞触发过程省略了ECDH密钥交换协商这一步。并且在第一步申请N字节时并未初始化内存。
- 漏洞触发利用过程
发包占坑布局N字节内存空间,并释放;
密钥交换初始化(申请N字节内存,该内存内容已被提前布局)
加解密数据触发漏洞**(由于缺少了密钥协商设置N字节内存块内函数指针这一步,所以会调用N字节内存中已被提前布局的函数地址);**
- 漏洞补丁原理
漏洞补丁限制了SSH通信过程,所以不会再导致内存中函数指针被攻击者提前布局并利用的情况。
通过分析该崩溃,确定了该漏洞大概率能够利用,因为Serv-U.dll并没有开启ASLR,为我们提供了用于布置ROP链的必要条件。除此之外,上述崩溃的位置在CALL指令处,这使得我们大概率可以控制EIP。当同时拥有以上两种能力后,就可以控制程序跳转到布置好的ROP链上执行预先指定的代码。
虽然Serv-U.dll中没有导入VirtualProtect函数,但是它导入了另外一个能够执行代码的函数ShellExecuteExW,所以目标就是构造ROP链传入指定参数执行ShellExecuteExW。
首先使用capstone编写小工具提取ROP,获取所需指令的地址。
然后拼接这些指令,达到执行ShellExecuteExW的目标,具体步骤是:切换栈+布局参数+调用函数。
切换栈是第一步,但非常简单,使用xchg、pop、mov以及lea等指令修改rsp即可。布局参数是整个过程中最难的,因为函数ShellExecuteExW只有一个参数,该参数为一个结构体指针,而结构体内部的字符串指针才是执行命令的核心,所以这里涉及到多级指针的布控。由于我们控制了整个栈,所以布置多级指针的也并不难,但步骤比较繁琐,容易出错,一定要耐心谨慎。
参数布置好之后,再次控制EIP跳转到导入表内的函数指针执行。一旦函数ShellExecuteExW执行完毕,就代表着用户指定的命令也已经执行完毕,但由于栈已经损坏,主程序将随之崩溃。
如果不利用ShellExecuteExW也可以利用下图所示位置的代码,自行获得VirtualProtect函数地址:
(上图地址DLL版本为15.2.3.723)
四、现有补丁说明
截止9月10日,发布的补丁情况如下:
| 版本号 | 发布时间 | 有无漏洞 | | <15.2.3.717 | ---- | 有 | | 15.2.3.717 | 2021/04/20 | 有 | | 15.2.3.723 hf1 | 2021/05/14 | 有 | | 15.2.3.742 hf2 | 2021/07/12 | 无(最新版) |
五、漏洞利用工具说明
5.1 受影响软件版本
SSH-2.0-Serv-U_15.1.6.25至SSH-2.0-Serv-U_15.2.3.723
备注:SSH-2.0-Serv-U_15.1.6.25版本为2017年发布,更早的版本肯定也受影响,只不过当前测试的最早版本为2017年。SSH-2.0-Serv-U_15.2.3.723版本为最新的补丁版本的前一个版本。
5.2 远程利用限制条件
Serv-U需要以服务方式启动才能利用成功,不过Serv-U默认安装本来就是以服务方式启动的。如果以非服务方式启动则无法利用成功。
5.3 远程利用执行演示效果及特殊情况说明
- 利用成功后,目标机器的Serv-U.exe程序会执行我们的ShellCode代码,并且启动一个PowerShell子进程(父进程为Serv-U.exe),并通过PowerShell脚本回连我们设置的IP和端口,获取的SHELL权限为SYSTEM权限;
- ShellCode代码启动的程序和执行的程序命令可以通过修改攻击脚本自行设定;
- 上述第2点提到的ShellCode执行的程序命令有长度限制,不能超过500个字节;
- 如果利用成功,Serv-U.exe程序会崩溃并自动重启(不会弹框,因为是服务方式启动所以会自动重启),所以可以无限次反复远程利用;
- 如果利用失败,攻击脚本执行完后稍等十秒再进行下一次攻击,直到成功为止;
- 每次的攻击成功率大概在20-50%;
- 单次攻击发出的网络数据包大小在2-3M左右,注意网络情况;
- 每个Serv-U版本需要有对应的ROP序列,所以每一个单独的小版本的Serv-U都需要定制化开发对应的攻击代码(程序有DEP,但关键DLL无ASLR)。
- 本文仅作安全技术分析,旨在为无法获得补丁的用户和安全研究人员提供此漏洞细节分析,所以不提供任何POC。
题外话
网络安全行业特点
1、就业薪资非常高,涨薪快 2022年猎聘网发布网络安全行业就业薪资行业最高人均33.77万!
2、人才缺口大,就业机会多
2019年9月18日《中华人民共和国中央人民政府》官方网站发表:我国网络空间安全人才 需求140万人,而全国各大学校每年培养的人员不到1.5W人。猎聘网《2021年上半年网络安全报告》预测2027年网安人才需求300W,现在从事网络安全行业的从业人员只有10W人。
行业发展空间大,岗位非常多
网络安全行业产业以来,随即新增加了几十个网络安全行业岗位︰网络安全专家、网络安全分析师、安全咨询师、网络安全工程师、安全架构师、安全运维工程师、渗透工程师、信息安全管理员、数据安全工程师、网络安全运营工程师、网络安全应急响应工程师、数据鉴定师、网络安全产品经理、网络安全服务工程师、网络安全培训师、网络安全审计员、威胁情报分析工程师、灾难恢复专业人员、实战攻防专业人员…
职业增值潜力大
网络安全专业具有很强的技术特性,尤其是掌握工作中的核心网络架构、安全技术,在职业发展上具有不可替代的竞争优势。
随着个人能力的不断提升,所从事工作的职业价值也会随着自身经验的丰富以及项目运作的成熟,升值空间一路看涨,这也是为什么受大家欢迎的主要原因。
从某种程度来讲,在网络安全领域,跟医生职业一样,越老越吃香,因为技术愈加成熟,自然工作会受到重视,升职加薪则是水到渠成之事。
关于网络安全学习指南
学习网络安全技术的方法无非三种:
第一种是报网络安全专业,现在叫网络空间安全专业,主要专业课程:程序设计、计算机组成原理原理、数据结构、操作系统原理、数据库系统、 计算机网络、人工智能、自然语言处理、社会计算、网络安全法律法规、网络安全、内容安全、数字取证、机器学习,多媒体技术,信息检索、舆情分析等。
第二种是自学,就是在网上找资源、找教程,或者是想办法认识一-些大佬,抱紧大腿,不过这种方法很耗时间,而且学习没有规划,可能很长一段时间感觉自己没有进步,容易劝退。
第三种就是去找培训。
接下来,我会教你零基础入门快速入门上手网络安全。
网络安全入门到底是先学编程还是先学计算机基础?这是一个争议比较大的问题,有的人会建议先学编程,而有的人会建议先学计算机基础,其实这都是要学的。而且这些对学习网络安全来说非常重要。但是对于完全零基础的人来说又或者急于转行的人来说,学习编程或者计算机基础对他们来说都有一定的难度,并且花费时间太长。
第一阶段:基础准备 4周~6周
这个阶段是所有准备进入安全行业必学的部分,俗话说:基础不劳,地动山摇
第二阶段:web渗透
学习基础 时间:1周 ~ 2周:
① 了解基本概念:(SQL注入、XSS、上传、CSRF、一句话木马、等)为之后的WEB渗透测试打下基础。
② 查看一些论坛的一些Web渗透,学一学案例的思路,每一个站点都不一样,所以思路是主要的。
③ 学会提问的艺术,如果遇到不懂得要善于提问。
配置渗透环境 时间:3周 ~ 4周:
① 了解渗透测试常用的工具,例如(AWVS、SQLMAP、NMAP、BURP、中国菜刀等)。
② 下载这些工具无后门版本并且安装到计算机上。
③ 了解这些工具的使用场景,懂得基本的使用,推荐在Google上查找。
渗透实战操作 时间:约6周:
① 在网上搜索渗透实战案例,深入了解SQL注入、文件上传、解析漏洞等在实战中的使用。
② 自己搭建漏洞环境测试,推荐DWVA,SQLi-labs,Upload-labs,bWAPP。
③ 懂得渗透测试的阶段,每一个阶段需要做那些动作:例如PTES渗透测试执行标准。
④ 深入研究手工SQL注入,寻找绕过waf的方法,制作自己的脚本。
⑤ 研究文件上传的原理,如何进行截断、双重后缀欺骗(IIS、PHP)、解析漏洞利用(IIS、Nignix、Apache)等,参照:上传攻击框架。
⑥ 了解XSS形成原理和种类,在DWVA中进行实践,使用一个含有XSS漏洞的cms,安装安全狗等进行测试。
⑦ 了解一句话木马,并尝试编写过狗一句话。
⑧ 研究在Windows和Linux下的提升权限,Google关键词:提权
以上就是入门阶段
第三阶段:进阶
已经入门并且找到工作之后又该怎么进阶?详情看下图
给新手小白的入门建议:
新手入门学习最好还是从视频入手进行学习,视频的浅显易懂相比起晦涩的文字而言更容易吸收,这里我给大家准备了一套网络安全从入门到精通的视频学习资料包免费领取哦!
如果你对网络安全入门感兴趣,那么你需要的话可以在下方扫码领取!!
更多推荐
所有评论(0)