HTB Write-Up: Mischief

This is a write-up on the Mischief machine access challenge from HTB.  For more information on challenges like these, check out my post on penetration testing.  Special thanks to HTB user trickster0 for creating the challenge.

Reconnaissance

A simple network scan doesn't yield much, so a full port scan is in order:

    nmap -p- 10.10.10.92 (full tcp port scan)
    nmap -sU -p- 10.10.10.92 (full UDP port scan)

The results show SSH, SNMP, and a web service on TCP 3366.  Browsing to the webpage on 3366 prompts for login credentials.

SNMP uses community strings to grant access, and the default community string for read-only in usually the word public. Use the snmpwalk command to enumerate SNMP.  It's a good idea to redirect the output to a file so it can be referenced later without the need to scan again. NOTE: It is a generally good practice to capture all output and I normally do this for just about any command I run.  Although the syntax below only captures standard output (STDOUT), I would normally make sure to capture standard error (STDERR) as well.  Here's the Wikipedia on redirection.

Building off of information already known or gathered can sometimes result in a quick win, so follow the snmpwalk with a search for the machine name.   Note that searching for port 3366 would have displayed the same information.

snmpwalk -c public 10.10.10.92 -v 2c > snmpwalk.log
grep -i mischief snmpwalk.log

Using what appears to be credentials for the user loki on the web service, return to the browser and login to the service on port 3366.  This displays another set of credentials for loki, but neither will work on SSH.  There is also a picture on the website, but it is a red herring and can be ignored.

Enter Version 6

Its still easy to forget about the latest version of IP, even though its been around for a while (it officially launched in 2012 but was actually first developed in 1998). Many manufacturers and operating systems now enable ipv6 by default, so it's important to include ipv6 in any initiatives involving network security.  

Having reached a dead end, further enumeration on the snmpwalk is in order.  Find ipv6 information by searching for .1.3.6.1.2.1.55, which is the IPV6 MIB (a MIB is a database containing objects with network management information) or the more generic IP MIB which is .1.3.6.1.2.1.4. NOTE: the IPV6 specific MIBs are obsolete, but old habits die hard.

    grep ".1.3.6.1.2.1.55|.1.3.6.1.2.1.4" snmpwalk.log

Ignoring the local / loopback interfaces, there is one other network interface.  The IP address needs to be converted to the standard hex format to be usable.  Instead of writing a new script to do this, use the script found here (notice who the author of the script is!)

Ping the ipv6 address to confirm it's correct and enumerate it using nmap.  This reveals another web server running on the ipv6 address. NOTE: Obviously, this required your own system to be setup with properly with IPv6. For an explanation of dead:beef, lookup hexspeak or magic debug values on your favorite search engine.

nmap -6 -p- dead:beef:0000:0000:0250:56ff:feb9:52a2
nmap -6 -sU -p- dead:beef:0000:0000:0250:56ff:feb9:52a2

Hacking the Website and Getting User

Trying the credentials for user loki, revealed on the first website, don't work.  However, they do work for user administrator.  Since its (unfortunately) common for passwords to be reused, and admin / administrator are common usernames, this was an easy guess.  Had guessing failed, a login cracker like Hydra could have been used.

Once logged in, there is form that allows commands to be run remotely, as well as a message indicating "In my home directory, i have my password in a file called credentials."  An unfortunate aspect of CTFs is that messages like that are extremely unlikely in a real-life situation. Its just a hint though, as it is all too common for credentials to be stored in files and left behind, sometimes for many years, so the scenario is realistic after all.

A few attempts to launch a reverse shell from the web form fail, making it clear that there is some input filtering.  Instead, execute this command:

cat /home/loki/creds* &

Guessing that loki was the username was easy.  The ampersand is necessary to interrupt redirection on the backend and ensure that standard output is visible in the browser.  The wildcard is needed because using the full filename "credentials" pattern matches with the ls command which gets filtered.  NOTE: after logging in, look at /var/www/html/index.php to see a list of everything that is filtered.

Using the newly discovered password, it is possible to log in as the loki user over SSH.

Multiple Escalations

Standard enumeration should include user history, which in this case reveals yet another password.  Trying to run the su command immediately returns a permission denied, which means that the loki user is not allowed to run the executable. A quick look at the extended file permissions confirms this.

getfacl /usr/bin/su

Fortunately, the ipv6 web server runs under the context of the www-user account, which does have permission to execute su.  It is possible to take an interim escalation to the service account and elevate from there to root.

Step 1 - Power Tools

Run the following commands to create a directory with that is writable to any user on the system.

cd /home/loki
mkdir comm; chmod +777 comm

create a script called /home/loki/foo with the following contents:
    #!/bin/bash
    echo start
    cp /bin/cp /home/loki/comm
    cp /bin/chmod /home/loki/comm
    chmod +s /home/loki/comm/*
    echo done
    
chmod +x /home/loki/foo

Next, return to the ipv6 website and execute /home/loki/foo.  Because new versions of the cp and chmod commands are created by the web server when the foo script is executed, the copies created in /home/loki/comm will be owned by the www-user.  The chmod +s in the script makes them setuid.  Files with the setuid bit enabled will run under the context of the user account that owns the file.  It is now possible to easily modify any file into a setuid www-user executable.  

Step 2 - A Setuid Wrapper

As a security measure, setuid only works on binary executables, not on interpreted executables (e.g. text-based scripts).  In order to be able run a script using setuid, a binary wrapper is needed.  

Create a wrapper that executes /home/loki/comm/script. In the /home/loki/comm directory, create a file called wrapper.c. with the contents below.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <error.h>

int main(int argc, char *argv[], char *envp[])
{
    int set_uid_result;
    int effective_user_id;
    int execute_script_error;
    char* script;

    effective_user_id = geteuid();

    // Set real and effective user ID
    set_uid_result = setreuid(effective_user_id, effective_user_id);

    if (set_uid_result != 0)
    {
        printf("Failed to set user id\n");
        return 1;
    }

    script = "/home/loki/comm/script";

    // This does not return on success.
    execve(script, argv, envp);
    execute_script_error = errno;

    // Show a fancy error message.
    error(execute_script_error, execute_script_error, script);

    // Shouldn't be necceary, but you never know.
    return 1;
}

This script originated from here.  This can actually be shrunk down to about 5 lines, but the code above includes basic error checking.  It is also designed to be called from php which although irrelevant here, can be useful in other scenarios.

Next compile the code, and use the setuid cp and chmod commands to make the wrapper, called wrapper.  Now, it is possible to modify the contents of /home/loki/comm/script and execute it as www-user by executing ./wrapper.

gcc wrapper.c 
./cp a.out wrapper
./chmod +s wrapper

As a side note, setuid wrappers like this are inherently insecure for a variety or reasons and should never actually be used as part of any production system.  It's also worth noting that this is one example of why keeping compilers on productions systems is a bad idea.

Step 3 - A Script Worth Wrapping

Create the script in file /home/loki/comm/script with the contents below, and use the chmod command to make it executable.  Note that the setuid bit is not needed and the file owner doesn't matter.

#!/bin/sh
/bin/bash

Execute /home/loki/comm/wrapper to spawn a shell running as www-user.

Step 4 - Wrapping Up

As www-user, it is possible to now run su and use the password found in loki's history to elevate to root.  In one last mischievous trick, root.txt doesn't contain the flag!  Use the find command to discover a different root.txt elsewhere and put this CTF to rest once and for all.

find / -type f -name root.txt