domingo, 15 de enero de 2012

Volcando datos al explotar un SQLi - Parte I

hace ya un buen tiempo que no publico a si  que aprovechando el silencio de la noche y un par de técnicas que me pidió un brother para explotar sqli e optado por explicar como volcar datos, manipulando o consultando de manera adecuada la BD information_schema propia del Mysql.
Para poder entender esta primera parte simularemos un entorno donde existe una vulnerabilidad SQLi de tipo Inbound es decir tendremos acceso a la información con procedimiento de listados, para ello e creado una aplicación php con mysql vulnerable la que llamare sqli.php el cual comparto el código ojo esta no es una clase de PHP así que no usen este código para algún proyecto (jajaj serias monce)
1.Para armar el LAB primero vamos a copiar este código que es nuestra pagina vulnerable ustedes deben de remplazar "password" por la contraseña asignada al mysql

<?php
//nunca lo usen en una web XD
class Conexion
{
     public static function con() {
    
    $conexion = mysql_connect("localhost","root","password");
    mysql_query("SET NAMES 'utf8'");
    return $conexion;
    }

    public function mostrar($id) {
    $mostrar = array();
    $sql = "select id, titulo, texto from sqli.novedades where id = $id";
    $consulta = mysql_query($sql,Conexion::con());
    if(!$consulta) {
    $x=mysql_error();
    die("Ocurrio un error en la conexion a la base de datos");
 }else {

    while ($vol = mysql_fetch_assoc($consulta)) {
  $mostrar[] = $vol;
  }
    
    return $mostrar;
         }
    }
}
?>
<html>
<head></head>
<body bgcolor="#FAFAFA">
<?php
if(isset($_GET["fileid"]))
{
$fileid = $_GET["fileid"];
$volcar = new Conexion;
$datos = $volcar->mostrar($fileid);
if (count($datos) != 1) {
header("Location:sqli.php");
}else {
echo $datos[0]["titulo"];
echo "<br/>";
echo $datos[0]["texto"];
}
?>
</body>
</html>
<?php
}else {
?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<head></head>
<body bgcolor="#FAFAFA">
Tema 1leer
<br/>
Tema 2leer
<br/>
Tema 3leer
</body>
</html>
<?php
}
?>

2. Vamos a crear dos bases de datos 1 que va a interactuar con la web y otra la cual vamos a volcar sus datos estas son "sqli" y "datos"
a. SQLI
CREATE DATABASE sqli;

CREATE TABLE IF NOT EXISTS `novedades` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `titulo` varchar(250) COLLATE utf8_general_ci NOT NULL,
  `texto` text COLLATE utf8_spanish_ci NOT NULL,
  `escritor` varchar(250) COLLATE utf8_spanish_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;

INSERT INTO `novedades` (`id`, `titulo`, `texto`, `escritor`) VALUES
(1, 'SQL injection', 'Inyección de código sql es un método muy utilizado que aprovecha una mala validación en los datos de entrada permitiendo a un atacante manipular la consulta sql y llegar a obtener información sensible bla bla ', 'neotrons'),
(2, 'Cross-site Scripting (XSS)', 'es un tipo de inseguridad informática o agujero de seguridad típico de las aplicaciones Web, que permite a una tercera parte inyectar código JavaScript en páginas web vistas por el usuario, evitando medidas de control como la Política del mismo origen.', 'wikipedia'),
(3, 'OWASP', 'es una comunidad abierta y libre de nivel mundial enfocada en mejorara la seguridad en las aplicaciones de software. ', 'owasp');


b. DATOS
CREATE DATABASE datos;

CREATE TABLE IF NOT EXISTS `usuarios` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user` varchar(25) NOT NULL,
  `nombre` varchar(250) NOT NULL,
  `password` varchar(250) NOT NULL,
  PRIMARY KEY (`id`)
);

INSERT INTO `usuarios` (`id`, `user`, `nombre`, `password`) VALUES
(1, 'neotrons', 'abcdef ghijkl', '2109273d6457e96abbe8fb88bf62c074'),
(2, 'fucken', 'fuckencio fucken', '5f4dcc3b5aa765d61d8327deb882cf99'),
(3, 'yao', 'yao ming', 'e636319c2b0bb71c27d8766631edbe7f');

Ya teniendo nuestra web vulnerable vamos a proceder a explicar un metodo utilizado para volcar información para ello realizaremos consultas a la base de datos "information_schema" esta base de datos proporciona acceso a los metadatos de la base de datos. definiendo metadatos como un diccionario o catalogo del sistema es decir almacena información de todos los elementos existentes en mysql , tales como el nombre de la base de datos o tabla, el tipo de datos de una columna, etc...
Lo primero a tener en cuenta es que para utilizar este método debemos de asegurarnos que exista esta DB esto lo hacemos verificando siempre que la versión del mysql sea la 5.0.2. para mayor información sobre "information_schema" puede revisar http://dev.mysql.com/doc/refman/5.0/es/information-schema.html

Ahora si basta de floro y comenzamos a explicar de -1 como explotar un sql injection y volcar datos, en esta entrada vamos a identificar la vulnerabilidad y veremos como explotarla.
1. Identificando la SQLi:
Veamos un sqli normalmente se presenta cuando un valor de entrada no es validado correctamente en este caso la variable es pasada mediante GET esta variable se llama "fileid" y recibe valores enteros el cual podría ser el PK de la tabla la cual contiene los datos mostrados para identificar si existe un sql debemos saber si eel valor pasado por fileid no es validado esto podemos hacerlo con algo asi:
http://localhost?fileid=1+and+1=1#
http://localhost?fileid=1+and+1=0#
en estas dos entradas que debería presentar comportamientos opuesto ya que uno tendría un valor de vedad y el otro un false.
como vemos la condición verdadera me llevo a la novedad 1 mientras que la falsa me llevo a la pagina de selección ahora corroboramos este resultado forzando a mostrar un error de conexión en la aplicación
http://localhot?fileid=1'
como vemos los errores en consulta muestras un mensaje "Ocurrió un error en la conexión a la base de datos" por lo cual podríamos tener la certeza que no se están validando los campos de entrada.

2. Buscando volcar información:
antes de poder volcar información sensible debemos de saber si la web permite este comportamiento, para poder demostrar esto se acostumbra a usar la clausula UNION, esta clausula se usa para combinar el resultado de un número de comandos SELECT en un conjunto de resultados. es decir su hacemos un UNION SELECT seremos capas de combinar la consulta que muestra la novedades con una nueva consulta que queramos mostrar, pero existe una restricción importante es que debemos de conocer el numero de campos mostrar en la consulta principal es decir si imaginamos que la consulta principal es:
SELECT titulo, detalle, loquesea FROM table
observamos que la consulta utiliza o selecciona 3 campos "titulo, detalle, loquesea" si queremos mostrar información adicional basándonos en esa consulta haríamos algo así
SELECT titulo, detalle, loquesea FROM table UNION SELECT 1,2,3
esto mostrara 1 en lugar de titulo, 2 en lugar de detalle, etc..
por lo tanto es importante conocer el numero de campos usados por la aplicación web para la consulta, esto lo solucionamos usando ORDER BY entonces como nos sirve esta clausula, creo que todos conocemos la utliidad de order by en una consulta sirve principalmente para ordenar una consulta de acuerdo al campo indicado por ejemplo:
SELECT titulo, detalle, loquesea FROM table ORDER BY titulo 
este mostrara los datos pero ordenados en orden alfabético ascendente basado en el campo titulo, lo que quizás muchos no conozcan es que en ORDER BY también se le puede pasar en valor de la posición que ocupa en campo en la consulta entonces para el ejemplo anterior seria algo así:
SELECT titulo, detalle, loquesea FROM table ORDER BY 2
esto al igual que la consulta anterior volcara el mismo resultado, pero que pasaría si pasamos un valor cuya posición no exista es decir en valor 100
SELECT titulo, detalle, loquesea FROM table ORDER BY 100
lo que ocurriría en un error ya que la mysql no es capas de identificar dicho campo asignado a esa posición entonces creo que ya se dan cuneta para la consulta que venimos haciendo el valor máximo para ordenar seria 3 si seleccionamos algo mas nos dará un error ahora como llevaríamos este ejemplo a nuestra web vulnerable:
http://localhost/sqli.php?fileid=1+order+by+1
http://localhost/sqli.php?fileid=1+order+by+100

como observamos para un valor valido nos muestra los texto mientras que para un dato no valido nos lanza un error.

entonces como podemos encontrar exactamente en numero de campos que intervienen en la consulta principal, para esto se hace uso de una técnica que puede reducir en numero de veces que probemos un valor para esto usamos la búsqueda binaria; haber les explico en la practica, primero necesitamos ponernos un mínimo que normalmente es 1 y un valor máximo posible de preferencia impar por ejemplo yo usare 9 por tanto probaremos con todos los elementos que se encuentran en ese intervalo
[1,9]
para hacerlo mas simple solo probaremos con en mínimo y el máximo luego de ellos crearemos un dos intervalos usando algo como (min + max)/2 lo explico mejor.
primero probamos con 1 y 9
http://localhost/sqli.php?fileid=1+order+by+1
http://localhost/sqli.php?fileid=1+order+by+9
para nuestro ejemplo 1 es correcto así que nos muestra los textos concernientes a la entrada 1 y el nueve nos muestra un error esto quiere decir que se están usando en la consulta menos de 9 valores pero mas de 1 por tanto creamos 2 nuevo intervalos
[1,5> y [5,9>
entonces probamos con 5
http://localhost/sqli.php?fileid=1+order+by+5
en este caso también nos muestra un error por lo que aseguramos que se tratan de menos de 5 campos utilizados por lo tanto descartamos en intervalo de [5,9 y solo nos enfocamos en [1,5>
ahora tendremos:
[1,3> y [3,5>
http://localhost/sqli.php?fileid=1+order+by+3
este valor nos es correcto por tanto decimos que pueden ser mayores o iguales a tres pero menores que 5 por ultimo probamos con 4 lo cual nos da un error por tanto llegamos a la conclusión que en la consulta de la web intervienen 3 campos en esa consulta.
teniendo la certeza que son 3 valores ya podemos usar UNION SELECT e identificar si se es capas de mostrar datos para ello hacemos algo como:
http://localhost/sqli.php?fileid=1+AND+1=0+UNION+SELECT+1,2,3
lo que hacemos en la petición anterior es hacer falsa la primera consulta y mostrar unicamente los valores 1,2,3 lo cual observamos que 2 se muestra en el campo titulo y 3 en el detalle, notemos que no muestra en campo uno que podría ser usado para alguna labor interna de aplicación o quizás solo fue llamada y ya. Bien ahora solo nos queda ver si la versión del mysql sea 5.0.2 o mayor para poder saber esto podríamos usar alguna función de información de mysql tal como VERSION() que retorna una cadena que indica la versión del servidor MySQL otra que nos podría servir para obtener mas información es USER(), DATABASE() si quieres conocer otras puedes entrar a http://dev.mysql.com/doc/refman/5.0/es/information-functions.html
entonces podríamos hacer lo siguiente:
http://localhost/sqli.php?fileid=1+AND+1=0+UNION+SELECT+1,VERSION(),USER()
http://localhost/sqli.php?fileid=1+AND+1=0+UNION+SELECT+1,DATABASE(),3


entonces en mi caso pude extraer estos datos usa la versión 5.1.58 le usuario es root (esta muerto) y la base de Datos se llama sqli
ahora ya tenemos la certeza que existe una BD information_schema la cual podemos consultar, al parecer esta entrada se hizo un poco larga a si que haré dos partes en la próxima entrada sera como consultar directamente a information_schema

By Neotrons

No hay comentarios:

Publicar un comentario