Great Lakes Security Conference CTF — Hackeando Apps NodeJS — Parte 4

Neptunian
3 min readApr 19, 2021

--

Kevin

Esta é a parte 4 da Série Great Lakes Security Conference CTF — Hackeando Apps NodeJS.

Seguindo a linha dos outros dois desafios acima, o Kevin também começa com o código-fonte da aplicação disponível:

Resumo do Código

  1. Atende em /flag, via parâmetro name.
  2. Valida se o tipo do name é string (bloqueia ataques com tipo de dados diferentes, como arrays).
  3. Valida se o name, convertido pra maiúsculo, é diferente de ‘KEVIN’.
  4. Valida se o name maiúsculo gerado acima, convertido pra minúsculo, é igual a ‘kevin’.

Caso essa função de validação acima (isThisReallyKevin) retorne verdadeiro, envia a flag.

Novamente uma condição que parece impossível precisa ser verdadeira pra retornar a flag: o nome enviado, maiúsculo, não pode ser KEVIN, mas convertido de volta pra minúsculo, precisa ser igual a kevin. (WTF!)

Vulnerabilidade

Esse desafio tem uma pista não técnica: caso o nome não seja validado, ele retorna a mensagem “Kevin spells his name in an unusual way to honor his ancestor William Thomson”.

O William Thomson é o primeiro barão keLvin (nome que originou a unidade de medida de temperatura). Vamos guardar esse nome Kelvin.

Como o tipo de Input é string e as operações são de upper e lower, isso indica fortemente que o tipo de ataque possível envolve conversão de caracteres especiais Unicode.

Isso é possível porque algumas bibliotecas (em várias linguagens), têm uma fragilidade que é característica da arquitetura do Unicode para caracteres que só existe em uma determinada localidade.

Quando elas fazem a conversão de alguns caracteres para maiúsculo ou minúsculo, transformam um caractere em outro, perdendo informação! Com isso, a conversão de volta não transforma o caractere no que era originalmente.

Um exemplo disso é o caractere ı (é um “i” turco, sem o ponto), que é o caractere \u0131. Quando convertido pra maiúsculo, ele vira um “I” normal. Se você converter de volta pra minúsculo, ele vira o nosso “i” normal. Demorei um tempinho aqui achando que o ataque seria em cima do i turco. O Github teve uma falha de segurança desse tipo, onde era possível recuperar a senha de contas de outros e-mails. Exemplo abaixo, validando o conceito com o node (que é o que vai rodar no ServerSide):

$ nodeWelcome to Node.js v14.15.0.Type ".help" for more information.> 'John@Gıthub.com'.toUpperCase()'JOHN@GITHUB.COM'> 'John@Gıthub.com'.toUpperCase() === 'John@Github.com'.toUpperCase()true

Após algumas análises, encontrei uma tabela interessante de caracteres que poderiam ser testados: https://websec.github.io/unicode-security-guide/character-transformations/

Tem mais itens nessa lista, mas o último chama a atenção: KELVIN SIGN! (Pista do William mais acima).

Isso quer dizer que o ‘K’ maiúsculo é o caractere Unicode \u004B, enquanto o Kelvin Sign, que é visualmente idêntico, é o caractere \u212A (diferente). O que ocorre é que o Kelvin Sign é maiúsculo, então é diferente de ‘K’, mas quando convertido para minúsculo, ele vira a nossa letra k minúscula.

Fazendo o mesmo teste com o Kelvin:

> Kelvin = '\u212A''K'> K_Normal = 'K''K'> Kelvin === K_Normalfalse> Kelvin.toUpperCase() === K_Normal.toUpperCase()false> Kelvin.toUpperCase().toLowerCase() === K_Normal.toUpperCase().toLowerCase()true

Resultado: Enviar Kevin no name, com Kelvin Sign no lugar do K causa o seguinte cenário:

  • A comparação do item 3 (do resumo) retorna Falso, porque o Kelvin Sign é diferente do K maiúsculo.
  • A comparação do item 4 retorna Verdadeiro, porque o Kelvin Sign, convertido pra minúsculo, fica igual ao k minúsculo.

Com isso, o Payload no parâmetro name fica da seguinte forma:

'\u212Aevin'

Convertendo com URLEncode, o exploit fica assim:

curl 'https://host/flag?name=%E2%84%AAevin'  --compressed

Mais uma Flag encontrada!!

GLSC{un1c0d3_ch4r4c73r5_4r3_1n73r3571n9}

Parte 5

O 5° e último desafio da série é o Mr. Roboto, que tem um perfil mais Scavenger Hunt.

Referências

--

--