Hack The Box: dynstr

Jump Ahead: EnumInitial ShellUserRootResources


Like all machines, we begin by enumerating open ports – finding ports 22, 53, and 80 open. Enumerating the webserver, we find a path that we further enumerate to find a file. When we try accessing the file, we receive an error message. Combining the error message with disclosed information we found on the main index page, we learn that we can supply arguments to a command running on the server backend. Fuzzing the arguments for command injection, we find that it is vulnerable. Exploiting the vulnerability, we get a shell on the machine as www-data. While enumerating the machine locally, we learn that several files potentially house the SSH private key for the bindmgr user. After updating DNS records, we are able to use the SSH key to log into the machine as bindmgr – which grants us access to user.txt. bindmgr is able to run a script as root, which is vulnerable to command injection. Exploiting the vulnerability, we are able to get a shell as root on the machine – allowing access to root.txt.


Like all machines, we begin by enumerating open ports – finding ports 22, 53, and 80 open.

$ sudo nmap -v -p- --min-rate 3000 $RHOST
$ sudo nmap -sV -A -oA enum/nmap/tcp-scripts $RHOST
# Nmap 7.91 scan initiated Sat Jun 12 19:33:08 2021 as: nmap -sV -A -oA enum/nmap/tcp-scripts
Nmap scan report for
Host is up (0.048s latency).
Not shown: 997 closed ports
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 05:7c:5e:b1:83:f9:4f:ae:2f:08:e1:33:ff:f5:83:9e (RSA)
|   256 3f:73:b4:95:72:ca:5e:33:f6:8a:8f:46:cf:43:35:b9 (ECDSA)
|_  256 cc:0a:41:b7:a1:9a:43:da:1b:68:f5:2a:f8:2a:75:2c (ED25519)
53/tcp open  domain  ISC BIND 9.16.1 (Ubuntu Linux)
| dns-nsid: 
|_  bind.version: 9.16.1-Ubuntu
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Dyna DNS
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:

Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 23/tcp)
1   50.05 ms
2   50.12 ms

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Jun 12 19:33:58 2021 -- 1 IP address (1 host up) scanned in 50.56 seconds

Running nikto, we do not find anything that stands outs. Next, we enumerate directories and files using gobuster and find a couple directories that seem interesting.

$ for i in files directories; do gobuster dir -t 30 -u $RHOST -w /opt/wordlists/seclists/Discovery/Web-Content/raft-medium-$i.txt; done
/assets               (Status: 301) [Size: 315] [-->]
/server-status        (Status: 403) [Size: 278]
/nic                  (Status: 301) [Size: 312] [-->]

Further enumerating the directories, we find /nic/update which sounds notable. Before we start attempting to find a path forward with the information we have, we should manually enumerate the webserver. Going to the main webpage, we learn the site is a dynamic DNS provider.

Looking throughout the webpage, we find a few interesting items. Under the “Services” section, we learn the provider uses the same dynamic DNS API as https://no-ip.com. Additionally, we are told the dynamic DNS is available for a few domains, and are also given a pair of credentials. Since we have several new FQDNs, we add them to /etc/hosts for further enumeration.

Attempting to use the credentials on the SSH server, however, does not gain us access. Lastly, since DNS is available over TCP, we attempt to enumerate the domains we’ve gathered, however, we only get 1 result.

Attempting to access the discovered subdomain and previously discovered domains returns the same webpage. This indicates the webserver may not be configured to use virtual hosts.

Initial Shell

Going to /nic/update in our browser, we are given a message that says “badauth”.

Since the website disclosed its use of the no-ip.com Dynamic DNS api, we research “no-ip authentication” to get more information. Based on the message we received, we may be able to use the credentials that were disclosed to authenticate. In our researched, we find documentation on using the credentials we found to log in. Additionally, the documentation details this API call allows us to update DNS records. After using curl to make the DNS update, we also use nslookup to verify our changes are made.

Since we are able to presumably supply input to a system command on the remote machine, we decide to test for code/command injection. In our tests, the “;” yielded a “nsupdate” error, so this may likely be a good shell metacharacter to use. For our proof of concept, we try to get a directory listing, but based on the documentation, the responses are fixed.

Since responses may be fixed, a basic out-of-band proof of concept we can perform is to get the machine to send us an ICMP Echo (ping) request. For this, we should also use tcpdump to monitor the network traffic. Additionally, since we may be executing commands in the shell, we can enclose the injected command in $() or ``. When we do this, we get a response that the first octet of our IP address is dropped, and that it doesn’t match the allowed domains. Since some level of input sansitization is taking place, we attempt to convert the IP address into an integer, and resubmit the request. This time we get a “nsupdate” error, however, we also get the ping requests.

Since this proved we have command injection, we now utilize this vulnerability to get a bash reverse shell as the www-data user.

Getting User

Having received a shell as www-data, the first thing we want to do is enumerate the local machine for paths of privilege escalation. We start manual enumeration, however, do not find anything immediately. Next, we use an automated enumeration script such as linpeas to do more thorough enumeration. From the script output, we get pointed to potential SSH keys located in a couple files owned by the bindmgr user.

Looking into /home/bindmgr/support-case-C62796521/strace-C62796521.txt, we find there is indeed a private SSH key we are able to extract from the read syscall output.

We copy the key, and correctly format it with echo -e "<key>" on our local machine. When we attempt to use the key to login as bindmgr, we are denied access. Looking at the /home/bindmgr/.ssh/authorized_keys file, we see the key is restricted to use from a “*.infra.dyna.htb” subdomain.

From our steps to get access on the machine, we know we are able to manipulate DNS records. To bypass the key restriction, we do more research on nsupdate. In our research, we find this article that gives examples on setting DNS records using nsupdate. The article says we will likely need a key file to sign the DNS update, so we attempt to find one using find.

We find several key files, however, /etc/bin/infra.key is likely the one we need. Next, we follow the guide to add PTR (reverse-DNS) and A (forward-DNS) records for our host. Since the subdomain does not matter, we used the subdomain khaotic.infra.dyna.htb. To verify our update was successful, we make DNS queries to the DNS server.

Since our DNS updates worked, we are now able to log into the machine via SSH as bindmgr, and read user.txt.

Getting Root

After gaining access to the machine as bindmgr, we begin to enumerate for additional access. The first command we run is sudo -l. Once we run this, we see we are able to execute /usr/local/bin/bindmgr.sh as root without a password.

Looking through the code, we make a couple observations. First, we see we will need to create a .version file which returns a value greater than that of $BINDMGR_DIR/.version. Secondly, we observe there is a potential command injection vulnerability with the cp command the script executes. Particularly, user-generated files can be submitted as command arguments.

Before we attempt to exploit the cp command, we need to make sure our .version value is larger, so we attempt to read the value of $BINDMGR_DIR/.version. When try to read the file, we get an error it doesn’t exist. This, however, is fine, since the error code is still returned. In this case, the returned value is “1”.

Since “1” is the value our .version file needs to be larger than, we create a file with the value of “2”. Next, we are ready to attempt to exploit the cp command. Essentially, the cp command will copy all files in the current directory to /etc/bind/named.bindmgr/. To exploit this, we can copy /bin/bash to our directory, and give it the “setuid” permission. Next, we need to create a file named --preserve=mode, so when our copy of bash is copied, the permissions are left as we set them. This works because the command will treat the filename as a command argument. Once we create the file, we execute the script using sudo. After checking the /etc/bind/named.bindmgr/ directory, we find .version and bash were successfully copied.

Lastly, we execute the copied bash with the “-p” argument to preserve the effective user id (due to setuid). Doing so, we get a shell as root, and can now read root.txt.

Thank you for taking the time to read my write-up. I am interested in other ways this machine has been solved. Feel free to reach out to me and we can discuss it. Thanks!