LNK快捷方式文件漏洞

[TOC]

漏洞简介

LNK 快捷方式文件漏洞,又叫 CPL Icon 加载漏洞。用户只要浏览一下 LNK 文件所在的目录病毒就能执行。

漏洞原理及利用分析

既然是快捷方式漏洞,那我们就先了解以下快捷方式文件的格式。

快捷方式文件的格式

快捷方式文件的结构是分段式的。

image-20220721221346481

触发漏洞的数据保存在 Shell Item Id List 段中,所以我们只介绍该段的数据结构。

Shell Item Id List 段为可选段,一个快捷方式文件中是否存在 Shell Item Id List 段是由文件头中偏移 0x14 位置处的值来决定,0bit 值为 1 时,表示该 lnk 文件包含该结构。同时如果存在该结构,偏移 0x4c 的位置的会存在一个 unsigned short int 型的变量,用来标识 Shell Item Id List 结构的大小,紧随其后的为一系列的 SHITEMID 结构,该结构体定义如下。

1
2
3
4
5
6
7
8
typedef struct _SHITEMID
{
unsigned short int cb; //cb标识一项SHITEMID结构大小
unsigned char abID[0]; //abID是可变结构,
//存储具体数据,但第0项里面的
//数据是不能修改的,
//否则.lnk文件无法运行。
}SHITEMID,*LPSHITEMID;
image-20220721222609971

漏洞触发的原理:SHELL32.DLL 在根据 Shell Item Id 加载快捷方式图标的时候未对被加载的项目(DLL 或者 CPL)进行有效性校验,造成了攻击者可能通过构造特殊的 Shell Item Id 来加载恶意的 DLL。

漏洞文件生成

实验环境:windows 2000 sp4

由于触发这个漏洞需要 CPL 加载机制,所以并不是所有的快捷方式文件都可以触发这个漏洞,只有指向控制面板下面功能的快捷方式才能够出发这个漏洞。

  1. 建立基础 LNK 文件:
    大家可以通过右键单击控制面板下面的图片,然后选择“创建快捷方式”选项来建立基础 LNK 文件。在这我们以“鼠标”为例。
image-20220731143316381
  1. 将建立好符合要求的基础 LNK 文件改造成能够触发漏洞的 POC 文件
    (1)用WinHex打开鼠标.LNK文件,将偏移 0x7A 到 0x7D 的 0x9CFFFFFF 修改为 0x00000000。需要注意的是,如果您在建立基础 LNK 文件时不是使用的“鼠标”项目, 0x7A 到 0x7D 的值可能不是 0x9CFFFFFF。
image-20220726105411454

​ (2)在偏移 0x8E 位置处写入我们要加载的 DLL 地址,在这我们使用 C:\DLL.DLL,其效果是弹出一个“test”对话框,当然您也可以选择使用其他的 DLL 来进行调试。

image-20220731143558861

漏洞产生原理

这个 POC 的最终目的是加载一个 DLL 文件,所以我们可以先在 LoadLibraryW 函数上设置断点,然后再通过回溯函数调用过程的方式找到上层函数,最终找到出问题的函数。

首先,我们先用下面的源码 再vc6.0中编写一个能弹出对话框的 DLL 文件,然后把这个文件重命名为 DLL.DLL 并放到 C 盘下。

1
2
3
4
5
6
7
8
9
10
11
//DLL.dll
#include "stdafx.h"

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
MessageBoxA(NULL,"Hello World","Test",MB_OK);
return TRUE;
}

然后再用 OllyDbg 附加到 explorer.exe 的进程上,对 LoadLibraryW 函数设置断点,接下来浏览以下保存我们修改的 LNK 文件的目录。此时,可能会出现两种情况。

  1. OllyDbg 中断触发。如果是这样我们就能在 view -->Call stack 菜单中查看当前函数调用情况。
  2. OllyDbg 中断未触发,这是因为您已经浏览过这个目录。由于快捷方式图标的加载具有缓存机制,如果以前已经加载过,现在他就不会再重复加载。此时您可以将 LNK 文件重命名,之后 OllyDbg 中的断点就可以触发了。

image-20220731154330734

中断后,我们能在栈中看到本次 LoadLibraryW 函数调用的 FileName 参数为 “C:\DLL.DLL”,说明我们找对地方了,并且我这里也直接出现了弹出框。如果没有看到这个参数,那就多按几次 F9。

接下来我们通过 Call stack 查看函数调用情况。
image-20220731154949928

shell32在处理lnk文件的时候要把它的图标显示出来,对于一般文件应该是从Icon filename string里面解析,但对于文件后面没有Icon filename string结构的控制面板快捷方式,是直接从0x7A那里的iconindex来解析。当这个iconindex是0的时候,会去加载cpl文件,调用CPlApplet接口,这样就存在执行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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
7D716064    53              push    ebx
7D716065 FF75 10 push dword ptr [ebp+10]
7D716068 8D5E 0C lea ebx, dword ptr [esi+C]
7D71606B 53 push ebx
7D71606C FF75 0C push dword ptr [ebp+C] ;C:\dll.dll,0,<-这个0就是从偏移7A那里得到的iconindex
7D71606F FF15 0015597D call dword ptr [<&KERNEL32.lstrcpynW>>; kernel32.lstrcpynW
7D716075 6A 2C push 2C
7D716077 FF75 0C push dword ptr [ebp+C]
7D71607A FF15 F41B597D call dword ptr [<&SHLWAPI.StrChrW>] ; shlwapi.StrChrW
7D716080 85C0 test eax, eax
7D716082 74 5D je short 7D7160E1
7D716084 66:8320 00 and word ptr [eax], 0
7D716088 83C0 02 add eax, 2
7D71608B 50 push eax
7D71608C FF15 641C597D call dword ptr [<&SHLWAPI.StrToIntW>] ; shlwapi.StrToIntW
7D716092 8B7D 14 mov edi, dword ptr [ebp+14]
7D716095 8907 mov dword ptr [edi], eax
7D716097 8B45 18 mov eax, dword ptr [ebp+18]
7D71609A C700 02000000 mov dword ptr [eax], 2
7D7160A0 8B0F mov ecx, dword ptr [edi]
7D7160A2 33D2 xor edx, edx
7D7160A4 3BCA cmp ecx, edx ;偏移0x7A必须得是0,才会LoadLibary
7D7160A6 75 33 jnz short 7D7160DB
7D7160A8 C700 1A000000 mov dword ptr [eax], 1A
7D7160AE 8D86 14020000 lea eax, dword ptr [esi+214]
7D7160B4 3910 cmp dword ptr [eax], edx
7D7160B6 8955 0C mov dword ptr [ebp+C], edx
7D7160B9 75 16 jnz short 7D7160D1
7D7160BB 8D4D 0C lea ecx, dword ptr [ebp+C]
7D7160BE 51 push ecx
7D7160BF 8D8E 18020000 lea ecx, dword ptr [esi+218]
7D7160C5 51 push ecx
7D7160C6 50 push eax
7D7160C7 53 push ebx
7D7160C8 E8 48C4F2FF call 7D642515 ;这里调用后面

后面
7D63866D FF15 6415597D call dword ptr [<&KERNEL32.GetCurrent>; kernel32.GetCurrentProcessId
7D638673 50 push eax
7D638674 56 push esi
7D638675 68 00001000 push 100000 ; UNICODE "f1df_6.0.2600.5512_x-ww_35d4ce83\"
7D63867A 8985 E4FDFFFF mov dword ptr [ebp-21C], eax
7D638680 FF15 6815597D call dword ptr [<&KERNEL32.OpenProces>; kernel32.OpenProcess
7D638686 3BC6 cmp eax, esi
7D638688 8985 E8FDFFFF mov dword ptr [ebp-218], eax
7D63868E 0F84 E5000000 je 7D638779
7D638694 8D85 F4FDFFFF lea eax, dword ptr [ebp-20C]
7D63869A 50 push eax
7D63869B FF15 A41C597D call dword ptr [<&SHLWAPI.PathFileExi>; shlwapi.PathFileExistsW
7D6386A1 85C0 test eax, eax
7D6386A3 C785 BCFDFFFF 2>mov dword ptr [ebp-244], 20
7D6386AD 74 14 je short 7D6386C3
7D6386AF 8D85 F4FDFFFF lea eax, dword ptr [ebp-20C]
7D6386B5 89B5 C0FDFFFF mov dword ptr [ebp-240], esi
7D6386BB 8985 C4FDFFFF mov dword ptr [ebp-23C], eax
7D6386C1 EB 1A jmp short 7D6386DD
7D6386C3 C785 C0FDFFFF 0>mov dword ptr [ebp-240], 8
7D6386CD 899D C4FDFFFF mov dword ptr [ebp-23C], ebx
7D6386D3 C785 D0FDFFFF 7>mov dword ptr [ebp-230], 7B
7D6386DD 8D85 BCFDFFFF lea eax, dword ptr [ebp-244]
7D6386E3 50 push eax
7D6386E4 FF15 6C15597D call dword ptr [<&KERNEL32.CreateActC>; kernel32.CreateActCtxW
7D6386EA 83F8 FF cmp eax, -1
7D6386ED 8985 F0FDFFFF mov dword ptr [ebp-210], eax
7D6386F3 75 06 jnz short 7D6386FB
7D6386F5 89B5 F0FDFFFF mov dword ptr [ebp-210], esi
7D6386FB 8B3D 8C15597D mov edi, dword ptr [<&KERNEL32.Activ>; kernel32.ActivateActCtx
7D638701 8D85 ECFDFFFF lea eax, dword ptr [ebp-214]
7D638707 50 push eax
7D638708 FFB5 F0FDFFFF push dword ptr [ebp-210]
7D63870E FFD7 call edi
7D638710 33F6 xor esi, esi
7D638712 46 inc esi
7D638713 56 push esi
7D638714 56 push esi
7D638715 56 push esi
7D638716 53 push ebx
7D638717 FF15 00F0787D call dword ptr [7D78F000] ; apphelp.ApphelpCheckExe
7D63871D 85C0 test eax, eax
7D63871F 75 08 jnz short 7D638729
7D638721 2185 E0FDFFFF and dword ptr [ebp-220], eax
7D638727 EB 0D jmp short 7D638736
7D638729 53 push ebx ;加载DLL
7D63872A FF15 A015597D call dword ptr [<&KERNEL32.LoadLibrar>; kernel32.LoadLibraryW
7D638730 8985 E0FDFFFF mov dword ptr [ebp-220], eax ; dll.01C00000

参考:

LNK快捷方式文件漏洞简要分析

​ 0day2:软件漏洞分析精要