Pyramid: Python scripts to evade EDRs
What is it
Pyramid is a set of Python scripts and module dependencies that can be used to evade EDRs. The main purpose of the tool is to perform offensive tasks by leveraging some Python evasion properties and looking as a legit Python application usage. This can be achieved because:
- the Python Embeddable package provides a signed Python interpreter with good reputation;
- Python has many legit applications, so there is a lot of different telemetry coming from the python.exe binary since the interpreter natively runs the APIs. This can be abused by operating within the Python.exe process and trying to blend in the huge “telemetry fingerprint” of the python.exe binary.
- There is a lack of auditing for Python code execution – PEP-578 tried to solve that but the stock python.exe binary does not have auditing capabilities enabled by default.
- Operations can be done natively from within python.exe natively using Python language to perform post-exploitation tasks such as dynamically importing Python modules to run offensive tools and executing Beacon Object Files (after some BOF modifications) directly within python.exe.
For more information please check the DEFCON30 – Adversary village talk “Python vs Modern Defenses” slide deck and this post on my blog.
Pyramid capabilities are executed directly from python.exe process and are currently:
- Dynamic loading of BloodHound Python, impacket secretsdump and paramiko.
- BOFs execution using in-process shellcode injection.
- In-process injection of a C2 agent and tunneling its traffic with local SSH port forwarding.
Pyramid is meant to be used unpacking an official embeddable Python package and then running python.exe to execute a Python download cradle. This is a simple way to avoid creating uncommon Process tree pattern and looking like a normal Python application usage.
In Pyramid the download cradle is used to reach a Pyramid Server (simple HTTPS server with auth) to fetch base scripts and dependencies.
Base scripts are specific for the feature you want to use and contain:
- Custom Finder class to in-memory import required dependencies (zip files).
- Code to download the required dependencies.
- Main logic for the module you want to execute (bloodhound, secretsdump, paramiko etc.).
BOFs are run through a base script containing the shellcode resulted from bof2shellcode and the related in-process injection code.
The Python dependencies have been already fixed and modified to be imported in memory without conflict.
There are currently 4 main base scripts available:
- base-bh.py script will in-memory import and execute python-BloodHound.
- base-secretsdump.py script will in-memory import and execute Impacket secretsdump.
- base-BOF-lsass.py script is using a stripped version of nanodump to dump lsass from python.exe. This is achieved in-memory injecting shellcode output obtained from bof2shellcode and COFFloader. To make complex BOFs work with this technique, they should first be adapted for Python execution.
- base-tunnel-inj.py script import and executes paramiko on a new Thread to create an SSH local port forward to a remote SSH server. Afterward a shellcode can be locally injected in python.exe.