Penetration Techniques - Parameter Hiding Techniques in Shortcut Files

Onedaysec
5 min read
0 views
docx image 1770014876974 0 7b016839ac

0x00 Preface

---

Recently, phrozensoft introduced exploitation techniques for shortcuts in a blog post, demonstrating how to embed applications within shortcut files. When users open the shortcut, a VBS script extracts and executes the application.

I found this particularly interesting because shortcut parameters have a default length limit of 260 characters, a constraint I also encountered while researching jsrat (ultimately resolved by invoking an sct file to bypass the length restriction).

phrozensoft shared POC code in Delphi format. This article will test it, study the lnk file format, develop corresponding POC code implemented in PowerShell, and briefly analyze the exploitation and defense methods of this technique.

phrozensoft's blog address:

https://www.phrozensoft.com/2016/12/shortcuts-as-entry-points-for-malware-poc-part-2-19

0x01 Introduction

---

Delphi

A renowned rapid application development tool for the Windows platform

Developed by Borland

It can also be used to develop applications on the LINUX platform, with its counterpart product on LINUX being Kylix

Common versions:

  • Borland Delphi 7
  • Delphi 2010

0x02 Delphi POC Testing

---

Phrozensoft's blog also shares POCs for other functionalities, such as a Python script for generating LNK files. This article will not cover those, focusing only on testing the Delphi POC.

Environment Setup:

Test System: Win7 x86

Delphi Version: Delphi 2010

Note:

Using Delphi 7 results in a compilation error: 'File not found System.sysutils.dcu'

After switching to Delphi 2010, the POC was slightly modified and compiled successfully.

1. Create a New Project

Open Delphi 2010

Select File-New-Other-Console Application

Directly pasting the POC code results in an error, as shown in the figure

1. Create a New Project — technical illustration 1

2. Modify POC

After testing, System.SysUtils needs to be changed to SysUtils

Compilation passed, as shown in the figure

2. Modify POC — technical illustration 2

3. Compile

Select Project-Build All Projects

As shown, compilation succeeded, generating Project1.exe

3. Compile — technical illustration 3

4. Test

Create a new test.txt, fill it with data exceeding 260 characters:



Execute the following command in cmd:

Generate test.lnk

View command-line parameters, only a string of length 260 can be seen, as shown in the figure

4. Test — technical illustration 4

However, the size of the lnk file is 2.45kb, as shown in the figure

4. Test — technical illustration 5

(Looks like we've found something interesting)

Opening test.lnk in cmd, the parameters of the lnk file execute normally, displaying characters exceeding 260 without truncation, as shown in the figure

4. Test — technical illustration 6

Using the hexadecimal editor Hex Editor to view the lnk file format, as shown in the figure

4. Test — technical illustration 7

Note:

Unable to use UltraEdit, as UltraEdit opens lnk files by default to open the file pointed to by the lnk

For example, as shown in the figure, pointing to cmd.exe

4. Test — technical illustration 8

0x03 Introduction to Lnk File Format

---

1、Overall Structure

  • File Header
  • Shell Item Id List Segment
  • File Location Information Segment
  • Description Character Segment
  • Relative Path Segment
  • Working Directory Segment
  • Command Line Segment
  • Icon File Segment
  • Additional Information Segment

2. File Header Structure

1.

| Offset | Length | Description |

|:--:|:--:|:--:|

| 0h | 4 bytes | Fixed value, character is L |

As shown in the figure

2. File Header Structure — technical illustration 9

2.

| Offset | Length | Description |

|:--:|:--:|:--:|

| 4h | 4 bytes | GUID |

As shown in the figure

2. File Header Structure — technical illustration 10

3.

| Offset | Length | Description |

|:--:|:--:|:--:|

| 14h | 4 bytes | Attribute flags |

Represent these four bytes in binary; if bits 0-6 are set to 1, they respectively indicate that the lnk file contains the following attributes:

Bit 0: Has shell item ID list

Bit 1: Points to a file or folder

Bit 2: Contains a description string

Bit 3: Contains a relative path

Bit 4: Working directory exists

Bit 5: Command-line arguments exist

Bit 6: Custom icon exists

As shown in the figure

2. File Header Structure — technical illustration 11

Offset 14h, take 4 bytes as 000000f5, binary representation is 11110101

Bits 0, 2, 4, 5, 6 are 1, corresponding to the following attributes:

  • Has shell item ID list
  • Description string exists
  • Working directory exists
  • Command-line arguments exist
  • Custom icon exists

4.

| Offset | Length | Description |

|:--:|:--:|:--:|

| 18h | 4 bytes | Target file attributes

| 1ch | 8 bytes | File creation time

| 24h | 8 bytes | File modification time

| 2ch | 8 bytes | File last access time

| 34h | 4 bytes | Target file length

| 38h | 4 bytes | Number of custom icons

| 3ch | 4 bytes | Window execution mode: 1.Normal 2.Minimized 3.Maximized

| 40h | 4 bytes | Hotkey

3. Shell Item ID List

The presence of a Shell Item ID List for test.lnk is determined from position 14h, so the first segment starting from 4ch is the Shell Item ID List

| Offset | Length | Description |

|:--:|:--:|:--:|

| 4ch | 2 bytes | Total length of Shell Item ID List |

As shown in the figure

3. Shell Item ID List — technical illustration 12

Total length of shell item id list is 0129

Starting address of next segment (description string) is 004e+0129=0177h

4. Description String

| Offset | Length | Description |

|:--:|:--:|:--:|

| 004e+0129=0177h | 2 bytes | Length (Unicode), actual length should be multiplied by 2 |

As shown in figure

4. Description String — technical illustration 13

Description string length is 000c (Unicode)

Starting address of next segment (working path) is 0177+2+000c×2=0191h

5. Working Path

| Offset | Length | Description |

|:--:|:--:|:--:|

| 0177+2+000c×2=0191h | 2 bytes | Length (Unicode), actual length should be multiplied by 2 |

As shown in figure

5. Working Path — technical illustration 14

Working path length is 0012 (Unicode)

The starting address of the next segment (command line arguments) is 0191+2+0012×2=01b7h

6. Command line arguments

| Offset | Length | Description |

|:--:|:--:|:--:|

| 0191+2+0012×2=01b7h | 2 bytes | Length (Unicode), actual length should be multiplied by 2 |

As shown in the figure

6. Command line arguments — technical illustration 15

Command line arguments length is 039f (Unicode)

The starting address of the next segment (custom icon) is 01b7+2+039f×2=08f7h

7. Custom icon

| Offset | Length | Description |

|:--:|:--:|:--:|

| 01b7+2+039f×2=08f7h | 2 bytes | Length (Unicode), actual length should be multiplied by 2 |

As shown in the figure

7. Custom icon — technical illustration 16

Custom icon length is 000bf (Unicode)

The starting address of the next segment (custom icon) is 08f7+2+000b×2=090fh

0x04 Implementation Principle

---

By comparing the differences between normal lnk files and POC files using Delphi POC code and Lnk file format, it was found that only the command-line parameter length differs

Hence the principle is inferred:

As long as the command-line parameter length exceeds 260!

Test PowerShell code:

$file = Get-Content "c:\test\test.txt"
$WshShell = New-Object -comObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut("c:\test\test.lnk")
$Shortcut.TargetPath = "%SystemRoot%\system32\cmd.exe"
$Shortcut.IconLocation = "%SystemRoot%\System32\Shell32.dll,21"
$Shortcut.Arguments = ' '+ $file
$Shortcut.Save()

Write the following content into test.txt:

Related Questions & Answers

Why does Windows Explorer or `cmd` show only 260 characters of a shortcut's command line, yet the full payload executes?

Windows Explorer and the `cmd` `dir` command use a legacy API or property handler that truncates the displayed command-line string at 260 characters (the classic `MAX_PATH` limit). However, when the shortcut is launched, the Windows shell reads the raw binary LNK file and passes the complete command-line arguments (stored as a Unicode string with explicit length) to the target process. The article demonstrates this by creating a `.lnk` file with a 2.45 KB file size, far larger than what a 260-character shortcut would be, proving the extra data is present and executable.

How does the LNK file's attribute flags field indicate the presence of a command-line arguments segment?

The attribute flags field at offset 0x14 is a 4-byte value where individual bits mark which optional segments are present. Bit 5 (value 0x20) corresponds to 'Command-line arguments exist'. In the example, the flag 0x000000F5 (binary 11110101) has bits 0, 2, 4, 5, and 6 set, meaning the LNK includes a shell item ID list, description string, working directory, command-line arguments, and custom icon. These flags guide the parser to locate and read each segment sequentially, as detailed in the article's LNK format breakdown.

What tools or languages were used to create a proof-of-concept for this shortcut parameter-hiding technique?

The original proof-of-concept by phrozensoft was written in Delphi (Delphi 2010) and later reproduced in PowerShell for easier testing. The PowerShell code reads a long payload from a text file, creates a shortcut using `WScript.Shell`, sets the `Arguments` property to a space plus the payload, and saves it. The article also mentions that Delphi 7 failed due to missing units, while Delphi 2010 worked after changing `System.SysUtils` to `SysUtils`. The resulting `.lnk` file stores the full payload, exceeding the 260-character display limit.

What is the key structural difference in a .lnk file that enables storing long command-line arguments?

The critical difference lies in the command-line arguments segment of the LNK file format. In a normal shortcut, this Unicode string is short, but the format itself does not impose a built-in length restriction. By manually manipulating the binary (e.g., using Delphi or PowerShell), an attacker can write a very long argument string into that segment. The `cmd` process reads the full string from the file, even though the default property viewer truncates it. The article's analysis of the LNK file header and segment offsets explains how each part (e.g., description, working path, command line) is parsed sequentially.

How can malware bypass the 260-character limit on command-line parameters in Windows shortcut (.lnk) files?

Malware can embed command-line parameters longer than 260 characters by manually constructing the .lnk file's binary structure. As demonstrated in [Penetration Techniques - Parameter Hiding Techniques in Shortcut Files](/news/penetration-techniques-parameter-hiding-techniques-in-shortcut-files), the Windows shell allows the command-line arguments segment of the LNK format to store arbitrary lengths, while the default display (e.g., in `cmd`) only shows up to 260 characters. This technique conceals the full payload from casual inspection.

Continue Reading