Seguridad En Programación

Post on 24-May-2015

4.244 views 0 download

description

Una pequeña presentación sobre lo que se debería tomar en cuenta par ala programación en torno a la seguridad + bonus code exploit en fácil.

Transcript of Seguridad En Programación

Seguridad en Programación

vladimir dot calderon at gmail dot com(16 – mayo – 2009)

Programa

• SQL Injection– Presentación– Formas de evitarlo

• Code Exploits– Formas de evitarlo

• El menospreciado try-catch– Error más común

• Un ejemplo de todo el ensamblado en una CAD• Generación de código

SQL INJECTION

SQL Injection

• Un usuario solicita datos al gestor de la base de datos, generalmente indicando un criterio de selección

• Los datos son devueltos al usuario de acuerdo al criterio de selección colocado en la consulta Gestor de Base de Datos

Cliente/Usuario

SQL : Tipos de comandos

Comandos DCL (Data Control Language Statements)

Cláusulas

Comandos DML (Data Manipulation Language Statements)

Comandos DDL (Data Definition Language Statements)

Operadores de Comparación

SQL : Comandos Básicos

Comandos DDL (Data Definition Language Statements)

CREATE Utilizado para crear nuevas tablas, campos e índices.

DROP Empleado para eliminar tablas e índices.

ALTERUtilizado para modificar las tablas agregando campos o

cambiando la definición de los campos.

Comandos DCL (Data Control Language Statements)

GRANT Utilizado para otorgar permisos.

REVOKE Utilizado para revocar permisos.

DENY Utilizado para denegar acceso.

SQL : Comandos Básicos

Comandos DML (Data Manipulation Language Statements)

SELECTUtilizado para consultar registros de una base de datos

que satisfagan un criterio determinado.

INSERTUtilizado para cargar lotes de datos en la base de datos

en una única posición.

UPDATEUtilizado para modificar los valores de los campos y

registros específicos.

DELETEUtilizado para eliminar registros de una tabla de base de

datos.

SQL Injection

• SQL Injection es cuando se pueden introducir consultas SQL en los formularios de una aplicación en una consulta previamente establecida.

• Mediante SQL Injection se logra manipular la manera en que el programa responde normalmente.

Por qué hablar de SQL Injection?

• Porque a pesar de que la técnica original tiene un par de años, aún hoy sigue siendo efectiva

• Porque el presente y parte del futuro de la seguridad informática se encuentra de una u otra forma relacionada con las aplicaciones web y los almacenes de datos.

• Porque en esencia es una técnica de intrusión sumamente sencilla, aspecto que la hace sumamente peligrosa.

Esquema simplificado

Internet

Web Server

FirewallDatabase Server

Usuario/Intruso

Usuario/Intruso

App.Web

App.Web

App.Web

App.Web

Típica página web

11

sql = “SELECT * FROM users WHERE username = '" + usuario + "' AND userpass = '" + clave + "' "

Comilla Simple : Single Quote

• Si logramos que la consulta interprete un texto con solamente una comilla simple, tendremos:

• Lo cual concluye en un error de sintáxis SQL!

SELECT * FROM users WHERE username = ‘ ‘ ' AND userpass =‘xx123'

Objetivos SQL Injection

• Identificar componentes dinámicos en el sitio web• Intentar formarse una idea de la estructura de la

aplicación

• Dónde encontramos posibles vulnerabilidades?– Páginas de Identificación y Autenticación de usuarios– Formularios de ingreso de datos– URIs / URLs en donde se lean valores / Variables

• En general es susceptible de ataque cualquier input del usuario

Pasando la autenticación

• En las páginas de autentificación trataremos de:– Ingresar a zonas restringidas– Falsear un usuario estándar– Identificar a un posible administrador y utilizarlo

• Algunas opciones:

'or 1=1-- admin'-- 'OR''=''--

Evadiendo la autenticación

• Por qué las opciones indicadas deberían funcionar?

SELECT * FROM users WHERE username = '' OR''=''-- AND userpass =''

SELECT * FROM users WHERE username = 'admin' -- AND userpass =''

'OR''=''--

admin'--

SELECT * FROM users WHERE username = '' or 1=1--' AND userpass =''

'or 1=1--

Evitando SQL Injection

• Lo más importante de conocer un ataque es poder evitarlo.

• Dependiendo del lenguaje de programación utilizado se deben aplicar las técnicas correspondientes.

• En reglas generales, – Se DEBEN utilizar los métodos nativos del lenguaje para la

asignación de parámetros a consultas SQL– Se ACONSEJA utilizar procedimientos almacenados para todas

las consultas y manejo de la base de datos

SQL Injection .vs. PHP

• Para leer datos numéricos o de un tipo definido (no para STRINGs)

<?php

settype($offset, 'integer');$consulta = "SELECT id, nombre FROM productos ";$consulta .= "LIMIT 20 OFFSET %d;";

// note el simbolo %d en la cadena de formato// usar %s no tendría sentido$consulta = sprintf($consulta, $offset);

?>

SQL Injection .vs. PHP

• Para incluir las variables en consultas SQL estándar (select, update, insert, etc)

<?php

$query = "INSERT INTO usuarios(nombre,contr) VALUES('%s','%s');“;$consulta = sprintf($query, pg_escape_string($nombre_usuario), md5($contrasenya));$resultado = pg_query($conexion, $consulta);

$query = "SELECT 1 FROM usuarios WHERE nombre='%s' AND contr='%s';“;$consulta = sprintf($query, pg_escape_string($nombre_usuario), md5($contrasenya));$resultado = pg_query($conexion, $consulta);?>

SQL Injection .vs. ASP.NET

• ASP.NET maneja esto de manera más transparente y haciendo uso de los objetos adecuados no debería tener problemas

string query="select * from Customers where city = @City“;SqlCommand cmd = new SqlCommand(query, conn);

SqlParameter param = new SqlParameter(); param.ParameterName = "@City"; param.Value = inputCity;

cmd.Parameters.Add(param); SqlDataReader reader = cmd.ExecuteReader();

SQL Injection .vs. JAVA

• Similar a ASP.NET (más bien ASP.NET similar a JAVA):

String query = "Select favorita from comida where gato = ?“;

PreparedStatement preparedStatement = connection.prepareStatement(query); preparedStatement.setString(1, “mufasa");

ResultSet resultSet = preparedStatement.executeQuery();

while (resultSet.next()) { System.out.println(“La comida favorita de mufasa " + resultSet.getString(1)); }

CODE EXPLOITS

Qué es un exploit?

• Un exploit es explotar una vulnerabilidad en un programa.

• Por cada 1000 líneas de código es probable que existan entre 6 a 8 errores. (peer review)

• Siempre se podrán encontrar fallas en los programas de cualquier índole: Windows, Linux, Mac, etc.

• No depende del lenguaje tampoco.• Quiénes?

– Hackers, crackers, especialistas en seguridad informática

Tipos de vulnerabilidades

• Buffer Overflow– Stack

• Integer Overflow• Format String• Cadenas sin terminación• SQL Injection• Cross Site Scripting• Manipulación de variables

Algo de terminología

• ASR: Address Space Randomisation– Es cuando el sistema operativo está preparado para que las

funciones cargadas en el mismo se encuentren en direcciones de memoria que muy probablemente cambian cada vez que se reinicia la máquina

• Registros de CPU– Son los registros de la máquina que se utilizan para ejecutar los

procesos y mantener el estado del proceso en ejecución: próxima línea a ejecutar, dirección de retorno de la función, etc

Un poco más de terminología

• Shellcode– Son simplemente comandos Assembler. Típicamente, se crean

programas que abran un shell o que ejecuten algún comando en particular.

• GDB– El debogueador de Linux, muy poderoso para encontrar

exactamente las direcciones de memoria en cualquier llamado

• GCC– Compilador de C/C++ que también compila assembler y otros

Llamado a una función en C

• Ejemplo del assembler producido por un código vulnerable

Int main(int argc, char* argv[]){

char buffer[256];

if (argc != 2)

exit(1);

Llamado a una función en C

• La continuación

strcpy(buffer, argv[1]);

return 0;

}

Overflow y Memoria

• Cuando ocurre un Overflow, datos pasan a sobre escribir lugares donde hay código, por lo tanto se vuelven ejecutables. Para ver cómo ocurre esto hay que entender cómo funciona la memoria:

• Una página es una parte de la memoria con direccionamiento propio. El kernel asigna un espacio (páginas) de memoria para el proceso, esta memoria consta de 3 partes:– Segmento de Código: instrucciones assembler que el CPU ejecuta. EIP

es el registro que tiene la próxima línea a ejecutarse

– Segmento de Datos: Para variables y bufferes dinámicos

– Segmento de Pila: utilizado para pasar argumentos a las funciones. ESP es el registro que apunta a la punta del Stack

Cómo se %$&! la memoria

Qué puede ocurrir?

• En el Shellcode que coloquemos podemos hacerle hacer lo que querramos

• Los espacios se llenan con NOPs o INCs

• Hay generadores de Shellcode http://www.metasploit.com

En la práctica

• Tenemos un programa que tiene un problema potencial:

void trucho (void) { char small[30]; gets (small); printf("%s\n", small); }

int main() { trucho (); return 0; }

Mostrando la vulnerabilidad

• Se puede observar cómo surge la vulnerabilidad• Los hackers buscan por todos los medios este

comportamiento en una aplicación

Busquemos las direcciones (GDB)

• Dirección de retorno interesante 0x08048418 (esto está originalmente en EBP)

La función trucho()

• Aumenta en 0x28 = 40 el stack. Esto viene de que nuestro char[] es de 30 + padding mod 16 = 32 + 8 (para las direcciones del EBP) = 40.

Cómo vemos el overflow?

• Se puede ver cómo justamente en el lugar donde se produce el overflow se va rellenando con los valores de datos el lugar del EBP (note que se llena en sentido contrario)

Modificando la dirección

• Se debe encontrar la dirección donde queremos ir:

main() { int i=0; char buf[44]; for (i=0;i<=40;i+=4) *(long *) &buf[i] = 0x84130804; puts(buf); }

Viendo el resultado

• Observe que también se debe tener cierto conocimiento para pasar el texto que queremos

• Salta el error y vuelve a ejecutarse la función trucho()

Shellcode

• Es un código assembler que va en el espacio donde existe la vulnerabilidad.

• Se debe programar un shellcode con tamaños diferentes (dependiendo del tamaño del buffer)

• Luego se convierte el shellcode a un hex char. De manera que tenemos algo así:

static char shellcode[]= "\xeb\x17\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d" "\x4e\x08\x31\xd2\xcd\x80\xe8\xe4\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x58";

Finalmente

• Se debe escribir un programa que:– Explote la vulnerabilidad enviando el Shellcode al lugar de la

memoria que corresponda– El shellcode generalmente puede ser una llamada a /bin/sh

• El resultado es que, cuando ejecutamos nuestro exploit, obtenemos un shell.

• El exploit puede ser a un programa, a un servicio (DNS, web, etc)

Programación Defensiva

Por qué?

• Según SANS, la primera de las 10 peores vulnerabilidades que hay es:

• ISO 27001

NO VERIFICACION de los parámetros de ENTRADA y SALIDA de las funciones de nuestros programas

12.2.1: El insumo de data en las aplicaciones debe ser validado para asegurar que esta data sea correcta y apropiada.12.2.2, 12.2.3 y 12.2.4: Que no hayan errores, integridad y validar output.

Políticas de programación

• La primera cosa que se debe hacer es redactar una política de programación, que contenga:– Las cosas que NO se deben hacer– La existencia de patrones– El know-how de la empresa o grupo de desarrolladores– Explícitamente indicar la suma importancia del seguimiento de

las reglas– Complejidad ciclomática

• Técnicamente, se puede cumplir con estas reglas– Logging (log4net, log4j)– Peer review (revisión de pares)– Try / catch

Logging

• Aproximadamente un 4% del código debe estar destinado a operaciones de logging (McConnell)

• Muy difícil enseñar a hacer buen logging, tiempo de aprendizaje aprox. 1 año.

• Mejor herramienta de logging: log4j / log4net: http://logging.apache.org

• Cada vez que ocurre una falla en el programa, podemos estar enterados por correo!!

Ejemplo Logging (log4net)

protected void Logon_Click(object sender, EventArgs e){ log.Info("Trata de autenticarse: " + UserEmail.Text + "/********"); if (verificar(UserEmail.Text, UserPass.Text)) { log.Info("Usuario autenticado"); … // redirección o a Inicio } else { log.Error("Usuario " + UserEmail.Text + "/" + UserPass.Text + " incorrectos"); Msg.Text = "Nombre o Clave de Usuario son inválidos, o el usuario ha sido dado de baja"; }}

Revisión de Pares

• SUMAMENTE difícil de implementar, sin embargo• De los 8 a 10 errores posibles en 1000 líneas de

código, 9 se resuelven / detectan con revisión de pares ANTES de la compilación o testeo

• En qué consiste?– REVISION sesuda del código por un tercero

• Consejo para la implementación– Bob realiza el código a ser aprobado por TOM– Alice presenta el código a ser aprobado a TOM– Si TOM descubre algún error, Alice es castigada

Try / catch

• Se debe utilizar este patrón en todo lugar donde sea necesario, las veces que sea necesario, es importante el uso de programación defensiva en este sentido.

try {

File f = new File(“algo.txt”); FileReader fr = new FileReader(f);

} catch {

log.error(“Algo pasó”); }

File f = null;FileReader fr = null;try { f = new File(“algo.txt”);} catch(Exception e) { log.error(“error”, e);}try { fr = new FileReader(f);} catch(Exception e) { log.error(“error”, e);}

Beneficios en producción

• Una vez se toman todos (al menos varios) de los recaudos en el tema de seguridad

• Una vez que se tienen los patrones en la empresa y se los aplica y la gente los conoce se pueden crear:– Herramientas de generación de código– Revisiones más ligeras aumentando la velocidad de desarrollo– Actualizar el software de manera más sencilla– No dependencia en los programadores

Generadores de código

Una pequeña aplicación con una DAO

Objetivo

• Las necesidades para el ejercicio son:

– Crear una librería de acceso a datos profesional

– Manejando concurrencia

– ABM de registros vistos como objetos

– Posible migración a otra base de datos o archivos no debe ser un problema

Modelo base

• Patrón de diseño J2EE DAO• http://java.sun.com/blueprints/corej2eepatterns/P

atterns/DataAccessObject.html

Modelo base – Abstract Factory

Resultado esperado

• Agregando un singleton a nivel del Factory se puede tener un patrón para consultas:

• Este patrón– No depende de la base de datos y no es necesario conocer la

manera en que el DAO ha sido implementado

Factory factory = Factory.getOrCreate();PersonaDAO dao = factory.nuevoPersonaDAO();

Persona dto = dao.seleccionar(4);dto.Nombre = “pedro”;

dao.actualizar();

Modelo extensible Objeto

Modelo extensible DAO

Generando…

Et voilà!!

FactoryDAO factory = FactoryDAO.Instancia;PersonaDAO dao = factory.newPersonaDAO();Persona dto = dao.nuevo();

dto.Nombre = txtNombre.Text;dto.Numero = Convert.ToInt32(txtNumero.Text);dto.Salario = Convert.ToDouble(txtSalario.Text);

dao.actualizar();

MUCHAS GRACIAS