πŸ€– Auto-generated by PacketHammer

Protocol report:
SimpleTCP

Closed-source binary reverse-engineered autonomously β€” authentication flow, session tokens, all 7 commands, and 5 vulnerabilities including a critical stack overflow discovered in a single ~4-minute run. Zero source code. Zero human guidance.

0
Commands found
0
Response codes
0
Vulnerabilities
0
TCP port

The engine

Autonomous probe loop

PacketHammer runs a 7-step cycle that continuously probes, instruments, decompiles, and models the target protocol β€” with no human guidance. The diagram below animates the live cycle. Steps 5–7 are conditional: they fire only when their trigger condition is met.

STEP 1
RESET
β†’
STEP 2
SEND
β†’
STEP 3
OBSERVE
β†’
STEP 4
UPDATE
β†’
STEP 5
CODE-ANALYZE
if new branch
β†’
STEP 6
SUPERVISOR
every 5 steps
β†’
STEP 7
HARVEST
if plateau
1
RESET
Clear Frida branch hit counters, Tier 1 stdlib comparison buffers, and Tier 2 per-address hit counts. Establishes a clean, reproducible baseline before every probe.
2
SEND
Craft the next packet from the current seed pool and protocol state. Send it over TCP. Packet shape is guided by which branches are still unvisited.
3
OBSERVE
Read the server response. Query Frida Tier 1 (stdlib comparison hooks β€” strcmp, memcmp) and Tier 2 (per-instruction argument captures). Extract new seeds from both oracle layers.
4
UPDATE
Merge newly-discovered branches, sequences, seeds, and packet field annotations into state.json and packet_graph.json. Increment probe counter and plateau tracker.
5
CODE-ANALYZE
Fires when a new branch address is first reached. Ghidra decompiles the function; string literals become seeds; exported symbols get Tier 2 Frida hooks; vulnerability patterns are appended to vulnerabilities.jsonl.
6
SUPERVISOR
A read-only analysis agent reviews coverage gaps every 5 steps (or when plateau β‰₯ 2). Recommends new probe directions and seed strategies without modifying protocol state.
7
HARVEST
Collect all seeds from Frida comparison buffers (Tier 1 + Tier 2). Reset hit counts. Write updated seeds to state.json so the next cycle can reach deeper, previously locked branches.

Protocol overview

SimpleTCP

Line-delimited ASCII authentication protocol on TCP/2121. Clients authenticate with a username + password pair, receive a fixed session token, then issue computation commands (sum, concat, greet, multiply) β€” each requiring the token as a first argument.

SimpleTCP
TCP port 2121 Β· line-delimited Β· ASCII Β· CR / CRLF terminated
7
Commands
8
Response codes
5
Vulnerabilities
12
Seeds harvested

Response codes

200
Command success β€” post-auth command executed and result returned
220
Server ready β€” sent as banner immediately on TCP connect
221
Bye β€” server closes connection after QUIT command
230
Authentication success β€” response includes session token TOKEN-LOCAL-12345
331
Password required β€” USER accepted, client must now send PASS
403
Bad token β€” invalid session token supplied; connection stays open
500
Unknown command β€” unrecognised command sent while authenticated
530
Not authenticated / Authentication failed β€” wrong credentials or unauthenticated command attempt

Session flow

How a conversation works

Every message exchanged between client and server β€” in the exact order the protocol requires β€” discovered purely through live instrumentation. No source code was read. The packet animation above the table represents the continuous bidirectional exchange.

Live packet exchange β€” CLIENT ↔ SERVER
πŸ’»
CLIENT
C β†’ S   command packets
β–Ά
S β†’ C   response packets
β—€
πŸ–₯️
SERVER
S→C
Server sends banner immediately on TCP connect β€” no client prompt required
C→S
USER admin
Initiates login. Username stored by server; compared later during PASS handling (not validated here)
S→C
331 Password required
Server acknowledges username, requests password β€” returned regardless of username validity (no enumeration)
C→S
PASS secret
Both username and password are checked simultaneously against config['login'] and config['password']. Mismatch β†’ 530 + disconnect
S→C
230 TOKEN TOKEN-LOCAL-12345
Auth success β€” server issues fixed 16-byte session token. Token must prefix all post-auth commands
C→S
HI TOKEN-LOCAL-12345 World
Post-auth greet command. Token validated first via operator!=; name passed to strcpy into 24-byte stack buffer β€” VULNERABLE
S→C
200 HI Hello World
Greeting response β€” result of snprintf("Hello %s", name_buffer) after strcpy
C→S
ST TOKEN-LOCAL-12345 10 20
Integer sum command. a and b parsed via std::istream::operator>>
S→C
200 ST 30
Sum result: 10 + 20 = 30
C→S
CT TOKEN-LOCAL-12345 hello world
String concatenation. s1 and s2 joined via std::operator+ β€” heap-safe
S→C
200 CT helloworld
Concatenation result: "hello" + "world" = "helloworld"
C→S
IV TOKEN-LOCAL-12345 7 3
Signed int32 multiplication. Overflow possible with large operands (see VULN-IV-INTOVF)
S→C
200 IV product=21
Product result: 7 Γ— 3 = 21
C→S
QUIT
Graceful disconnect β€” available both pre-auth and post-auth, sets disconnect flag iVar8=1
S→C
221 Bye
Server confirms disconnect and closes TCP connection

Command set

7 commands discovered

Every command the server accepts β€” syntax, authentication requirement, behaviour, and any security flags identified during live instrumentation and Ghidra decompilation.

USER
Pre-auth
USER <username>

Initiates the login sequence. Username is read via std::istream::operator>> and stored in a local variable. The server always responds 331 regardless of whether the username exists β€” username enumeration is not possible from response codes alone.

PASS
Pre-auth
PASS <password>

Completes login. Server simultaneously checks stored username against config['login'] and supplied password against config['password'] via std::operator==. Both must match. Success: 230 TOKEN TOKEN-LOCAL-12345, session continues. Failure: 530 Authentication failed, connection closed immediately.

QUIT
Any state
QUIT

Graceful disconnect. Server responds 221 Bye and closes the TCP connection. Available both before and after authentication. Sets internal flag iVar8=1 which terminates the dispatch loop.

ST
Post-auth
ST <token> <a> <b>

Returns the integer sum of a and b as 200 ST <a+b>. Both operands parsed via std::istream::operator>> into signed int variables. Implemented at command_st (0x103fe4). No overflow concern β€” result formatted via std::to_string.

CT
Post-auth
CT <token> <s1> <s2>

Concatenates two strings and returns 200 CT <s1s2>. Uses std::operator+ on std::string objects β€” heap-allocated, no buffer overflow risk. Implemented at command_ct (0x10409a).

HI
Post-auth
HI <token> <name>

Greets with name: returns 200 HI Hello <name>. The name argument (no length limit from istream) is passed to strcpy into a 24-byte stack buffer β€” any name > 23 bytes overwrites the saved return address. Stack canary present but bypassable via info-leak.

⚠ Critical overflow
IV
Post-auth
IV <token> <a> <b>

Returns signed int32 product: 200 IV product=<a*b>. The product is used directly as the length argument to memset on a 64-byte scratch buffer. If a*b overflows and wraps to [0,63], memset fires with the wrapped value β€” unexpected but bounded. Implemented at command_iv (0x104342).

⚠ Integer overflow

Vulnerabilities found

5 security issues discovered automatically

PacketHammer's code-analyzer agent flagged these dangerous patterns by combining Ghidra static decompilation with live Frida instrumentation β€” every finding below was produced without a human reading a single line of assembly.

VULN-HI-BO High stack buffer overflow

Unchecked strcpy / stack buffer overflow

command_hi @ 0x1041ba

The user-supplied name argument (read via std::istream::operator>> with no length limit) is passed directly to strcpy(name_buffer, src) where name_buffer is a 24-byte stack array. Any name longer than 23 bytes overflows the buffer and overwrites the saved RBP and return address.

A stack canary is present (__stack_chk_fail @ 0x103790), providing partial mitigation β€” a direct overflow triggers abort. However, if an attacker can leak the canary value (e.g. through a format-string or memory read primitive), full RIP control is achievable. The overflow is reachable after successful authentication: USER admin β†’ PASS secret β†’ HI TOKEN-LOCAL-12345 <payload>.

Proof-of-concept trigger (crashes on stack canary check)
HI TOKEN-LOCAL-12345 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
VULN-RECV-DOS Medium resource exhaustion

Unbounded memory growth in recv_line

recv_line @ 0x103eff

The line-reading function at 0x103eff loops recv(fd,&ch,1,0) and appends each byte to a std::string via push_back() until '\n' is received. There is no maximum line length, no timeout, and no iteration cap.

An attacker sending a continuous stream of non-newline bytes forces the string to grow without bound. Each reallocation doubles capacity, leading to exponential memory consumption. The server process is OOM-killed by the OS. This requires no authentication and affects all concurrent sessions β€” a single TCP connection causes a reliable denial of service.

Proof-of-concept trigger
Connect to TCP/2121 β€” send continuous non-'\n' bytes until OOM kill (no auth needed)
VULN-IV-INTOVF Low integer overflow

Signed integer overflow β†’ unexpected memset

command_iv @ 0x104342

The product __val = a * b is computed as a signed 32-bit multiplication with no overflow check. If the mathematical product overflows int32 and wraps to a value in [0, 63], the code executes memset(scratch, 0x41, (long)__val) on a 64-byte scratch buffer β€” writing exactly __val bytes of 'A'.

No out-of-bounds write occurs (scratch is 64 bytes, __val < 64), but the unexpected control flow may interact with adjacent memory depending on stack layout. Exploiting this requires engineering a*b mod 2Β³Β² ∈ [0,63] β€” mathematically constrained but achievable with chosen large operands.

Proof-of-concept trigger
IV TOKEN-LOCAL-12345 65536 65536
VULN-UAF Info use after free

Use-after-free (suspected β€” not confirmed)

handle_client @ 0x1043aa

Ghidra's decompilation of handle_client (0x1043aa, 2637 bytes) shows manual destructor call sequences β€” basic_string() constructor, send_line(), ~string(), ~__new_allocator() β€” interleaved with complex branch chains. If send_line() throws or control flow is interrupted mid-sequence, a string object could be left in an inconsistent state.

Most likely this is a Ghidra decompilation artefact from inlined std::string code β€” actual RAII semantics in the binary are likely intact. Not confirmed exploitable. Recorded because the pattern warrants fuzzing attention, particularly under exception-triggering conditions.

Proof-of-concept trigger
<trigger input not deterministic β€” fuzz handle_client exception paths manually>
VULN-FMT Info format string

Format string vulnerability (safe as decompiled)

command_hi @ 0x1041ba

snprintf(result, 0x28, "Hello %s", name_buffer) uses a hardcoded format string with user data supplied as the %s argument β€” this is safe as currently decompiled. The format string "Hello %s" is a constant literal, not attacker-controlled.

Recorded because a decompile discrepancy (e.g. Ghidra misidentifying the argument order) or an alternate code path that passes user input directly as the format argument would make this a critical vector. Current static analysis confirms the format string is constant. Verify manually in the assembled binary if this target is high-value.

Proof-of-concept trigger
<trigger input not deterministic β€” current decompile indicates safe; verify in disassembly>

AI-assisted security testing

Manual testing vs PacketHammer

Same target. Same vulnerabilities. The difference is whether you find them in minutes or days β€” and whether the documentation writes itself or stays in someone's head.

2+ days
Minimum manual mapping time
experienced pentester, closed-source binary
VS
~4 min
PacketHammer full run
commands + vulns + report, zero guidance
Β·
12
Seeds auto-harvested
from Frida runtime comparisons
Β·
$0
Per subsequent rerun
vs $15,000+ manual pentest
πŸ‘€

Manual Penetration Testing

⏱
Time to map protocol
2–5 days minimum
πŸ“Š
Branch coverage
~30–40% (estimated)
πŸ”
Vulnerability detection
Analyst skill β€” inconsistent
🌱
Hidden comparison seeds
Source code or lucky guess
πŸ“‹
Output documentation
Ad-hoc notes, often incomplete
πŸ”„
Reproducibility
Varies between analysts
πŸ€–

PacketHammer AI Pipeline

⏱
Time to map protocol
~4 minutes
πŸ“Š
Branch coverage
100% logical paths validated
πŸ”
Vulnerability detection
Automated (Frida + Ghidra)
🌱
Hidden comparison seeds
Runtime oracle: Tier 1 + Tier 2
πŸ“‹
Output documentation
Structured JSON + this HTML report
πŸ”„
Reproducibility
Deterministic across runs
CapabilityπŸ‘€ Manual testingπŸ€– PacketHammer
Protocol structure discovery❌ Manual reverse engineeringβœ… Automated (Ghidra + Frida)
Seed / credential harvesting❌ Source code or deep RE requiredβœ… Runtime comparison hooks
Vulnerability pattern scanning❌ Analyst code reviewβœ… Static + live dynamic analysis
Session flow documentation❌ Ad-hoc notes, often lostβœ… Structured JSON + visual HTML
Zero-day seeds (hidden comparisons)❌ Frequently missed without sourceβœ… Tier 1 + Tier 2 oracle capture
Branch coverage tracking❌ Estimated / gut feelβœ… Branch-level Frida instrumentation
Scales with binary complexity❌ Analyst time scales linearlyβœ… Consistent regardless of binary size
Cost per rerun❌ Full analyst time at hourly rateβœ… Compute cost only
Time to first vulnerability❌ Hours to daysβœ… Minutes

Key addresses

Function map

Static analysis addresses from Ghidra. Live addresses after PIE rebase will differ β€” use get_base() via frida-live to compute the runtime offset, then add these values to get live addresses.

SymbolStatic address
handle_client0x1043aa
command_dispatch gate0x1044d4
recv_line0x103eff
trim_crlf0x103a89
command_hi  β† strcpy vuln0x1041ba
command_st0x103fe4
command_ct0x10409a
command_iv  β† int overflow0x104342
__stack_chk_fail (canary)0x103790