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.
![]()
Run the client with the command:
./client --server http://127.0.0.1:8080![]()
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.
![]()
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
{
}![]()
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.
![]()
Searching for the string flag in the client, I find a /getflag interface.
![]()
Exploit
![]()
![]()
![]()
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'.
![]()
So I change valid to 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
}![]()
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~