XShellGhost软件供应链安全事件
这里分享一篇关于在线安全和数据隐私的文章《Data Breach and Leak Glossary: Every Technical Term Explained》,感谢@Louis Martin的真诚推荐!
0x00 前言
如果说,作为“软件供应链攻击”的典型案例,XCodeGhost事件虽然影响面较大,但其本质上毕竟只是作为软件推广的小后门而存在,攻击性并不显著。本文将分析的XShellGhost后门案例则是继XCodeGhost之后下一个 “供应链安全”的经典案例,并且相较之下其攻击特征尤其突出,技术水准也直线上升,是真正令人细思极恐的高级幽灵。
0x01 事件背景
2017年7月,著名安全公司卡巴斯基通过在合作伙伴的网络环境中分析可疑的DNS请求发现了NetSarang(XShell所属公司)生产和分发的软件最新版本已被秘密修改,用于包含可以让攻击者远程激活的加密载荷。之后卡巴斯基通知厂商与其发布了联合安全声明,并以“Shadowpad”来命名此类软件后门(国内安全厂商则习惯将其命名XShellGhost)。
随后,各大安全厂商开始争相分析和报道此事件,尤其关注其“供应链安全”的属性和该后门特别使用到的DNS隧道传输技术。由于相关软件在国内程序开发和运维人员中被广泛使用,可能导致大量用户服务器账号密码泄露,所以影响面和关注度在当时也不断地进行发酵。
2017年8月,联合声明被更新,声称发现了在香港利用该软件后门的案例。
此外,卡巴斯基在他们的对外报告中提及因为攻击者非常小心地隐藏自己所以很难定性谁是幕后黑手,只是此事件相关的某些技术曾被应用于另一种已知的恶意软件如PlugX和Winnti。
0x02 样本分析
本事件受影响的产品包括主版本号为5的Xmanager、XShell、XFtp和Xlpd,被感染的恶意模块是这些产品共同使用的一个基础网络通讯库“nssock2.dll”。
(一)、后门位置
以XShell 5.0.1322版本为例,后门代码位于安装目录下的“nssock2.dll” 模块,包含NetSarang公司的合法签名(当前为被吊销状态)。
该模块在软件启动后会自动被加载运行,植入的后门并不影响其原本的正常功能。恶意代码如下所示,可以看到从全局数据区解密一段shellcode代码运行。
该段恶意代码执行在本模块初始化CRT(C运行时库)期间,由函数“_CRT_INIT”进行调用。
“_CRT_INIT”运行在DllMain主函数之前,即恶意代码在此模块正常工作前就已经执行完毕。
(二)、植入机制
这里在分析具体的恶意shellcode功能之前先探究一下本模块被污染的方式。由上述可知被插入的恶意代码函数在“_CRT_INIT”初始化函数中被引用,具体的位置是在“xc_a” 和“xc_z”之间函数地址表中的第二项。此函数地址表中的每一项函数在“_CRT_INIT”期间通过“_initterm” 调用被依次执行。
趋势科技的一篇报告因此认为本模块被污染的方式可能是攻击者污染了开发环境的crt静态链接库“libcmt.lib/msvcrt.lib”,下面就分析验证一番此结论是否正确。以vs2010为例,这2个静态库位于“C:Program Files (x86)Microsoft Visual Studio 10.0VClib”。用IDA打开“libcmt.lib”可以看到包含多个目标文件,每个目标文件都是一段代码单元,用于在项目编译链接期间进行组织。此时我们关注的目标单元是“crt0data.obj”,里面包含了“_initterm”函数的具体实现。
“_initterm”函数的功能就是依次调用2个地址(“xc_a” 和“xc_z”)之间的非0函数指针,“xc_a” 和“xc_z”则分别是函数指针列表的开始地址和结束地址。
“msvcrt.lib”关注的目标单元是“crtdll.obj”,里面则包含了“_CRT_INIT”的具体实现。和“nssock2.dll”中的“_CRT_INIT”函数类似,这里调用“_initterm”函数执行函数指针列表,注意其参数“__xc_a”被声明是一个外部的变量。也就是说,控制函数指针列表区域位置(开始地址和结束地址)的是真正定义这2变量的位置,仅仅是污染这个模块单元的代码(或“crt0data.obj”单元代码)并不容易形成“nssock2.dll”中被植入的代码结构。
事实上,调用“_initterm”执行的函数指针列表是C++全局对象的构造函数,为了验证XShellGhost后门的植入机制,可以简单新建一个MFC DLL的测试项目,在全局“CtestApp”对象之前定义2个全局对象global_a和global_b,此时这2个对象的构造函数test_a和test_b的地址将被依次写入上述函数指针列表中。
将编译好的测试dll文件拖进IDA进行分析,就可以看到global_a和global_b的构造函数分别位于函数地址列表中的第二项和第三项,和XShellGhost被插入恶意代码的位置结构一致。因此,有理由相信攻击者并不是污染了开发环境的静态库,而更有可能是在“nssock2.dll”的项目文件前面的位置插入了第一个自定义全局对象,以此来获得解密shellcode运行的机会。
(三)、shellcode1(Loader模块)分析
本阶段shellcode主要做准备加载工作,本质上是一个“Loader”,并且此加载器在后续阶段将多次出现和复用。首先从PEB的ldr获取模块加载列表,遍历列表找到“kernel32.dll”的基址后进而解析其导出表函数来获得所需API函数的地址。
接着分配一块包含可执行属性的内存用于解密下一阶段的shellcode(下文简称shellcode2),解密前先按照一种特殊的自定义算法初始化其内存数值。
shellcode2的解密算法如下。
解密完成后还需要准备shellcode2的API,这里使用了一种特殊的方式来导入所需的API地址。首先API调用统一用9字节的“gadget”代码实现,每段“gadget”通过对实际API地址取反解码后进行跳转;同时,如果调用的API地址被设置了调试器断点(软中断INT3字节码即 0xCC),则会随机对“gadget”代码前置指令码和API地址的取反值(下图中的0x***)进行干扰,使其不能正常调用API。
准备完毕调用一个寄存器call进入shellcode2代码。
(四)、shellcode2(后门上线模块)分析
本阶段shellcode的主要任务是信息采集,用于筛选目标用户进而决定是否执行下一阶段的shellcode(下文简称shellcode3),首先创建一个单独的线程来进行接下来的任务。
判断是否执行shellcode3是根据该后门存储在用户系统注册表中的感染标志来决定的,注册表的路径根据用户的硬盘序列号异或“0xD592FC92”生成,感染标志的数据则在该路径(HKLMSOFTWARE%d或HKCUSOFTWARE%d)“Data”字段存储,此字段存储的数据不仅包含感染标志信息,还包含shellcode3的2个解密key等相关信息。
事实上,shellcode3的解密算法和“nssock2.dll”解密第一阶段shellcode的算法是相同的,并且解密key(“0xC9BED351”和“-0x57A25E37”即0xA85DA1C9)也一致,只不过在第一次感染(感染标志不为1)时这2个解密key(“data.key1”和“data.key2”)是通过云端下发更新到“Data”字段。
第一次感染时,会判断当前时间与上次感染时间(“last_run_time”)的时间差,若满足一定的时间间隔则发送dns来请求云端数据,进而决定是否可以执行shellcode3。
发送dns请求云端数据的过程是被各大安全厂商分析较多的部分。原本DNS协议是用于查询某个特定域名所对应的ip地址,这里却被攻击者用来作为隐蔽传输数据的一种方式,并且为了降低被锁定发现的风险,还另外采用一种被称之为“DGA”的动态域名生成算法来自动更换查询上线的域名。本后门采用的“DGA”算法是每个月更换一次上线域名,比如当前月份(2021年11月)的上线域名是“xonqzedybmdidyd.com”,攻击者将通过构造这个域名的DNS查询数据并发送到网关默认DNS服务器以及4个指定的公共DNS服务IP地址(如下8.8.8.8等)来进行云端操控后门的运行开关。
具体的“DGA”算法生成域名的过程如下,可以看出是通过把当前系统时间值按照特定的算法转换成了特定字符串来充当域名的前缀主域部分。
发送的数据按照特定格式进行组织后再加密和编码转换成上线域名的子域字符串部分,如下是数据的加密算法,加密前的数据前部有个“DOOR”的标志字符串(小端存储,猜测此处表征后门之意),紧接着还包含了被攻击系统的主机名和用户名等信息可供控制端进行筛选。
编码子域字符串部分的算法如下,每个字节将被简单编码成对应的2个字符,所以根据该算法也比较容易从一些DNS查询记录中恢复出受害用户的相关信息。
同时,由于此数据编码后的子域长度较大,其实反而容易显得可疑而暴露自身,根据卡巴斯基报告中关于“在调查期间发现了可疑的DNS请求”的描述可能指代的就是这里。若是没有此缺陷,XShellGhost后门可能存活的时间还会更长一些,并且经此一役,各大安全厂商也开始加强对此类“DNS隧道攻击”的监控。
由于时间过去较久,XShellGhost作者早已下线,此后门相关的“DGA”域名也陷入了假死状态。不过这里有一个意外的发现,本月(2021年11月)的“DGA”域名查询返回了一条通知数据如下,该数据反映出此上线域名此时已被“ns*.honeybot.us”的DNS服务器接管,从其名称关键词“honeybot”可以猜测是蜜罐跟踪之类的意思,很可能是希望对此后门的后续活动进行监控。
若能成功接收到攻击方从远端下发的执行命令,就可以从中获得下一阶段shellcode3的解密key,进而完成下面的控制过程。
(五)、shellcode3(Loader模块)分析
通过上一节的分析,虽然此时已无法获得攻击者下发的控制数据,但基于对解密shellcode3的算法/密钥与解密第一阶段shellcode相一致的猜测,最终可以解出shellcode3的代码。同时,由于shellcode3的功能代码是复用了第一阶段shellcode那个加载器,只是要加载运行的下一阶段代码不同而已,所以本节也不再赘述直接进入下一节shellcode4的分析。
(六)、shellcode4(远控模块)分析
本阶段shellcode就是XShellGhost最核心的远控模块,此模块最大的特点就是采用插件式(“Plugin”)管理,整套远控程序由一个母体插件(“Root”)管理多个子功能插件的方式来运行。
每个插件的入口和DllMain有点类似,均通过fdwReason来定义具体要执行的操作。通用的操作码如1表示插件初始化,102表示获取插件的编号id,103表示获取插件的名称,104表示获取插件提供的API功能列表。如下即母体插件“Root”的入口函数,插件id为100。
通过上述操作码可获得本模块共计6个插件的编号和名称,具体说明如下。
“Root”母体插件在初始化阶段会加载其他5个子插件并调用“Install”插件来进行安装操作。
加载插件的过程其实还是复用上述shellcode1的“Loader”代码,可见此后门是基于此方式来实现模块化调用。
另外所有插件模块中还存在一个通用的字符串解密函数,专门用于在需要使用字符串的时候进行临时解密,通过此方式来隐藏自身的静态特征以阻碍安全人员分析和躲避安全软件的查杀。
当然,通过此解密算法我们也很容易就可以写出辅助脚本可以方便的解出插件中包含的加密字符串用于分析,如下是一个IDA Python的示例解密脚本仅供参考。
(七)、子功能插件分析
本节简单按照插件编号的顺序分别介绍一下5个子插件的功能。
“Plugins”插件
本插件除了向其他插件提供注册表查询、写入和删除的操作接口之外,最重要的功能就是实现了一种拓展外部插件的机制。具体是监控注册表“HKLMSOFTWAREMicrosoft\%rand%”(或HKCU路径下)的变化,若捕捉到变化就去加载存储在该路径下的插件数据。
捕捉到变化后循环枚举该路径下各项的数据,检查该数据是否为有效插件并调用“Root”插件提供的相关接口加载。
“Config”插件
本插件最重要的功能就是读写运行配置,其中即包含默认的远控C&C地址、安装时注入到的进程等重要信息。这些信息同样以加密字符串的形式进行存储,解密后可见C&C地址为“dns://www.notped.com”(猜测仿冒记事本“notepad”域名),被注入的进程路径是系统进程“svchost.exe” ,指定的DNS查询服务器同上述的“8.8.8.8”等4个公用IP。
这些运行配置在每次后门运行时都会被加载并重新加密写入路径为“%ALLUSERSPROFILE%%rand%%rand%%rand%%rand%”的文件中存储,此路径根据用户的硬盘信息生成,每台机器看上去随机但对用户来说是相对固定的。
“Install”插件
本插件主要就是进行后门的安装,将母体插件“Root”注入到上述“Config”插件指定的进程“svchost.exe”中运行。注入过程先尝试以“Winlogon.exe”的系统进程权限来创建傀儡进程“svchost.exe”,若失败再以普通权限创建。
傀儡进程创建(挂起状态)成功后调用“Root”插件提供的一个API接口来完成注入操作。具体是先注入通用的“Loader”加载器代码,然后注入“Root”母体插件的数据,最后通过劫持傀儡进程入口点或创建远程线程的方式来执行“Loader”代码加载运行“Root”母体后门。
注入后成功加载“Root”插件后门:
除了安装后门的功能外,本插件还会检查运行环境是否正在被调试或被监控,调试检测主要是调用“IsDebuggerPresent”判断或遍历活动窗口判断是否包含“WinDbgFrameClass”等调试工具的窗口类。
监控检测主要检测2款著名的工具,一款是系统资源监控工具“ProcMon”,判断方式是每隔1秒尝试打开如下几个诸如“.ProcmonDebugLogger”的全局对象,若存在则立即退出进程。
另外一款则是网络流量监控工具“Wireshark”,判断方式是每隔5秒尝试检查
“Wireshark-is-running-{9CA78EEA-EA4D-4490-9240-FC01FCEF464B}”互斥体对象是否存在,若存在则立即退出进程。
“Online”插件
本插件主要就是根据“Config”插件设置的C&C地址选择相应的网络通讯协议进行上线,首先使用“InternetCrackUrlA”解析完整的C&C地址“dns://www.notped.com”(包含协议头和网络地址)。
接着就是判断协议头“scheme”来设置相应的通讯协议ID,如下可见总共支持7种地址协议:TCP(200)、HTTP(201)、HTTPS(204)、UDP(202)、DNS(203)、SSL(205)和URL,由于本后门设置的是DNS协议地址则选择DNS通讯模块进行调用。
这里比较特别的是URL类型的通讯协议,若配置的C&C地址是该类型,则会通过WinHttp请求对应的地址来获取远程数据作为实际的C&C地址,请求之前还会先通过设置注册表“HKCUSoftwareMicrosoftWindowsCurrentVersion\Internet Settings”的“SecureProtocols”字段值为-1来禁用WinHttp的安全协议。
并且URL类型地址还另外支持3种协议头:“HTTP”、“HTTPS”和“FTP”。
最终调用对应通讯模块来发送上线请求,若成功接收到响应则执行相应的指令,比如收集目标用户的系统运行信息。
“DNS”插件
本插件核心的功能就是提供网络通讯的接口来收发C&C指令,因为是基于DNS协议所以“Online”插件会调用本插件接口来建立专用的DNS隧道进行通信,选用的DNS服务器即网关默认DNS和“Config”插件指定的4个“8.8.8.8”等公用IP。
发送的数据就类似上述shellcode2阶段被编码成DNS查询的全域名(FQDN)的子域部分,最终控制端靠解析此部分编码来接收传输数据。不过这里使用的主域部分不再是使用“DGA”生成的域名,而是“Config”插件指定的C2域名“www.notped.com”,发送时构造类型为“TXT”的DNS查询数据包依次发送给公共DNS服务器IP列表来完成数据传输。
发送完DNS查询数据后正常可以马上接收到响应包,但是需要检查其中是否包含正确的“TXT”回复包,后门需要据此获得控制端设置的控制指令。
只有当响应的“TXT”回复包满足特定的编码格式才能解析出指令数据成功进行控制操作,而这通常需要控制者对其C&C域名设置自定义的NS解析服务器,才能方便的接收来自公共DNS的查询数据包实时返回自定义控制数据包。
当前由于C&C域名早已失效,所以直接返回了服务端失败的标志,无法进入指令解析的流程。
0x03 溯源分析
本节仅简要整理并罗列出一些网上公开的报告信息。首先看一下当时与该后门直接相关的一些C&C域名:
2017年7月23和24日,攻击者在NameSilo网站注册了7月至12月相关的6个域名,启用了隐私保护服务,但是没有指向IP地址。
2017年8月1日,攻击者再次在NameSilo网站注册了2018年1月、2月、3月、7月相关的4个域名,注册者为Lucy Anteo,注册邮箱为“lucyaggregate@gmail.com”。
2017年7月份的DGA域名“ribotqtonut.com”存在多个子域名,在7月24日至26日曾将该域名的NS解析服务地址指向ns*.ribotqtonut.com,且这些子域名分别指向“209.105.242.187”和“108.60.212.78”两个IP地址(属地均为美国)。
根据微步在线的报告分析,另一个Gmail邮箱“hostay88@gmail.com”与2个IP地址存在较强关联,该邮箱于2014年、2015年期间注册了“paniesx.com”、“notped.com”、“techniciantext.com”、“operatingbox.com”和“dnsgogle.com”5个域名。其中“notped.com”和“dnsgogle.com”均存在多个与此次事件类似的超长子域名,据此判断攻击者为同一团伙的可能性较大,活动时间或可追溯至2014年。
0x04 DNS隧道防御检测
本节仅简单介绍一下防御检测恶意利用DNS隧道的思路。
XShellGhost后门主要有2个阶段用到了DNS隧道传输数据,第一阶段是ShellCode2使用DGA域名将用户信息编码到子域部分上传到控制端解码筛选,利用TXT回复包下发解密key;第二阶段则是远控模块使用类似的方式进行C&C指令的传输交互。这2个阶段在发包时候都是连续地向至少5个DNS服务IP地址发送超长域名查询,且通过TXT类型的包来携带数据。此外,发送DNS查询包的载体进程也较为可疑(通常是系统网络服务进程“svchost.exe”),其中第一阶段是后门载体进程如“xshell.exe”在发包,第二阶段则是其傀儡子进程“svchost.exe”发包。
针对这些可疑的特征进行归纳,首先可以把主机名(子域部分)超过52个字符的DNS查询请求作为识别DNS隧道的特征,因为正常的域名满足“Zipf”定律,而走DNS隧道的域名遵循的是随机分布。然后可以进行流量层面的监测,如单位时间内DNS报文的速率,或者连续多个TXT类型的DNS报文等都可以作为识别特征进行监控。最后就是结合发送DNS报文的进程名或进程链进行参照分析,提高甄别筛选的效率。
0x05 总结
XShellGhost事件是一起针对IT基础设施平台(软件)的经典供应链攻击案例,其本质是攻击者在入侵知名公司NetSarang后污染其软件产品源代码植入后门,并利用该产品分发传播来实施定向攻击。随着该事件的发生和披露,预示着此类攻击事件将在未来频繁演绎,所有的单位或个人都可能成为被渗透和攻击的对象,防不胜防。关于软件供应链安全的话题和研究,也将激起未来安全形势新的变化和浪潮。
0x06 参考链接
1、 ShadowPad in corporate networks,https://securelist.com/shadowpad-in-corporate-networks/81432/
2、 ShadowPad: popular server management software hit in supply chain attack,https://media.kasperskycontenthub.com/wp-content/uploads/sites/43/2017/08/07172148/ShadowPad_technical_description_PDF.pdf
3、 Xshell高级后门完整分析报告,https://security.tencent.com/index.php/blog/msg/120
4、 Xshell被植入后门代码事件分析报告,https://www.anquanke.com/post/id/86655
5、 Xshellghost技术分析——入侵感染供应链软件的大规模定向攻击,https://www.anquanke.com/post/id/86657
6、 XShellGhost事件技术回顾报告,https://cert.360.cn/static/files/XShellGhost%E4%BA%8B%E4%BB%B6%E6%8A%80%E6%9C%AF%E5%9B%9E%E9%A1%BE%E6%8A%A5%E5%91%8A.pdf
7、 C/C++ Runtime Library Code Tampering in Supply Chain,https://www.trendmicro.com/en_us/research/19/d/analyzing-c-c-runtime-library-code-tampering-in-software-supply-chain-attacks.html
8、 调试实战——dll加载失败之全局变量初始化篇,https://www.shangmayuan.com/a/b15e4d7d24f9466584cd3f89.html
9、 XshellGhost再现?使用DNS隧道传输的PlugX远控变种分析,https://bbs.zkaq.cn/t/1073.html
10、rdp连接_揭开谍中谍的好戏,关键词:HW、RDP漏扫、红蓝对抗,https://blog.csdn.net/weixin_36443823/article/details/112720716
11、DNS报文格式,https://www.cnblogs.com/qrxqrx/articles/8034781.html
12、微步通告: XShell官方软件被植入后门溯源分析,https://m.threatbook.cn/detail/67
13、Xshell后门事件中用到的DNS Tunneling技术分析,https://slab.qq.com/news/tech/1638.html
14、XShell后门DNS Tunnel编码分析,https://www.anquanke.com/post/id/86630
15、Xshell dns tunnel攻击,https://www.cnblogs.com/bonelee/p/7850493.html
16、隧道技术之DNS和ICMP与其检测防御,https://www.lper.cn/post/sui-dao-ji-zhu-zhi-dns-he-icmp-yu-qi-jian-ce-fang-yu/#xshellghost
17、一次误报引发的DNS检测方案的思考:DNS隧道检测平民解决方案,https://www.163.com/dy/article/D09THVKG05119F6V.html
目前没有反馈
表单载入中...