Yummy
Resumo
Essa máquina expõe uma aplicação web vulnerável à LFI, o que permite a leitura arbitrária de arquivos da máquina. Dentro do arquivo /etc/crontab, é possível identificar um script de manutenção do banco de dados que pode ser explorado para obter uma shell reversa como usuário mysql. Após o acesso inicial, é possível explorar as permissões de escrita em um outro script sendo executado por um cronjob pelo usuário www-data. Alterando esse script para um payload de shell reversa, é possível escalar privilégios lateralmente como www-data. Após isso, é possível encontrar as credenciais para o usuário qa, o que permite acesso SSH à máquina. O usuário qa tem privilégios para executar o Mercurial como usuário dev e realizar o pull de um repositório. Explorando os hooks do Mercurial, é possível escalar privilégios para o usuário dev. Como usuário dev, é possível executar o rsync como root, porém é passando um wildcard para validar a execução do comando, possibilitando a passagem de argumentos como --chmod e --chown para o comando. Por conta disso, é possível copiar o binário do BASH com SUID do root, e então escalar privilégios.
Reconhecimento
Realizei uma varredura de portas com as ferramentas Rustscan
e nmap
, obtendo os seguintes resultados:
É possível identificar dois serviços em execução, um OpenSSH
para acesso remoto à máquina e um servidor web na porta 80 (HTTP) por trás de uma instância do Caddy. Ao tentar acessar o servidor web, fui redirecionado para o domínio yummy.htb
, então adicionei uma entrada para esse domínio no arquivo /etc/hosts
da minha máquina:
Isso me permitiu acessar a seguinte página web:

Na captura acima, perceba o item Dashboard
que destaquei na barra de navegação, indicando uma possível área disponível após se autenticar à página. Ao tentar acessar ela, fui redirecionado para a página Login
:

Utilizei a opção de cadastro para criar uma conta na aplicação e navegar como usuário autenticado. Assim que autentiquei, foi possível utilizar uma funcionalidade para reservar mesas:

Preenchi esse formulário e ao voltar para a seção Dashboard
, é possível visualizar a reserva que foi feita:

Perceba a opção Save iCalendar
disponível na última coluna da tabela. Ao clicar nessa opção, a página realiza duas requisições:
- uma requisição
GET
para/reminder/{ID}
, em que o id da reserva é passado; - uma requisição
GET
para/export/{PATH}
, em que é passado um caminho para um arquivo JSON.
Com isso, enviei a requisição para a rota /export/{PATH}
ao repetidor e busquei por uma falha de Local File Inclusion, porém a rota sempre retorna um status 500, independentemente do caminho passado. Entretanto, ao interceptar a requisição em tempo real e alterar o caminho antes de ser redirecionado, o seguinte comportamento é apresentado:

Ou seja, é possível explorar uma LFI ao alterar o caminho após o /export/
para um arquivo.
Exploração
Mesmo encontrando a vulnerabilidade de LFI, o processo manual de exploração pode tomar muito tempo, então desenvolvi o seguinte script para facilitar:
Dessa forma, é possível simular uma shell para download de arquivos (você pode alterar o local onde os arquivos são salvos para se adaptar ao seu ambiente). Com o processo automatizado, agora basta procurar por dados sensíveis na máquina. De início, procurei por arquivos padrões do Linux, até que encontrei o seguinte conteúdo no arquivo crontab, que é um arquivo responsável pela definição de tarefas agendadas no Linux:

Perceba na imagem acima que o caminho para 3 arquivos são expostos. No arquivo /data/scripts/app_backup.sh
é realizada uma cópia comprimida como Zip e salva em /var/www/backupapp.zip
:
No arquivo /data/scripts/table_cleanup.sh
, é realizada a limpeza do banco de dados por meio de um script SQL:
No arquivo /data/scripts/dbmonitor.sh
, é realizada uma validação do banco de dados para identificar possíveis instabilidades:
Por fim, decidi baixar o backup da aplicação (presente em /var/www/backupapp.zip
) para analisar o código-fonte. Dentre os arquivos, foi possível encontrar uma vulnerabilidade de SQL injection:

Observe na imagem acima que o parâmetro order_query
é passado sem qualquer sanitização por meio de uma f-string do Python, fazendo com que seja possível injetar instruções SQL na query. Entretanto, essa rota é restrita ao usuário administrator
, o que é validado pelo conteúdo presente no campo role
no payload do token JWT. Analisando o código que verifica o token JWT, é possível identificar onde a chave está sendo gerada:

O seguinte conteúdo está presente no arquivo signature
:
No código acima, q
está sendo gerado num intervalo muito pequeno, o que possibilita um ataque de fatoração e permite gerar um par de chaves público/privada para modificar o token JWT e assinar novamente de forma que a aplicação valide ele. Entretanto, é necessário o valor de n
para o ataque, que pode ser obtido da seguinte forma:
- Crie um usuário na aplicação;
- Obtenha o token JWT por meio do cookie
X-AUTH-Token
; - Utilize uma ferramenta como o jwt_tool ou jwt.io para obter o valor de n:

Com base no código que gera a chave e com o auxílio do Llama, foi possível desenvolver o seguinte script que obtém as chaves pública e privada, permitindo forjar um token válido passando administrator
como role
:
Com o par de chaves, basta utilizar uma das ferramentas citadas anteriormente para gerar um token válido. Como exemplo do jwt.io, é possível passar o par de chaves logo abaixo do payload:

Agora, é possível alterar o cookie X-AUTH-Token
no navegador para o token forjado e acessar o painel do administrador. Com isso, é possível explorar a vulnerabilidade de SQL injection citada anteriormente e obter uma shell reversa como usuário mysql
. Para isso, criei um payload de shell reversa em BASH localmente, coloquei um servidor Python em execução usando o comando python3 -m http.server
, e executei uma query para alterar o conteúdo de dbstatus.json
- indicando uma falha no banco de dados - e escrevendo um script em BASH num arquivo de fixer que baixa o payload de shell reversa e a executa:

Assim que o cronjob que verifica o banco de dados executa, uma conexão se abre com o listener local:

Pós exploração
Escalação de Privilégio Lateral
Usuário www-data
Como usuário mysql
, é possível apagar o arquivo app_backup.sh
e escrever outro arquivo com o mesmo nome. Como no arquivo crontab está definido para esse script ser executado como o usuário www-data
, é possível injetar um payload de shell reversa no arquivo e escalar privilégio para o usuário www-data
quando o arquivo for executado:

Usuário qa
Assim que consegui acesso como usuário www-data, identifiquei que o usuário tem acesso ao diretório em que está hospedado o código-fonte da aplicação. Nesse diretório, é possível visualizar um subdiretório .hg
, o que indica que o Mercurial está sendo utilizado para controle de versionamento. Assim como o git, o Mercurial também permite visualizar o histórico de commits por meio do comando hg tip -p
, e ao executar esse comando eu obtive acesso às credenciais do usuário qa
:

Usuário dev
Com acesso SSH à máquina por meio do usuário qa
, é possível observar no diretório home do usuário um arquivo de configuração do Mercurial com o nome de .hgrc
. Por meio desse arquivo, é possível configurar um hook, isto é, uma ou mais instruções que executam a partir de um gatilho. Além disso, ao executar o comando sudo -l
, a seguinte entrada é retornada:
Indicando que o usuário qa
pode executar o comando listado como usuário dev
. Com essas informações, é possível elaborar um ataque para escalar privilégios para o usuário dev
. Primeiro, é necessário copiar o arquivo .hgrc
para um subdiretório .hg
a qual o usuário qa
tenha permissão de escrita; depois, criar um script BASH com um payload de shell reversa, e então fazer com que esse arquivo seja executado com um hook de post-pull pelo Mercurial:
Agora, basta acionar o hook realizando um pull no repositório, e a shell reversa será estabelecida:

Para não ficar como uma shell limitada, adicionei a chave pública da minha máquina ao arquivo ~/.ssh/authorized_keys
da máquina remota, e então autentiquei como usuário dev
via SSH mesmo sem ter a senha do usuário.
Escalação de Privilégio Vertical
Considero ter sido a parte mais fácil dessa máquina; logo após fazer login como usuário dev
, é possível executar o comando sudo -l
e encontrar a seguinte entrada:
O problema na entrada acima é a utilização do wildcard *
, que permite injetar argumentos para o comando rsync
. Consultando a documentação do comando rsync
, é possível encontrar flags como --chown
e --chmod
, que permitem manipular as permissões dos arquivos copiados. De início, copiei o binário cat
para o direotório /home/dev/app-production
e criei arquivos que tinham como nome as flags --chown
e --chmod
, alterando a permissão dos arquivos copiados. Passando o SUID como parâmetro do chmod
, foi possível criar um binário cat que persistia as permissões do usuário root
, permitindo ler arquivos sensíveis (como a chave privada desse usuário):

Por mais que eu tenha feito dessa forma, algum tempo depois um usuário do fórum entrou em contato comigo e compartilhou uma outra solução, que seria passando os parâmetros diretamente no comando. Como o wildcard se encontra antes do diretório de destino, é possível especificar os parâmetros diretamente no comando:
