22 de octubre de 2009

Server casero

Para explicar como montar un servidor casero primero voy a esplitar unos cuantos conceptos basicos a grandes rasgos.

Dirección IP:
La dirección IP es la dirección de nuestro equipo en la red. Es como la dirección de nuestra casa. La dirección IP es una dirección numerica que nos identifica de forma unica.

IP Dinamica:
Cuando comenzó internet las ISP daban una IP fija a cada uno de sus clientes. Pasado el tiempo las ISP tenian más clientes que IPs.
Durante IP fija las ISP observaron que muchos de sus clientes no siempre estaban conectado, por tanto pensaron que cuando un cliente no estubiera conectado podrían dar esa IP a otro cliente que se fuera a conectar en ese momento. De este modo el numero de IPs que tiene un ISP es menor que el numero de clientes ya que por ejemplo con 10 IPs podrían dar servicio a 20 clientes; siempre que como maximo no estenc conectados más de 10 clientes a la vez.

Dominios:
Dado que memorizar una lista de numeros es complicado para las personas, se crearon los nombres de dominios. El nombre de dominio no es más que un texto que referencia un IP. Una misma IP puede tener distintos nombres de dominios. Para poder saver sus equivalencias se usan los servidores DNS(Domain Name Server).
Cuando queremos acceder a una web como "http://rollanwar.net" hacemos una pregunta a un servidor DNS que nos responde la dirección por ejemplo "101.121.141.161" y tras conocer su dirección realizamos la conexión.

NAT:
El nat es una tabla que se raliza cuando varios equipos van ha salir a internet con una misma IP. Consiste en asignar IPs locales a puertos externos.
Me explico, cuando A (host local) se conecta con B (host externo), A hace una petición a su router R para conectarse con B. A se conecta por el puerto 29023 al puerto 80 de B, pero R que esta en medio y es quien realiza la conexión con el exterior y puede cambiar el puerto que ve B. De este modo queda una cosa así:
- A ver: A:29023 -> B:80
- B ve: B:80 -> R:23456
Para A, R es un punto más del recorrido hasta B, pero B no conoce a A, sino que habla con el puerto 23456 de R (quien tiene la IP publica). R save que la conexión al puerto 23456 le pertenece a la IP de A y al puerto 29023 y lo que llege por ahi se lo manda.

Bueno vamos a empezar un poco a montar nuestro servidor casero.
Lo primero que necesitamos es un nombre de dominio. Para poder tener un identificador facil de recordar y que no cambie, ya que nuestra IP si que lo hace.
Existen varios servicios que nos permiten desde ir modificando la IP de nuestro dominio de forma automatica.
Si el servicio esta en el Router el router cuando cambie de IP mandará un mensaje al servidor DNS actualizando la IP.
Si el servicio esta en un pc de la red ira realizando latidos cada X tiempo para que la IP sea actualizada si cambia.
Los dos servicios gratuitos más conocidos en este respecto son: no ip y dyndns.

Una vez activo este servicio en nuestro router o host ya tenemos nuestro dominio que nos dará siempre nuestra IP aunque esta cambie.

Ahora tenemos nuestro dominio por ejemplo "http://mi-host.casero.es" que nos da la IP publica de nuestro router. Pero si intentamos acceder a el dominio este nos rechaza las conexiones. Esto es porque tenemos que configurar una tabla de nat estaticamente, de este modo todas las peticiones que se llegen a un puerto se dirigiran directamente el host donde queramos.

Resumen:

  1. Tener una cuenta en un servidor DNS dinamico.

  2. Configurar el router o pc para que modifique nuestro servidor DNS.

  3. Abrir los puertos al router para añadir parte estaticas a la tabla NAT.

19 de octubre de 2009

DoS en Wordpress via TrackBackr

¿Que es TrackBack?


TackBack es un sistema de notificación de mención, es decir, sirve para saver quien ha mencionado o escrito sobre tu post.

¿Como funciona TrackBack?


Para informar al blog de que se escribe sobre lo primero es que tiene que tener el sistema de TrackBack.

Mandaremos a una petición POST al sitio que vamos a mencionar. La patición HTTP seria algo así:
POST http://www.example.com/trackback/ID
Content-Type: application/x-www-form-urlencoded; charset=utf-8

title=Mencion+sobre+ID&url=http://www.mi-blog.com/mencion&excerpt=Mi+Entrada&blog_name=Mi+blog

Las variables del POST son:

  • url: Direccion del blog permanente de la entrada (Obligatoria)

  • title: Titulo de la entrada (Opcional)

  • except: Nombre de la entrada (Opcional)

  • blog_name: Nombre del blog (Opcional)


La variable charset se encuentra en el valor de la cabecera Content-Type, en el ejemplo utf-8

Como respuesta ha este POST obtendremos lo siguiente en caso de que todo sea correcto:
<?xml version="1.0" encoding="utf-8"?>
<response>
<error>0</error>
</response>

En caso de error:
<?xml version="1.0" encoding="utf-8"?>
<response>
<error>1</error>
<message>Mensaje de error</message>
</response>

Las variable

¿Que errores se cometen?


En el caso del ejemplo anterior basado en uno de las especificaciones en el valor de Content-Type contiene el valor de charset. En Wordpress el valor de charset es obtenido mediante $_POST['charset']. Este error puede ser poco importante si el resto de aplicaciones que se comunican con el lo hacen igual.

El error de denegación de servicio es causado al no filtrar correctamente el valor de la variable charset que es recibido.

Con el valor de este dato se llama a la función mb_convert_encoding() para cambiar el tipo de codificación a la base del datos del blog.
Si se inserta como valor de charset varias codigicaciones separadas por ',' esta llamada se convierte en una operación muy pesada. Si se realizan varias conexiones el servidor atacado se queda rapidamente sin recursos.

Parche


El parche propuesto por el descubridor:
$charset = str_replace(",", "", $_POST['charset']);
if(is_array($charset)) { exit; }

El parche que propongo yo:
if(isset($_POST['charset']))
$charset = $_POST['charset'];
if (is_array($charset))//Si es un array da error
trackback_response("charset is array");
if(strpos($charset, ",") !== false)//Si tiene una , da error
trackback_response("charset have many values");

Referencias:


Especificaciones de trackback
Prueba de concepto
Más datos sobre el DoS

14 de octubre de 2009

Conceptos basicos del sistema de archivos en Linux

Linux trata a todo como ficheros. Una carpeta, un disco duro, un USB, todo son archivos.

Carpetas básicas:


/home -> Fichero de usuario
/boot -> Donde se encuentran los ficheros de arranque.
/usr/local -> Programas de usuario y ficheros usados en los entornos gráficos
/opt -> Carpeta opcional, se usa bastante en Gentoo (para las compilaciones) y en
/var -> Donde se almacena ficheros variables como Syslog o DBs.
/dev -> Donde se encuentran los distintos dispositivos.
/etc -> Donde se encuentran los ficheros de configuración.
/etc/skel -> El contenido de esta carpeta se copia al crear un usuario nuevo
/media o /mnt -> En estas carpetas se suelen montan los dispositivos.
/proc -> En esta carpeta se representan los distintos procesos de Linux.

Tipos de permisos:


Existen tres tipos de permisos lectura, escritura y ejecución (Read-Write-eXecution) representados por "r","w" y "x" respectiva mente.
Si queremos ver los permisos de un fichero deberemos escribir "ls -l" y nos mostrar los permisos ordenados por usuario, grupo y otros.
¿pero que pasa si quiere dar a un usuario permiso, no a su grupo y a otro usuario también permiso?, pues para ello se usa las ACL (Lista de control de acceso) incluidas desde el kernel 2.6 y que se puede compilar para el kernel 2.4 .

Atributos:


Para ver los atributos de un fichero usamos el comando "lsattr"
Para cambiarlos usamos:
chattr SIGNO VALOR FICHERO

i Inmutable, no se puede hacer nada, ni borrar, ni editar, ni hacer un acceso directo, ...
c Comprime en tiempo real los fichero con este atributo
d No deja hacer backup
s Borrar todo, incluso el fichero en el sector de disco (Pone todos los bits a 0)
u Si es eliminado, sus contenidos son guardados permitiendo su recuperación

12 de octubre de 2009

Saca la versión de Wordpress gracias a Gears

Bueno, cuando estuve mirando el error del FPD observé que existía un fichero que mostraba con un contenido demasiado explicito, en un principio pesé que podía ser un fallo por el que se descubriría la versión del wordpress instalada, movido por un dato muy claro:
"version" : "ae52efa2f066ffc235840dc615f051d7"

En ese momento me mosqueo un poco y me puse a buscar. Que diablos era ese fichero con referencias a javascripts.

Resulta que es un fichero usado por Gears, antes Google Gears.

¿Que es Gears? os preguntareis algunos. Pues bien Gears es un programa diseñado en principio por Google y que posteriormente ha liberado para la comunidad. Este es el software que en el que se basa Gmail offline o GoogleDocs offline entre otros. Con estos datos el software se descarga de tu sitio la información para que puedas usarla sin conexión y luego se sincroniza con el servidor.

Pero vamos a lo interesante.

¿Como calcula la versión?


En la versión 2.8.x el calculo se realiza a partir de:
//El generador que da soporte a Gears usa estos datos
md5( $tinymce_version . $manifest_version ) //Como aparece en manifest.php
//Donde:
$tinymce_version = "3241-1141" //Para 2.8.x
//Y
$manifest_version = "20090610" //Para 2.8
$manifest_version = "20090616" //Para v2.8.1 - 2.8.4
//Por tanto:
//En v2.8 podriamos poner
echo '"version" : "068d0a4281fb2a342ba6fd73b6b93982"';
//En v2.8.1-2.8.4
echo '"version" : "ae52efa2f066ffc235840dc615f051d7"';

En las versiones 2.6.x y 2.7.x el valor de $man_version se calcula mediante unas funciones que crean un dato que parece aleatorio; pero bueno eso no es un muy importante ya que se le añade un "_DIGITOS" que nos indica la versión. Haciendo por tanto que el valor de $man_version sea poco relevante.
//En v2.7.x
$man_version = bucles_1($man_version)//Por resumir
$man_version = md5($man_version);
//Podríamos poner algo asi en v2.7.x
echo '"version" : "'."$man_version"."_20081201".'"';
//En v2.6
$man_version = bucles_2($man_version)//Por resumir
$man_version = md5($man_version);
echo '"version" : "'."$man_version"."_20080710a".'"';
//En v2.6.1 - 2.6.5
echo '"version" : "'."$man_version"."_20080810".'"';

Lo curioso del caso es que según las especificaciones de Geads el valor de "version" es un String, que solo indica si ha cambiado o no el contenido del fichero. Por tanto sería igual de valido hacer un md5 de la fecha de la ultima actualización si es que esta actualización cambiase el valor de este fichero. O incluso lo que seria más óptimo, cuando se instalase el blog se creara un fichero estático y se modificara en caso de ser necesario en vez de estar generandose continuamente con cada petición.

Pero aun hay algo más, dado que en los datos mostrados existe más información sobre versiones de los distintos ficheros js, podríamos obtener más diferencias.

En la versión 2.7 thickbox.js?ver=3.1-20080430

En la versión 2.7.1 thickbox.js?ver=3.1-20090123

Si en el caso de 2.7.x hay que mirar en "thickbox", en las versiones 2.6.x lo tenemos aún más fácil, ya que podemos encontrar varios sitios donde viene directamente la versión, por ejemplo, wp-admin.css?ver=2.6.x entre otros.
//Parte del código de gears-manifest.php en la versión 2.6.1
foreach ( $wp_scripts->registered as $script ) {
if ( empty($script->src) || strpos($script->src, 'tiny_mce_config.php') ) continue;
$ver = empty($script->ver) ? $wp_version : $script->ver; //Aquí en ocasiones se incluye la versión
$src = str_replace( array( '/wp-admin/', '/wp-includes/' ), array( '', '../wp-includes/' ), $script->src );
$defaults .= '{ "url" : "' . $src . '?ver=' . $ver . '" },' . "\n";
$man_version .= $ver;
}

Conclusiones


Aunque en principio podría haber parecido un vector claro para conocer la versión del Wordpress, parece que en las versión 2.8.x estos datos claros se han eliminando.

Aún así en la versión actual sigue dejando un claro punto para saber si la versión en cuanto cambien los valores de $tinymce_version o $manifest_version.

Bajo mi punto de vista, como ya he dicho antes, modificaría el modo de crear el valor de "version" y lo convertiría en un dato aleatorio, que solo cambien cuando sea necesario.
De este modo un posible atacante solo sería capaz de conocer si un wordpress se ha actualizado conociendo el valor anterior de "version" si esa actualización cambiara este dato, hecho que no siempre ocurre.

Referencia:
Tutorial de gears
Arquitectura de gears
Aplicaciones disposibles

11 de octubre de 2009

Lista de Password

Tras leer en varios sitio sobre la publicación de más de 10.000 contraseñas de cuentas de correo, y tras confirmar por distintas fuentes que las contraseñas suelen ser las mismas y que en su mayor parte son simples de sacar con un ataque de fuerza bruta por diccionario, me he propuesto hacer un diccionario ordenado por probabilidad de aparición de las contraseñas.

Se que existen infinidad de diccionarios en muchos sitios (http://passwords.openwall.net) pero yo quiero crear uno bastante reducido, para tardar a menos y realizar el menor numero de intentos posibles.

¿Porque usar diccionarios?


Existen varias razones pero las dos principales son estas:

  • La primera es la más clara, intentar probar todas requiere demasiado tiempo. El calculo es simple, simplemente hay que hacer la variación con repetición. He realizado un test empírico de un algoritmo que calcula 10000 contraseñas (solo números) tarda 0.047 segundos y por tanto en generar y probar un millón vamos a suponer que tarda 5 segundos; con estos cálculos aproximados veamos la siguiente tabla:

    Tamaño Posibles (85)Tiempo (85) Posibles (26)Tiempo (26)
    4 caracteres52 millones4,33 minutos456.9762,28 segundos
    5 caracteres4.437 millones6,16 horas11 millones59,40 segundos
    6 caracteres377.149 millones21,83 días308 millones25,74 min
    7 caracteres32 billones5,07 años8.031 millones11,15 horas
    8 caracteres2.724 billones4,31 siglos208.827 millones12,08 días
    9 caracteres231.616 billones36,6 milenios5 billones10,47 meses
    10 caracteres19 trillones3010 milenios141 billones22,69 años
    11 caracteres1.673 trillones265070 milenios3.670 billones5,9 siglos

    NOTA: 2x(26 Letras + ñ) + (21 caracteres especiales [!|"@.#$~%&/()=?¿'*+] ) + (10 digitos) = 85
    Como se observa en la tabla cuando la contraseña tiene más de 5 caracteres el tiemplo empleado para obtener la contraseña es de más de una semana, tiempo de sobra para ser detectados sin problema.

  • Otra de las razones por las que realizar un diccionario está relacionado con el modo que tenemos de recordar las personas. Dado que recordar "E46!fhJd9@" nos resulta muy complicado usamos otras contraseñas simples de recordad, normalmente palabras que existen. Por tanto podemos reducir el número de intento a tantas como palabras hay en el diccionario, más de 160 mil palabras según la rae, lo que reduce en numero de posibles claves.Lo mejor a la hora de usar diccionarios es realizar uno personalizado para cada objetivo, no es igual intentar sacar el password de un ingles o americano que de un egipcio o un español, ya que las palabras que usarán serán distintas.


Creación del Diccionario


Para crear mi diccionario he cogido los datos desde los siguientes sitios:

  1. Top 10 contraseñas de PC Magazine

  2. Contraseñas más usadas de las publicadas de "Flirtlife.de"

  3. Contraseñas más usadas en las publicadas de "Hotmail.com"

  4. Contraseñas por defecto de los Routers


Para que me resultara más simple la creación del diccionario he programado en python un simple código para ordenar:
'''
Programa que descarga y ordena las contraseñas más por defecto de los routers
@author: ehooo
'''

import httplib, os
from HTMLParser import HTMLParser
class ParseTable(HTMLParser):
'''
Parser para obtener los datos de la columna indicada
'''

def __init__(self, columna):
HTMLParser.__init__(self)
self._columna = columna
self._colAct = 0
self._data = False
self._fin = True
self.lista = {}

def handle_data(self, data):
if self._data:
dato = str(data)
if dato in self.lista:
self.lista[dato] += 1
else:
self.lista[dato] = 1
self._data = False

def handle_starttag(self, tag, attrs):
if self._fin:
if tag == "table":
self._fin = False
elif tag == "tr":
self._colAct = 0
elif tag == "td":
if self._colAct == self._columna:
self._data = True
self._colAct += 1

def handle_endtag(self, tag):
if self._fin:
pass
elif tag == "tr":
self._colAct = 0
elif tag == "table":
self._fin = True

if __name__ == '__main__':
conn = httplib.HTTPConnection("www.phenoelit-us.org")
conn.request("GET", "/dpl/dpl.html")
res = conn.getresponse()
if res.status == httplib.OK:
html = res.read()
p = ParseTable(5)
p.feed(html)
lista = p.lista
n_elem = len(lista)
list = {}
try:
while True:#Cuando se queda sin elementos lanza una Excepcion "KeyError"
(key, valor) = lista.popitem()
if valor in list:
list[valor] += ", "+str(key)
else :
list.setdefault(valor, str(key))
except(KeyError):
valores = list.keys()
valores.sort()
valores.reverse()
ord = []
for valor in valores:
ord += [list[valor]]
elem = 0
for passwords in ord:
porcentaje = (valores[elem]* 100) / n_elem
print valores[elem],"de",n_elem,"son",porcentaje,'% ->',passwords
elem += 1
else:
print "ERROR en la descarga"

La lista que he obtenido ha quedado reducida ha 46 palabras, cogiendo las más comunes de los routers y de las personas; eliminando ciertas passwords sin demasiada relevancia. Puedes descargar el diccionario desde http://rollanwar.net/pass+usados.txt. De todos modos puedes crear el diccionario de routers usando parte del código publicado.

Otros datos de interés:
http://onemansblog.com/2007/03/26/how-id-hack-your-weak-passwords/

10 de octubre de 2009

Nuevo 0 day en Adobe Reader y Acrobat

Reciente mente ha sido publicado en la Una Al Día de Hispasec sistemas la noticia de la existencia de una vulnerabilidad que ha sido catalogada por Adobe como critica. El texto dice lo siguiente:
---
Se ha publicado un anuncio oficial de Adobe que informa sobre la existencia de un grave problema de seguridad que permite a un atacante remoto ejecutar código arbitrario a través de vectores no especificados. El fallo está siendo aprovechado activamente por atacantes.

Los productos afectados son Reader y Acrobat en las versiones 9.x y 8.x para Windows, Macintosh y UNIX y en las versiones 7.x en sistemas Windows y Macintosh.

Adobe ya ha anunciado que el CVE asignado será CVE-2009-3459 y que este error será solucionado en su siguiente boletín trimestral de actualizaciones que se espera para el 13 de este mes.

Se recomienda desactivar JavaScript en los documentos PDF para mitigar en la medida de lo posible los ataques y si se tiene Windows Vista con la versión 9.1.3, activar el sistema DEP (Prevención de ejecución de datos) puesto que aprovecha esta característica del sistema operativo.

Recomendamos, si es posible, usar otro lector de archivos PDF hasta que se solucione el fallo. Aunque no estén exentos de contener problemas de seguridad, al menos por ahora no son objetivo claro de atacantes. Hay un buen puñado donde elegir para todas las plataformas en: http://pdfreaders.org/
---
FUENTE: UAD HISPASEC Sistemas

5 de octubre de 2009

Recuperación de sistema Linux

Cuando se nos olvida la contraseña de root en un sistema Linux salvo que tengamos otro usuario con los mismos privilegios (lo cual no esta recomendado en absoluto) perderemos el control del sistema.

Para recuperarlo podríamos lanzar un exploit de elevación de privilegios contra nuestra propia maquina y conseguir una consola de root, pero si el sistema está actualizado y se actualiza con regularidad entontrar un exploit que podamos lanzar será bastante complicado por no decir que no lo coseguiremos, además tampoco es una solución esperar a que aparezca uno para poder usarlo.

Pensando en que se nos puede olvidar la contraseña de root los sistemas Linux nos permite cambiarla para evitar tener que reinstalar todo el sistema.

Para poder hacer esto tendremos que tener acceso fisico al sistema y seguir los siguientes pasos:

1. Cuando arranque el GRUB pausamos el arranque y pulsamos "e" (edit).
No aparecera una pantalla con los distintos modos de arranque.
2. Seleccionamos el que aparece con "root=DISCO ro" (read only) y pulsamos "e" para editar.
3. Cambiamos "ro" por "rw" (read and write) para poder hacer que se guarden los cambios.
4. Añadimos "init=/bin/sh" esto nos mostrara una consola al arrancar, recordar no poner nada despues de esto.
5. Por ultimo arrancamos pulsando "b" (boot).
Ahora hemos entrado como root, como se ve por la prom #
6. Para cambiar la contraseña escribimos "passwd" y ponemos la contraseña nueva.

Y listo ya tenemos nueva contraseña de root en nuestro sistema.

NOTA: DISCO será un disco contenido en /dev

Obtencion de informacion de las DNS usando nslookup

Para obtener la información de una web usando un servidor de DNS usaremos la utilidad “nslookup”.
Del siguiente modo:
1.Ejecutamos el lookup para dns
C:\> nslookup
Servidor predeterminado: 192.168.1.1
Address: 192.168.1.1

2.Nos informamos de los datos que tenemos de la web de la que queremos sacar la información
> SITE.COM
Servidor: Unknown
Address: 192.168.1.1
Respuesta no autoritativa:
Nombre: site.com
Address: 74.125.XX.XX, 216.239.XX.XX, 72.14.XX.XX

Podemos observar la linea que dice “Respuesta no autoritativa:” lo que nos indica que no es la autoridad que conoce todos los datos sobre dicha web.

3.Pedimos que nos de la información sobre quien es la identidad que sabe dicha información
> set type=NS
> SITE.COM
Servidor: Unknown
Address: 192.168.1.1
Respuesta no autoritativa:
site.com nameserver = ns1.site.com
site.com nameserver = ns2.site.com
site.com nameserver = ns3.site.com
site.com nameserver = ns4.site.com
ns1.site.com internet address = 216.239.XX.XX
ns2.site.com internet address = 216.239.XX.XX
ns3.site.com internet address = 216.239.XX.XX
ns4.site.com internet address = 216.239.XX.XX

4.Nos conectamos al servidor DNS principal de la web para que nos de todos los datos sobre la web que queremos investigar.
> server ns1.site.es
Servidor predeterminado: ns1.site.com
Address: 216.239.XX.XX

5.Como ahora estamos conectados al servidor que tiene toda la información sobre la web que queremos informarnos y pedimos todos los datos que tanga.
> set type=all
> site.com
Servidor: ns1.site.com
Address: 216.239.X.XX
site.com
primary name server = ns1.site.com
responsible mail addr = dns-admin.site.com
serial = 2009033100
refresh = 21600 (6 hours)
retry = 3600 (1 hour)
expire = 1209600 (14 days)
default TTL = 300 (5 mins)
site.com nameserver = ns1.site.com
site.com nameserver = ns2.site.com
site.com nameserver = ns3.site.com
site.com nameserver = ns4.site.com
site.com internet address = 216.239.XX.XX
site.com internet address = 72.14.XX.XX
site.com internet address = 74.125.XX.XX
site.com MX preference = 10, mail exchange = smtp2.site.com
site.com MX preference = 10, mail exchange = smtp3.site.com
site.com MX preference = 10, mail exchange = smtp4.site.com
site.com MX preference = 10, mail exchange = smtp1.site.com
ns1.site.com internet address = 216.239.XX.XX

Ya tenemos toda la información alojada en las DNS de este sitio.

2 de octubre de 2009

XSS en la web del COI

Con motivo de la celebración de las votaciones del comité olímpico internacional para elegir el lugar donde se celebrarán los próximos juegos olímpicos los chicos de Security by default han publicado un XSS sobre la web del COI.
xss en el coi
Para aquellos que no sepan que es un XSS se lo explico a continuación en pocas palabras. Un XSS (Cross site scripting) es un tipo de fallo de seguridad cuando se diseña una pagina web. Cuando un sitio web no comprueba correctamente los valores de las variables que va ha recibir y escribir en su frontal se puede insertar código HTML y en especial javascript para escribir en la web. Este tipo de ataques se han usado para hacer engañar a un usuario que acceda a este enlace o para robar credenciales.