根据软件工程高内聚低耦合的思想,把程序要重复使用的代码封装成函数/类方法,将软件要重复使用的程序封装成链接库。库分为静态链接库和动态链接库,静态链接库顾名思义就是在程序链接阶段打包进文件中,而动态链接库则是在程序运行时再导入调用。动态链接库有着加载时复用节省内存、补丁更新时可符合开闭原则等优点,也有容易发生版本冲突、容易被劫持等缺点。Windows平台下的动态链接库常为dll文件,linux则常为so文件。

dll劫持概念与类型

dll劫持就是要想方设法地调用到恶意dll。为了便于理解,需要了解一下目前Windows默认的dll调用顺序:

  • Known DLL 特指 定义在HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs中且只能在System目录中加载的dll们

由此可以引出几种dll劫持的形式:

  1. 直接将恶意dll暴力替换掉正常dll,软件正常功能会受影响

  2. 将恶意dll作为中间人,转发调用正常dll的导出函数,同时加入额外的恶意操作

  3. 利用加载顺序的机制,让恶意dll先于正常dll加载

  4. 利用软件本身缺失的dll加载恶意dll

  5. 更改环境变量或是.exe.manifest/.exe.local文件实现dll重定向

  • 如果利用低权限劫持的dll文件,会被高权限程序加载运行,就是一个权限提升漏洞

找dll劫持的一种方法

通过 Process Monitor 监控dll调用是一种最基础的寻找dll劫持的方式,在filter中添加Path ends with .dllResult is NAME NOT FOUND规则,并且可以加上Process Name contains xxx来针对性的找xxx的dll劫持。

编写一个加载dll的demo,让它加载一个不存在的dll,可以监控到加载的路径顺序(请无视中文路径乱码Orz)。如果这是一个真实的常用软件,则可以用来实现上文中的第4种劫持。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <Windows.h>

int main(int argc, char *argv[])
{
HMODULE hModule = LoadLibrary(argv[1]);
if (hModule) {
wprintf(L"Load Success\n");
FreeLibrary(hModule);
}
else {
wprintf(L"Load Error: %d\n", GetLastError());
}
}

劫持notepad++的dll

下面以notepad++为例,实现上文中的第2种劫持,这类dll转发利用#pragma comment(linker, "/EXPORT:xxx,@y)可以很方便地实现。

出于免杀上线以及权限维持的考虑,我们物色一下尽量符合这些特点的dll:

  1. 后台进程稳定不挂,避免主进程退出导致dll一起挂了

  2. 容易触发上线,行为隐蔽不易被杀软和人工发现

然后我看到了会被 updater/GUP.exe 拉起的 libcurl.dll,以及安装版中存在且可方便地附加到绿色版中的 NppShell_06.dll。前者是一个软件更新组件,后者是Windows右键中Edit with Notepad++的组件,会随explorer.exe加载且不会重复执行,只要在文件上按右键就会触发(并不需要点击它,看到时就已经加载了dll):

由于 GUP.exe 容易退出,需要让它加到常驻服务里去,我们优先看看 NppShell_06.dll。这是一个会随安装包的Context Menu Enty选项一起安装到软件目录的dll,通过 Process Monitor 监控并筛选注册表,发现有如下变动:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[HKEY_CLASSES_ROOT\CLSID\{B298D29A-A6ED-11DE-BA8C-A68E55D89593}]
@="ANotepad++64"

[HKEY_CLASSES_ROOT\CLSID\{B298D29A-A6ED-11DE-BA8C-A68E55D89593}\InprocServer32]
@="C:\\Program Files\\Notepad++\\NppShell_06.dll"
"ThreadingModel"="Apartment"

[HKEY_CLASSES_ROOT\CLSID\{B298D29A-A6ED-11DE-BA8C-A68E55D89593}\Settings]
"Title"="Edit with &Notepad++"
"Path"="C:\\Program Files\\Notepad++\\notepad++.exe"
"Custom"=""
"ShowIcon"=dword:00000001
"Dynamic"=dword:00000001
"Maxtext"=dword:00000019

[HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\ANotepad++64]
@="{B298D29A-A6ED-11DE-BA8C-A68E55D89593}"

也就是说只需要将安装文件中的 NppShell_06.dll 拷贝到绿色版文件中,并将上述变动导入注册表就可以手动实现添加右键打开的功能,不过该操作需要管理员权限。

  • regedit /s nppi.reg

构造了还不错的触发条件后,接下来将原dll更名为 NppShell_05.dll、找出导出函数,在我们的恶意dll中按顺序转发原函数调用并附加恶意操作(比如加载shellcode),目前已经有很多成熟的工具可以帮助找出这些导出函数们:

  • 开始调试时为了避免干扰因素,通常不会直接上shellcode而是用MessageBox弹窗做试验

免杀与权限维持

将恶意dll的shellcode简单处理一下后再伪造一个原dll的签名,此时就是正常签名程序->伪造签名的dll->正常签名的dll,测试了几款主流杀软和defender,可以挺人畜无害地上线CS:

对于权限维持而言,恶意dll会在第一次导入注册表操作时加载,之后可由任意文件上右键的行为被explore进程拉起,不会在任务管理器中看到恶意进程,也没有类似于开机自启这种敏感行为。而且有意思的是管理员会因为右键用杀软扫描文件的行为而上线2333


这是Web狗学习Windows的一点小测试记录,希望师傅们能分享更多好玩的tricks鸭~

参考链接

Dynamic-Link Library Search Order

Windows DLL Hijacking (Hopefully) Clarified

Hijacking DLLs in Windows

Adaptive DLL Hijacking

添加 Notepad++ 至右键菜单的几种方法

DLL劫持之权限维持篇(二)

shellcode加载总结