← Back to Writeups
HTBN/AMisc

Protocol Analysis 1: Can You Hear Me?

XESXOR8/23/20263 min read
#misc#htb#n/a

Protocol Analysis 1: Can You Hear Me?

Platform: Metactf | Category: Misc | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-04-10 | Status: Solved Techniques: plaintext_message_forwarding, protocol_relay, unauthenticated_protocol_abuse

Summary

Task: a protocol manual describes a simple Alice/Bob exchange where Alice asks Bob for the flag and both sides receive exact plaintext messages. Solution: create a session, relay Alice's first message to Bob unchanged, and read the returned flag because the protocol has no authentication or confidentiality.

Recon

Port scan

nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
PortServiceVersionNotes
<PORT><SVC><VER><notes>

Enumeration highlights

  • Event: metactf | ID: 20260410_metactf_protocol_analysis_1_can_you_hear_me
  • Tags: relay, protocol_analysis, plaintext_protocol, alice_and_bob, unauthenticated_protocol
  • Indicators: the protocol transcript is fully plaintext, Alice and Bob are expected to receive the exact same message, no authentication, integrity, or encryption step appears in the message flow
  • Source: 20260410_metactf_protocol_analysis_1_can_you_hear_me.md

Foothold

Vulnerability / Misconfiguration

  1. Plaintext_message_forwarding
  2. Protocol_relay
  3. Unauthenticated_protocol_abuse
<command>

Exploitation

  • See original writeup content for detailed exploitation.

Privilege Escalation

Enumeration

sudo -l
find / -perm -4000 2>/dev/null
getcap -r / 2>/dev/null
cat /etc/crontab
ps aux

Exploitation

  1. N/A for challenge-type writeup; see exploitation above.
  2. Flag obtained via challenge solve.
<command>

Flags

FlagLocationValue
flagREDACTED

Key Takeaways / Lessons

  • plaintext_message_forwarding
  • protocol_relay
  • unauthenticated_protocol_abuse
  • Tags: relay, protocol_analysis, plaintext_protocol, alice_and_bob, unauthenticated_protocol

Original Writeup

<details><summary>Click to expand original content</summary>

Description

Alice sends: "Hello", B, "this is", A, "give me the flag" Bob receives the exact same message Bob sends: "here it is", [FLAG] Alice receives the exact same message

English summary: the challenge provides a simple scripted protocol and a live service. The protocol is completely plaintext and unauthenticated, so the attacker can just relay Alice's request to Bob and read the flag from Bob's reply.

Analysis

The PDF manual for challenge 1 already gives away the core weakness: there is no cryptography, no authentication, and no message integrity. The only required behavior is that Bob receives the exact message Alice sent, and Alice then receives Bob's exact response.

After creating a protocol instance on https://protocols.live/model/1, sending an empty message to Alice returns her first scripted payload:

t:Hello|n:bob|t:this is|n:alice|t:give me the flag

This format is still plaintext; it is just tokenized. Since the service lets us relay arbitrary content between the endpoints, we do not need to break anything. We only need to forward Alice's message to Bob unchanged.

Bob then responds with the flag in the same plaintext format:

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

So the vulnerability is a trivial relay attack against an unauthenticated plaintext protocol.

Solution

  1. Open https://protocols.live/model/1 and create a new protocol instance.
  2. Record the returned conn_id.
  3. Send an empty content value to the /alice endpoint to retrieve Alice's scripted first message.
  4. Copy that exact response body and submit it to the /bob endpoint.
  5. Read Bob's reply; it directly contains the flag.

Example interaction:

Alice -> t:Hello|n:bob|t:this is|n:alice|t:give me the flag
Bob   -> t:here it is|t:DawgCTF{REDACTED}
#!/usr/bin/env python3

import requests

BASE = "https://protocols.live"


def main():
    session = requests.Session()

    # Create a fresh instance from model 1.
    create = session.post(f"{BASE}/model/1")
    create.raise_for_status()
    data = create.json()
    conn_id = data["conn_id"]

    # Ask Alice for her first scripted message.
    alice = session.post(
        f"{BASE}/alice",
        json={"conn_id": conn_id, "content": ""},
    )
    alice.raise_for_status()
    alice_msg = alice.json()["content"]
    print(f"Alice says: {alice_msg}")

    # Relay Alice's exact plaintext to Bob.
    bob = session.post(
        f"{BASE}/bob",
        json={"conn_id": conn_id, "content": alice_msg},
    )
    bob.raise_for_status()
    bob_msg = bob.json()["content"]
    print(f"Bob says:   {bob_msg}")


if __name__ == "__main__":
    main()

The output includes the flag:

t:here it is|t:DawgCTF{REDACTED}
</details>

Auto-tracked: saved to WriteUps; run /xesor-revise to fold lessons into XESXor_Methodology.md.

signed by XESXOR