Artigo: CTFZone Quals 2019: Chicken

Apesar do adiamento da conferência OFFZONE 2020 , haverá uma final da CTFZone ! Este ano, será realizado pela primeira vez online e será transmitido ativamente nas redes sociais.

Anunciaremos os detalhes mais tarde, mas, por enquanto, sugerimos explorar a inicialização da webtask a partir da fase de qualificação. A análise da solução foi enviada por Devand MacLean do Canadá. Especialmente para Habr, traduzimos o texto da startup local e convidamos você a descobrir qual cadeia de vulnerabilidades os participantes encontraram e o que a galinha tem a ver com isso.



informação geral


Autor da tarefa: Pavel Sorokin
Pontos: 470
Número de equipes que resolveram a tarefa: 2

Links Úteis:




, - :


  • (/Home/Index);
  • (/Home/Hens);
  • (/Home/Contact);
  • (/Auth/Login).

,   , :


  • ;
  •  API ,   .


A página / Home / Hens contém links para fazer o download de “passaportes” de frango.


Após decodificar o Base64, encontramos o parâmetro filename: 1.txt. Usando o CyberChef, codificamos / etc / passwd na Base64 e seguimos o link:

http://web-chicken.ctfz.one/File/Download?filename=L2V0Yy9wYXNzd2Q=

O conteúdo do arquivo / etc / passwd no servidor é aberto no navegador , o que significa temos o direito de ler arquivos arbitrários no sistema.

Ao tentar encontrar outros arquivos no sistema, você pode perceber um erro que aparece toda vez que você solicita um arquivo inexistente (ou um arquivo que não pode ser lido com os direitos de usuário do aplicativo):


Tendo observado que o erro se refere à variável de ambiente ASPNETCORE_ENVIRONMENT , começamos a estudar os layouts de aplicativos da web do ASP.NET Core. E vemos o seguinte:


Para converter os caminhos e nomes de arquivos necessários e extraí-los para Base64, escrevemos um pequeno script Python ( fetch.py ):


Usando esse conhecimento sobre a estrutura do aplicativo Web MVC criado no ASP.NET Core, usando fetch.py, obtemos o código-fonte para os seguintes arquivos:


  • ../Views/Shared/_Layout.cshtml
  • ../Views/Home/Index.cshtml
  • ../Views/Home/Contact.cshtml
  • ../Views/Home/Hens.cshtml
  • ../Views/Auth/Login.cshtml

Tendo feito isso e estudado o código fonte de cada página, encontramos um detalhe interessante no Hens.cshtml


A linha 1 contém a instrução de inclusão @ usando StackHenneryMVCAppProject, que no ASP.NET significa um link para um arquivo DLL.

Abrimos ../StackHenneryMVCAppProject.dll - mas não através do utilitário Python no Kali Linux, mas no navegador do Windows, porque vamos descompilar esse arquivo no Windows. Através do uso de tais URL:

http://web-chicken.ctfz.one/File/Download?filename=Li4vU3RhY2tIZW5uZXJ5TVZDQXBwUHJvamVjdC5kbGw=

Abrindo DLL-arquivo em dnSpy (.NET decompiler), ver imediatamente que no método Initialize () da classe de configuração. A configuração , que é executada quando o aplicativo Web é iniciado, lê o conteúdo do arquivo chicken_domains_internal.txt . Usando um script Python, extraímos o conteúdo deste arquivo:

web-chicken-flag
web-chicken-auth

O método Initialize () se conecta ao  web-chicken-flag pela porta 4321 e recebe vários parâmetros: secret_token , RSA_keyflag .

Infelizmente, não é possível iniciar uma conexão com web-chicken-flag. Mas, quando configuramos o registro de hosts DNS locais para converter web-chicken-auth no endereço IP externo do servidor ( 34.89.232.240 ), conseguimos abrir http: // web-chicken-auth / com a interface Swagger UI usada para descrever e executar comandos por meio da API REST.


Após investigar o arquivo DLL descompilado, você pode observar que o controlador AuthController não tinha apenas o método Login () , mas também o método Change_Password_Test () :


Quando vamos para  / Auth / Change_Password_Test , vemos este formulário:


Ao estudar o método Change_Password_Test () , entendemos que ele processa quatro parâmetros do tipo String por meio de uma solicitação HTTP POST:


  • nome do usuário;
  • Nova senha;
  • Senha Antiga;
  • base_url.


Um pouco mais baixo no método Change_Password_Test () que vemos: sem receber um valor para base_url , o método pega o valor conf.auth_server , que é web-chicken-auth , e adiciona / auth / login ao final do valor base_url , atribuindo a sequência resultante à variável requestUri :


Na próxima parte importante do código, os valores da string dos parâmetros usernameold_password da solicitação HTTP POST e, com eles, o  secret_token da configuração, são inseridos na string JSON. Em seguida, um objeto JSON StringContent é criado a partir desses dados , que são enviados como dados HTTP POST para a variável requestURI criada na etapa anterior.


Agora, o servidor aguarda a solicitação HTTP POST para  requestUri para retornar o objeto JSON com o parâmetro code igual a 0. Se isso não acontecer, chegamos ao ramo de código que começa na linha 6 e retorna a visualização / Views / Auth / Login com o erro Login inválido / senha .

Se a solicitação HTTP POST ainda retornar um objeto JSON com o parâmetro code igual a 0, iremos para a ramificação de código da linha 11. Em seguida, a variável requestUri2 obtém o valor http: // web-chicken-auth , outro objeto JSON StringContent é criadocom os parâmetros da solicitação HTTP POST original, como na parte anterior, e esses dados são enviados para o endereço requestUri2  na solicitação HTTP PUT. Por fim, a mensagem de senha alterada é retornada ao cliente .


Em poucas palavras: todo o processo começa com uma solicitação HTTP POST para  / Auth / Change_Password_Test , que espera um certo número de parâmetros. Ele pega esses valores e cria um objeto JSON para enviá-lo para  <base_url> / auth / login via HTTP POST. Se em resposta receber JSON com o parâmetro code igual a 0, ele cria outro objeto JSON e envia uma solicitação HTTP PUT para  http: // web-chicken-auth / auth / change_password .

Ao aprender a API REST na interface do usuário do Swagger, vemos que no arquivo DLL descompilado não havia apenas as rotas / auth / login e  / auth / change_password , mas também a rota para / auth / password_recovery .


Essa rota da API esperava um objeto JSON com dois parâmetros: emailsecret_token . Se ele o recebeu, ele retornou um objeto JSON com uma propriedade de código 0 e seqüências de mensagenstoken .


Acontece que, se de alguma forma forçarmos o método Check_Password_Test () a solicitar imediatamente a rota / auth / password_recovery em vez de / auth / login , para inserir o ramo de alteração de senha, será suficiente inserir um endereço de email válido.

Estudamos novamente a parte do código na qual o método Check_Password_Test () atribui o valor requestUri na solicitação HTTP POST original e entendemos que precisamos enviar o valor http: // web-chicken-auth / auth / password_recovery # como o parâmetro base_url e requestUri na final o resultado será http: // web-chicken-auth / auth / password_recovery # / auth / login .

O caractere # na URL HTTP indica que parte do endereço de solicitação foi finalizada. Portanto, o servidor que recebe a solicitação simplesmente ignora a parte / auth / login .


Isso, é claro, é bom, mas precisamos descobrir como o terminal REST, onde agora redirecionamos a solicitação, receberá o valor do email . Sem esse valor, a solicitação falhará e não iremos mais longe.

Examinamos cuidadosamente como o método Check_Password_Test () cria dados JSON e vemos que os dados de entrada não são limpos, o que significa que você pode implementar facilmente seus parâmetros. É suficiente enviar os seguintes parâmetros na solicitação HTTP POST:

nome do usuário = admin
old_password = pwned "," email ":" admin@chicken.ctf.zone "," lol ":" new_password
= p0tat0
base_url = http: // web-chicken-auth / auth / password_recovery #

O objeto JSON resultante é enviado para  / auth / password_recovery :


Com esses dados JSON, atendemos aos requisitos de que / auth / password_recovery deve retornar uma resposta, após o qual o servidor inserirá a ramificação de alteração de senha (o objeto JSON contém a propriedade email ). Agora não precisamos mais do valor de old_password . Nesta ramificação de código, fornecemos todos os valores necessários para alterar a senha (a propriedade username é admin e a propriedade password é p0tat0 ). A solicitação foi concluída e a senha foi alterada em resposta.


Resta apenas inserir um novo nome de usuário e senha na página de login!


E aqui está a nossa bandeira:


All Articles