Protocol Analysis 2: Liar
Protocol Analysis 2: Liar
Platform: Metactf | Category: Forensics | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-04-10 | Status: Solved Techniques: protocol_replay, sender_impersonation, unauthenticated_protocol_abuse
Summary
Task: a PDF-defined HTTP POST protocol has Bob release the flag if he receives a specific plaintext sequence ending with the sender name charlie. Solution: create a fresh model 2 session, impersonate Charlie by changing the name field in the posted message, and read the flag from Bob's response.
Recon
Port scan
bash read-only • copy allowednmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <PORT> | <SVC> | <VER> | <notes> |
Enumeration highlights
- Event:
metactf| ID:20260410_metactf_protocol_analysis_2_liar - Tags: http_post, protocol_analysis, alice_and_bob, unauthenticated_protocol, impersonation
- Indicators: the receiver validates only a claimed name field, the protocol is implemented as attacker-controlled HTTP POST requests, there is no authentication or cryptographic proof of sender identity, changing n:alice to n:charlie satisfies Bob's checks
- Source:
20260410_metactf_protocol_analysis_2_liar.md
Foothold
Vulnerability / Misconfiguration
- protocol_replay
- sender_impersonation
- unauthenticated_protocol_abuse
bash read-only • copy allowed<command>
Exploitation
- See original writeup content for detailed exploitation.
Privilege Escalation
Enumeration
bash read-only • copy allowedsudo -l find / -perm -4000 2>/dev/null getcap -r / 2>/dev/null cat /etc/crontab ps aux
Exploitation
- N/A for challenge-type writeup; see exploitation above.
- Flag obtained via challenge solve.
bash read-only • copy allowed<command>
Flags
| Flag | Location | Value |
|---|---|---|
| flag | REDACTED |
Key Takeaways / Lessons
- protocol_replay
- sender_impersonation
- unauthenticated_protocol_abuse
- Tags: http_post, protocol_analysis, alice_and_bob, unauthenticated_protocol, impersonation
Original Writeup
<details><summary>Click to expand original content</summary>Description
All protocol messages are HTTP POST requests to
https://protocols.live.Alice sends: "Hello", B, "this is", A, "give me the flag"
Bob expects to recv: "Hello", B, "this is", C, "give me the flag"
Bob then sends: "here it is", [FLAG]
English summary: the challenge gives a scripted message flow for a live HTTP-based protocol. Bob releases the flag if he receives the right plaintext sequence and the sender name is charlie, but the protocol never authenticates who actually sent the request.
Analysis
The key flaw is trust in a user-controlled identity field. Alice's scripted request uses n:alice, while Bob's acceptance logic expects the same message except for n:charlie.
Because every protocol action is just an HTTP POST to https://protocols.live, the attacker can submit arbitrary content directly to Bob. There is no signature, shared secret, session binding to a real participant, or any other proof that the sender is actually Charlie. Bob only checks the plaintext fields, so impersonation is enough.
The winning payload is:
text read-only • copy allowedt:Hello|n:bob|t:this is|n:charlie|t:give me the flag
Submitting that to /bob in a fresh /model/2 session returns:
json read-only • copy allowed{"content":"t:here it is|t:DawgCTF{REDACTED}"}
Solution
- Start a new challenge instance with
POST /model/2. - Record the returned
conn_id. - Send the forged content
t:Hello|n:bob|t:this is|n:charlie|t:give me the flagtoPOST /bob. - Read Bob's response and extract the flag from the returned plaintext field.
Minimal solver:
python read-only • copy allowed#!/usr/bin/env python3 import requests BASE = "https://protocols.live" PAYLOAD = "t:Hello|n:bob|t:this is|n:charlie|t:give me the flag" def main(): session = requests.Session() create = session.post(f"{BASE}/model/2") create.raise_for_status() conn_id = create.json()["conn_id"] resp = session.post( f"{BASE}/bob", json={"conn_id": conn_id, "content": PAYLOAD}, ) resp.raise_for_status() print(resp.json()["content"]) if __name__ == "__main__": main()
Example output:
</details>text read-only • copy allowedt:here it is|t:DawgCTF{REDACTED}
signed by XESXOR