xchg2pwn

xchg2pwn


Entusiasta del reversing y desarrollo de exploits



HackTheBox

Hunting License



Método 1


Una vez descomprimido el zip solo nos deja un compilado llamado license

❯ ls
 license  

Al ejecutarlo nos da a escoger entre (y/n) enviamos y, después nos pregunta una contraseña, nos dice que no esta oculta, si enviamos una incorrecta simplemente sale

❯ ./license
So, you want to be a relic hunter?
First, you're going to need your license, and for that you need to pass the exam.
It's short, but it's not for the faint of heart. Are you up to the challenge?! (y/n)  
y
Okay, first, a warmup - what's the first password? This one's not even hidden: 123
Not even close!

Podemos analizarlo con ida donde a la derecha podemos ver el codigo main en c

El codigo comprueba que hayamos introducido y si es asi llama a la función exam()

int __fastcall main(int argc, const char **argv, const char **envp)
{
  char input; // [rsp+Fh] [rbp-1h]

  puts("So, you want to be a relic hunter?");
  puts("First, you're going to need your license, and for that you need to pass the exam.");
  puts("It's short, but it's not for the faint of heart. Are you up to the challenge?! (y/n)");
  input = getchar();
  if ( input != 'y' && input != 'Y' && input != '\n' )
  {
    puts("Not many are...");
    exit(-1);
  }
  exam("It's short, but it's not for the faint of heart. Are you up to the challenge?! (y/n)", argv);  
  puts("Well done hunter - consider yourself certified!");
  return 0;
}

Podemos ver exam como todas las demas funciones igual que hicimos con el main

void exam()
{
  char password3[8]; // [rsp+0h] [rbp-30h] BYREF
  char password2[8]; // [rsp+1Ch] [rbp-14h] BYREF
  char *password; // [rsp+28h] [rbp-8h]

  password = (char *)readline("Okay, first, a warmup - what's the first password? This one's not even hidden: ");  
  if ( strcmp(password, "PasswordNumeroUno") )
  {
    puts("Not even close!");
    exit(-1);
  }
  free(password);
  *(_QWORD *)password2 = 0LL;
  reverse(password2, t, 11LL);
  password = (char *)readline("Getting harder - what's the second password? ");
  if ( strcmp(password, password2) )
  {
    puts("You've got it all backwards...");
    exit(-1);
  }
  free(password);
  *(_QWORD *)password3 = 0LL;
  xor(password3, &t2, 17LL, 19LL);
  password = (char *)readline("Your final test - give me the third, and most protected, password: ");
  if ( strcmp(password, password3) )
  {
    puts("Failed at the final hurdle!");
    exit(-1);
  }
  free(password);
}

Para la primera contraseña muestra un mensaje con readline y el input que recibe lo almacena en password despues lo compara con la string PasswordNumeroUno

strcmp(password, "PasswordNumeroUno")  

Podemos comprobarlo ejecutando el binario al enviar la contraseña que obtuvimos nos pide la segunda contraseña, quiere decir que esta es correcta

Okay, first, a warmup - what's the first password? This one's not even hidden: PasswordNumeroUno  
Getting harder - what's the second password?

En la segunda contraseña lo que hace es usar la función reverse pasandole como argumento t que es el valor y 11 que es la longitud, despues almacena el resultado en password2, despues recibe el input y lo compara con lo que vale

reverse(password2, t, 11LL);  
strcmp(password, password2)

La variable t no podemos verla en el c pero la vemos representada al hacer clic

Sabemos que le da la vuelta, asi que podemos hacer el proceso inverso con rev

❯ echo 0wTdr0wss4P | rev  
P4ssw0rdTw0

De nuevo podemos comprobarla en el binario enviandola y recibiendo otro input

Getting harder - what's the second password? P4ssw0rdTw0
Your final test - give me the third, and most protected, password:  

Para la contraseña 3 lo que hace es usar la función xor usando 19 como key y 17 como longitud lo almacena el password3 despues lo compara con nuestro input

xor(password3, &t2, 17LL, 19LL);  
strcmp(password, password3)

Para obtener t2 podemos ver sus valores en hexadecimal haciendo clic sobre el

En un script de python definimos el valor de t2 y lo basamos a formato bytes, despues hacemos el xor usando 19 como clave y mostramos el resultado de ello

#!/usr/bin/python3

t2 = bytes.fromhex("477b7a6177527d77557a7d727f32323213")  

key = 19

result = bytes([i ^ key for i in t2])

print(result.decode())

Al ejecutarlo nos muestra la contraseña que podemos comprobar en el binario

❯ python3 exploit.py  
ThirdAndFinal!!!

Your final test - give me the third, and most protected, password: ThirdAndFinal!!!  
Well done hunter - consider yourself certified!


Método 2


Otra forma es con gdb haciendo breakpoints en cada uno de los strcmp para ver la comparación, para ver las direcciones donde lo llama usamos objdump

❯ objdump -d license | grep 'call.*strcmp'
  4012ac:	e8 af fd ff ff       	call   401060 <strcmp@plt>  
  401316:	e8 45 fd ff ff       	call   401060 <strcmp@plt>  
  40138a:	e8 d1 fc ff ff       	call   401060 <strcmp@plt>  

Abrimos el programa con gdb y definimos un breakpoints en la primera llamada a strcmp, corremos el programa enviando y para seguir y cualquier contraseña

❯ gdb -q license
Reading symbols from license...
(No debugging symbols found in license)
pwndbg> break *0x4012ac
Breakpoint 1 at 0x4012ac
pwndbg> run
Starting program: /home/kali/license
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
So, you want to be a relic hunter?
First, you're going to need your license, and for that you need to pass the exam.
It's short, but it's not for the faint of heart. Are you up to the challenge?! (y/n)
y
Okay, first, a warmup - what's the first password? This one's not even hidden: password  

Breakpoint 1, 0x00000000004012ac in exam ()
pwndbg>

Como nos detenemos en el breakpoint en el disasm deberiamos ver la llamada a strcmp con los argumentos que son nuestra contraseña y la que se espera

pwndbg> context disasm
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────[ DISASM / x86-64 / set emulate on ]───────────────────────
 ► 0x4012ac <exam+34>    call   strcmp@plt                      <strcmp@plt>
        s1: 0x425770 ◂— 'password'
        s2: 0x402170 ◂— 'PasswordNumeroUno'
 
   0x4012b1 <exam+39>    test   eax, eax
   0x4012b3 <exam+41>    je     exam+63                      <exam+63>
 
   0x4012b5 <exam+43>    mov    edi, 0x402182
   0x4012ba <exam+48>    call   puts@plt                      <puts@plt>

   0x4012bf <exam+53>    mov    edi, 0xffffffff
   0x4012c4 <exam+58>    call   exit@plt                      <exit@plt>
──────────────────────────────────────────────────────────────────────────────────  
pwndbg>

Hacemos lo mismo esta vez enviando la primera contraseña y asi vemos la segunda

❯ gdb -q license
Reading symbols from license...
(No debugging symbols found in license)
pwndbg> break *0x401316
Breakpoint 1 at 0x401316
pwndbg> run
Starting program: /home/kali/license
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
So, you want to be a relic hunter?
First, you're going to need your license, and for that you need to pass the exam.
It's short, but it's not for the faint of heart. Are you up to the challenge?! (y/n)
y
Okay, first, a warmup - what's the first password? This one's not even hidden: PasswordNumeroUno  
Getting harder - what's the second password? password

Breakpoint 2, 0x0000000000401316 in exam ()
pwndbg> context disasm
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────[ DISASM / x86-64 / set emulate on ]───────────────────────
 ► 0x401316 <exam+140>    call   strcmp@plt                      <strcmp@plt>
        s1: 0x424f90 ◂— 'password'
        s2: 0x7fffffffe4ec ◂— 'P4ssw0rdTw0'
 
   0x40131b <exam+145>    test   eax, eax
   0x40131d <exam+147>    je     exam+169                      <exam+169>
 
   0x40131f <exam+149>    mov    edi, 0x4021c8
   0x401324 <exam+154>    call   puts@plt                      <puts@plt>
 
   0x401329 <exam+159>    mov    edi, 0xffffffff
   0x40132e <exam+164>    call   exit@plt                      <exit@plt>
──────────────────────────────────────────────────────────────────────────────────
pwndbg>

Repetimos el mismo proceso y obtenemos la ultima contraseña ThirdAndFinal!!!

❯ gdb -q license
Reading symbols from license...
(No debugging symbols found in license)
pwndbg> break *0x40138a
Breakpoint 1 at 0x40138a
pwndbg> run
Starting program: /home/kali/license
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
So, you want to be a relic hunter?
First, you're going to need your license, and for that you need to pass the exam.
It's short, but it's not for the faint of heart. Are you up to the challenge?! (y/n)
y
Okay, first, a warmup - what's the first password? This one's not even hidden: PasswordNumeroUno  
Getting harder - what's the second password? P4ssw0rdTw0
Your final test - give me the third, and most protected, password: password

Breakpoint 1, 0x000000000040138a in exam ()
pwndbg> context disasm
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────[ DISASM / x86-64 / set emulate on ]───────────────────────
 ► 0x40138a <exam+256>    call   strcmp@plt                      <strcmp@plt>
        s1: 0x425770 ◂— 'password'
        s2: 0x7fffffffe4d0 ◂— 'ThirdAndFinal!!!'
 
   0x40138f <exam+261>    test   eax, eax
   0x401391 <exam+263>    je     exam+285                      <exam+285>
 
   0x401393 <exam+265>    mov    edi, 0x40222c
   0x401398 <exam+270>    call   puts@plt                      <puts@plt>
 
   0x40139d <exam+275>    mov    edi, 0xffffffff
   0x4013a2 <exam+280>    call   exit@plt                      <exit@plt>
──────────────────────────────────────────────────────────────────────────────────


Método 3


Los metodos anteriores son bastante bonitos y todo pero hay una forma mas facil con ltrace filtrando por strcmp enviamos el y cuando nos pregunte la contraseña enviamos 123, nos mostrara con el strcmp la comparacion que hace, podemos ver la string que espera que es la primera contraseña PasswordNumeroUno

❯ ltrace -e strcmp ./license
So, you want to be a relic hunter?
First, you're going to need your license, and for that you need to pass the exam.
It's short, but it's not for the faint of heart. Are you up to the challenge?! (y/n)
y
Okay, first, a warmup - what's the first password? This one's not even hidden: 123
license->strcmp("123", "PasswordNumeroUno")                                                         = -31  
Not even close!
+++ exited (status 255) +++

license->strcmp("123", "PasswordNumeroUno")                    = -31  

Repetimos el proceso esta vez enviando la primera contraseña despues del y, cuando nos pide la segunda enviamos nuevamente la string 123, al enviarlo esto nos devolvera de nuevo el strcmp pero ahora con la segunda contraseña P4ssw0rdTw0

❯ ltrace -e strcmp ./license
So, you want to be a relic hunter?
First, you're going to need your license, and for that you need to pass the exam.
It's short, but it's not for the faint of heart. Are you up to the challenge?! (y/n)
y
Okay, first, a warmup - what's the first password? This one's not even hidden: PasswordNumeroUno
license->strcmp("PasswordNumeroUno", "PasswordNumeroUno")                                           = 0
Getting harder - what's the second password? 123
license->strcmp("123", "P4ssw0rdTw0")                                                               = -31  
You've got it all backwards...
+++ exited (status 255) +++

De nuevo repetimos ahora enviando y ademas de las 2 contraseñas, nos mostrara el strcmp esta vez con la tercera contraseña que es la final ThirdAndFinal!!!

❯ ltrace -e strcmp ./license
So, you want to be a relic hunter?
First, you're going to need your license, and for that you need to pass the exam.
It's short, but it's not for the faint of heart. Are you up to the challenge?! (y/n)
y
Okay, first, a warmup - what's the first password? This one's not even hidden: PasswordNumeroUno
license->strcmp("PasswordNumeroUno", "PasswordNumeroUno")                                           = 0
Getting harder - what's the second password? P4ssw0rdTw0
license->strcmp("P4ssw0rdTw0", "P4ssw0rdTw0")                                                       = 0
Your final test - give me the third, and most protected, password: 123
license->strcmp("123", "ThirdAndFinal!!!")                                                          = -35  
Failed at the final hurdle!
+++ exited (status 255) +++

Enviamos todas las contraseñas, nos devuelve que nos consideremos certificados

❯ ./license
So, you want to be a relic hunter?
First, you're going to need your license, and for that you need to pass the exam.
It's short, but it's not for the faint of heart. Are you up to the challenge?! (y/n)
y
Okay, first, a warmup - what's the first password? This one's not even hidden: PasswordNumeroUno  
Getting harder - what's the second password? P4ssw0rdTw0
Your final test - give me the third, and most protected, password: ThirdAndFinal!!!
Well done hunter - consider yourself certified!


Cuestionario


Nos conectamos con netcat a el host proporcionado por hackthebox y al responder las preguntas de acuerdo a lo que explotamos se nos devuelve finalmente la flag

❯ netcat 165.141.104.69 30427

What is the file format of the executable?
> ELF 
[+] Correct!

What is the CPU architecture of the executable?
> amd64
[+] Correct!

What library is used to read lines for user answers? (`ldd` may help)
> libreadline.so.8
[+] Correct!

What is the address of the `main` function?
> 0x401172
[+] Correct!

How many calls to `puts` are there in `main`? (using a decompiler may help)  
> 5
[+] Correct!

What is the first password?
> PasswordNumeroUno
[+] Correct!

What is the reversed form of the second password?
> 0wTdr0wss4P
[+] Correct!

What is the real second password?
> P4ssw0rdTw0
[+] Correct!

What is the XOR key used to encode the third password?
> 19
[+] Correct!

What is the third password?
> ThirdAndFinal!!!
[+] Correct!

[+] Here is the flag: `HTB{l1c3ns3_4cquir3d-hunt1ng_t1m3!}`