Obfuscating Payloads

the fun part 😊

Now that we have a successful workflow, we can start messing around with removing Indicators of Compromise (IOCs) and obfuscating our payloads with a variety of methods. We will re-use our Seatbelt example from the previous section

Module Objectives

  • Create a build step to check for Indicators of Compromise (IOC)

  • Use Powershell to remove the IOC from our project

  • Obfuscate our payload using ConfuserEx

  • Check the payload against ThreatCheck

  • Obfuscate Go Binaries

  • Periodic Scanning with VirusTotal*

Required Tools

Payloads

We will be using Ligolo-ng and Seatbelt

Detection Tools

Obfuscation

Installing Detection Tools

Section Objectives

  • Install YARA

    • Download YARA Rules

    • Test our artifact against YARA

  • Install and Build ThreatCheck

    • Analyse our artifact with ThreatCheck

    • Detect Bad Bytes

Before we begin, we will need to install some tools that will detect our payload - which we can later use within our build steps to pass or fail the project before publishing an artifact.

YARA

YARA is a file analysis tool which dissects and searches for bad characters based on a set of rules. Rules can be downloaded from many sources - for our demo, we have included the rules that we will be using.

Download the binary from the link above, then place it in a reachable directory. I will store all of the tools we're using in C:\Tools to keep things organised. After extracting YARA, download the rules from this repository and place them inside YARA's root folder. It should look like this

Directory: C:\Tools\yara


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         4/24/2024   6:24 PM            735 rubeus.yar
-a----         4/24/2024   6:24 PM            756 safetykatz.yar
-a----         4/24/2024   6:24 PM            750 seatbelt.yar
-a----         4/24/2024   6:24 PM            484 sharpligolo.yar
-a----         2/13/2024  11:02 AM        2417152 yara64.exe
-a----         2/13/2024  11:02 AM        2362880 yarac64.exe

Test the rule against a Seatbelt artifact:

PS> .\yara64.exe -s .\seatbelt.yar C:\..\Seatbelt\bin\Release\Seatbelt.exe

HackTool_MSIL_SEATBELT_2 C:\BuildAgent\work\8306664e377be4bb\Seatbelt\bin\Release\Seatbelt.exe

We can see that YARA found the hardcoded GUID which is included in Seatbelt's original project - we will need to remove this IOC if we want to be slightly stealthier.

ThreatCheck

ThreatCheck is a tool developed by Daniel Duggan (RastaMouse) which cuts up binaries and detect the exact bytes which AV solutions hate. We can use this tool to detect if anything needs to be patched post obfuscation

To install it, clone the repository to your directory of choice, compile it using Visual Studio 2019 or through dotnet.exe - I will be using VS 2019 for this

git clone https://github.com/rasta-mouse/ThreatCheck.git
mv .\ThreatCheck\ThreatCheck\ ThreatC
echo A | rm -Force .\ThreatCheck\
mv .\ThreatC\ ThreatCheck

Open the solution in Visual Studio, then select Release and build

Once built, you will find the binary in the bin folder

C:\Tools\ThreatCheck\ThreatCheck\bin\Release

In order for ThreatCheck to work properly, we need to disable Windows Defender on our system so that the data isn't being deleted during analysis

PS> C:\Tools\ThreatCheck\...\ThreatCheck.exe -f C:\...\Seatbelt.exe

Removing IOCs using Powershell

Now that we know how basic detections can screw up our payload, let us see how we can bypass them. The first step is removing the hard-coded GUID string in Seatbelt\Properties\AssemblyInfo.cs (The same applies for Rubeus and the rest)

In our Seatbelt build configuration, add a new build step and select Powershell, we will use a small script to generate a random GUID, then replace the old one with it (Slightly modified from Devops for PT)

# Get relative path of AssemblyInfo.cs
$teamCityProjectName = "%teamcity.projectName%"
$path = ".\$teamCityProjectName\Properties\AssemblyInfo.cs"
Write-Output "Project Path: $path"

# Read file
$content = Get-Content -Path $path -Raw
Write-Output "Original Content:"
Write-Output "$content" 

# Generate a new random GUID
$newGuid = [System.Guid]::NewGuid().ToString()
Write-Output "Random GUID: $newGuid"

# Replace the GUID with our random one (Will work with any GUID)
$content = $content | ForEach-Object { $_ -replace '\[assembly: Guid\("[^"]*"\)\]', "[assembly: Guid(`"$newGuid`")]"}
Write-Output $content

# Overwrite the file
$content | Set-Content -Path $path

Then move the build step above the compilation step using the Reorder Build Steps option

Now, we need to add a parameter to our builder which includes the TeamCity project name using %system.teamcity.projectName%

Save this, then build the project. Check the file using YARA afterwards - you should see from the build logs that our GUID changed from aec32155-d589-4150-8fe7-2900df4554c8 to a9d35d54-019f-45dd-839d-6243648dcac6

We can confirm this change using YARA

...and dnSpy

The Powershell template being used can be re-used for the other GhostPack projects. This method is not sufficient to not get detected by ThreatCheck - though our next method will

Removing IOCs using ConfuserEx

Section Objectives

  • Use ConfuserEx GUI to pack Seatbelt

  • Use the different rules given by ConfuserEx

  • Check Seatbelt against ThreatCheck before and after obfuscation

  • Integrate ConfuserEx CLI into our Build Pipeline

ConfuserEx is a .NET obfuscation tool which hides symbols and makes it difficult to understand what a C# executable does statically. To get started, download the latest binary (ConfuserEx.zip) from the Release page, and save it in your Tools folder (Mine is in C:\Tools)

ConfuserEx templates are written in XML , and can be referenced at:

A basic template which uses an aggressive preset can be written as follows

<?xml version="1.0" encoding="utf-8"?>
<project baseDir="<BASE DIRECTORY>" outputDir="<OUTPUT DIRECTORY>" xmlns="http://confuser.codeplex.com">
    <rule pattern="true" preset="aggressive" inherit="false" />
    <packer id="compressor" />
    <module path="<TARGET FILE>" /> 
</project>

The project element describes where the file will reside after ConfuserEx runs. The rule element refers to which rules it should use, packer specifies what type of packer ConfuserEx should utilise, and module is for the target path. ConfuserEx lets you specify multiple rules and modules, and can cover both DLLs and binary files alike - which can be useful for DLL type payloads.

You can also add more protections listed in the third link

<?xml version="1.0" encoding="utf-8"?>
<project baseDir="<BASE DIRECTORY>" outputDir="<OUTPUT DIRECTORY>" xmlns="http://confuser.codeplex.com">
    <rule pattern="true" preset="aggressive" inherit="false">
        <protection id="anti debug" />
        <protection id="anti dump" />
        <protection id="anti ildasm" />
        <protection id="anti tamper" />
        <protection id="constants" />
        <protection id="ctrl flow" />
        <protection id="invalid metadata" />
        <protection id="resources" />
    </rule>
    <packer id="compressor" />
    <module path="<TARGET FILE>" />
</project>

Some protections take additional parameters as well, such as the anti debug protection which takes 3 arguments (taken from here)

  • safe: ConfuserEx would detect debugger/profiler using managed API (default)

  • win32: ConfuserEx would detect debugger/profiler using unmanaged WinAPI (Incompatible with OS other than Windows)

  • antinet: ConfuserEx would detect debugger/profiler using antinet by @0xd4d

In XML form, it will look like this

<protection id="anti debug">
  <argument name="mode" value="win32" />
</protection>

This allows us to beef up some of our default rules when it comes to templates and automating the obfuscation process

GUI Version

Before creating our pipeline, let's first use the GUI tool to examine the before and after of our Seatbelt executable. This will help us understand what to expect once a build has been completed. We will also testing our executable against ThreatCheck to confirm that it worked

Start the ConfuserEx application located in C:\Tools\ConfuserEx\ConfuserEx.exe (the directory you've extracted to), and create a new folder within the Tools directory where you will store the output - I've included our payload from the previous build inside of our output folder for comparison

Drag and drop your binary into the modules tab, then click on Settings. You should be able to see your binary's name displayed in the list. Click on this, then press the plus button to add a rule. Click on the packer check box as well.

Press the Edit button on the left to bring up the rules you want to use - for this, we will be using the basic Aggressive preset - experiment on your own to see what works well for you

Click Done once you're happy with the settings, then go to the Protect tab on the main interface and hit Protect to start packing your binary. Once it's complete, run ThreatCheck on your test binary, and the one you've packed to see the difference

You can decrease the detected bytes through other means as well - such as running the executable through a loader, or by using more protections/rules through ConfuserEx.

Integrating ConfuserEx into our build pipeline

Instead of doing this manually, we can integrate ConfuserEx's template into our build pipeline with the use of a PowerShell script. Create the following scripts inside the C:\Tools\ConfuserEx directory, and save it as aggressive_template.ps1

param 
(
[Parameter(Mandatory=$true)] [String]$path, 
[Parameter(Mandatory=$true)] [String]$projectName 
)

$template = @"
<project baseDir="$path" outputDir="$path" xmlns="http://confuser.codeplex.com">
    <rule pattern="true" preset="aggressive" inherit="false">
        <protection id="anti debug" />
        <protection id="anti dump" />
        <protection id="anti ildasm" />
        <protection id="anti tamper" />
        <protection id="constants" />
        <protection id="ctrl flow" />
        <protection id="invalid metadata" />
        <protection id="resources" />
    </rule>
    <packer id="compressor" />
    <module path="$projectName.exe" />
</project>
"@

Write-Output "[+] Using ConfuserEx with $PSCommandPath"

$template | Out-File -FilePath "$path\$projectName.crproj"
C:\Tools\ConfuserEx\Confuser.CLI.exe -n "$path\$projectName.crproj"

Where:

  • $path is where the release directory is

  • $projectName is the project name

These variables will be used in TeamCity as such:

  1. Create a new build step for ConfuserEx using the PowerShell runner

  1. Specify the script file and the arguments TeamCity should execute

"%teamcity.build.checkoutDir%\%teamcity.projectName%\bin\Release"
"%teamcity.projectName%"

Run the build step, then verify that it worked by using dnSpy

PS C:\Tools\SEATBELT - TESTING> C:\ThreatCheck.exe -f "C:\Seatbelt.exe"
[+] No threat found!

Build Tests using ThreatCheck

Section Objectives

  • Integrate ThreatCheck into our build pipeline

  • Fail builds that get detected by ThreatCheck

The last step (for now) is to check the artifact against ThreatCheck to make sure that it's properly obfuscated. To do this, we will create a new PowerShell script with the following:

param 
(
[Parameter(Mandatory=$true)] [String]$path,
[Parameter(Mandatory=$true)] [String]$projectName 
)

Write-Output "[+] Executing Threat Check"
C:\Tools\ThreatCheck\ThreatCheck\bin\Release\ThreatCheck.exe -f "$path\$projectName.exe"

Then, repeat the previous execution arguments for TeamCity

"%teamcity.build.checkoutDir%\%teamcity.projectName%\bin\Release"
"%teamcity.projectName%"

To test our build step we will run our program twice - once with our ConfuserEx step, and once without.

We can see that there is a fixed message when a bad segment is detected by Threat Check, we can use this to create a filter which fails our build in case the program is not obfuscated

In your build's Failure Conditions, add a new failure condition to match the message received - you can also add other messages if ThreatCheck has other failure messages

Text to look for: [!] Identified end of bad bytes at offset

Test this on our last build step to see if it works

We can also test this by re-running our build

Re-enable your obfuscation step and you're done! The next steps would be to

  1. Publish artifacts to central file share

  2. Copy your build step into a global configuration

  3. Check artifact hashes against VirusTotal (Using their API) daily to make sure the binaries aren't burned

  4. Create a tool to download your artifact onto your operations machine or into your Command and Control team server

  5. Your own creativity :)

VirusTotal Vetting (WIP)

https://n3nu.medium.com/automating-hash-vetting-using-virustotal-api-v3-ef53a65c2121

Last updated