Jump Ahead: Enum – Initial Shell – User – Root – Resources
TL;DR;
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
.
Enumeration
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 10.129.125.12
Nmap scan report for 10.129.125.12
Host is up (0.048s latency).
Not shown: 997 closed ports
PORT STATE SERVICE VERSION
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:
OS:SCAN(V=7.91%E=4%D=6/12%OT=22%CT=1%CU=43100%PV=Y%DS=2%DC=T%G=Y%TM=60C5527
OS:6%P=x86_64-pc-linux-gnu)SEQ(SP=FF%GCD=1%ISR=108%TI=Z%CI=Z%TS=A)OPS(O1=M5
OS:4DST11NW7%O2=M54DST11NW7%O3=M54DNNT11NW7%O4=M54DST11NW7%O5=M54DST11NW7%O
OS:6=M54DST11)WIN(W1=FE88%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN(R=Y%D
OS:F=Y%T=40%W=FAF0%O=M54DNNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0
OS:%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=
OS:Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%
OS:RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%I
OS:PL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 23/tcp)
HOP RTT ADDRESS
1 50.05 ms 10.10.14.1
2 50.12 ms 10.129.125.12
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] [--> http://10.129.125.12/assets/]
/server-status (Status: 403) [Size: 278]
/nic (Status: 301) [Size: 312] [--> http://10.129.125.12/nic/]
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”.
/nic/update
fileSince 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.
www-data
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.
bindmgr
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.
bindmgr
is restrictedFrom 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
.
find
to search for nsupdate keysWe 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
.
bindmgr
, and reading 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.
cp
to create a root shellLastly, 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
.
root
and reading 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!