El fuzzing
Introducción
Procedente del término inglés fuzzy (difuso en español), el fuzzing es un método de automatización de pruebas. Se basa en los fuzzers (herramientas software) para automatizar la identificación de bugs o fallos en aplicaciones. Aporta un ahorro de tiempo importante al hacer frente a programas que pueden contener miles de líneas de código.
El proceso consiste en verificar las posibles entradas para una aplicación determinada, y forzar operaciones en el caso de que esta reaccione de manera anormal. El fuzzer servirá así para bombardear la aplicación con códigos anómalos de forma intencionada.
Su finalidad es la mejora de los desarrollos, una vez identificado un bug (error). El fuzzing está destinado principalmente a los desarrolladores e investigadores de seguridad. Sin embargo, los piratas resultan ser también beneficiarios del proceso.
Existen fuzzers "llave en mano", que nos permiten hacer las primeras pruebas y nos dan a menudo buenos resultados, pero con frecuencia tendremos que crear nuestro propio fuzzer para un caso específico.
Podemos citar algunos fuzzers como Spike, Fusil, zzuf, wfuzz...
Los fuzzers son específicos a un protocolo o un servicio, como por ejemplo los fuzzers FTP, web, etc.
Fuzzing FTP
Tomemos para comenzar un caso simple con la aplicación Ability Server 2.34 que es un software comercial que permite crear de forma sencilla un servidor FTP, HTTP o e-mail.
Vamos a atacar a este servidor FTP porque conocemos sus vulnerabilidades.
Vamos a Settings para configurar un usuario con la identificación de ftp y su contraseña ftp por ejemplo.
A partir de ese momento, cuando hacemos clic en Activate en la línea de FTP Server, obtenemos un acceso al FTP que nos conecta como usuario ftp con la contraseña ftp.
Partiremos de esta situación para crear un script que tratará de hacer fallar a la aplicación.
Estamos en presencia del protocolo FTP, debemos saber cuáles son las pruebas que podemos realizar.
Una de las pruebas posibles es proporcionar como argumento a un comando un número de argumentos no previsto.
Además, debemos identificar los comandos FTP que aceptan argumentos. Para esto, tenemos una documentación muy útil que es la RFC.
Así podemos ir a consultar la RFC 959 y podremos ver que los comandos CWD, MKD y STOR aceptan argumentos.
Para el ejemplo, solo tomaremos estos tres comandos, pero en la práctica habría que probar todos los comandos que aceptan un argumento.
Vamos a comenzar escribiendo un script en Python que efectúe la conexión para probarla.
script_conexion_ftp.py
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) ...
Fuzzing con Scapy
La función fuzz() es capaz de cambiar cualquier valor por defecto, tal como el checksum de un objeto cuyo valor es aleatorio y el tipo adecuado para el campo. Esto nos permitirá crear rápidamente un fuzzer y enviarlo en un bucle.
En el siguiente ejemplo, la capa IP es normal y las capas UDP y NTP han sido distorsionadas (fuzzed). El checksum UDP será correcto, el puerto UDP de destino se sobrecargará, NTP tendrá el valor 123 y la versión se forzará a 4. Todos los demás puertos serán asignados de forma aleatoria.
Podemos por supuesto, como hemos visto en el capítulo Red: la librería Scapy, configurar la función fuzz() como queramos.
Ahora podemos iniciar el fuzzing y observar con un "examinador de paquetes", como Wireshark o tcpdump, el intercambio entre el cliente y el servidor.
La captura de pantalla siguiente muestra el resultado en Wireshark. Wireshark es un software gratuito, disponible para su descarga y con muchos tutoriales. Su uso es sencillo e instintivo.
Vemos aquí los paquetes enviados al equipo 192.168.1.16.
Intentemos ahora un fuzzing sobre nuestro servidor Ability Server mediante el siguiente comando:
send(IP(dst="192.168.1.16")/fuzz(TCP(dport=21)),loop=1)
Podemos constatar que se envían muchos paquetes al objetivo (192.168.1.16). Al examinar los paquetes por separado, podemos observar los diferentes datos enviados...
Fuzzing con PyDbg: Format string
1. Introducción
El objetivo es aquí también reescribir los datos para controlar el flujo de ejecución y así aumentar nuestros privilegios.
Este tipo de error proviene también de errores de programación que de forma aparente no generan ningún riesgo de seguridad.
El formato string - o formato de cadena - surgió con las funciones de tipo printf y todos sus derivados que son mal utilizados.
Vamos a estudiar en un primer lugar la función printf y sus argumentos para comprender el fallo y luego poder explotarlo.
printf(’’su opción: %d\n, opciones_usuario);
-
%d: sirve para mostrar opciones_usuario en formato decimal
-
%u: decimal sin signo
-
%x: hexadecimal
-
%s: cadena de caracteres
-
%n: almacena el número de caracteres escritos por la función printf
-
%n: palabra de memoria
-
%hn : "short" (16 bits)
-
%hhn: "char" (8 bits)
Cuando el usuario introduce el parámetro %x y este se pasa como argumento a la función printf(), se muestra la representación hexadecimal de una palabra de 4 bytes de la pila (por ejemplo 0xbfe3B024).
Este parámetro puede utilizarse para examinar la memoria.
Se podrían utilizar otros parámetros como %s o %n para leer las cadenas de caracteres o para escribir en la memoria.
Este es el tipo de fallo que queremos probar mediante PyDbg.
2. Fuzzer de archivos
Las vulnerabilidades de tipo format string se convertirán en una de las principales opciones para los ataques por parte del cliente, por esto nos interesaremos en ellas aquí.
fuzzer_archivo.py
from pydbg import *
from pydbg.defines import *
import utils
import random
import sys
import struct
import threading
import os
import shutil
import time
import getopt
class file_fuzzer:
def __init__(self, exe_path, ext, notify):
self.exe_path = exe_path
self.ext = ext
self.notify_crash =...
Sulley
1. Introducción
Existen muchas herramientas, librerías, o framework en Python para realizar fuzzing. Para el contexto de este libro, vamos a estudiar un framework muy completo llamado Sulley.
2. Instalación
a. Instalación normal
La instalación estándar requiere algunas instalaciones de software en el orden siguiente:
Instale WinPcaP con una instalación por defecto. Descargue WinPcaP developer’s pack requerido para la compilación de pcapy (http://www.winpcap.org/install/bin/WpdPack_4_1_2.zip).
Instale MinGW (http://sourceforge.net/projects/mingw/files/Automated%20MinGW%20Installer/mingw-get-inst/mingw-get-inst-20110530/mingw-get-inst-20110530-src.tar.gz/download). Realice la instalación por defecto, a excepción de la etapa de selección del tipo de compilador donde marcaremos C++ Compiler. Después de la instalación, indique la ruta del binario MinGW en la variable PATH (C:\MinGW\BIN).
Instale Python (http://www.python.org/ftp/python/2.7.2/python-2.7.2.msi). Después de la instalación, indique la ruta del binario en la variable PATH.
Instale pydasm, descargue libdasm (http://code.google.com/p/libdasm/downloads/list), extráigalo, introduzca en el directorio pydasm, compile e instale como se indica a continuación:
C:\Documents and Settings\javier\Desktop\libdasm-1.5\pydasm>python
setup.py build_ext -c mingw32
running build_ext
building 'pydasm' extension
---[snip]---
C:\MinGW\bin\gcc.exe -mno-cygwin -shared -s build\temp.win32-
2.7\Release\..\libdasm.o build\temp.win32-2.7\Release\pydasm.o
build\temp.win32-2.7\Release\..\pydasm.def -LC:\Python27\libs
-LC:\Python27\PCbuild -lpython27 -lmsvcr90 -o build\lib.win32-
2.7\pydasm.pyd
C:\Documents and Settings\fasm\Desktop\libdasm-1.5\pydasm>python
setup.py install
running install
---[snip]---
Writing C:\Python27\Lib\site-packages\pydasm-1.5-py2.7.egg-info
C:\Documents and Settings\fasm\Desktop\libdasm-1.5\pydasm>
Install PaiMei by issuing ”python setup.py install” from whatever
directory you checked it out to. Post installation - delete or
rename C:\Python27\Lib\site-packages\pydbg\pydasm.pyd
Install pcapy...
Puesta en práctica
1. Fuzzing 1: HTTP
Enunciado
Requisitos previos: Sulley, protocolo HTTP.
Objetivo: crear un fuzzing de sitio web.
Enunciado:
Queremos crear un fuzzer con varios bloques.
Un bloque, por ejemplo, permitirá al fuzzer actuar sobre todas las cadenas de caracteres del argumento /index.html HTTP/1.1 para todos los comandos: GET, HEAD, POST, OPTIONS, TRACE, PUT, DELETE y PROPFIND.
Implementará muchos bloques según el alcance de su imaginación, solo ésta y los límites del protocolo le pueden detener.
Ejemplo corregido
from sulley import *
################################################################
s_initialize("HTTP VERBS")
s_group("verbs", values=["GET", "HEAD", "POST", "OPTIONS",
"TRACE", "PUT", "DELETE", "PROPFIND"])
if s_block_start("body", group="verbs"):
s_delim(" ")
s_delim("/")
s_string("index.html")
s_delim(" ")
s_string("HTTP")
s_delim("/")
s_string("1")
s_delim(".")
s_string("1")
s_static("\r\n\r\n")
s_block_end()
################################################################
s_initialize("HTTP VERBS BASIC")
s_group("verbs", values=["GET", "HEAD"]) ...