KHP Protocol
KHP Protocol is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator
Scenario
KHP Protocol attack path
KHP Protocol is a sanitized challenge note from the local HTB archive, organized for quick review by category, difficulty, evidence flow, and reusable operator
Objective
Challenge walkthrough focused on Pwn evidence, validation, and reusable operator lessons.
Walkthrough flow
Triage the non-stripped TCP server binary and map KHP...
Identify that AUTH checks in-memory profiles against...
Validate direct packaged-admin auth locally, then...
Use REKE heap overflow to overwrite the loaded...
Authenticate the fake admin and trigger EXEC from a...
Source coverage
High source coverage
Status: complete. This article is generated from 4 sanitized Markdown sources and keeps raw flags, credentials, keys, cookies, and reusable secrets out of the rendered blog.
High confidence: the page is reconstructed from a primary walkthrough plus multiple supporting notes or evidence sources. Treat the chain as source-backed, while still checking the listed source files for sensitive values.
- Pwn/KHP-Protocol/writeup.md
- htb-challenge/Pwn/KHP-Protocol/notes.md
- htb-challenge/Pwn/KHP-Protocol/memory-summary.md
- htb-challenge/Pwn/KHP-Protocol/hypothesis-board.md
Technical Walkthrough
Writeup
Challenge
- Name: KHP-Protocol
- Category: Pwn
- Difficulty: Medium
- Mode: hybrid
Summary
KHP Protocol ships a non-stripped amd64 ELF service that manages username:role key; entries over a simple TCP protocol. The intended path was a protocol and heap-state bug, not shellcode or ROP. The final exploit uses REKE to create a fake admin profile, abuses an overflow from a reused key chunk to overwrite the loaded users.keys heap buffer, authenticates the fake admin, then triggers the built-in admin-only EXEC shell from a second client.
Artifact Inventory
khp_server: non-stripped 64-bit PIE ELF TCP server.users.keys: local key database used byAUTHexistence checks.Dockerfile: Ubuntu 22.04 runtime exposing port 1337.- Remote:
<TARGET>:31791.
Analysis
Static triage showed the protocol commands REKE, SAVE, AUTH, DEKE, DDKE, RLDB, GTPR, and admin-only EXEC. AUTH checks whether an in-memory key profile exists in the loaded database buffer; EXEC then trusts global authenticated role state and spawns /bin/sh.
The first hypothesis used the packaged admin entry directly. That worked locally but failed remotely because the live database did not contain the same exact admin profile. Public research was then used only as a lead, and the matching local disassembly confirmed the real primitive: REKE allocates a fixed-size heap chunk but formats attacker-controlled fields into it with sprintf, allowing overflow into the subsequently allocated database buffer.
The final solver keeps the exploit stable by using a safe padding SAVE record to make the next database load larger, DEKE -3 to free/null the loaded database buffer, then a controlled REKE overflow to inject a fake admin profile into the heap copy of users.keys. After AUTH succeeds, a second TCP client runs EXEC so the spawned shell is attached to the correct socket.
Solve
Reproducible solver:
python3 solve/solve.py --strategy heap --host <TARGET> --port 31791 --output analysis/flag-candidate.txt --transcript analysis/remote-solve-transcript.txtThe script uses only Python stdlib sockets. It writes raw flag material only to the requested output path for harness capture; transcripts redact the flag.
Flag
Raw flag is stored in loot/flag.txt and intentionally not reproduced here.
Lessons
- Validate direct packaged secrets locally, but do not assume remote challenge state uses the same database contents.
- For stateful threaded pwn services, global auth/session variables can create cross-client exploit paths.
- If failed heap attempts pollute the process, stop and let the instance restart instead of continuing blind probes.
- Keep remote attempts gated and low-noise; local Docker reproduction was enough to build the final exploit.
Source-Backed Dossier
The sections below are merged from companion Markdown notes for the same case. They are rendered after sanitization so the article stays precise without publishing raw flags, credentials, or target-specific secrets.
Notes
Scope
- Challenge: KHP-Protocol
- Category: Pwn
- Difficulty: Medium
- Mode: hybrid
- Remote instance: <TARGET>:31791
- Start time: 2026-06-12T12:56:37Z
- Operator: harness
- State file:
challenge-state.json
Harness Status
- Current phase: see
challenge-state.json - Next allowed actions: see
next-action.json - Raw flags and sensitive material stay in
loot/only. Do not paste them here.
Artifact Inventory
| File | Size | SHA256 | Type | Notes |
|---|---|---|---|---|
files/a12c73b3-5c5a-4eae-be26-cff6516b5964.zip | 9540 | <hash redacted> | Zip archive data, at least v1.0 to extract, compression method=store | zip entries: 7 shown in artifact inventory JSON |
files/extracted/pwn_khp_protocol/Dockerfile | 201 | <hash redacted> | ASCII text | |
files/extracted/pwn_khp_protocol/build-docker.sh | 110 | <hash redacted> | POSIX shell script text executable, ASCII text | |
files/extracted/pwn_khp_protocol/challenge/flag.txt | 27 | <hash redacted> | ASCII text | |
files/extracted/pwn_khp_protocol/challenge/khp_server | 27304 | <hash redacted> | ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=<hash redacted>, for GNU/Linux 3.2.0, not stripped | |
files/extracted/pwn_khp_protocol/challenge/users.keys | 248 | <hash redacted> | ASCII text |
Evidence Ledger
| Time | Action | Output/File | Finding | Confidence | Next |
|---|---|---|---|---|---|
| 2026-06-12T12:56:37Z | harness init | challenge-state.json | Workspace initialized with deterministic state file | High | Inventory artifacts |
| 2026-06-12T12:57:12Z | artifact inventory | analysis/artifact-inventory.json | 6 artifact(s) inventoried | High | Build or update hypotheses |
| 2026-06-12T13:04:04Z | hypothesis recorded | hypothesis-board.md | Two-client global auth-state confusion: register packaged admin profile in memory on client A, authenticate it, keep A open, then trigger EXEC from client B. | High | Run solve/solve.py once through challenge_exec against <TARGET>:31791 and capture the flag candidate if returned. |
| 2026-06-12T13:04:20Z | research record | analysis/research/research-records.md | Research tagged MATCHED | Medium | Validate against current evidence |
| 2026-06-12T13:04:20Z | instrumentation plan | analysis/instrumentation-plan.md | Validate and exploit KHP Protocol admin EXEC using the least remote interaction. | High | Stop after one failed gated attempt unless the failure returns a new concrete protocol fact; do not brute force keys or fuzz the remote blindly. |
| 2026-06-12T13:04:37Z | source audit | analysis/source-audit.md | Source audit recorded | High | Gate before exploit |
| 2026-06-12T13:04:56Z | checkpoint recorded | analysis/checkpoint-analysis-20260612T130456412258Z-4ad0d86e.md | Checkpoint for ANALYSIS | High | Use checkpoint to drive next decision |
| 2026-06-12T13:05:14Z | local memory search | analysis/research/local-memory-search-20260612T130514763361Z-d6f6abc4.md | Found 5 safe prior-note result(s) | Medium | Record useful result or skip |
| 2026-06-12T13:06:06Z | RAG query | analysis/rag/rag-query-20260612T130556089145Z-027d867e.txt | RAG helper exited 0; output saved | Medium | Record retrieval tag and validation |
| 2026-06-12T13:06:27Z | local memory record | analysis/local-memory-records.md | Prior local notes reviewed as fallback/advisory context | Medium | Validate against current evidence |
| 2026-06-12T13:06:27Z | RAG record | analysis/rag-records.md | Retrieved memory tagged MISSING | Medium | Validate or reject with live evidence |
| 2026-06-12T13:06:38Z | evaluator | analysis/evaluator-20260612T130638171103Z-3b0bd603.md | Proceed | High | Run gated remote solver and capture flag via harness. |
| 2026-06-12T13:07:42Z | checkpoint recorded | analysis/checkpoint-analysis-20260612T130742679436Z-052c191c.md | Checkpoint for ANALYSIS | High | Use checkpoint to drive next decision |
| 2026-06-12T13:12:13Z | research record | analysis/research/research-records.md | Research tagged MATCHED | Medium | Validate against current evidence |
| 2026-06-12T13:12:13Z | checkpoint recorded | analysis/checkpoint-analysis-20260612T131213544024Z-293792a2.md | Checkpoint for ANALYSIS | High | Use checkpoint to drive next decision |
| 2026-06-12T13:12:13Z | evaluator | analysis/evaluator-20260612T131213594508Z-5f62fded.md | Proceed | High | Run gated remote heap solver and capture flag. |
| 2026-06-12T13:15:53Z | checkpoint recorded | analysis/checkpoint-analysis-20260612T131553657753Z-eab3aa4f.md | Checkpoint for ANALYSIS | High | Use checkpoint to drive next decision |
| 2026-06-12T13:17:34Z | checkpoint recorded | analysis/checkpoint-analysis-20260612T131734514160Z-b4524821.md | Checkpoint for ANALYSIS | High | Use checkpoint to drive next decision |
| 2026-06-12T13:18:28Z | checkpoint recorded | analysis/checkpoint-analysis-20260612T131828786272Z-c5e4c61b.md | Checkpoint for ANALYSIS | High | Use checkpoint to drive next decision |
| 2026-06-12T13:18:57Z | flag capture | loot/flag.txt | HTB-format flag captured; raw value kept in loot only | High | Write solution and run completion gate |
| 2026-06-12T13:21:26Z | completion gate | challenge-state.json | Completion gate passed; state marked COMPLETE | High | Optional sanitized memory summary approval |
Key Findings
khp_serveris a non-stripped amd64 ELF with a custom KHP TCP protocol and built-in admin-onlyEXECshell path.- Direct packaged-admin authentication worked locally but failed remotely because the live
users.keyscontent did not match the packaged admin profile. - The working primitive is
REKEheap overflow into the loadedusers.keysheap buffer, validated locally in linux/amd64 Docker and remotely after the instance restarted cleanly. - The final solver uses safe DB padding,
DEKE -3to resetKEYS_BUF, heap database injection of a fake admin profile,AUTH, then cross-clientEXEC. - Remote flag was captured through the harness and stored only in
loot/flag.txt.
RAG / Advisory Memory
RAG output is advisory only. Record evaluated retrievals with:
scripts/challenge_harness.py rag-record <workspace> --query "..." --tag MATCHED|PARTIAL|MISSING|<secret redacted>|GENERIC --validation "..."Secrets/Flags
Raw flags and sensitive material stay in loot/ only. Use scripts/challenge_harness.py capture-flag to validate and record flag capture without printing the value.
Memory Summary
Metadata
- Platform: HackTheBox Challenges
- Category: Pwn
- Challenge: KHP-Protocol
- Difficulty: Medium
- Source workspace:
<local workspace>
Validated Solve Chain
Concepts only. Do not include raw flags, reusable credentials, tokens, cookies, private keys, or live secrets.
- Triage the non-stripped TCP server binary and map KHP commands.
- Identify that
AUTHchecks in-memory profiles against the loadedusers.keysbuffer andEXECtrusts global authenticated role state. - Validate direct packaged-admin auth locally, then close it for remote when the live database did not match.
- Use
REKEheap overflow to overwrite the loaded database buffer with a fake admin profile. - Authenticate the fake admin and trigger
EXECfrom a second client to attach the shell to the desired socket. - Read the remote flag through the shell and capture it with the harness.
Reusable Lessons
- For pwn services with local Docker assets, prove heap/protocol behavior locally before touching remote.
- A packaged local database may be useful for structure, but live remote content can differ.
- Stateful threaded services can have exploitable global auth/client socket state across connections.
- Failed heap attempts can pollute the process; stop, let the instance restart, then rerun the clean exploit.
Dead Ends
- Direct packaged-admin authentication: worked locally, failed remotely because the live DB did not contain the same profile.
- Repeating heap attempts on a polluted process: caused allocator instability; clean restart was needed.
Tool Quirks
- The Mac host lacked
gdb,pwntools, andchecksec; the final solver used Python stdlib sockets. - Docker required
--platform linux/amd64to run the provided amd64 ELF on Apple Silicon. readelfwas unavailable locally; static review usedstrings,nm, andobjdump.
Evidence Paths
analysis/research-direct-static-protocol-review.mdanalysis/research-public-khp-writeup.mdanalysis/local-solve-transcript.txtanalysis/remote-solve-transcript.txtsolve/solve.pyloot/flag.txt
Ingestion Decision
- Proposed for LightRAG: yes
- Requires user approval before ingestion: yes
Hypothesis Board
Keep no more than 3 active hypotheses on Easy/Medium and 5 on Hard unless the user explicitly asks for breadth.
| Rank | Path | Evidence | Missing Proof | Cheapest Validation | Confidence | Status |
|---|---|---|---|---|---|---|
| 1 | Two-client global auth-state confusion: register packaged admin profile in memory on client A, authenticate it, keep A open, then trigger EXEC from client B. | Static disassembly shows AUTH checks exact in-memory profile against users.keys and EXEC trusts global <secret redacted>/cli. Local linux/amd64 Docker proof reached shell; transcript redacted in analysis/local-admin-auth-shell-proof.txt and analysis/local-solve-transcript.txt. | Remote instance must use the same packaged users.keys profile and keep the same global-state threading behavior. | Run solve/solve.py once through challenge_exec against <TARGET>:31791 and capture the flag candidate if returned. | High | Active |
Closed Branches
| Branch | Evidence Tested | Failure Output | Reason Closed | Revisit Condition |
|---|
Technical analogy
How to remember this solve
Think of the challenge as a small system with one rule that matters more than the rest. The solve is finding that rule, validating it, and using it carefully enough to reach the final proof.
For KHP Protocol, keep the mental model simple: identify the trusted assumption, prove it with the smallest safe test, then automate or repeat only the part that directly leads to the flag.