技术分享
警惕!攻防演练期间针对攻击队的钓鱼执法
发布时间 · 2022-08-09

XOA反序列化命令执行漏洞利用工具样本分析

  

  攻防演练期间,矢安科技安全研究部在社交媒体、代码托管平台、公众号、IM群组等渠道检测到大量漏洞利用样本。其中部分样本“换汤不换药”,依然使用历史payload,部分样本编译为exe,其中捆绑了后门。

  在攻防演练接近尾声时,防守成员利用部分攻击成员“最后冲刺”的心理,公开投递了部分捆绑后门的样本。现针对名为“X达OA-list接口反序列化命令执行漏洞.exe”的样本进行分析。


本信息:


样本分析

首先对样本进行简单分析,查看样本字符串信息:




发现有创建管道、创建线程的函数,并且格式化的字符串信息


动态运行: 

在虚拟机中动态运行查看效果


运行后没有界面反馈,查看其运行的基本信息


根据上面创建线程的函数,判断exe可能创建线程进行一些操


通过443端口访问远程地址,可能有如下可

1.下载新的样本执行

2.样本连接C2服务


调试分析:

64位程序放入IDA中进行分析:进入主函数查看:

 


主函数较简单,经分析得知sub_401795()为关键函数

进入关键函数sub_401795()分析



首先可以看到,第一个红框中定义了几位字符,并结合sprintf函数的格式化字符串信息可知,此处是创建管道的字符串信息,并且管道名称MSSE-xxx-server,其 ‘xxx’ 是通过GetTickCount()函数获取开机以来的时间,并和0x26AA运算后得到的结果,作为XXX的名字

接着创建了线程,线程的起始地址为sub_401685()跟进函数查看:



unk_404014()函数:



nNumberOfBytesToRead()函数

 


dword数据,值为0x39F进入sub_4015D0()函数查看可以看到通过CreateNamePipeA()函数创建管道



其中ConnectNamedPipe()函数来维持管道,直到遇见CreateFile()函数,该函数才会返回非零的值,后面WriteFile()函数才会执行,否则该线程一直等待


从后面WriteFile()函数可以看到,之前数据通过管道进行传输,而nNumberOfBytesToWrite()则为一次传输的数据量

继续往下分析其他函数


进入sub_401742()函数,

 

在行x64dbg中调试发现,此处Sleep函数执行后,刚刚的线程才开始执行先分析sub_4016A2()函数:

 

如前文所述,遇到CreateFileA函数管道开始传输的数据,在这里接受管道传输的数据

最后分析sub_40152E()函数:

 


v0为通过malloc()函数分配的内存指针指向接收到的未知数据 nNumberOfBytesToRead()值为39F,进入unk_404008()函数

 

 

可以看到将接收到的未知数据:

第一位和 ‘4’ 异或

第二位和 ‘0x3C’ 异或第三位和 ‘0x97’ 异或第四位和 ‘0xCE’ 异或

依次循环,将数据进行解密,解密后的数据地址就是下面CreateThread()函数的线程地址;

以上功能基本分析完成,但是发现程序主动联网行为,访问了远程IP地址,可知是在创建的线程中执行

 

调试线程:

由上面静态分析可知,创建线程的时候会用到函数VirtualAlloc()创建内存空间,用于存储解密后的数据在x64dbg中,查找跨模块调用,可以看到VirtualAlloc()函数


在这里下断点,F9执行,F8步过VirtualAlloc()函数


函数VirtualAlloc()返回值在rax寄存器中,内存的空间地址是0x20000转到0x20000地址,下硬件执行断点,F9执行


程序在0x20000地址处停止,前面一部分汇编代码是检测字符串是否完成,检测PE标识是否被修改


该部分用于从各dll文件中获取需要的API地址,查找到对应函数后,由0x200C4地址处的jmp rax指令调用函数,由于不是使用call指令,所以返回时会直接返回到下面call rbp指令的下一条指令,其中rbp的值都是0x2000A


每个call rbp指令都会查找API并执行执行的过程中可得到IP地址,


依次会执行一下函数,


LoadLibraryExA 加载了wininet.dll

InternetOpenA 初始化应用程序对 WinINet 函数的使

InternetConnectA 打开47.113.192.46:443站点的http会话

HttpOpenRequestA 创建http请求句柄,请求https://47.113.192[.]46:443/OuET

InternetSetOptionA 设置 Internet 选项


HttpSendRequestA  将指定的请求发送到 HTTP 服务器


http请求到的数据读取,并存储到VirtualAlloc申请到的内存里之后程序会跳转到0x37D0000区执行,先是检测个别字符串的完整度,然后查找MZ和PE标志,随后会查找以下函数的地址:


GetModuleHandleA() 检索指定模块的模块句柄。该模块必须已由调用进程加载

GetProcAddress() 从指定的动态链接库 (DLL) 中检索导出函数(也称为过程)或变量的地址

LoadLibraryA() 将指定的模块加载到调用进程的地址空间中。指定的模块可能会导致加载其他模块。

LoadLibraryExA()  将指定的模块加载到调用进程的地址空间中。指定的模块可能会导致加载其他模块。

VirtualAlloc() 在调用进程的虚拟地址空间中保留、提交或更改页面区域的状态。此函数分配的内存自动初始化为零。

VirtualProtect() 在调用进程的虚拟地址空间中更改对已提交页面区域的保护。


可以看到查找了6个函数,首先使用VirtualAlloc()分配了一块内存空间,然后将上面找到的MZ和PE标志对应的PE文件存入该内存空间中。使用LoadLibraryExA()函数加载KERNEL32.DLL动态库,并且使用GetProcAddress()获取函数的地址,获取的函数地址会存入PE文件中,修复后为dll文件,将dll文件dump出来进行分析:

 

DLL文件分析


x64调试中发现,修复完dll文件后会执行该文件的一个导出函数:


跟进导出函数查看:


导出函数里面调用了_DllMainCRTStartup()函数,继续跟进:


可以看到调用了DLLMain()函数


主要的远控操作在sub_225CA74()中:



sub_2263A30()函数中获取了系统的版本信息以及主机的相关信息

主要查看网络操作sub_255DF30函数:


首先函数sub_22653C8()中获取了Cookie的信息,图如下:

 

访问该服务器,从服务器中接收数据(远控指令),执行相应的远控操作

但是因为截止撰文时远控服务器并没有开启,无法接收远控的指令,只能静态分析一些远控的操作

文件操作:

 

通过循环获取文件目录

进程操作:




通过循环输出进程列表中的所有进程信息以及一些常见的远控操作,典型的Cobalt Strike行为。



总结

攻防演练接近尾声,攻击队成员迫切想要得分获取成果,但也要在钓鱼防守方成员的时候防范来自防守方的投毒。