Fwhibbit CTF 2017 - Bomb

Published on:
Tags: reversing

Enunciado

Points: 500

Country: Kazakhstan

Attatchment: https://mega.nz/#!1tsFgIAR!JhnKO62d5jAcGvXM4pYsxbF5mMEyNz07UggP_e8lAEM

Description: An evil rabbit has installed a nuclear bomb in the building and only a competitor like you, can defuse it and avoid its self-destruction. Be patient but please..DEFUSE THE BOMB!

Solución

En este caso nos daba un binario que te pedía un pin para desactivar una bomba (Jack Bauer powa):

file bomb-500 
bomb-500: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=a3990f9a0782759b97fc39aa38540656adc497c2, stripped

./bomb-500 

        .--``..---.                
         .````--:ohdmNms/`         
          -:/+++/-.:smNd+          
       ```..--:ohmNNdhh.           
     `-. `.``.-+sosshd.         :. 
   -os--/sosdmmNNMMNy         .+// 
  :h+.+hNNMMMNNNMMNm/      `/yNN.` 
 .do/oNNMMMMMmohs+:`    .+hNMMMM-` 
 `yohNhNNNMh-           dosNMMMmo- 
  -mN+hMMMy             .smNMNdd/+`
   yN.hMMh               +NMMNmhds:
   +N//m+                 .osshyho 
  ..smhh                           
   ::oNmy-                         
      .//yhs/:`                    
          :ymNN/                   
         .-+shdho.                 
             `.--..` '''   
   _______ ___ 
  | 7 | 8 | 9 |
  |___|___|___|
  | 4 | 5 | 6 |
  |___|___|___|
  | 1 | 2 | 3 |
  |___|___|___|
  | 0 | enter |
  |___|_______|
  Deactivation Code 
  > 1111 
BOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOM!
       _.-^^---....,,--       
   _--                  --_   
  <                        >) 
  |                         | 
   ._                   _./  
      ```--. . , ; .--'''     
            | |   |           
         .-=||  | |=-.        
         `-=#$%&%$#=-'        
            | ;  :|           
   _____.,-#%&$@%#&#~,._____  

Con un strings no te mostraba nada interesante, había que ponerse a bucear en el desensamblado para ver si encontrabamos algo. Lo primero es averiguar el punto de entrada:

>>> set stop-on-solib-events 1
>>> info target
Symbols from "/root/Documents/FwhibbitCTF/reversing/bomb-500".
Local exec file:
    `/home/pericodelospalotes/FwhibbitCTF/reversing/bomb-500', file type elf64-x86-64.
    Entry point: 0x5555555555d0

A partir de ese punto de entrada llegamos a la función main:

br *0x000055555555591e

Esta es la primera parte del código donde metemos el pin:

191e:  push   rbp
191f:   mov    rbp,rsp
1922:   push   r12
1924:   push   rbx
1925:   sub    rsp,0xd0
192c:   mov    DWORD PTR [rbp-0xd4],edi
1932:   mov    QWORD PTR [rbp-0xe0],rsi
1939:   call   1700 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x150>  <== Función que pinta el dibujito ASCII
193e:   lea    rsi,[rip+0x102b]        # 2970 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x13c0>
1945:   lea    rdi,[rip+0x202914]        # 204260 <_ZSt4cout@@GLIBCXX_3.4>
194c:   call   1470 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
1951:   mov    rdx,rax
1954:   mov    rax,QWORD PTR [rip+0x20269d]        # 203ff8 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x202a48>
195b:   mov    rsi,rax
195e:   mov    rdi,rdx
1961:   call   1510 <_ZNSolsEPFRSoS_E@plt>
1966:   lea    rsi,[rip+0x1018]        # 2985 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x13d5>
196d:   mov    rdi,rax
1970:   call   1470 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
1975:   lea    rax,[rbp-0x90]
197c:   mov    rsi,rax
197f:   lea    rdi,[rip+0x2027ba]        # 204140 <_ZSt3cin@@GLIBCXX_3.4>
1986:   call   14d0 <_ZStrsIcSt11char_traitsIcEERSt13basic_istreamIT_T0_ES6_PS3_@plt>   <== Función que lee el nº pin y lo almacena
198b:   lea    rax,[rbp-0x90]
1992:   mov    rdi,rax
1995:   call   1480 <strlen@plt>  <== Función que comprueba el tamaño del pin
199a:   cmp    rax,0x8            <== El PIN tiene que tener 8 números
199e:   je     19a5 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x3f5>

Básicamente lo que hace todo esto es reservar memoria, guardar el pin introducido en memoria y comprobar que tenga 8 dígitos. En este caso he puesto de pin 11111111 que lo almacena en esta posición de memoria:

0x7fffffffe0f0:    0x31313131  0x31313131

Una vez superado que el pin sea de 8 dígitos, hay un bucle en el que recorre cada dígito del pin para comprobar que sea un número y no cualquier otro carácter inválido:

19a5:  mov    DWORD PTR [rbp-0x14],0x0
19ac:   cmp    DWORD PTR [rbp-0x14],0x7     <== Inicio del bucle (0..7)
19b0:   jg     19df <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x42f>  <== Si es mayor que 7 se sale del bucle
19b2:   mov    eax,DWORD PTR [rbp-0x14]
19b5:   cdqe   
19b7:   movzx  eax,BYTE PTR [rbp+rax*1-0x90]    <== Coge el siguiente dígito del pin (eax=pin[i])
19bf:   cmp    al,0x39          <== Comprueba que el valor ASCII no sea mayor que 0x39 ('9')
19c1:   jg     19d4 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x424> <== Nos manda al dibujito de la bomba si no se cumple la condición anterior
19c3:   mov    eax,DWORD PTR [rbp-0x14]     
19c6:   cdqe   
19c8:   movzx  eax,BYTE PTR [rbp+rax*1-0x90]    <== Vuelve a coger el mismo pin[i]
19d0:   cmp    al,0x2f          <== Comprueba que el valor ASCII sea mayor que 0x2f ('/')
19d2:   jg     19d9 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x429>
19d4:   call   184b <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x29b>  <== Nos manda al dibujito de la bomba y sale del programa
19d9:   add    DWORD PTR [rbp-0x14],0x1 <== i=i+1
19dd:   jmp    19ac <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x3fc>

Una vez hechas las comprobaciones vamos a la pimera parte del meollo. Lo primero que hace es reservar memoria para copiar un patrón de caracteres. Este patrón de caracteres (le llamaremos Patron1) se usa para ofuscar (con operaciones lógicas) los valores del pin correcto.

19f4:  call   1560 <_ZNSaIcEC1Ev@plt>
19f9:   lea    rdx,[rbp-0x82]
1a00:   lea    rax,[rbp-0xb0]
1a07:   lea    rsi,[rip+0xf7c]        # 298a <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x13da>    <== Patron1 de caracteres que nos va a servir para ofuscar el pin (al menos 4 de los dígitos).
1a0e:   mov    rdi,rax
1a11:   call   1550 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3_@plt>    <== Hace una copia del patron1 en otra posición de memoria donde va a ir guardando el resultado de las operaciones.
1a16:   lea    rax,[rbp-0x82]
1a1d:   mov    rdi,rax
1a20:   call   14e0 <_ZNSaIcED1Ev@plt>

Tendríamos el patron1 original y una copia del mismo, que vamos a usar para operar con nuestro pin introducido, en la siguientes posiciones de memoria respectivamente (va a ocupar 0x12 bytes):

>>> x/32xw 0x000055555555698a
0x55555555698a: 0x83b5fcf7  0x8983a781  0x9ebffdbd  0xf49aa6fa
0x55555555699a: 0x0000a284  0xa8bb0000  0xcad784ea  0xa9ee8080
>>> x/32xw 0x55555576b440
0x55555576b440: 0x83b5fcf7  0x8983a781  0x9ebffdbd  0xf49aa6fa
0x55555576b450: 0x0000a284  0x00000000  0x0001fbb1  0x00000000

Veamos las operaciones que hace el algoritmo en este bucle entre el pin introducido por nosotros y el patron1:

1a25:  mov    QWORD PTR [rbp-0x20],0x0     <== i=0 (Asignación inicial, esta instrucción está fuera del bucle
1a2d:   lea    rax,[rbp-0xb0]           <== Inicio del bucle. Sitio ideal para poner un breakpoint.
1a34:   mov    rdi,rax              <== Mueve la posición de memoria de la copia del patron1 a $rdi
1a37:   call   1420 <_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6lengthEv@plt> <== Calcula tamaño de copia_patron1
1a3c:   cmp    rax,QWORD PTR [rbp-0x20]     <== Comprueba si i=18 (longitud de copia_patron1)
1a40:   seta   al
1a43:   test   al,al
1a45:   je     1a97 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x4e7>  <== Sale del bucle si i=18
1a47:   mov    rdx,QWORD PTR [rbp-0x20]     <== Vuelve a traer valor de i
1a4b:   lea    rax,[rbp-0xb0]           <== Valor de la posición de memoria que apunta a la copia del patron1
1a52:   mov    rsi,rdx              <== Arg1=i
1a55:   mov    rdi,rax              <== Arg2=&copia_patron1
1a58:   call   1590 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEixEm@plt>   <== Calcula la posición de memoria de la copia del patron1 + i. Devuelve &copia_patron1+i. Es la forma de recorrer el patron1 byte a byte
1a5d:   mov    rbx,rax              <== Guarda en $rbx &copia_patron1+i. $rbx=&copia_patron+i
1a60:   movzx  r12d,BYTE PTR [rbx]      <== Guarda en r12 el valor copia_patron[i] 
1a64:   mov    rax,QWORD PTR [rbp-0x30]     <== Trae la posición de memoria de nuestro pin introducido (&pin_introducido)
1a68:   mov    rdi,rax
1a6b:   call   1480 <strlen@plt>      <== Trae la longitud del pin (long=8)
1a70:   mov    rcx,rax              <== $rcx=8
1a73:   mov    rax,QWORD PTR [rbp-0x20]     <== $rax=i
1a77:   mov    edx,0x0              <== Deja vacio $edx para recoger el resto de la siguiente división
1a7c:   div    rcx              <== $rax=$rax/$rcx, el resto en $edx. j = i mod 8
1a7f:   mov    rax,QWORD PTR [rbp-0x30]     <== $rax = &pin_introducido
1a83:   add    rax,rdx              <== &pin_introducido=&pin_introducido+j
1a86:   movzx  eax,BYTE PTR [rax]       <== Trae el valor pin[j] a $eax
1a89:   not    eax              <== Not lógico del valor de pin[j]
1a8b:   xor    eax,r12d             <== Xor lógico entre Not(pin[j]) y patron[i]. NuevoValor= Not(pin[j]) XOR patron[i]
1a8e:   mov    BYTE PTR [rbx],al        <== Guarda nuevo valor en &copia_patron1+i. patron[i]=NuevoValor
1a90:   add    QWORD PTR [rbp-0x20],0x1     <== i=i+1
1a95:   jmp    1a2d <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x47d>

Ya se que están un poco liosos los comentarios en el código, pero básicamente lo que hace este bucle es ofuscar el pin introducido en el patron1 realizando las siguientes operaciones:

for (i=0; i < 18; i = i + 1) {
    j = i mod 8;
    copia_patron1[i] = NOT(pin[j]) XOR copia_patron1[i];
}

Así quedaría el patron1 después de realizar el bucle anterior con el pin 12345678:

0x55555576b440:    0x4b783539  0x44486d49  0x56723473  0x39516c32
0x55555576b450: 0x00006b4a  0x00000000  0x00000031  0x00000000

Lo que sigue a continuación en el código es una serie de comprobaciones para ver si ciertos valores del pin introducido son correctos. Concretamente comprueba cuatro dígitos del pin, las posiciones 0x1, 0x8, 0xb, 0xe del patron1_codificado. Estas posiciones corresponden con los dígitos que se encuentran en las posiciones 1,0,3 y 6 del pin respectivamente. Tener en cuenta que la posición de cada dígito del pin se calcula haciendo el mod 8 con las posiciones del patron_codificado:

1a97:  48 8d 85 50 ff ff ff    lea    rax,[rbp-0xb0]
1a9e:   48 89 c7                mov    rdi,rax
1aa1:   e8 8a fa ff ff          call   1530 <_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE5c_strEv@plt>
1aa6:   48 89 45 c8             mov    QWORD PTR [rbp-0x38],rax
1aaa:   48 8b 45 c8             mov    rax,QWORD PTR [rbp-0x38]
1aae:   48 83 c0 01             add    rax,0x1          <== Comprueba la posición 0x1 del patron1_codificado
1ab2:   0f b6 00                movzx  eax,BYTE PTR [rax]
1ab5:   3c 35                   cmp    al,0x35          <== La posicón 1 (0x1 mod 8) del pin está codificado con este valor 
1ab7:   75 2d                   jne    1ae6 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x536>
1ab9:   48 8b 45 c8             mov    rax,QWORD PTR [rbp-0x38]
1abd:   48 83 c0 08             add    rax,0x8          <== Comprueba la posición 0x8 del patron1_codificado
1ac1:   0f b6 00                movzx  eax,BYTE PTR [rax]
1ac4:   3c 73                   cmp    al,0x73          <== La posicón 0 (0x8 mod 8) del pin está codificado con este valor
1ac6:   75 1e                   jne    1ae6 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x536>
1ac8:   48 8b 45 c8             mov    rax,QWORD PTR [rbp-0x38]
1acc:   48 83 c0 0b             add    rax,0xb          <== Comprueba la posición 0xb del patron1_codificado
1ad0:   0f b6 00                movzx  eax,BYTE PTR [rax]
1ad3:   3c 56                   cmp    al,0x56          <== La posicón 3 (0xb mod 8) del pin está codificado con este valor
1ad5:   75 0f                   jne    1ae6 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x536>
1ad7:   48 8b 45 c8             mov    rax,QWORD PTR [rbp-0x38]
1adb:   48 83 c0 0e             add    rax,0xe          <== Comprueba la posición 0xe del patron1_codificado
1adf:   0f b6 00                movzx  eax,BYTE PTR [rax]
1ae2:   3c 51                   cmp    al,0x51          <== La posicón 6 (0xe mod 8) del pin está codificado con este valor
1ae4:   74 05                   je     1aeb <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x53b>
1ae6:   e8 60 fd ff ff          call   184b <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x29b>

De esta manera ya podemos saber esos cuatro valores del pin haciendo las operaciones inversas del bucle anterior, por ejemplo para la posición 1, el valor codificado tiene que ser 0x35. Por lo tanto:

patron_original[1]=0xfc; pin[1] = not(0xffffff35 XOR 0xfc) = 0x36 (6)
patron_original[8]=0xbd; pin[0] = not(0xffffff73 XOR 0xbc) = 0x31 (1)
patron_original[11]=0x9e; pin[3] = not(0xffffff56 XOR 0x9e) = 0x37 (7)
patron_original[14]=0x9a; pin[6] = not(0xffffff51 XOR 0x9a) = 0x34 (4)

Ya tenemos los siguientes valores del pin: 16X7XX4X

Aquí se podría haber hecho fuerza bruta con un diccionario de los cuatro dígitos que faltan y pasarlo al programa, pero yo decidí seguir adelante y ver como se calculaban el resto de dígitos del pin que faltaban.
Lo que vemos a continuación es algo muy parecido a lo que hemos visto en el primer bucle que codificaba nuestro pin con el patron1. La diferencia es que este bucle codifica el patron1_codificado de 0x12 bytes(18) con un patron2 de 0x21 bytes(33). Aquí se puede ver en el código como se accede al patron2 y se hace una copia.

1aeb:  lea    rax,[rbp-0x81]
1af2:   mov    rdi,rax
1af5:   call   1560 <_ZNSaIcEC1Ev@plt>
1afa:   lea    rdx,[rbp-0x81]
1b01:   lea    rax,[rbp-0xd0]
1b08:   lea    rsi,[rip+0xe91]        # 29a0 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x13f0>    <== Patron2 de caracteres que nos va a servir para codificar otra vez el patron1_codificado.
1b0f:   mov    rdi,rax
1b12:   call   1550 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3_@plt>    <== Hace una copia del patron2 en otra posición de memoria, done va ir guando el resultado de las operaciones.  
1b17:   lea    rax,[rbp-0x81]
1b1e:   mov    rdi,rax
1b21:   call   14e0 <_ZNSaIcED1Ev@plt>

Luego tendríamos un bucle muy similar al primero pero con diferentes valores de i y de j al ser patron2 y patron1_codificado de diferente tamaños, en este caso j=i mod 18.

1b26:  mov    QWORD PTR [rbp-0x28],0x0
1b2e:   lea    rax,[rbp-0xd0]
1b35:   mov    rdi,rax
1b38:   call   1420 <_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6lengthEv@plt>
1b3d:   cmp    rax,QWORD PTR [rbp-0x28]
1b41:   seta   al
1b44:   test   al,al
1b46:   je     1b98 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x5e8>
1b48:   mov    rdx,QWORD PTR [rbp-0x28]
1b4c:   lea    rax,[rbp-0xd0]
1b53:   mov    rsi,rdx
1b56:   mov    rdi,rax
1b59:   call   1590 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEixEm@plt>
1b5e:   mov    rbx,rax
1b61:   movzx  r12d,BYTE PTR [rbx]
1b65:   mov    rax,QWORD PTR [rbp-0x38]
1b69:   mov    rdi,rax
1b6c:   call   1480 <strlen@plt>
1b71:   mov    rcx,rax
1b74:   mov    rax,QWORD PTR [rbp-0x28]
1b78:   mov    edx,0x0
1b7d:   div    rcx
1b80:   mov    rax,QWORD PTR [rbp-0x38]
1b84:   add    rax,rdx
1b87:   movzx  eax,BYTE PTR [rax]
1b8a:   not    eax
1b8c:   xor    eax,r12d
1b8f:   mov    BYTE PTR [rbx],al
1b91:   add    QWORD PTR [rbp-0x28],0x1
1b96:   jmp    1b2e <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x57e>

No pongo anotaciones en el código porque es idéntico al anterior y además así practicais vosotros para ir viendo lo que hace ;-). Básicamente hace esto:

for (i=0; i < 33; i = i + 1) {
    j = i mod 18;
    copia_patron2[i] = NOT(patron1_codificado[j]) XOR copia_patron2[i];
}

Igual que en el primer patrón, al salir de este segundo bucle se van a realizar una serie de comprobaciones para saber si el pin introducido es correcto. De esta manera podemos calcular, si vamos haciendo las operaciones inversas, los cuatro valores restantes que nos quedan por saber del pin (posicones 2,4,5 y 7). En este código se muestra esas comprobaciones que con la práctica anterior podéis seguir sin ayuda:

1bb3:  48 8d 85 30 ff ff ff    lea    rax,[rbp-0xd0]
1bba:   be 1d 00 00 00          mov    esi,0x1d     <== Comprueba la posición 0x1d del patron2_codificado
1bbf:   48 89 c7                mov    rdi,rax
1bc2:   e8 c9 f9 ff ff          call   1590 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEixEm@plt>
1bc7:   0f b6 00                movzx  eax,BYTE PTR [rax]
1bca:   3c 69                   cmp    al,0x69      
1bcc:   75 51                   jne    1c1f <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x66f>
1bce:   48 8d 85 30 ff ff ff    lea    rax,[rbp-0xd0]
1bd5:   be 07 00 00 00          mov    esi,0x7      <== Comprueba la posición 0x7 del patron2_codificado
1bda:   48 89 c7                mov    rdi,rax
1bdd:   e8 ae f9 ff ff          call   1590 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEixEm@plt>
1be2:   0f b6 00                movzx  eax,BYTE PTR [rax]
1be5:   3c 31                   cmp    al,0x31
1be7:   75 36                   jne    1c1f <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x66f>
1be9:   48 8d 85 30 ff ff ff    lea    rax,[rbp-0xd0]
1bf0:   be 1e 00 00 00          mov    esi,0x1e     <== Comprueba la posición 0x1e del patron1_codificado
1bf5:   48 89 c7                mov    rdi,rax
1bf8:   e8 93 f9 ff ff          call   1590 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEixEm@plt>
1bfd:   0f b6 00                movzx  eax,BYTE PTR [rax]
1c00:   3c 68                   cmp    al,0x68
1c02:   75 1b                   jne    1c1f <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x66f>
1c04:   48 8d 85 30 ff ff ff    lea    rax,[rbp-0xd0]
1c0b:   be 1f 00 00 00          mov    esi,0x1f     <== Comprueba la posición 0x1f del patron1_codificado
1c10:   48 89 c7                mov    rdi,rax
1c13:   e8 78 f9 ff ff          call   1590 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEixEm@plt>
1c18:   0f b6 00                movzx  eax,BYTE PTR [rax]
1c1b:   3c 77                   cmp    al,0x77      
1c1d:   74 07                   je     1c26 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x676>
1c1f:   b8 01 00 00 00          mov    eax,0x1
1c24:   eb 05                   jmp    1c2b <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x67b>
1c26:   b8 00 00 00 00          mov    eax,0x0
1c2b:   84 c0                   test   al,al
1c2d:   74 05                   je     1c34 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm@plt+0x684>

Si revertimos las operaciones para esas posiciones, el PIN final sería: 16274248.

 Deactivation Code 
  > 16274248

fwhibbit{d34c71v473d_r4bb17_b0mb}

¡¡Buen trabajo Bauer!!

Fwhibbit CTF 2017 - How Many Rabbits

Published on:
Tags: reversing

Enunciado

How Many Rabbits

Points: 200

Country: Morroco

Attatchment: https://mega.nz/#!N4dDVSYY!mcH-FyRD9cwCuL8i3OFy_1zrA55djoLk9s2Qd7-hPuo

Description: We need the information in this binary password protected...can you help us?

Solución

Este binario es muy parecido al de 150 puntos, pero aquí añadía la dificultad de encontrar el 'entrypoint' del programa para poder insertar un breakpoint en ese punto para iniciar el reversing. Veamos como se hace con gdb:

gdb-peda$ set stop-on-solib-events 1
gdb-peda$ info target
Symbols from "/root/Documents/FwhibbitCTF/Reversing/rabbits-200".
Local exec file:
    `/home/pericodelospalotes/FwhibbitCTF/Reversing/rabbits-200', file type elf64-x86-64.
    Entry point: 0x555555554de0

Aquí vemos guardar en el stack frame algunos valores sospechosos

 b31:  mov    ecx,0x6f77                   <== Cadena 'ow'
 b36:   mov    eax,0x6867                   <== Cadena 'hg'
 b3b:   mov    edx,0x7774                   <== Cadena 'wt'
 b40:   mov    esi,0x7774                   <== Cadena 'wt'
 b45:   sub    rsp,0x220
 b4c:   mov    WORD PTR [rsp+0x30],cx
 b51:   mov    WORD PTR [rsp+0x10],ax
 b56:   lea    rbx,[rsp+0x120]
 b5e:   mov    WORD PTR [rsp+0x20],dx
 b63:   mov    WORD PTR [rsp+0xf0],si
 b6b:   mov    DWORD PTR [rsp+0x50],0x
 b73:   mov    DWORD PTR [rsp+0x60],0x357431    <== Cadena '5t1'
 b7b:   mov    BYTE PTR [rsp+0x12],0x0
 b80:   mov    DWORD PTR [rsp+0x70],0x77745f    <== Cadena 'wt_'
 b88:   mov    DWORD PTR [rsp+0x80],0x79746e    <== Cadena 'ytn'
 b93:   mov    BYTE PTR [rsp+0x22],0x0
 b98:   mov    DWORD PTR [rsp+0x90],0x725f30    <== Cadena 'r_0'
 ba3:   mov    DWORD PTR [rsp+0xa0],0x72615f    <== Cadena 'ra_'
 bae:   mov    BYTE PTR [rsp+0x32],0x0
 bb3:   mov    DWORD PTR [rsp+0xb0],0x746e65    <== Cadena 'tne'
 bbe:   mov    DWORD PTR [rsp+0xf2],0x746e65    <== Cadena 'tne'
 bc9:   call    sub_F10             <== Función que hace el dibujo en ASCII del conejo

Si seguimos la ejecución vemos como llama a una función en C++ que recoge nuestro valor por pantalla (¿cin?) y más abajo la llamada a strcmp para comparar las cadenas.
La cadena con la que la va a cotejar se construye dinámicamente con los valores almacenados previamente. Al final $rsi va a apuntar a la cadena completa reconstruída:

=> 0x555555554c0b:  call   0x555555554ad0 <_ZStrsIcSt11char_traitsIcEERSt13basic_istreamIT_T0_ES6_PS3_@plt>
   0x555555554c10:  mov    eax,DWORD PTR [rsp+0x50]
   0x555555554c14:  lea    rsi,[rsp+0xf0]
   0x555555554c1c:  mov    rdi,rbx
   0x555555554c1f:  mov    DWORD PTR [rsp+0xf5],eax
   0x555555554c26:  movzx  eax,WORD PTR [rsp+0x30]
   0x555555554c2b:  mov    WORD PTR [rsp+0xf8],ax
   0x555555554c33:  movzx  eax,BYTE PTR [rsp+0x32]
   0x555555554c38:  mov    BYTE PTR [rsp+0xfa],al
=> 0x555555554c3f:   call   0x555555554af0 <strcmp@plt>
   0x555555554c44:  test   eax,eax

Esto es los valores que van cogiendo los registros hasta completar la palabra:

RAX: 0x6f77 ('wo')
RAX: 0x745f79 ('y_t')
RSI: 0x7fffffffe050 --> 0x746e657774 ('twent')
....
RSI: 0x7fffffffe050 ("twenty_two")
RDI: 0x7fffffffe080 --> 0x41414141 ('AAAA')

Y aquí como se ve en memoria:

gdb-peda$ x/32xw $rsi
0x7fffffffe050: 0x6e657774  0x745f7974  0x00006f77  0x00000000

Ejecutamos y nos devuelve la flag:

./rabbits-200 

        .--``..---.                
         .````--:ohdmNms/`         
          -:/+++/-.:smNd+          
       ```..--:ohmNNdhh.           
     `-. `.``.-+sosshd.         :. 
   -os--/sosdmmNNMMNy         .+// 
  :h+.+hNNMMMNNNMMNm/      `/yNN.` 
 .do/oNNMMMMMmohs+:`    .+hNMMMM-` 
 `yohNhNNNMh-           dosNMMMmo- 
  -mN+hMMMy             .smNMNdd/+`
   yN.hMMh               +NMMNmhds:
   +N//m+                 .osshyho 
  ..smhh                           
   ::oNmy-                         
      .//yhs/:`                    
          :ymNN/                   
         .-+shdho.                 
             `.--..` '''   

 one rabbit, two rabbit... 
 > twenty_two

fwhibbit{Tw3nty_tw0_r4bb1t5_ar3_en0ugh}