1、漏洞描述
ZDI-CAN-25373 是一个 Windows 快捷方式文件(.LNK)漏洞,它允许攻击者通过精心制作的恶意快捷方式文件来执行隐藏的恶意命令。攻击者通过在 .LNK 文件的 COMMAND_LINE_ARGUMENTS 结构中填充大量空白字符(如空格、水平制表符、换行符等)来隐藏恶意命令。这些填充字符使得恶意负载在 Windows UI 中不可见,从而规避了检测。
2. LNK 文件格式结构详解
Windows 快捷方式文件,也称为 Shell 链接文件(.lnk),是 Windows 操作系统使用的一种二进制文
件,用作文件、文件夹或应用程序的快捷方式。了解这些字段对于文件取证、恶意软件分析以及对 Windows 快捷方式的深入理解都非常重要。
以下是 MS-SHLLINK 文件格式的主要组成部分和关键字段介绍:
一个典型的 MS-SHLLINK 文件由以下几个主要结构组成,其中一些是必须的,一些是可选的:
SHELL_LINK_HEADER (必须):快捷方式文件的核心头部,包含许多重要的标志和基本信息。
LINKTARGET_IDLIST (可选):如果快捷方式指向一个 Shell 项(如文件、文件夹、控制面板项等),这个结构会描述其在 Shell 命名空间中的位置。
LINKINFO (可选):包含有关链接目标位置的详细信息,例如卷序列号、网络路径等,用于在目标移动后帮助系统找到它。
STRING_DATA (可选):包含各种字符串数据,如目标路径、工作目录、命令行参数、图标位置等。
EXTRA_DATA (可选):一个包含一个或多个额外数据块的区域,用于存储其他可选信息。
主要字段和结构详解
2.1 SHELL_LINK_HEADER
这是每个 .LNK 文件的开头部分,提供了关于快捷方式的基本属性和其后续结构的信息。
HeaderSize (4 字节):头的大小,通常为 0x0000004C。
LinkCLSID (16 字节):一个固定的 GUID,用于标识这是一个 Shell Link 文件,通常为 {00021401-0000-0000-C000-000000000046}。
LinkFlags (4 字节):一个位字段,包含指示文件中是否存在哪些可选结构的标志,以及快捷方式行为的各种标志。重要的标志包括:
HasLinkTargetIDList:指示是否存在 LINKTARGET_IDLIST 结构。
HasLinkInfo:指示是否存在 LINKINFO 结构。
HasName:指示是否存在 STRING_DATA 中的 NAME_STRING。
HasRelativePath:指示是否存在 STRING_DATA 中的 RELATIVE_PATH。
HasWorkingDir:指示是否存在 STRING_DATA 中的 WORKING_DIR。
HasArguments:指示是否存在 STRING_DATA 中的 COMMAND_LINE_ARGUMENTS(这在 ZDI-CAN-25373 漏洞中尤其重要)。
HasIconLocation:指示是否存在 STRING_DATA 中的 ICON_LOCATION。
IsUnicode:指示字符串数据是否为 Unicode 格式。
FileAttributes (4 字节):链接目标的原始文件属性(例如,只读、隐藏、系统等),与 GetFileAttributes 函数返回的值类似。
CreationTime (8 字节):链接目标的创建时间(FILETIME 格式)。
AccessTime (8 字节):链接目标的最后访问时间(FILETIME 格式)。
WriteTime (8 字节):链接目标的最后写入时间(FILETIME 格式)。
FileSize (4 字节):链接目标的文件大小(低 32 位)。
IconIndex (4 字节):如果 IconLocation 字段指向一个包含多个图标的文件(如 DLL 或 EXE),这个字段指定要使用的图标的索引。
ShowCommand (4 字节):指示链接目标在启动时的窗口状态(例如,正常、最小化、最大化)。
Hotkey (2 字节):分配给快捷方式的热键组合(如果存在)。
Reserved1, Reserved2, Reserved3 (保留字段):通常为 0。
2.2. LINKTARGET_IDLIST (链接目标 ID 列表)
这个可选结构描述了 Shell 命名空间中链接目标的位置。它由一系列 ITEMID 结构组成,每个 ITEMID 代表一个 Shell 对象(如桌面、我的电脑、驱动器、文件夹、文件等)。
IDListSize (2 字节):整个 ITEMIDLIST 的大小。
ItemID (变长):一个或多个 ITEMID 结构,描述从桌面到链接目标的路径。每个 ITEMID 都包含一个 Size 字段和 Data 字段,Data 字段是具体的 Shell 对象标识符。
TerminalID (2 字节):一个 0x0000 终止符,标记 ITEMIDLIST 的结束。
2.3. . LINKINFO (链接信息)
这个可选结构提供了链接目标在物理文件系统或网络上的位置信息。当目标被移动或重命名时,这些信息可以帮助系统重新定位它。
LinkInfoSize (4 字节):LINKINFO 结构的总大小。
LinkInfoHeaderSize (4 字节):LINKINFO 头的固定大小,通常为 0x0000001C 或 0x00000024。
LinkInfoFlags (4 字节):位字段,指示哪些可选字段存在:
VolumeIDAndLocalBasePath:指示存在 VolumeID 和 LocalBasePath。
CommonNetworkRelativeLinkAndPathSuffix:指示存在 CommonNetworkRelativeLink 和 PathSuffix。
VolumeIDOffset (4 字节):LINKINFO 结构开始到 VolumeID 结构的偏移量。
LocalBasePathOffset (4 字节):LINKINFO 结构开始到 LocalBasePath 字符串的偏移量。
CommonNetworkRelativeLinkOffset (4 字节):LINKINFO 结构开始到 CommonNetworkRelativeLink 结构的偏移量。
CommonPathSuffixOffset (4 字节):LINKINFO 结构开始到 CommonPathSuffix 字符串的偏移量。
VolumeID (可选):如果 VolumeIDAndLocalBasePath 标志被设置,此结构包含卷(驱动器)的信息,如驱动器类型、卷序列号、卷标等。
LocalBasePath (可选):如果 VolumeIDAndLocalBasePath 标志被设置,此字段包含链接目标在本地文件系统上的路径字符串。
CommonNetworkRelativeLink (可选):如果 CommonNetworkRelativeLinkAndPathSuffix 标志被设置,此结构包含网络路径信息,如网络共享名称、设备名称等。
CommonPathSuffix (可选):如果 CommonNetworkRelativeLinkAndPathSuffix 标志被设置,此字段包含链接目标的通用路径后缀,通常用于在目标位于不同驱动器时提供相对路径信息。
2.4. . STRING_DATA (字符串数据)
这个可选结构包含多个字符串,它们的出现与否由 SHELL_LINK_HEADER 中的 LinkFlags 控制。这些字符串通常以 NULL 终止。
NAME_STRING (可选):快捷方式的名称或描述。
RELATIVE_PATH (可选):从快捷方式文件位置到目标文件的相对路径。
WORKING_DIR (可选):快捷方式启动时的工作目录。
COMMAND_LINE_ARGUMENTS (可选):传递给链接目标的命令行参数(例如,当快捷方式指向一个可执行文件时)。这是 ZDI-CAN-25373 漏洞利用的关键字段,攻击者可以在这里隐藏恶意命令。
ICON_LOCATION (可选):快捷方式图标的来源路径(例如 C:WindowsSystem32shell32.dll)。
2.5. . EXTRA_DATA (额外数据)
这个可选结构包含一个或多个额外的任意数据块。每个数据块都有自己的头部,指示其类型和大小。常见的额外数据块类型包括:
ConsoleDataBlock:控制台应用程序的设置。
ConsoleFEDataBlock:控制台应用程序的前景和背景颜色设置。
DarwinDataBlock:与 Windows Installer (MSI) 相关的信息,用于修复损坏的快捷方式。
EnvironmentVariableDataBlock:包含链接目标使用的环境变量。
IconEnvironmentDataBlock:包含用于解析图标位置的环境变量。
KnownFolderDataBlock:如果链接目标是一个已知文件夹(如“我的文档”、“下载”等),此块包含其 GUID。
PropertyStoreDataBlock:包含自定义属性,如文件哈希、安全描述符等。
ShimDataBlock:与应用程序兼容性垫片(shims)相关的信息。
SpecialFolderDataBlock:与特殊 Shell 文件夹(如桌面、程序菜单)相关的信息。
TrackerDataBlock:包含分布式链接跟踪器(DLT)信息,用于在文件或卷移动后跟踪目标。这包括机器 ID、MAC 地址、卷创建时间等。
3、漏洞利用机制
3.1 COMMAND_LINE_ARGUMENTS 隐藏原理
LNK 的字符串字段支持最长 65535 字符,但 UI 通常仅显示 260 字符以内内容
攻击者使用不可见控制字符填充前缀,如空格、Tab、换行符、回车等,将恶意命令压至 UI 看不到的区域
ZDI-CAN-25373漏洞就是利用MS-SHLLINK 文件格式与实际windows解析时UI所能显示的差异来实现。
根据 MS-SHLLINK 文件格式的定义,字符串长度通常由一个 2 字节的字段表示,这意味着它能够存储的最大字符数理论上为 2^16 - 1 = 65535 个。
而实际UI能够显示的特别小,因此可以通过填充大量的特殊字符从而实现UI隐藏恶意负载。
![图片[1] - 深度剖析 LNK 参数隐藏攻击 (ZDI-CAN-25373) - 宋马](https://pic.songma.com/blogimg/20250707/74542ee5c537485eb34e9dd64766c835.png)


用作填充命令行参数的特殊十六进制如下所示
| Hex Value 十六进制值 | 描述 |
|---|---|
| x20 | Space 空间 |
| x09 | Horizontal Tab 水平制表符 |
| x0A | Line Feed 换行符 |
| x0B | Vertical Tab 垂直制表符 |
| x0C | Form Feed 换页符 |
| x0D | Carriage Return 回车 |
4、漏洞变种:WORKING_DIR 利用分析
实际在样本分析过程中发现,有一些样本并没有把恶意负载放在 COMMAND_LINE_ARGUMENTS 中,而是放在WORKING_DIR,后续跟的是结构不正常的COMMAND_LINE_ARGUMENTS ,但是可以正常运行payload。接下来具体分析下。
4.1、基本数据
样本基本信息:fae06cd491519b67a08739365bd40ff2+cbf4671ea72268a9bd618ab3f753442c2fc38a2a
3.2、分析过程
010editor 打开
![图片[2] - 深度剖析 LNK 参数隐藏攻击 (ZDI-CAN-25373) - 宋马](https://pic.songma.com/blogimg/20250707/b02c9907755a4283a10c4725789a862a.png)

LinkFlags 中描述发现,HasWorkingDir、HasArguments、HasIconLocation 都是被置位的,也就是说按照正常情况下这三个结构都是有的,但是解析时发现 Arguments是不完整的,IconLocation是没有被解析的。

为什么payload 在 Working_DIR 仍然可以运行呢,原理可能是下面的解释
4.3 WorkingDir 可执行原理
LNK文件的工作目录字段本意
LNK的Working Directory字段(WorkingDir)本意是告诉目标程序“启动时的当前目录”。
比如快捷方式指向notepad.exe,WorkingDir设为C:docs,则打开notepad时,默认目录就是C:docs。
利用原理
Windows解析LNK的机制
当你双击LNK时,Windows会读取LNK的Header、TargetIDList、LinkInfo、WorkingDir、Arguments等字段。
Windows会调用ShellExecute/WinExec等API,把WorkingDir字段内容作为启动参数传递给目标程序。
某些程序的“命令行解析”特性
有些程序(如cmd.exe、powershell.exe、wscript.exe等)会把WorkingDir字段内容当作命令行参数来解析(尤其是当Target字段本身就是解释器/命令行工具时)。
如果WorkingDir字段被填入了恶意命令或payload,这些程序就会直接执行该内容。
兼容性和利用场景
并不是所有程序都会“执行”WorkingDir里的内容。只有当目标程序本身会解析/执行工作目录参数时才会发生。
恶意LNK常见的做法是:Target设为cmd.exe,WorkingDir填入/c calc.exe或更复杂的payload,这样双击LNK时就会执行payload。
实际测试
实际测试,将WorkingDir字段、RelativePath 字段都会被解析执行。通过修改LinkFlags 里的HasRelativePath、HasWorkingDir来切换被解析的数据。

报错提示
当 LNK 文件中的 LinkFlags 标志设置了某个可选结构存在(例如 HasArguments),但实际数据却没有按规范填充完整时,解析工具确实会报错。这可能是攻击者为了规避某些简单解析器的检测而故意为之。

LEcmd 解析报错

5、防御与检测建议
开启显示扩展名,避免 .lnk 文件伪装成文档或图片
限制未知来源的快捷方式执行权限
检查 LinkFlags 标志与结构是否匹配,发现 HasArguments 但内容为空需警惕
示例 YARA 检测逻辑:
rule LnkHiddenArguments : malicious lnk
{
strings:
$lnk_magic = { 4C 00 00 00 01 14 02 00 }
$unicode_space = "x20x00" * 20
condition:
$lnk_magic and $unicode_space
}
6、总结
ZDI-CAN-25373 漏洞揭示了 LNK 文件中 COMMAND_LINE_ARGUMENTS 等 字段可被用于执行恶意命令的潜力。攻击者通过巧妙利用结构设计差异和 UI 展示限制,使得恶意代码难以被察觉。研究人员应深入了解 LNK 格式细节,并结合静态结构验证与动态行为监测手段,有效检测与防御此类攻击。
7、脚本下载链接
生成测试样本的脚本以及010editor的模板文件如下
链接: https://pan.baidu.com/s/1Q0H75EyK_7AFhxTn0E-q9w?pwd=kjkn 提取码: kjkn



















暂无评论内容