Hacking N' Roll - CTF do INSERT/UECE - Reverse Eng. Writeup
Este é o writeup dos 5 níveis dos desafios de engenharia reversa do II Hacking N’ Roll, CTF organizado pelo grupo INSERT da UECE.
REV100
Olhando as strings na seção .rodata do binário, que vai de 0x538 até 0xcc8 como mostra o objdump:
$ objdump -j .rodata -x rev100 (...) Sections: Idx Name Size VMA LMA File off Algn 14 .rodata 00000590 08048738 08048738 00000738 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA (...)
Encontramos uma string interessante(leia: resposta) no editor hexadecimal, como mostra o screenshot a seguir:
REV200
Verificamos que o código em Assembly mostrado não fazia muito sentido, pois acessava a memória de maneira estranha e não parecia corresponder a nenhum algoritmo conhecido.
08048054 <_start>: 8048054: eb 00 jmp 8048056 <get_call> 08048056 <get_call>: 8048056: 09 79 20 or %edi,0x20(%ecx) 8048059: 30 20 xor %ah,(%eax) 804805b: 75 20 jne 804807d <get_call+0x27> 804805d: 7c 32 jl 8048091 <get_call+0x3b> 804805f: 20 20 and %ah,(%eax) 8048061: 20 6b 20 and %ch,0x20(%ebx) 8048064: 33 20 xor (%eax),%esp 8048066: 79 20 jns 8048088 <get_call+0x32> 8048068: 20 20 and %ah,(%eax) 804806a: 69 35 20 3a 09 49 27 imul $0x525f6d27,0x49093a20,%esi 8048071: 6d 5f 52 8048074: 33 40 6c xor 0x6c(%eax),%eax 8048077: 6c insb (%dx),%es:(%edi) 8048078: 59 pop %ecx 8048079: 5f pop %edi 804807a: 34 6e xor $0x6e,%al 804807c: 5f pop %edi 804807d: 61 popa 804807e: 73 63 jae 80480e3 <get_call+0x8d> 8048080: 49 dec %ecx 8048081: 49 dec %ecx 8048082: 0a .byte 0xa
Percebe-se a grande quantidade de 0x20(espaço). Utilizando o seguinte código de uma linha em Python:
''.join([a[1].strip() for a in [s.split('\t') for s in open('rev200').xreadlines()] if len(a)==3]).replace(' ','').decode('hex')
Verificamos como era o binário original antes de ser disassemblado, representado pela seguinte string:
“\xeb\x00\ty 0 u | 2 k 3 y i5 :\tI’3@llY_4n_ascII\n” |
Onde aparece a palavra-chave para o problema ( I’3@llY_4n_ascII ).
REV300
Dentro da função inside2, encontramos uma chamada às funções reveal e scramble, o que indica que a função constrói a chave e depois embaralha com a função scramble.
Então entramos na função scramble e colocamos uma instrução ‘ret’ logo no início da mesma, para que ela não seja executada quando for chamada
Salvamos o programa com a modificação acima e executamos, passando as telas, até que ele mostra a chave.
REV400
Verificando os símbolos existentes no binário, encontramos uma função com nome sugestivo – reveal.
Essa função reveal é chamada em apenas um local. Seguindo o xref, achamos a função flag. A função flag, por sua vez, não é utilizada em nenhum local do programa.
Abrimos o gdb, colocamos um breakpoint em main, executamos o programa, e chamamos a função flag usando o comando call do gdb, e verificamos que ela mostra a string desejada.
REV500
Percebemos que várias funções do programa gravavam dados numa região de memória associada ao símbolo ‘hidden’.
Consta no binário que o comprimento do símbolo é de 98 bytes.
Verificamos um ponto na função ‘main’ que estaria depois da chamada de todas as funções.
Executamos o gdb e colocamos um breakpoint nesse ponto. Mandamos executar o programa. Ao chegar no breakpoint, dumpamos a região de memória do símbolo ‘hidden’. Visualizamos uma string cerca de 39 bytes à frente do início do símbolo, e demos um comando print para visualizar melhor. Nessa string aparece a chave.
Infelizmente, nós do grupo CACTUS do IFCE não levamos esta por diversas razões e aproveitamos para congratular os vencedores e organizadores.