Medinova
Difficulty: Medium | OS: Linux
Last updated
Difficulty: Medium | OS: Linux
Last updated
Em breve.
Quando colocamos o ip no navegador, ele redireciona para um nome chamado medinova.hc
então vamos colocar no /etc/hosts
Agora conseguimos acessar a página de forma correta
Navegando pela pagina web, chegamos na página "Consultation”
Essa página tinha um formulário de login e também nos dava a possibilidade de logar como usuário "guest”
Após realizar esse login com a conta guest
, fomos redirecionados a uma página de marcação de consulta.
E vermos que temos um "Welcome Guest
” demonstrando que estamos na conta do usuário Guest.
Quando logamos, normalmente temos um Cookie de sessão, analisando via burp, podemos comprovar pelo header inicial que se trata de um JWT.
O cookie JWT e formado exatamente como e exibido na sua forma decodada.
Um header
, payload
e uma assinatura
.
Há uma misconfiguration se tratando no Algoritmo(alg
) no header do Jwt. Podemos definir esse algoritmo como none
, quando esse tipo de algoritmo e aceito pelo servidor, ele possibilita a aceitacao desse token sem a necessidade de uma assinatura.
Como nao e necessario a assinatura com essa tecnica, podemos entao retirar a ultima parte do token jwt que corresponde a assinatura, deixando apenas o .
E agora podemos alterar o payload sem necessitar assinar o mesmo.
Vamos alterar o username para verificarmos se teremos sucesso na mensagem de boas vindas.
Normalmente o usuario administrativo vem como administrador ou admin, vamos tentar admin.
Agora jogue essa parte decodada para o Input, altere o algoritmo(alg
) para none
e coloque para encodar em base64
Observe que ele colocou o caractere =
, ele não e aceito na hora da formação do JWT, então pode retirá-lo.
Agora colamos o output no header do token.
E vai ficar assim o token final.
Poderíamos ter montado todo payload através do base64, já que e o encode do JWT. Mas dessa forma fica mais intuitiva e funcional.
Agora podemos copiar o token final e alterar no navegador.
Podemos nos utilizar de plugins para facilitar essa troca de cookie, mas também podemos usar os recursos nativos do navegador.
Exemplo no firefox, aperte o F12 → Storage → Cookies
Altere o valor do token para o que alteramos e aperte enter.
Após isso só atualizar a página.
Observe que o username foi alterado para o que colocamos no token JWT, ou seja, temos aqui uma vulnerabilidade de JWT None Attack.
Como não temos mais nenhuma função que o admin possa executar, podemos tentar verificar se esse template pode ter alguma vulnerabilidade. Essa mentalidade surge, no momento que trocamos de usuario guest para admin e apenas isso faz com que o Welcome mude o nome do usuário.
Então caso manipulemos o username
para forçar um XSS Reflected podemos confirmar que ele está colocando tudo que fica em username diretamente na página.
Alteramos o cookie novamente e atualizamos a página. Após a atualização, confirmamos que a página pega o username
e coloca diretamente na página.
Com isso temos uma vulnerabilidade de XSS Reflected
E apos clicar em OK, fica sem nada do lado de Welcome.
Nessa hora você talvez estivesse pensando em um possível Stealer Cookie, já que a flag HTTP Only esta como false,
para elevar para usuário administrativo, mas ja conseguimos mudar para usuário administrativo. E nao faz sentido, pois o usuario administrativo nao tem nenhuma funcao a mais que possamos aproveitar para um acesso ao servidor.
Bom, como trigamos o XSS e percebemos que tudo que colocamos no username
ele coloca no template, podemos tentar agora uma falha de Server Side Template Injection (SSTI)
Verificando as tecnologias que temos nesse alvo, podemos observar que ele está rodando em PHP.
Temos uma tecnica para tentar descobrir qual template que esta rodando, conforme a imagem abaixo, iremos seguir esse fluxograma para poder encontrar qual payload triga essa vulnerabilidade.
O primeiro payload ${7*7}
, não funcionou, então podemos seguir para o {{7*7}}
O segundo payload, já funcionou, ele interpretou a expressão matemática e nos trouxe o resultado de 49.
Então possivelmente seja um template do tipo Twig, que é um template muito usado em PHP.
Para podermos explorar essa falha, precisamos registrar uma função de callback para funções indefinidas no php.
_self
= objeto especial que representa o template atual.
env
= instancia de Twig_environment, que gerencia a lógica principal do twig como funções registradas, etc.
registerUndefinedFunctionCallback()
= não e uma função nativa do php, ela faz parte do ambiente Twig. Ela registra uma função de callback que será chamada sempre que o Twig encontrar uma funcao nao registrada (indefinida)
system
= funcao do php que permite execução de comandos no sistema
callback
= e uma chamada indireta em resposta a algum evento ou condição.
E precisamos agora chamar uma função que nao está registrada, ou seja indefinida, para que o motor do Twig chame a função de Callback que registramos anteriormente. Com isso, ele ira executar o comando do sistema que eu estou passando.
getFunction()
= é um handler para funções registradas no Twig.
id
= comando do linux, como não é uma função do twig, será chamado o callback para funções indefinidas que registramos anteriormente.
O payload final ficará assim:
Alterando agora o cookie no navegador e atualizando a página, conseguimos explorar o SSTI e conseguir uma execução remota de código (RCE).
Como o alvo não tem acesso à internet, vamos copiar o script para nossa máquina e vamos subir um servidor web em python para trigar com nosso alvo.
Altere o JWT com o payload para baixar e passar a saída para o comando bash
.
Não esqueça de colocar um listener com netcat na porta que criamos o nosso script de reverse shell.
E com isso conseguimos o shell no alvo.
Vamos deixar o shell mais interativo para que possamos trabalhar melhor.
Não podemos ler a flag ainda, pois somos o usuário www-data
, e precisamos fazer uma escalação de privilégio horizontal para o usuário Tom
, para poder ler essa flag.
Esse script não tínhamos permissão de editar, mas podíamos executar.
lendo esse arquivo descobrimos que ele seta o diretório do repositório git com --git-dir
na pasta home do usuário tom
que não temos permissão de acessar.
Porém, nesse mesmo script temos a flag --work-tree
que permite especificar um diretório de trabalho alternativo. Diretório de trabalho é onde os arquivos do repositório são extraídos e manipulados, e está apontando para /var/www/html
e como somos o usuário www-data
então temos permissão para alterar essa pasta.
E mais abaixo temos a chamada do /bin/bash -c
, então temos um possível command injection aqui. Porém, como está entre aspas duplas, tudo que ficar entre eles é definido como string, então precisamos conseguir bypassar isso.
Mas precisamos saber se esse script é chamado por alguém, então podemos analisar os processos do alvo, para ver se algum usuário está chamando esse script através de uma tarefa agendada.
baixamos no alvo.
Da permissão de execução
Após executarmos o pspy, conseguimos verificar que o usuário com UID=1001
executava o script que encontramos em /opt
.
Se analisarmos o arquivo /etc/passwd
do alvo, conseguimos descobrir que o uid 1001
é do usuário Tom
Então agora que já sabemos que é o usuário TOM que executa esse script, podemos tentar nos aproveitar da execução desse script que tem um possível command injection, para podermos escalar privilegio para o usuário TOM.
Vamos testar esse command injection então, o última comando do script, vamos copiar e alterar a variável $verify
por um comando linux.
Lembrando que podemos executar comandos no linux colocando entre $()
ou ``
E como o tee
gera um novo arquivo com a saída do comando anterior, criamos o arquivo chamado teste.txt com o conteúdo do comando id
.
Então realmente conseguimos confirmar que da para executarmos comando aqui.
Bom, precisamos inicializar o git
no diretório /var/www/html
que esta como work-tree
no script.
Então ele sempre pega o novo arquivo e coloca na última linha substituindo a variável $verify
Se salvarmos um arquivo com um nome de comando, ele deve executar o comando que pedimos.
Observe que quando o usuário TOM executa o script, ele pega os arquivos novos e exibe, como colocamos um nome de arquivo como um comando do linux, ele executou o comando curl
com sucesso.
Agora podemos criar um reverse shell para conseguir escalar para o usuário Tom.
Mas tem um problema nessa nossa Poc, não dá para colocar o caractere da barra /
no nome do arquivo.
Uma boa estratégia é encodarmos em base64 do comando completo e fazer o decode.
E conseguimos agora confirmar nessa nova poc que dá para salvar em base64 o comando com barra e na hora do decode ele consegue executar.
Podemos tentar pegar um reverse shell agora.
E agora só basta encodar e criar o arquivo
Finalmente conseguimos acesso ao usuário Tom, e podemos agora ler a primeira flag.
Agora precisamos escalar para usuário root.
Verificando direto no sudo -l
encontramos o binário read_pickle_files
que roda com qualquer usuário, inclusive root sem precisar de senha.
Bom, o nome do binário já traz uma dica. Ele lê arquivos pickle
Com uma pesquisa na documentação do Python, podemos ver que o pickle
é um módulo para serializar e deserializar um objeto python.
Vamos criar então um script para serializar com o pickle um objeto python
Observe que funcionou, com certeza esse script executa a função loads()
da biblioteca pickle
pois o objeto está sendo desserializado e executado.
Podemos então utilizar novamente um payload de reverse shell como fizemos anteriormente para conseguir escalar para root.
E conseguimos a última flag do alvo.
Vamos verificar o conteúdo desse JWT com a ferramenta
Antes disso, vale lembrar que esses campos do JWT se tratam de um encode base64, vamos jogar a assinatura no para podermos alterar e depois iremos retornar para o Jwt.io
Só mudei o header pelo base64 no CyberChef, pois se fizesse essa alteração o iria deixar tudo branco, e um comportamento desse site, poderíamos usar outro que não tem esse compotamento, ou ate plugins para o burp suite para facilitar essa troca.
Agora podemos tentar conseguir um reverse shell. Iremos usar o site para criar diversos payloads de reverse shell, pois caso o alvo não tenha um, ele passa para outro.
Enumerando o sistema encontramos na pasta /opt
um