Seguridad y Protección a nivel web.

Iniciado por Xt3mP, Agosto 14, 2010, 12:05:44 AM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Agosto 14, 2010, 12:05:44 AM Ultima modificación: Agosto 23, 2010, 10:31:26 PM por Xt3mP
Protección y seguridad a nivel web, versión 1.

He visto por hay varios temas (no solo en este foro) en donde el punto príncipal es la seguridad web "parchando" así las posibles fallas que pueda tener la programación y/ó la estructuración del sitio, es lamentable ver (al decir lamentable me refiero a que no es bueno) que explican como parchar la vulnerabilidad (ó al menos la mayoría) pero no explican el porque de la vulnerabilidad. (Es como querer enseñar a un niño a correr cuando todavía no sabe caminar), por lo tanto mi punto es: explicar "PORQUE" existe ó se puede llevar a cabo la vulnerabilidad y una vez explicada, explicar como parcharla.

Cabe mencionar que no explicaré ni diré todas las vulnerabilidades a nivel web por tres razones:
1- Falta de tiempo.
2- No puedo hacer un post demasiado largo, perdería el toque, en próximas versiones tál vez explique otras.
3- Al aprender el porque y como parchar unas cuantas, estoy seguro que cuando encuentren otra en su sitio web sabran parcharla.

Por lo que solo explicaré las más "comúnes/típicas".
------------------------------------------------------------
XSS/HTML Injection
------------------------------------------------------------
XSS (Cross Site Scripting), se le denominó XSS para no confundir con las hojas de estilo (CSS), la vulnerabilidad se explota mediante la inyección de código "script/scripting" en alguna variable tanto POST como GET.

HTML Injection (Inyección HTML), la vulnerabilidad se explota mediante la inyección de código (príncipalmente HTML) en alguna variable tanto POST como GET.

¿Qué tienen de diferencia? Que XSS hace correr script (Ej: <script>alert('XSS');</script>) y por otro lado, HTML Injection hace correr tags literalmente (Ej: <marquee>HTMLi</marquee>, <table></table>, <iframe></iframe>, etc).

Puse las dos juntas en el mismo subtítulo ya que la forma en que se pueden parchar se pueden utilizar para las dos. Tomaré de ejemplo el siguiente "buscador":

Código: php

<?php
$buscar = $_GET['buscar'];
echo "La busqueda de: ".$buscar." no encontro ningun resultado";
/*
En donde si ponemos tanto script como tags se ejecutaria en la misma pagina
*/
?>


Entonces, ¿Como se parcharían estos tags? PHP te brinda 3 funciones escenciales, las cuales son strip_tags(), y htmlentities().
strip_tags() = Elimina las etiquetas de los tags (<h1>test</h1> = test);
htmlentities() = Obtiene los tags de la inyección y evita que se ejecute. (<h1>test</h1> = <h1>test</h1>);

Pueden utilizar cualquiera

Podemos hacerlo directamente:
Código: php

<?php
$buscar = strip_tags(htmlentities($_GET['buscar']));
echo "La busqueda de: ".$buscar." no encontro ningun resultado";
/*
En donde si ponemos <h1>Vulnerable</h1> votaria exactamente:
La busqueda de: <h1>Vulnerable</h1> no encontro ningun resultado

En donde si ponemos <table border="0"> votaria exactamente:
La busqueda de: <table border=\"0\"> no encontro ningun resultado
Como se puede apreciar ya no se ejecutaron los tags.
?>


Generalmente se utiliza una inyección HTML solo para fastidiar al programador, por otro lado, con XSS se pueden hacer cosas interesantes como el robo de cookies, la verdad no pretendo enseñarles a como llevar acabo una vulnerabilidad si no como parcharla, así que les daré solo un breve ejemplo de un robo de cookies:

Nota: No explicaré mediante código esta vulnerabilidad ya que no se trata de "incitarlos" a que lo hagan, si no a parcharlo.

Un robo de cookies mediante XSS se caracteriza (su nombre lo dice todo) por "inyectar" en la vulnerabilidad mediante script un código que al ser enviado (en este caso a un supuesto administrador) y dar click en el enláce, automáticamente se envía un correo (esto depende de la página atacante) con la cookie del Administrador, posteriormente con algun editor de cabezeras (el mejor para mi es Tamper DATA) se cambia la cookie de sesión nuestra por la que obtuvimos por el administrador y listo, sesión de Administrador robada:

Citar
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta<script>window.location='No tienes permitido ver los links. Registrarse o Entrar a mi cuenta</script>

Ya solo es cuestión de agarrar la variable "cookie" en este caso y guardarla (tanto en .txt como correo), solo sería cuestión de disfrazar y meterle ingeniería social, y para parcharlo con las funciones de arriba se lleva acabo.
Es algo interesante este par de vulnerabilidades ya que sabiendo utilizarlas se puede hacer algo de daño, así que si son vulnerables, es hora de que lo dejen de ser.
------------------------------------------------------------
SQL Injection
------------------------------------------------------------
SQL Injection [Inyección SQL (Structured Query Language)], se caracteriza por no filtrar la petición a la base de datos conllevando con esta, un error en la implementación del valor a "pedir" y así exponiendo el código, es decir, que gracias a una mala estructuración/programación del código para hacer una petición (no filtrar las variables) se puede explotar dejando así toda la base de datos a la vista del atacante.

Aquí entra algo de polémica, la mayoría solo cree que una inyección SQL siempre será: -1+SELECT+UNION+1,2--, pero nó, existen muchos tipos de inyecciones SQL pero en este caso indicarémos como parchar la "típica".

Un ejemplo de una mala estructuración es (es parecida al error de la vulnerabilidad XSS/HTMLi), suponiendo que el link seria No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
Código: php

<?php
include("connect.php"); //Conexion a la base de datos
$id = $_GET['id']; //Obtenemos el ID
$query = mysql_query("SELECT * FROM noticias WHERE id=".$id." "); //Hacemos la peticion
/*
web.com/noticia_id.php?id=-1 pediria la peticion como:
$query = mysql_query("SELECT * FROM noticias WHERE id=' ")
Y mostraria un error como este:
You have an error in your SQL syntax; check the manual that corresponds toyour MySQL server version for the right syntax to use near '' at line 1
*/
?>


Daría error, entonces al intentar acceder como (-1+UNION+SELECT+1) daría:
Citar
The used SELECT statements have a different number of columns

Entonces así podemos ir explotando la vulnerabilidad hasta obtener datios valiosos (en una experiencia personal, logré obtener cerca de 5000 tarjetas de crédito).

Viene lo agradable ¿Como parcharla? como se han dado cuenta, se lleva acabo por una mala petición en el código, entonces así como PHP nos brinda funciones para filtrar, SQL tiene una por su lado que es mysql_escape_string() que con este filtraremos el GET, tambien podemos comprobar que exista la noticia antes de mostrarse, este sería el código:

Código: php

<?php
include("connect.php"); //Conexion a la base de datos
$id = strip_tags($_GET['id']); //Obtenemos el ID

if (is_numeric($id)){ //Comprobamos que sea numerico

$query = mysql_query("SELECT * FROM noticias WHERE id=".mysql_escape_string($id)." "); //Hacemos la peticion

if ($row = mysql_fetch_array($query)){ //Comprobamos que exista
echo "Noticia: ".$row['titulo']."<br />";
}else{
echo "La noticia no existe";
}
}else{
echo "La noticia no existe";
}
?>


¿Qué hacemos? Incluímos la conexión a la base de datos, obtenemos el ID por GET y lo filtramos, comprobamos si es númerico el ID, hacemos la petición filtrada con mysql_escape_string(), comprobamos que exista la noticia, por otro lado, si no es númerico ó no existe la noticia te marcará un error (echo...).
Así de sencillo parchamos (ó mejor dicho, hacemos menos posible la vulnerabilidad) SQL Injection.
------------------------------------------------------------
Full Path Disclosure
------------------------------------------------------------
Esta vulnerabilidad en lo personal me agrada, ¿Por? Porque por un pequeño error en el código te muestra el "Full Path", es decir, con un error que nos tire te muestra todos los paths por donde pasa el script, generalmente sucede en descargas ya que no filtramos muy bien la ruta de los archivos y dejamos al descubierto todos los directorios, por ejemplo:

Suponiendo que nuestra página tiene un link para descargar los archivos que nosotros indiquemos, algo como:
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Entonces como vemos hace un "query" prácticamente al archivo a descargar, pero que sucede si nosotros recorremos el path con los comandos que tál vez conozcas (.. , ., etc) para recorrer ó avanzar directorios, quedaría algo así:

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Citar
Warning: fopen(testing) [function.fopen]: failed to open stream: No such file or directory in
/var/www/name/html/descargar.php on line 5

Y como vemos, en este caso es "/var/www/name/html/admin/", cuando una web es vulnerable, el atacante comúnmente busca el archivo /etc/passwd por default, entonces la url quedaría:

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

En donde cada ../ es una carpeta anterior, todo depende de donde este situado esta vulnerabilidad, te preguntarás, ¿Pero en qué nos afecta?
En que si nosotros ingresamos por (suponiendo que tengamos una carpeta llamada admin):

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Se nos descargaría el "Script" completo del admin y sería cuestión de ir jugando con los archivos para ver que otras vulnerabilidades tienen.

¿Como parchar? Para wordpress existe (este código no es mío, pero esta muy conocido en la red):

Citar
if(function_exists('add_action')) {
[...]
}

Y por mi parte las recomendaciones serían:

1.- Evitar mostrar el error en pantalla, tanto modificando el php.ini como editando todo archivo para que no muestre error, ó bien agregando error_reporting(0);
2.- Si haran descarga de archivos "web.com/descargar.php?file=" sería preferible que mejor pongan:
2.1- Descargas directas: No tienes permitido ver los links. Registrarse o Entrar a mi cuenta"
2.2- Hacer un array ó switch para cada "case" y no poner directamente el nombre (archivo.php) si no alguna abreviación como
web.com/descargar.php?file=videos_anio_nuevo y ya con un "file_exists()" comprobamos la existencia del archivo.
3.- Si bien deciden dejar el script así, pueden implementar un código más ó menos de esta manera para fijar el directorio en una carpeta en específico y comprobar la existencia de este, claro esta, tambien sustituímos los carácteres (".","/") que son los usuales en estos casos:

Código: php

<?php
$file = str_replace(array('.','/'),'',$_GET['file']);
$file = "./".$file; //Indicamos con el ./ que el fichero debe encontrarse en el mismo directorio.
if (!file_exists($file)){
echo "No intentes bugear";
}else{
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$file\"\n");
$filepath=fopen("$file", "r");
fpassthru($filepath);
}
?>

------------------------------------------------------------
RFI/LFI
------------------------------------------------------------
RFI (Remote File Inclusion), consiste en como su nombre lo dice, incluír archivos remótamente en el servidor.
LFI (Local File Inclusion), consiste en como su nombre lo dice, incluír archivos localmente en el servidor.

Estas vulnerabilidades antes eran muy típicas, pero conforme PHP fue avanzando de versión fueron "más díficiles" encontrarnos con una.
Lo explicaré brevemente ya que es parecido lo mismo que Full Path Disclosure.

Para RFI:
Suponiendo que tenemos una página llamada No tienes permitido ver los links. Registrarse o Entrar a mi cuenta y tenemos un código parecido a este:
Código: php

<?php
$file = $_GET['path'];
include ($path);
?>


Como se observa, incluímos directamente el GET sin filtrarlo ni comprobar que exista, entonces ¿Por qué les puede perjudicar?
Si yo en su página hago No tienes permitido ver los links. Registrarse o Entrar a mi cuenta ¿Que pasaría? Se incluiría en su página mi script malicioso y tendría acceso a todo su servidor/hosting ocasionando que yo pueda malusa resta vulnerabilidad y destrozarles su página (cosa que nunca hago).

Para LFI:
Suponiendo que tenemos la misma página, pero ahora si filtramos el archivo y comprobamos que exista de esta manera:
Código: php

<?php
$file = $_GET['path'];
if (file_exists($file)){
include ($path);
}else{
echo "No intentes buggear";
}
?>


Aquí pasaríamos de nuevo con el Full Path Disclosure, comenzamos a "navegar" con "../" , "./" hasta encontrar algún archivo vulnerable y comenzar a atacar.

¿Como parcharlo?
Esta manera que explicaré será para las dos vulnerabilidades:
Código: php

<?php
$file = str_replace('/','',$_GET['path']);
$file = "./".$file;
if (file_exists($file)){
include ($path);
}else{
echo "No intentes buggear";
}
?>


Como se observa, se utilizó "casi" la misma manera de parchar el Full Path Disclosure, solo es cuestión de que analizen su código línea por línea.
------------------------------------------------------------
Tips
------------------------------------------------------------
Les daré un par de tips para hacer segura su web que en lo personal me han servido de mucho:
1.- Si se trata de sesiones, comprobar en "cada página" que solo usuarios autorizados puedan acceder.
2.- Filtrar todas y cada una de las variables.
3.- Generar "errores" marcados por nosotros, por ejemplo:

Código: php

<?php
$error = array('Error de existencia', 'Error numerico');
if (file_exists($archivo)){
//Todo el codigo
}else{
$file = fopen("error.txt", 'a+'); //Permisos de escritura y lectura con a+
fwrite($file, '
Error: '.$error[0].' a las: '.date('r').' de la IP: '.$_SERVER[REMOTE_ADDR].'\n');
fclose($file);
}

if (is_numeric($id)){
// Todo el codigo
}else{
$file = fopen("error.txt", 'a+'); //Permisos de escritura y lectura con a+
fwrite($file, '
Error: '.$error[1].' a las: '.date('r').' de la IP: '.$_SERVER[REMOTE_ADDR].'\n');
fclose($file)
}
?>


4.- Evitar mostrar errores en pantalla mediante "@" ejemplo:

Código: php

<?php
$file = @fopen('index.php','a+');
@fwrite($file, 'Xt3mP');
@fclose($file);
?>


5.- Entre otros
------------------------------------------------------------
Espero que este manual les haya aclarado muchas dudas, y para los que digan que ya existen otros noten la diferente entre "Como hacerlo/Parcharlo" y "Porque sucede eso".
P.D: En la próxima versión hablaré sobre otras vulnerabilidades, entre ellas asp injection.
P.D.2: Si se me paso algo ó escribe algo mal fue porque lo escribí continuamente sin descansar y a veces se confunde uno.
Saludos.
------------------------------------------------------------
Cada vez que me das Karma me motivas

Muy bueno Xt3mP, resolvió algunas dudas sobre este tema del cual no estoy muy enterado.

Gracias

Perfecto, en nuevas versiones hablare sobre Flash, ASP, entre otras, saludos.
Cada vez que me das Karma me motivas

Buenas, muy buenas las ganas que le hechas para hacer este tutorial y muchos mas, es bueno tener personas así en el foro xD.

Hablando del tutorial, tienes algunas malas definiciones pero no cosa del otro mundo...




Citar

htmlentities() = Obtiene los tags de la inyección y evita que se ejecute. (<h1>test</h1> = <h1>test</h1>);
Lo que hace No tienes permitido ver los links. Registrarse o Entrar a mi cuenta es cambiar los caracteres a su entidad HTML, si se establece como segundo parámetro ENT_COMPAT a la función, convertirá también las comillas simples y dobles a entidades html.

Ejemplo:

Código: php
<?php
echo htmlentities('<script>alert("Hola")</script>', ENT_QUOTES);
?>

Salida:
Código: php

&lt;script&gt;alert(&quot;Hola&quot;)&lt;/script&gt;





Lo que se trata de hacer con inyección SQL, es tratar de manejar la consulta SQL...

Ejemplo...
Código: php
SELECT * FROM noticias WHERE id=".$_GET['id']." 


Y el parámetro id tiene como valor la consulta SQL siguiente:
Código: sql
1 union select 1,user()


Se ejecutara la siguiente consulta SQL
Código: sql
 select * from nombres where id=1 union select 1,user()


Osea, intento combinar la consulta...

Ejemplo:
Código: sql

mysql> select * from nombres where id=1 union select 1,2;
+----+--------+
| id | nombre |
+----+--------+
|  1 | edwin  |
|  1 | 2      |
+----+--------+
2 rows in set (0.00 sec)

Código: sql
mysql> select * from nombres where id=1 union select 1,nombre from nombres;
+----+--------+
| id | nombre |
+----+--------+
|  1 | edwin  |
|  1 | Antrax |
|  1 | jesus  |
|  1 | jose   |
|  1 | Xt3mP  |
+----+--------+
5 rows in set (0.00 sec)


mysql>





Para evitar LFI, simplemente hay que hacer includes seguros.

Ejemplo:
Código: php
<?php
if($_GET['index']){
include('index.php');
}


?>


Saludos.
Mi madre me dijo que estoy destinado a ser pobre toda la vida.
Engineering is the art of balancing the benefits and drawbacks of any approach.

Lo de la definición me referia a que te los mostrará, es bueno saber quien te quiere jugar un poco :P y si como dice en el texto:
<h1>test</h1> sacaría <h1>test</h1>, es decir, que no interpretará el código pero lo sacaría con el mismo formato, es divertido (como dije arriba) saber quien te quiere jugar xD.

Sobre la inyección SQL dijiste:
Citarselect * from nombres where id=1 union select 1,user()

Y yo dije:
Citar$query = mysql_query("SELECT * FROM noticias WHERE id=' ")

En donde el ' es lo que obtuvimos del path, pero como en el ejemplo no escribí id=1+union+select si no que escribí solo una comilla simple, por eso el query de ejemplo lo puse con la comilla.

Así que como escribiste, tál vez me expliqué mal o lo malentendiste, pero me referia a exáctamente lo mismo que tú.

Sobre LFI:

Código: php
<?php
$file = str_replace('/','',$_GET['path']);
$file = "./".$file;
if (file_exists($file)){
include ($path);
}else{
echo "No intentes buggear";
}
?>


Creo que hay queda mas que claro que es un include seguro, eliminamos posibles carácteres, comprobamos que exista el archivo y luego incluímos, pero igual saludos y gracias por tu comentario brother, hasta pronto.

P.D. Ya vi donde dices:
CitarNo tienes permitido ver los links. Registrarse o Entrar a mi cuenta pediria la peticion como:
$query = mysql_query("SELECT * FROM noticias WHERE id=' ")

Solo fue un error de dedo y me confundí por eso puse la comilla simple, saludos.
Cada vez que me das Karma me motivas

No tienes permitido ver los links. Registrarse o Entrar a mi cuenta
Sobre LFI:

Código: php
<?php
$file = str_replace('/','',$_GET['path']);
$file = "./".$file;
if (file_exists($file)){
include ($path);
}else{
echo "No intentes buggear";
}
?>


El problema de ese source, esque solo puedes hacer include en los archivos que se encuentran en el mismo directorio, osea si necesito hacer un include a un archivo que se encuentra en una carpeta del DOCUMENT_ROOT, no podre hacerlo...




evitar mostrar errores en pantalla mediante "@"...

Tambien se puede usar la funcion No tienes permitido ver los links. Registrarse o Entrar a mi cuenta o también puedes desactivar la directiva No tienes permitido ver los links. Registrarse o Entrar a mi cuenta del php.ini, viene desactivada en PHP 5.3.2.



Si fuera ANTRAX, fueras moderador de PHP, ya que les pones muchas ganas, pero eso dependería si le haces el tutorial al foro...

Saludos.
Mi madre me dijo que estoy destinado a ser pobre toda la vida.
Engineering is the art of balancing the benefits and drawbacks of any approach.

Lo sé, pero en este caso di de ejemplo descargas de ficheros que estarían en el mismo directorio, por eso situé antes el "./" para forzar literalmente que el archivo se encuentre en el mismo directorio, obviamente el usuario si tiene digamos otro path cambiaría el "./" por "./path/" ó conforme lo necesite, pero igual gracias así el usuario que se confundió sabe que puede cambiar esa parte del código.

Sobre el mostrar error, claro esta que modificando el php.ini, de hecho lo dije en esta línea del texto:

Citar1.- Evitar mostrar el error en pantalla, tanto modificando el php.ini como editando todo archivo para que no muestre error, ó bien agregando error_reporting(0);

Y sobre moderador PHP, pertenezto al Team de Ash-Team y tengo permisos de administrador, ayudo en lo que puedo, saludos brother, se ve que eres buena persona.

ByeOFF.
Cada vez que me das Karma me motivas