Google CTF JS2.0
Neste tutorial, vou apresentar a você minha solução para o desafio JS SAFE 2.0 do GoogleCTF2018. Todos os anos, costumo enfrentar uma série de desafios fascinantes em uma variedade de tópicos gerais:
- CRYPTO
- MISC
- PWN
- RE
- WEB
Tento todos os anos resolver pelo menos 1-2 desafios da web, são desafios relativamente difíceis em comparação com outras competições CTF das quais participo.
O objetivo deste desafio é contornar todas as técnicas anti-depuração do arquivo js_safe_2 que recebemos no início do desafio.
No final da competição gravei um vídeo demonstrando a solução:
Este desafio começa quando você obtém o arquivo js_safe_2 assim:
Para encontrar a função que lida com a entrada de dados no campo de entrada, clique em inspecionar e vá para a guia Event Listeners:
Clique na função e ela nos moverá para-source:
Vamos procurar open_safe no arquivo e ver o seguinte código:
Neste código temos uma expressão regular que se ela não existir ou se a função x retornar False então o cofre nos imprime Acesso negado caso contrário obteremos Access granted.
A função x está configurada e pode ser vista minified, então podemos ver prettify usando o navegador:
Eu dividi o código 7 em partes para você, para tornar mais fácil entender o que este código faz:
- No início do código, 3 funções auxiliares são definidas para o software, elas mudaram as funções para sua estrutura em python para que fossem mais fáceis de usar..
- A função Ord converte um caractere em seu valor decimal.
- A função chr converte um valor decimal em um caractere, o inverso da ord.
- A função str converte a variável-String.
- Na segunda parte vemos uma função interessante que recebe algum texto e executa sobre ele 2 operações matemáticas que parecem relativamente estranhas.
Normalmente, quando você vê um pedaço de código como este, trata-se de um algoritmo existente que executa algo familiar, então eu pesquisei no google a palavra algorithm % 65521 E encontrei o algoritmo Adler-32:
A partir disso, pode-se deduzir que a função realiza um cálculo de assinatura para algum texto, de modo que se algo enviar a h um sinal de que o código está tentando assiná-lo, o resultado da assinatura será 2 bytes de b outros 2 bytes de a.
-
Esta função realiza XOR entre informações que aceita e os quatro caracteres na assinatura, encadeia-los e retornar. Código relativamente simples, não há nada a acrescentar aqui..
-
Loop de anti-depuração cujo trabalho é promover "a" em 1000 e no caminho, se as ferramentas do desenvolvedor estiverem abertas, ele nos impede de depurar chamando a função debugger.
Para contornar a parte do código, tudo o que precisamos fazer é alterar o tempo de execução "a" para 999 e, portanto, "a" função não irá interferir em nosso processo:
5. O comando a seguir altera x para o resultado da assinatura de:
`` str(x)`
Que é o código fonte da própria função:
Sobre isso assinamos com adler e recemos:
6. Implementação de outra técnica anti-depuração que converte a expressão regular em texto e, ao imprimir, passa para a função c que conecta o navegador.
- Usando with e rodadando o seguinte código:
`` with (source)
return eval('eval(c(source,x))')
`
A função with prepara a fonte para o escopo de modo que não tenhamos que fazer uma chamada para source.source. Para obter mais informações, consulte o vídeo de resolucao do desafio no início deste tutorial.
Além disso, a função também realiza:
eval(c(source,x))` Que realmente executa o conteúdo de:
c(source,x) Conhecemos os valores porque são os resultados da assinatura da função e da expressão regular definida, se os colocarmos no código a seguir: ![Obteremos х==c('¢×&Ê´cʯ¬$¶³´}ÍÈ´T©Ð8ͳÍ|Ô÷aÈÐÝ&¨þJ',h(х))//᧢](/img/tutorials/google_ctf_js2.0-11.png) Foi assim que obtivemos o código: `` х==c('¢×&Ê´cʯ¬$¶³´}ÍÈ´T©Ð8ͳÍ|Ô÷aÈÐÝ&¨þJ',h(х))//᧢
Este código executa novamente a operação h em х apenas desta vez é o x da nossa entrada e nele executa a operação xor este segmento de código também será convertido em código python com a seguinte lógica:
Primeiro criamos uma fila de tarefas com 8 realizadores.:
`` from queue import Queue
from threading import Thread
worker_thread = 8
my_queue = Queue()
`
Em seguida, definiremos nossa tarefa - procurar os caracteres apropriados a e b que, após inserir o código adler-32, nos darão uma assinatura lógica que contém o FLAG, a distancia para a e b está entre 0 e 65521 porque é o meio de adler- 32:
``
for a in range(5600, 65521): for b in range(0, 65521): data = [chr(b >> 8) , chr(b & 0xFF) ,chr(a >> 8) , chr(a & 0xFF)] my_queue.put(data)
`
Assim que tivermos definido a tarefa, iremos escrever o código dos realizadores, os realizadores farão o cálculo xor na assinatura que recebemos e verificar se ela se ajusta à expressão regular do nosso programa que vimos no início, se realmente houver uma correspondência, o código imprimirá o resultado.
``
def worker_func(q): while True: data = q.get() print_at_exit = True looking_for = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_@!?-" a = '¢×&Ê´cʯ¬$¶³´}ÍÈ´T©Ð8ͳÍ|Ô÷aÈÐÝ&¨þJ' b = data output = [] for i in range(len(a)): xor = chr(ord(str(a[i])) ^ ord(str(b[i % 4]))) if not xor in looking_for: print_at_exit = False break output.append(xor) if print_at_exit: print ("".join(output)) q.task_done()
`
O código leva cerca de uma hora para encontrar o FLAG, é claro que você pode atualizar o código e usar-
multiprocessing` Para que possamos executar o código em vários processos e, assim, obter o resultado em menos tempo, recomendo usar:
multiprocessing.Pool E: `` pool.apply_async
Para resolver o exercício muito mais rápido.
O código do desafio: