![7f02fc4ed8e09725c1ff7972ff9f8c93.png](https://img-blog.csdnimg.cn/img_convert/7f02fc4ed8e09725c1ff7972ff9f8c93.png)
![7f02fc4ed8e09725c1ff7972ff9f8c93.png](https://img-blog.csdnimg.cn/img_convert/7f02fc4ed8e09725c1ff7972ff9f8c93.png)
LoadLibrary*
函数来利用DLL中的功能。应用程序可以引用为该应用程序自定义创建的DLL,也可以引用位于System32路径下的已有DLL。开发人员可以定义应用程序从System32加载DLL,以使用Windows中已实现的功能,这样就不必再自行编写特定功能。
例如,如果应用程序需要发出HTTP请求,那么开发人员就可以利用WinHTTP库(
winhttp.dll
),而不需要再使用原始套接字实现HTTP请求。
![7f02fc4ed8e09725c1ff7972ff9f8c93.png](https://img-blog.csdnimg.cn/img_convert/7f02fc4ed8e09725c1ff7972ff9f8c93.png)
HKEY_LOCAL_MACHINESystemCurrentControlSetControlSession ManagerSafeDllSearchMode
)。在启用安全的DLL搜索模式后,搜索顺序如下:
1、加载应用程序的目录;
2、系统目录,使用
GetSystemDirectory
函数获取该目录的路径;
3、16位系统目录,没有获取该目录路径的函数,但会对该目录进行搜索;
4、Windows目录,使用
GetWindowsDirectory
函数获取该目录的路径;
5、当前目录;
6、PATH环境变量中列出的目录,这里不包括
App Paths
注册表项指定的每个应用程序路径,在计算DLL搜索路径是不会使用到
App Paths
键。
在系统中可以包含同一个动态链接库(DLL)的多个版本。应用程序可以通过指定完整路径或使用其他机制(例如清单)来控制DLL的加载位置。
如果应用程序未指定从哪里加载DLL,那么Windows将会默认使用上述DLL搜索顺序。因此,作为攻击者来说,往往就会对DLL搜索的第一个位置(加载应用程序的目录)感兴趣。
如果应用程序开发人员希望从C:WindowsSystem32加载DLL,但在应用程序中没有明确写入,那么就会在搜索System32中的合法DLL之前,先加载应用程序目录中被植入的恶意DLL。这种恶意DLL加载方式被称为DLL劫持,攻击者以这种方式将恶意代码加载到受信任或已签名的应用程序中。
![7f02fc4ed8e09725c1ff7972ff9f8c93.png](https://img-blog.csdnimg.cn/img_convert/7f02fc4ed8e09725c1ff7972ff9f8c93.png)
userenv.dll
来实现DLL劫持。
攻击者针对了特定的应用程序进行攻击,因为在默认情况下,这些程序会被配置为在Windows启动时自动启动。我们可以在任务管理器中找到它们。
配置为开机时自动启动的Windows应用程序:
![3133dc7a806081352e00b91e93417d23.png](https://img-blog.csdnimg.cn/img_convert/3133dc7a806081352e00b91e93417d23.png)
userenv.dll
,并将其复制到易受攻击的应用程序的目录中。在启动该应用程序之后,我就看到了新的Beacon回调。
通过DLL劫持实现Cobalt Strike Beacon:
![410fe65845b08f5d206ce4d93b3a1ac7.png](https://img-blog.csdnimg.cn/img_convert/410fe65845b08f5d206ce4d93b3a1ac7.png)
![b8df12b22fba5e8126ea525f3696f6a4.png](https://img-blog.csdnimg.cn/img_convert/b8df12b22fba5e8126ea525f3696f6a4.png)
![7f02fc4ed8e09725c1ff7972ff9f8c93.png](https://img-blog.csdnimg.cn/img_convert/7f02fc4ed8e09725c1ff7972ff9f8c93.png)
5.1 案例分析:Slack
在一开始,我在进程管理器(ProcMon)中使用了以下过滤器: 1、进程名称为slack.exe
;
2、结果包含
NOT FOUND
;
3、路径以
.dll
结尾。
使用ProcMon过滤丢失的DLL:
![beb07a5800c8c4e2393541b6063f70a0.png](https://img-blog.csdnimg.cn/img_convert/beb07a5800c8c4e2393541b6063f70a0.png)
![1fad75172ad81eb597502296fb587710.png](https://img-blog.csdnimg.cn/img_convert/1fad75172ad81eb597502296fb587710.png)
GetModuleHandleEx
和
GetModuleFileName
来确定加载的DLL的名称,并将其写入文本文件。
我们的下一个目标是解析CSV文件,以获得DLL路径列表,遍历这个路径列表,将测试DLL复制到指定的路径,启动目标进程,停止目标进程,并删除测试DLL。如果这个测试DLL能成功加载,就会将这个文件名写入到结果文件中。
在这一过程完成时,我们就有了一个文本文件,其中包含可以用于DLL劫持的列表。
在我的DLLHijackTest项目中,主要使用PowerShell脚本来完成所有工作。它负责接受ProcMon生成的CSV文件中包含的路径、恶意DLL路径、要启动的进程路径以及要传递给该进程的所有参数。
Get-PotentialDLLHijack
参数:
![83199f91c4d3d7dba1de5dd32f2042ff.png](https://img-blog.csdnimg.cn/img_convert/83199f91c4d3d7dba1de5dd32f2042ff.png)
Get-PotentialDLLHijack.ps1
:
![bc5110deb5bb3e87c22d98dac07ebb8c.png](https://img-blog.csdnimg.cn/img_convert/bc5110deb5bb3e87c22d98dac07ebb8c.png)
PS C:UsersJohnDesktop> Get-PotentialDLLHijack -CSVPath .Logfile.CSV -MaliciousDLLPath .DLLHijackTest.dll -ProcessPath "C:UsersJohnAppDataLocalslackslack.exe"C:UsersJohnAppDataLocalslackapp-4.6.0WINSTA.dll
C:UsersJohnAppDataLocalslackapp-4.6.0LINKINFO.dll
C:UsersJohnAppDataLocalslackapp-4.6.0ntshrui.dll
C:UsersJohnAppDataLocalslackapp-4.6.0srvcli.dll
C:UsersJohnAppDataLocalslackapp-4.6.0cscapi.dll
C:UsersJohnAppDataLocalslackapp-4.6.0KBDUS.DLL
5.2 案例分析:Microsoft Teams
再次进行以上的步骤: 1、使用ProcMon识别出潜在的DLL劫持,并将数据导出为CSV文件; 2、确定启动进程的路径; 3、确定要传递给进程的所有参数; 4、使用适当的参数运行Get-PotentialDLLHijack.ps1
。
最后发现,Microsoft Teams存在以下劫持:
PS C:UsersJohnDesktop> Get-PotentialDLLHijack -CSVPath .Logfile.CSV -MaliciousDLLPath .DLLHijackTest.dll -ProcessPath "C:UsersJohnAppDataLocalMicrosoftTeamsUpdate.exe" -ProcessArguments '--processStart "Teams.exe"'C:UsersJohnAppDataLocalMicrosoftTeamscurrentWINSTA.dll
C:UsersJohnAppDataLocalMicrosoftTeamscurrentLINKINFO.dll
C:UsersJohnAppDataLocalMicrosoftTeamscurrentntshrui.dll
C:UsersJohnAppDataLocalMicrosoftTeamscurrentsrvcli.dll
C:UsersJohnAppDataLocalMicrosoftTeamscurrentcscapi.dll
C:UsersJohnAppDataLocalMicrosoftTeamscurrentWindowsCodecs.dll
C:UsersJohnAppDataLocalMicrosoftTeamscurrentTextInputFramework.dll
需要特别说明的是,在这里需要对PowerShell脚本进行少量修改,才能终止
Teams.exe
,因为我的脚本试图终止它尝试启动的进程,即
Update.exe
。
5.3 案例分析:Visual Studio Code
重复上述过程,我发现了Visual Studio Code存在以下劫持:
PS C:UsersJohnDesktop> Get-PotentialDLLHijack -CSVPath .Logfile.CSV -MaliciousDLLPath .DLLHijackTest.dll -ProcessPath "C:UsersJohnAppDataLocalProgramsMicrosoft VS CodeCode.exe"C:UsersJohnAppDataLocalProgramsMicrosoft VS CodeWINSTA.dll
C:UsersJohnAppDataLocalProgramsMicrosoft VS CodeLINKINFO.dll
C:UsersJohnAppDataLocalProgramsMicrosoft VS Codentshrui.dll
C:UsersJohnAppDataLocalProgramsMicrosoft VS Codesrvcli.dll
C:UsersJohnAppDataLocalProgramsMicrosoft VS Codecscapi.dll
5.4 共同的DLL劫持
在进行上述分析之后,我们注意到,Slack、Microsoft Teams和Visual Studio Code共享了以下的DLL劫持: WINSTA.dllLINKINFO.dll
ntshrui.dll
srvcli.dll
cscapi.dll 这非常值得关注,我们想要分析是什么导致了这样的情况。
![7f02fc4ed8e09725c1ff7972ff9f8c93.png](https://img-blog.csdnimg.cn/img_convert/7f02fc4ed8e09725c1ff7972ff9f8c93.png)
WINSTA.dll
、
LINKINFO.dll
、
ntshrui.dll
、
srvcli.dll
和
cscapi.dll
时,我观察了堆栈跟踪。
6.1 延迟加载的DLL
在加载WINSTA.dll
、
LINKINFO.dll
、
ntshrui.dll
和
srvcli.dll
时,我注意到堆栈跟踪中存在相似之处。
Code.exe尝试加载
WINSTA.dll
时的堆栈跟踪:
![f30baa800dbd51234bf21239bda9a4b8.png](https://img-blog.csdnimg.cn/img_convert/f30baa800dbd51234bf21239bda9a4b8.png)
LINKINFO.dll
时的堆栈跟踪:
![4b6fa8cf09be24c766bb69a9169f5cf9.png](https://img-blog.csdnimg.cn/img_convert/4b6fa8cf09be24c766bb69a9169f5cf9.png)
ntshrui.dll
时的堆栈跟踪:
![2bf90a321ca5aa28a6a2c97f6b4a99b3.png](https://img-blog.csdnimg.cn/img_convert/2bf90a321ca5aa28a6a2c97f6b4a99b3.png)
_tailMerge__dll
、
delayLoadHelper2
的调用,然后是
LdrResolveDelayLoadedAPI
。这三个应用程序之间的行为是一致的。
我可以确定,这样的行为与延迟加载的DLL有关。在加载
WINSTA.dll
时的堆栈跟踪中,我们发现负责延迟加载的模块是
wtsapi32.dll
。
于是,在Ghidra中打开
wtsapi32.dll
,并选择“Search” -> “For Strings” -> “Filter: WINSTA.dll”,双击找到的字符串,就可以查看其在内存中的位置。
wtsapi32.dll
中的“WINSTA.dll”字符串:
![bb3d40386f60cdd08b31716d878912df.png](https://img-blog.csdnimg.cn/img_convert/bb3d40386f60cdd08b31716d878912df.png)
WINSTA.dll
的引用:
![1958c29694dce2d3bca47e2185be5f41.png](https://img-blog.csdnimg.cn/img_convert/1958c29694dce2d3bca47e2185be5f41.png)
WINSTA.dll
字符串会传递给名为
ImgDelayDescr
的结构。我们查看有关此结构的文档,可以确认它与延迟加载的DLL相关。
typedef struct ImgDelayDescr {
DWORD grAttrs; // attributes
RVA rvaDLLName; // RVA to dll name
RVA rvaHmod; // RVA of module handle
RVA rvaIAT; // RVA of the IAT
RVA rvaINT; // RVA of the INT
RVA rvaBoundIAT; // RVA of the optional bound IAT
RVA rvaUnloadIAT; // RVA of optional copy of original IAT
DWORD dwTimeStamp; // 0 if not bound,
// O.W. date/time stamp of DLL bound to (Old BIND)
} ImgDelayDescr, * PImgDelayDescr;
可以将这个结构传递给
__delayLoadHelper2
,它将使用
LoadLibrary/GetProcAddress
加载指定的DLL,并在延迟加载导入地址表(IAT)中修补导入函数的地址。
FARPROC WINAPI __delayLoadHelper2(
PCImgDelayDescr pidd, //Const pointer to a ImgDelayDescr struct
FARPROC * ppfnIATEntry //A pointer to the slot in delay load IAT
);
查找对
ImgDelayDescr
结构的其他引用,我们可以找到对
__delayLoadHelper2
的调用,该调用随后会调用
ResolveDelayLoadedAPI
。在这里,我已经将函数名称、类型和变量进行重命名,以使其更加易于理解。
在Ghidra中查看的
__delayLoadHelper2
和
ResolveDelayLoadedAPI
:
![cdaabb7cc6431aa0c73ea5b8ee176beb.png](https://img-blog.csdnimg.cn/img_convert/cdaabb7cc6431aa0c73ea5b8ee176beb.png)
WINSTA.dll
时在ProcMon堆栈跟踪中看到的结果相匹配了。
ProcMon中的
__delayLoadHelper2
和
ResolveDelayLoadedAPI
:
![356918ca220fe62e89ff897ff9b852fe.png](https://img-blog.csdnimg.cn/img_convert/356918ca220fe62e89ff897ff9b852fe.png)
WINSTA.dll
、
LINKINFO.dll
、
ntshrui.dll
和
srvcli.dll
之中,行为是一致的。每个延迟加载的DLL之间,主要区别在于它们的父DLL。在这三个应用程序中:
wtsapi32.dll
延迟加载
WINSTA.dll
;
shell32.dll
延迟加载
LINKINFO.dll
;
LINKINFO.dll
延迟加载
ntshrui.dll
;
ntshrui.dll
延迟加载
srvcli.dll
。
观察到了什么有趣的地方吗?似乎
shell32.dll
加载了
LINKINFO.dll
,而
LINKINFO.dll
又加载了
ntshrui.dll
,最后由
ntshrui.dll
加载了
srvcli.dll
。
6.2 NetShareGetInfo和NetShareEnum中的DLL劫持
当Slack尝试加载cscapi.dll
时,我观察了堆栈跟踪,看到其中有一个
LoadLibraryExW
调用,该调用似乎源自
srvcli.dll
。
加载
cscapi.dll
时的堆栈跟踪:
![3cd13a5b67bb22a92476f8eb31ace1e9.png](https://img-blog.csdnimg.cn/img_convert/3cd13a5b67bb22a92476f8eb31ace1e9.png)
srvcli.dll
,并选择“Search” -> “For Strings” -> “Filter: cscapi.dll”,双击找到的字符串,并在跟踪引用,看能否找到预期的
LoadLibrary
调用。
srvcli.dll
在
cscapi.dll
上调用
LoadLibrary
:
![3b20019d730511254f2ce8ae8f217f68.png](https://img-blog.csdnimg.cn/img_convert/3b20019d730511254f2ce8ae8f217f68.png)
LoadLibrary
调用的函数进行重命名,并跟踪引用,最后找到了两个函数的位置:
NetShareEnumNetShareGetInfo
NetShareEnum
加载
cscapi.dll
:
![61e653439f38f301986b62d253b8a665.png](https://img-blog.csdnimg.cn/img_convert/61e653439f38f301986b62d253b8a665.png)
NetShareGetInfo
加载
cscapi.dll
:
![264aa7e7a9787db6babeddf48a3d0a99.png](https://img-blog.csdnimg.cn/img_convert/264aa7e7a9787db6babeddf48a3d0a99.png)
NetShareEnum
和
NetShareGetInfo
,可以对PoC程序进行验证。
NetShareEnum
加载
cscapi.dll
:
![0733c8fb06acb6e1d14e18df1362e753.png](https://img-blog.csdnimg.cn/img_convert/0733c8fb06acb6e1d14e18df1362e753.png)
NetShareGetInfo
加载
cscapi.dll
。
![e2a9ddea01d03b5d7ba4dd4735c2f4cf.png](https://img-blog.csdnimg.cn/img_convert/e2a9ddea01d03b5d7ba4dd4735c2f4cf.png)
![7f02fc4ed8e09725c1ff7972ff9f8c93.png](https://img-blog.csdnimg.cn/img_convert/7f02fc4ed8e09725c1ff7972ff9f8c93.png)
C:UsersJohnAppDataLocalslackapp-4.6.0WINSTA.dll
C:UsersJohnAppDataLocalslackapp-4.6.0LINKINFO.dll
C:UsersJohnAppDataLocalslackapp-4.6.0ntshrui.dll
C:UsersJohnAppDataLocalslackapp-4.6.0srvcli.dll
C:UsersJohnAppDataLocalslackapp-4.6.0cscapi.dll
C:UsersJohnAppDataLocalslackapp-4.6.0KBDUS.DLL
以下DLL劫持存在于Microsoft Teams中:
C:UsersJohnAppDataLocalMicrosoftTeamscurrentWINSTA.dll
C:UsersJohnAppDataLocalMicrosoftTeamscurrentLINKINFO.dll
C:UsersJohnAppDataLocalMicrosoftTeamscurrentntshrui.dll
C:UsersJohnAppDataLocalMicrosoftTeamscurrentsrvcli.dll
C:UsersJohnAppDataLocalMicrosoftTeamscurrentcscapi.dll
C:UsersJohnAppDataLocalMicrosoftTeamscurrentWindowsCodecs.dll
C:UsersJohnAppDataLocalMicrosoftTeamscurrentTextInputFramework.dll
以下DLL劫持存在于Visual Studio Code中:
C:UsersJohnAppDataLocalProgramsMicrosoft VS CodeWINSTA.dll
C:UsersJohnAppDataLocalProgramsMicrosoft VS CodeLINKINFO.dll
C:UsersJohnAppDataLocalProgramsMicrosoft VS Codentshrui.dll
C:UsersJohnAppDataLocalProgramsMicrosoft VS Codesrvcli.dll
C:UsersJohnAppDataLocalProgramsMicrosoft VS Codecscapi.dll
此外,我发现使用
NetShareEnum
和
NetShareGetInfo
的程序,由于其中包含硬编码的
LoadLibrary
调用,因此以
cscapi.dll
的形式引入了DLL劫持。通过Ghidra和PoC,我们最终得以确认了这种行为。
![7f02fc4ed8e09725c1ff7972ff9f8c93.png](https://img-blog.csdnimg.cn/img_convert/7f02fc4ed8e09725c1ff7972ff9f8c93.png)
NetShareEnum
加载
cscapi.dll
和
NetShareGetInfo
加载
cscapi.dll
)将DLL劫持引入了所有调用它们的程序之中。
感谢大家抽出宝贵的时间来阅读这篇文章,希望通过本文,能让大家对于Windows API、Ghidra、ProcMon、DLL和DLL劫持都能有所了解。
![7f02fc4ed8e09725c1ff7972ff9f8c93.png](https://img-blog.csdnimg.cn/img_convert/7f02fc4ed8e09725c1ff7972ff9f8c93.png)
译文声明
译文仅供参考,具体内容表达以及含义原文为准。
![29adc4ad5d801554065a4b6fc5f716d3.gif](https://img-blog.csdnimg.cn/img_convert/29adc4ad5d801554065a4b6fc5f716d3.gif)