Enumerating two very different targets — a hardened, real Windows 10 laptop and a deliberately vulnerable Metasploitable 2 VM — with nmap, a threaded Python port scanner and banner grabber built from scratch, and a from-scratch netcat replacement. Ends in a cross-machine PowerShell reverse shell and an unauthenticated route straight to root.
One attacker platform, two deliberately different targets: a physical Windows laptop with its own defenses live, and a Metasploitable 2 VM left unhardened to validate technique. Every target is my own hardware or a VM I run — an authorised, self-contained lab.
Scanner, banner grabber, and netcat replacement all live in the GitHub repo.
| Host | Role | Network |
|---|---|---|
| Kali Linux | Recon and exploitation platform | Dual-homed — bridged + host-only |
| Windows 10 (physical) | Realistic, defended target — Defender and firewall active | 192.168.0.0/24 · home LAN |
| Metasploitable 2 (VM) | Deliberately vulnerable target for technique validation | 172.20.10.0/28 · VMware host-only |
nmap for mature, proven recon; hand-rolled Python for the case that eventually matters — a compromised host with no tools installed except Python.
A raw-socket scanner using connect_ex() so closed ports return a status code instead of raising an exception, farmed out across a ThreadPoolExecutor pool so the scan waits on hundreds of timeouts in parallel instead of one at a time.
Reads whatever a chatty service (FTP, SMTP) volunteers on connect, distinguishing that from silent binary protocols like SMB that need a protocol-specific handshake rather than a plaintext nudge.
An argparse-driven listener/client pair (Black Hat Python, ch. 2) that pipes a command shell over a raw socket — a working subprocess.check_output-backed shell built from nothing but the standard library.
Established by hand with plain netcat first (two terminals, localhost) to isolate the mechanic, then repeated cross-machine against the Windows target with a PowerShell one-liner in place of a native nc binary.
Every tool and target writeup lives in Obsidian, version-controlled and pushed to a private GitHub repo — the same habit this page itself comes out of.
Packet fragmentation (-f) and decoy source addresses (-D) tried against the Windows target's live firewall — and reported as unsuccessful, because a stateful modern firewall reassembles fragments before filtering.
scanner.py — threaded scan with banner grab
# fresh socket per port; connect_ex returns a code instead of raising
def scan_port(port):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(1)
result = s.connect_ex((target, port))
if result == 0:
banner = grab_banner(s)
print(f"Port {port} is OPEN {banner}")
s.close()
# 100 workers waiting on timeouts in parallel — ~500x faster than serial
with ThreadPoolExecutor(max_workers=100) as executor:
executor.map(scan_port, range(1, 1025))
netcat.py — the command-shell branch (BHP ch. 2)
elif self.args.command:
cmd_buffer = b''
while True:
client_socket.send(b'BHP: #> ')
while b'\n' not in cmd_buffer:
cmd_buffer += client_socket.recv(64)
response = execute(cmd_buffer.decode())
if response:
client_socket.send(response.encode())
cmd_buffer = b''
Each finding was cross-checked between nmap and the from-scratch scanner before being treated as real.
nmap and scanner.py agreed exactly on the five open ports found on the Windows target (135, 139, 445, 902, 912) once the host's own firewall was accounted for.
SMB signing confirmed enabled but not required on the Windows target — a concrete NTLM-relay precondition, found by nmap's NSE scripts rather than a plain port scan.
Metasploitable enumerated top to bottom — 14 open ports, six carrying a named, specific vulnerability rather than a generic service label.
vsftpd 2.3.4 and anonymous FTP identified on port 21 — one of the most widely known backdoored service versions in the field.
Cross-machine reverse shell obtained — a PowerShell one-liner on the Windows target called back to a Kali nc listener and returned an interactive prompt.
Unauthenticated root shell obtained on Metasploitable by connecting directly to an exposed bind shell on port 1524 — no exploit and no credentials required.
Metasploitable — nmap -sV -sC (excerpt)
21/tcp open ftp vsftpd 2.3.4
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
22/tcp open ssh OpenSSH 4.7p1 Debian 8ubuntu1
139/tcp open netbios-ssn Samba smbd 3.X - 4.X
445/tcp open netbios-ssn Samba smbd 3.0.20-Debian
1524/tcp open ingreslock Metasploitable root shell
scanner.py — matching result, own code
Port 21 is open 220 (vsFTPd 2.3.4)
Port 22 is open SSH-2.0-OpenSSH_4.7p1 Debian-8ubuntu1
Port 25 is open 220 metasploitable.localdomain ESMTP Postfix (Ubuntu)
Port 139 is open
Port 445 is open
1.19 seconds
Scan complete.
Root shell — direct connection, no exploit
$ nc 172.20.10.6 1524
root@metasploitable:/# whoami
root
root@metasploitable:/# id
uid=0(root) gid=0(root) groups=0(root)
Four real failures across the two targets — not staged for the writeup. The firewall one is the one that actually made me stop and think.
Ping showed 100% loss and nmap returned 0 hosts up, despite the same MAC answering an ARP scan seconds earlier. Cause was the laptop's Wi-Fi adapter powering itself down to save battery — a host that's genuinely asleep, not blocked. ARP told the truth; ICMP couldn't, because there was no host awake to answer it. Fixed by disabling adapter power management on the target NIC.
With the host confirmed alive via ARP, a full port sweep still came back all-filtered — and neither -Pn, a higher --min-rate, nor packet fragmentation (-f) changed the result. The cause was Windows Defender Firewall dropping unsolicited SYNs and ICMP silently rather than rejecting them, which looks identical to a dead host from a single scan. Distinguishing "alive but silent" from "actually down" — ARP reachable, zero TCP replies — is what resolved it, not re-running the same scan with more flags.
A canonical PowerShell TCP reverse-shell one-liner was quarantined before it ever ran. Defender pattern-matched the exact, widely published payload text on sight — no execution needed. Confirmed the payload itself was sound by disabling real-time protection on the owned lab target only for the test; genuine AV/EDR evasion is scoped to a later phase, not attempted here.
Restarting the custom netcat listener on the same port repeatedly failed with "Address already in use." SO_REUSEADDR alone didn't help because a previous run was still live, not just lingering in TIME_WAIT. lsof -i :<port> to find the PID, kill -9 to free it.
A live host behind a silent firewall reads identically to an offline machine on a single scan. Treating "no response" as "nothing here" wastes hours on targets that were never actually unreachable.
vsftpd 2.3.4 and Samba 3.0.20 aren't generic labels — they're a bundled backdoor and CVE-2007-2447 respectively, the moment the exact version is on record.
Outbound traffic is trusted far more than inbound by default. A payload that dials home rides through the gap defenders leave open, rather than trying to punch through the wall they actually built.
Site-based or remote, in and around Milton Keynes.