tryhackme - vulnversity

https://tryhackme.com/room/vulnversity

Reconnaissance

Quick vs Full

Run a quick scan first to find things to enumerate.

By “quick” we don’t mean fast, we’ll talk about that in a second, but rather running our scan without any ports specified. Why? The default behaviour of Nmap is to only scan the top 1000 most popular ports unless you tell it otherwise.

nmap -sC -sV -oA vulnuniversity 10.10.155.146

-sC (script scan): Performs a script scan using the default set of scripts. It is equivalent to --script=default. Some of the scripts in this category are considered intrusive and should not be run against a target network without permission. https://nmap.org/book/man-nse.html

-sV (version detection): After TCP and/or UDP ports are discovered using one of the other scan methods, version detection interrogates those ports to determine more about what is actually running. The nmap-service-probes database contains probes for querying various services and match expressions to recognize and parse responses. Nmap tries to determine the service protocol (e.g. FTP, SSH, Telnet, HTTP), the application name (e.g. ISC BIND, Apache httpd, Solaris telnetd), the version number, hostname, device type (e.g. printer, router), the OS family (e.g. Windows, Linux). When possible, Nmap also gets the Common Platform Enumeration (CPE) representation of this information. https://nmap.org/book/man-version-detection.html

-oA <basename> (output to all formats): As a convenience, you may specify -oA <basename> to store scan results in normal, XML, and grepable formats at once. They are stored in <basename>.nmap, <basename>.xml, and <basename>.gnmap, respectively. As with most programs, you can prefix the filenames with a directory path, such as ~/nmaplogs/foocorp/ on Unix or c:\hacking\sco on Windows. https://nmap.org/book/man-output.html

If you do not specify the port range you run the risk of missing some open services so it’s good to run two scans:

  1. The first scan to find any low-hanging fruit

  2. The second scan to check all 65535 ports (run it in the background while you poke around with whatever the first scan found)

To specify a range of ports you use the “-p” flag followed by the port numbers:

nmap -sC -sV -oA vulnversity_full -p- 10.10.155.146

-p-: the same as “-p 1-65535” or “ALL” ports

The other thing to be sensitive to while scanning in a production environment is the scan intensity, or frequency.

-T<paranoid | sneaky | polite | normal | aggressive | insane>: While the fine-grained timing controls discussed in the previous section are powerful and effective, some people find them confusing. Moreover, choosing the appropriate values can sometimes take more time than the scan you are trying to optimize. Fortunately, Nmap offers a simpler approach, with six timing templates. You can specify them with the -T option and their number (0–5) or their name. The template names are paranoid (0), sneaky (1), polite (2), normal (3), aggressive (4), and insane (5). The first two are for IDS evasion. Polite mode slows down the scan to use less bandwidth and target machine resources. Normal mode is the default and so -T3 does nothing. Aggressive mode speeds scans up by making the assumption that you are on a reasonably fast and reliable network. Finally, insane mode assumes that you are on an extraordinarily fast network or are willing to sacrifice some accuracy for speed. https://nmap.org/book/man-performance.html

Since our scan shows an Apache server is running and this is a beginner hacking challenge it’s usually a good idea to start there first.

 

Enumeration

dirbuster vs dirb vs gobuster vs dirsearch

The tasks in the challenge room want you to use Gobuster to enumerate the target website directories, which is fine, but just be aware that there are other tools that do similar types of directory scanning. See below for a brief breakdown of the more popular ones but understand they they all do the same thing - automate the time consuming task of finding various directories on a website.

dirbuster - commonly used in a lot of hacking challenge videos/write-ups though it’s popularity seems to be fading in favor of Gobuster. Can run multi-threaded and has a (not great) GUI interface.

dirb - operates similarly to dirbuster but is CLI only. Some people think it’s slower than dirbuster while others say dirb gives them more consistent results. Your mileage may vary.

gobuster - the new hotness. Written in golang and meant to address the failings of both dirbuster and dirb.

dirsearch - I came across this one while reading another write-up for this challenge. It seems to perform well enough so it’s included here and you can make your own decision whether you like it or not.

I used Gobuster for this write-up but had to install it first.

Once you install Gobuster you simply point it at your target’s IP and specify a dictionary wordlist for it to use:

gobuster dir -e -u http://10.10.164.121:3333 -w /usr/share/wordlists/dirb/common.txt

dir: uses directory/file brute forcing mode

-e: expanded mode, print full URLs

-u: the target URL or domain

-w: path to word list

This wordlist can only find 4,614 possible directories but includes the most common ones

Keep in mind that the size of your word list matters! A smaller word list will finish faster but may miss potentially interesting directories while a larger one may find more but could potentially take way longer to finish. Kali comes preinstalled with a bunch and you should play around with them to find the best ones for the situation you are in.


Status Codes

Let’s take a quick pause to look at HTTP status codes.

You can see in the Gobuster results that we got a couple different responses from our target and it’s important to understand the difference between them:

2XX - This class of status codes indicates the action requested by the client was received, understood and accepted.

3XX - This class of status code indicates the client must take additional action to complete the request.

4XX - This class of status code is intended for situations in which the error seems to have been caused by the client.

The first three results indicate a status 403 which means “forbidden”. They are actually admin files so it makes sense that our unauthenticated probing would get a 403 as a response.

The single 200 in the list is for the default index page for the website - expected and not very interesting.

The mix of 301 responses are boilerplate Apache folders with permanent redirects.

After we’ve scanned enough systems and memorized the various code meanings we start to get better at quickly identifying interesting targets - or at least mentally filtering out the ones that are obviously not interesting.


Out of all the results (that we have access to) the one for /internal is the most interesting. Sure enough, when we browse to it we get a file upload page :)

 

Fuzzing and Compromise

We want to abuse the file upload functionality to get a foothold on the target - but what types of files will the target accept?

There’s a tool for that

One way you could go about this process is to manually upload a file and if the server rejects it then change the file’s extension and repeat until something gets through.

That method is tedious, time consuming, and prone to human error. The better way is to automate the process and naturally there’s a tool for that.

Burp Suite is the go-to for this sort of thing. Normally I would reserve a separate section of the write-up for a tool this important but it’s so big and has so many useful features that it would take forever. There is a free “Community” edition which comes preinstalled with Kali and is usually more than adequate for hacking challenges or practice VMs. There is a “Pro” version that cost money and includes additional features that are valuable to professional pentesters but for the average person are probably unnecessary.

Side note: a popular alternative to Burp is ZAProxy. I’ve not used it myself but I’ve heard and read good things about it and it’s completely free. It doesn’t come preinstalled with Kali but is super easy to get from the repos.

Getting set up

If you’ve never used Burp before there are a couple housekeeping things to do first. When it’s active it functions as a web proxy so you need to configure your browser to use it. It also helps to install Burp’s CA certificate in your browser’s trust store.

If you are a Firefox user then a good quality of life companion to use with Burp is FoxyProxy. It’s an add-on that once configured will allow you to easily switch between web proxies with a single click.

The last component to set up are SecLists (you’ll see why in a minute). These are also super easy to install, just use APT to pull it from the repos.

Ready to Intrude

Now that we have all the pieces in place we are going to use Burp Intruder to fuzz the target and find a file extension that the server will accept.

Burp Intruder works by taking an HTTP request (called the "base request"), modifying the request in various systematic ways, issuing each modified version of the request, and analyzing the application's responses to identify interesting features.

For each attack, you must specify one or more sets of payloads, and the positions in the base request where the payloads are to be placed. Numerous methods of generating payloads are available (including simple lists of strings, numbers, dates, brute force, bit flipping, and many others). Payloads can be placed into payload positions using different algorithms. Various tools are available to help analyze the results and identify interesting items for further investigation
”. https://portswigger.net/burp/documentation/desktop/tools/intruder/using

The Vulnversity challenge room has some instructions for how to do this process but honestly I found them to be unclear and a bit confusing so here is a more detailed step-by-step procedure.

Make sure FoxyProxy is configured and set to use Burp

On the target website browse to the upload page and upload a file (it doesn’t matter what kind - I used a jpg for this example).

Switch over to Burp and click on the Proxy tab. Make sure intercept is ‘on’ and click the Forward button.

Send the intercepted request to Intruder (you can right click somewhere on the page or just hit CTRL+i).

Within the Intruder tab click on the Positions tab

On the right side of the screen you should see four buttons - click the Clear button

Go back to the left side of the screen and look for the line that starts with “Content-Disposition” and includes the filename that we uploaded (“mlp.jpg” in my case, yours will be different)

With your mouse, select the file extension (do NOT include the dot “.”) then go back to the right side of the screen and click the Add button

It should look like this when you are done

Click on the Payloads tab, go to the section called Payload Options [Simple list], click the Load button and load the file /usr/share/seclists/Fuzzing/extensions-most-common.fuzz.txt

These are the “SecLists” that we installed a few minutes ago

It should look like this when you are done

Go back to the Target tab, look to the right side of the screen and click the Start attack button

If you are using the Community version of Burp you might see a window pop up warning you about disabled functionality, just click OK and move on

What is happening here? Intruder is taking the jpg I uploaded, swapping out the file extension with one from the list that I configured, submitting it on my behalf, logging the result, and then repeating the process with the next file extension type (or “Payload” in Burp vernacular) in the list.

Select the php payload and look at the filename in the request - we can see how Intruder has changed the file extension from “jpg” to “php”

That's cool but how can we tell which extension wasn’t filtered? If you click on the Response tab and scroll to the bottom you can see the response generated by the target server “Extension not allowed”

Now look at the Length column for each payload - see anything that stands out?

The server response length for the phtml payload is smaller because the word “Success” in the body is literally fewer bytes than “Extension not allowed”

Congratulations, you’ve successfully fuzzed the target and found that it filters most file types but will allow uploads with the phtml extension.

external-content.duckduckgo.com.jpeg
 

Reverse Shell

Now that we know what kind of file will make it through the target's upload filter we can customize a reverse shell, upload it, and gain a foothold.

Kali comes preloaded with a bunch of useful web shells located in /usr/share/webshells. From there if you look in the php directory you see a reverse shell that will meet our needs; let’s make a copy because we need to customize it a bit before we can use it.

We always read code before we deploy it, right?

The section we care about is located a bit below the description . Delete the loopback address and type in the current IP of your local machine; in this case it doesn't matter if you change the port number, as you'll see in a second, just make note of whatever number you leave in there.

Save your changes and then rename the file to use the “phtml” extension that we discovered with our Burp fuzzing

Set up a netcat listener on the port that you configured in your reverse shell

Go back to the upload page on the target, browse to the shell you just configured (make sure you turn off Burp before you do!), and click the Submit button

Now what?

We need to locate the file we just uploaded but where is it?

That mlp file looks familiar ; )

Click on the reverse shell file and then check your netcat listener - Voila!

 

Privilege Escalation

Now that we have a remote shell on our target the next step is to try to escalate our privileges to root. A common technique for privesc when doing CTFs or online challenges like this is to look for files that have the SUID bit set. Here is a great article that explains in-depth what the SUID bit is and includes several examples to break it down further.

So how do we find SUID files on our target?

find / -perm /4000 2>&1 | grep -v “Permission denied”

find /: calls the built-in find utility and starts looking at the root “/” directory

-perm: Any of the permission bits are set for the file

/4000: the numerical value for files that have the SUID bit

2>&1 |: This instruction allows you to tell the shell to make one stream got to the same destination as another stream. In this case, we’re saying “redirect stream 2, stderr, to the same destination that stream 1, stdout, is being redirected to. We then pipe that output into the next command.

grep -v “Permission denied”: use grep to filter the output with the “-v” flag which Inverts the sense of matching to select non-matching lines. Basically “show me everything BUT lines that contain Permission denied”.

Searching Haystacks

It helps to know a little bit about modern Linux operating systems in order to pick out the binary that doesn’t belong in the output above. Take for example the /bin/ping binary. If you read the SUID article linked above they explained why it’s normal for ping to have the SUID bit enabled:

Similarly if we take ping command, when we have to execute this command internally it should open socket files and open ports in order to send IP packets and receive IP packets to remote server. Normal users don’t have permissions to open socket files and open ports. So SUID bit is set on this file/command so that whoever executes this will get owner (Root user’s) permissions to them when executing this command. So when this command start executing it will inherit root user permissions to this normal user and opens require socket files and ports.

Systemd

We talked about ping and why it normally has the SUID bit enabled but do you see /bin/systemctl in the output?

Systemctl is the tool used to control the systemd init service.

In ye olde tymes Linux used SysV as it’s init system to prepare user space after boot and ready the system for operation. Within the last decade a new init system was developed called systemd and basically took over every major Linux distribtution.

If we combine what we now know about SUID and systemd we can appreciate the red flag that goes up when we see those two things together.

Our target system allows any logged in user to create a system service and run it as root!

The following screenshot shows the process of us creating a service and using it to read the root flag. Below that is a description of each part with an explanation of what each part does.

eop=$(mktemp).service - we are creating an environment variable called “eop” (you can call it whatever you want). Within that variable we are calling the mktemp command to create a temporary file as a systemd service unit file (the “.service” part at the end)

Below is a screenshot of the config we need our unit file to execute. The problem is that our current logged-in user does not have permission to write to /etc/systemd/system where this would normally go. We get around that by echoing our unit file one line at a time into the env variable we just created.

echo ‘[Service] - calls the echo command to start echoing the input (notice the single quote? By not including the second single quote to close the line we are able to enter multiple single line inputs and complete our systemd unit file)

ExecStart=/bin/sh -c “cat /root/root.txt > /tmp/output” - when the service starts call the default system shell (the -c tells the shell to execute everything inside the quotes), use cat to display the contents of the root.txt file and output that to a file called output in the /tmp directory

[Install] - the second part of our unit file

WantedBy=multi-user.target’ > $eop - sets the state (or runlevel) at which this service will run (notice the closing single quote?), the > directs all our inputs to the eop env variable

/bin/systemctl link $eop - per the systemctl man page, this makes our unit file available for systemctl commands even though it is outside of the standard search paths

/bin/systemctl enable —now $eop - also per the systemctl man page “…Enable one or more units or unit instances. This will create a set of symlinks, as encoded in the "[Install]" sections of the indicated unit files. After the symlinks have been created, the system manager configuration is reloaded (in a way equivalent to daemon-reload), in order to ensure the changes are taken into account immediately. Note that this does not have the effect of also starting any of the units being enabled. If this is desired, combine this command with the --now switch…”

From here we check the output file we created and are greeted with the root flag.

 

Kill Chain Summary

  1. Network scan revealed a web server running on port 3333

  2. Website directory enumeration revealed a page that allowed file upload

  3. Fuzzing revealed that the website filtered some file types but allowed the phtml file type to be uploaded

  4. A reverse shell was crafted with the phtml extension and successfully uploaded to the target which allowed us to gain a foothold within the remote server

  5. Directory enumeration on the target revealed that the systemctl binary (belonging to root) was incorrectly configured with the SUID bit

  6. Abused the incorrect SUID configuration on systemctl to create a service that called a shell running as root to use the cat command to display the contents of the root flag