Challenge / Pwn

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

MediumPublished 2025-04-07Sanitized local writeup

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.

KHP Protocol sanitized attack graph

Walkthrough flow

01

Triage the non-stripped TCP server binary and map KHP...

02

Identify that AUTH checks in-memory profiles against...

03

Validate direct packaged-admin auth locally, then...

04

Use REKE heap overflow to overwrite the loaded...

05

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.

100% coverage
Evidence verdict

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 by AUTH existence 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:

bash
python3 solve/solve.py --strategy heap --host <TARGET> --port 31791 --output analysis/flag-candidate.txt --transcript analysis/remote-solve-transcript.txt

The 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

FileSizeSHA256TypeNotes
files/a12c73b3-5c5a-4eae-be26-cff6516b5964.zip9540<hash redacted>Zip archive data, at least v1.0 to extract, compression method=storezip entries: 7 shown in artifact inventory JSON
files/extracted/pwn_khp_protocol/Dockerfile201<hash redacted>ASCII text
files/extracted/pwn_khp_protocol/build-docker.sh110<hash redacted>POSIX shell script text executable, ASCII text
files/extracted/pwn_khp_protocol/challenge/flag.txt27<hash redacted>ASCII text
files/extracted/pwn_khp_protocol/challenge/khp_server27304<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.keys248<hash redacted>ASCII text

Evidence Ledger

TimeActionOutput/FileFindingConfidenceNext
2026-06-12T12:56:37Zharness initchallenge-state.jsonWorkspace initialized with deterministic state fileHighInventory artifacts
2026-06-12T12:57:12Zartifact inventoryanalysis/artifact-inventory.json6 artifact(s) inventoriedHighBuild or update hypotheses
2026-06-12T13:04:04Zhypothesis recordedhypothesis-board.mdTwo-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.HighRun solve/solve.py once through challenge_exec against <TARGET>:31791 and capture the flag candidate if returned.
2026-06-12T13:04:20Zresearch recordanalysis/research/research-records.mdResearch tagged MATCHEDMediumValidate against current evidence
2026-06-12T13:04:20Zinstrumentation plananalysis/instrumentation-plan.mdValidate and exploit KHP Protocol admin EXEC using the least remote interaction.HighStop 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:37Zsource auditanalysis/source-audit.mdSource audit recordedHighGate before exploit
2026-06-12T13:04:56Zcheckpoint recordedanalysis/checkpoint-analysis-20260612T130456412258Z-4ad0d86e.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-12T13:05:14Zlocal memory searchanalysis/research/local-memory-search-20260612T130514763361Z-d6f6abc4.mdFound 5 safe prior-note result(s)MediumRecord useful result or skip
2026-06-12T13:06:06ZRAG queryanalysis/rag/rag-query-20260612T130556089145Z-027d867e.txtRAG helper exited 0; output savedMediumRecord retrieval tag and validation
2026-06-12T13:06:27Zlocal memory recordanalysis/local-memory-records.mdPrior local notes reviewed as fallback/advisory contextMediumValidate against current evidence
2026-06-12T13:06:27ZRAG recordanalysis/rag-records.mdRetrieved memory tagged MISSINGMediumValidate or reject with live evidence
2026-06-12T13:06:38Zevaluatoranalysis/evaluator-20260612T130638171103Z-3b0bd603.mdProceedHighRun gated remote solver and capture flag via harness.
2026-06-12T13:07:42Zcheckpoint recordedanalysis/checkpoint-analysis-20260612T130742679436Z-052c191c.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-12T13:12:13Zresearch recordanalysis/research/research-records.mdResearch tagged MATCHEDMediumValidate against current evidence
2026-06-12T13:12:13Zcheckpoint recordedanalysis/checkpoint-analysis-20260612T131213544024Z-293792a2.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-12T13:12:13Zevaluatoranalysis/evaluator-20260612T131213594508Z-5f62fded.mdProceedHighRun gated remote heap solver and capture flag.
2026-06-12T13:15:53Zcheckpoint recordedanalysis/checkpoint-analysis-20260612T131553657753Z-eab3aa4f.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-12T13:17:34Zcheckpoint recordedanalysis/checkpoint-analysis-20260612T131734514160Z-b4524821.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-12T13:18:28Zcheckpoint recordedanalysis/checkpoint-analysis-20260612T131828786272Z-c5e4c61b.mdCheckpoint for ANALYSISHighUse checkpoint to drive next decision
2026-06-12T13:18:57Zflag captureloot/flag.txtHTB-format flag captured; raw value kept in loot onlyHighWrite solution and run completion gate
2026-06-12T13:21:26Zcompletion gatechallenge-state.jsonCompletion gate passed; state marked COMPLETEHighOptional sanitized memory summary approval

Key Findings

  • khp_server is a non-stripped amd64 ELF with a custom KHP TCP protocol and built-in admin-only EXEC shell path.
  • Direct packaged-admin authentication worked locally but failed remotely because the live users.keys content did not match the packaged admin profile.
  • The working primitive is REKE heap overflow into the loaded users.keys heap buffer, validated locally in linux/amd64 Docker and remotely after the instance restarted cleanly.
  • The final solver uses safe DB padding, DEKE -3 to reset KEYS_BUF, heap database injection of a fake admin profile, AUTH, then cross-client EXEC.
  • 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:

bash
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.

  1. Triage the non-stripped TCP server binary and map KHP commands.
  2. Identify that AUTH checks in-memory profiles against the loaded users.keys buffer and EXEC trusts global authenticated role state.
  3. Validate direct packaged-admin auth locally, then close it for remote when the live database did not match.
  4. Use REKE heap overflow to overwrite the loaded database buffer with a fake admin profile.
  5. Authenticate the fake admin and trigger EXEC from a second client to attach the shell to the desired socket.
  6. 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, and checksec; the final solver used Python stdlib sockets.
  • Docker required --platform linux/amd64 to run the provided amd64 ELF on Apple Silicon.
  • readelf was unavailable locally; static review used strings, nm, and objdump.

Evidence Paths

  • analysis/research-direct-static-protocol-review.md
  • analysis/research-public-khp-writeup.md
  • analysis/local-solve-transcript.txt
  • analysis/remote-solve-transcript.txt
  • solve/solve.py
  • loot/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.

RankPathEvidenceMissing ProofCheapest ValidationConfidenceStatus
1Two-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.HighActive

Closed Branches

BranchEvidence TestedFailure OutputReason ClosedRevisit 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.