Archivo

Posts Tagged ‘elasticsearch alias’

Seguridad en ElasticSearch: ES desde la perspectiva de un pentester – Parte V

octubre 14, 2019 1 comentario

Cuando ponemos un nodo en modo “cluster” es cuando realmente se empiezan a complicar las cosas desde el punto de vista de la seguridad. Algunas consideraciones que fácilmente se pueden detectar desde el punto de vista de un pentester son las siguientes:

Sin mecanismos de autenticación o autorización en el acceso a la API Rest.

Como se ha visto en los post anteriores de ésta serie (parte1, parte2, parte3, parte4), la API Rest de una instancia de ES es muy potente, de hecho es el corazón del motor. Desafortunadamente, por defecto no se implementa ningún mecanismo de seguridad para la autenticación de usuarios. Recordad que ES es una base de datos, con un modelo de funcionamiento diferente a las bases de datos relacionales pero su objetivo principal es el mismo: el almacenamiento de información. Si en una base de datos tradicional se permite que cualquier usuario sin autenticación previa, ejecute consultas SQL sobre las tablas y que tenga la posibilidad de lanzar procedimientos almacenados, estamos en una situación poco deseable en la que como mínimo, es posible que se produzcan fugas de información sensible y a mayores, en la explotación del sistema. Pues bien, por defecto esto es lo que tenemos con cualquier instancia de ES. Alguien podría decir: “pero no pasa nada, porque la API Rest de ES se vincula únicamente a la interfaz de red local, que no está expuesta a otros sistemas y por lo tanto únicamente un administrador podrá acceder a ella”. Sí y no. Si utilizamos ES en modo de desarrollo, es decir, con un único nodo local y sin activar el modo cluster esto es cierto, pero aún así, si el sistema ya ha sido comprometido y un atacante tiene la posibilidad de ejecutar comandos, se podría crear fácilmente un túnel SSH que exponga el puerto en el que se encuentra en ejecución la API Rest de ES y de esta forma, acceder a la información almacenada en el cluster. Incluso, sin llegar al supuesto de que el sistema haya sido comprometido, es posible que el administrador quiera acceder a la instancia remotamente y lanzar consultas, para ello también podría crear un túnel SSH abriendo la posibilidad de que él y cualquiera pueda entrar ya que por defecto, no hay mecanismos de autenticación y autorización.

ssh -L 0.0.0.0:9999:127.0.0.1:9200 esuser@localhost

Por ejemplo, si se ejecuta el comando anterior sobre el sistema en el que se encuentra en ejecución la instancia de ES, se abrirá el puerto “9999” en todas las interfaces de red disponibles y se podrá acceder a la API Rest de ES utilizando dicho puerto. Esta es solo una forma, existen otras más, por ejemplo utilizando redirecciones con socat. Este y muchos otros temas relacionados con la post-explotación de sistemas los enseño en los cursos que imparto en Securízame por si estás interesado.

Operaciones de administración de la instancia de ES sin protecciones de ningún tipo.

Ahora bien, en el caso de que efectivamente, lo anterior no sea posible porque el sistema está correctamente securizado y no hay agujeros de seguridad que le permitan a un atacante crear un túnel como el anterior, aún hay que considerar que si la instancia de ES se ha configurado en modo “cluster”, cualquiera se podrá conectar a ella, ya que como se ha visto en la parte anterior de esta serie, para que el modo cluster funcione correctamente la instancia tiene que permitir la conexión remota por parte de otros nodos. Esto significa que lo más probable es que otras instancias puedan consultar cualquier endpoint de la API Rest, incluyendo aquellos que permiten la administración completa del nodo, nuevamente sin ningún tipo de restricción.

Fugas de información sensible con instancias maliciosas en el cluster

Otra cuestión a tener en cuenta en el modo cluster, es que se puede consultar fácilmente si una instancia actúa como “master” y levantar otra instancia que funcione en modo “esclavo” para obtener las replicas de la información almacenada en el cluster. Esto está muy bien sino fuese porque nuevamente, no hay ningún mecanismo de autenticación y autorización por defecto en ES para este tipo de operaciones, es decir, que por defecto se “confía” en que la instancia que se quiere unir al cluster es legitima y no hay ningún mecanismo para indicar cuáles son aquellas instancias que realmente están autorizadas para unirse al cluster y cuáles no. Es posible que el lector recuerde o haya visto alguna vulnerabilidad de transferencia de zona en servidores DNS mal configurados, pues en este caso estamos ante una situación muy similar. Es posible levantar una instancia de ES y editar la configuración por defecto para que apunte al master y obtener la replica de los documentos almacenados en el cluster, es decir, la información propiamente dicha.

Denegación del servicio sobre nodos del cluster.

Existe otro problema inherente al funcionamiento de ES relacionado con el almacenamiento de la información. Como se ha mencionado anteriormente, la estructura de los documentos almacenados en ES parte de un índice, que funciona como un esquema en una base de datos relacional. Esta información se carga en memoria con el objetivo de que el acceso sea rápido, por lo tanto la máquina sobre la que se ejecutan dichas instancias tienen que ser lo suficientemente potente (tanto en términos de memoria como de procesamiento) para admitir la carga de estos documentos. Se tiene que tener un muy buen control sobre lo que se va a almacenar, es decir, permitir la inserción de documentos únicamente con la información estrictamente necesaria y evitar que sean estructuras JSON muy grandes. Si la API Rest de ES puede ser consultada por cualquiera o simplemente, no se tiene cuidado con las cuestiones indicadas antes, es posible que hayan problemas de almacenamiento en una o varias instancias del cluster, pudiendo incluso provocar condiciones de denegación de servicio. Por otro lado, tal como se ha explicado en uno de los posts anteriores de la serie, gracias a la API Rest de ES es posible abrir y cerrar índices, acción que se encarga de volcar los documentos del índice en cuestión a disco (operación de cierre) o de disco a memoria (operación de apertura). El problema de estas operaciones es que son costosas en términos de recursos como resulta evidente y si se ejecutan constantemente sin ningún control sobre índices con miles de documentos (ejecutando un script malicioso, por ejemplo) es bastante probable que se produzca una condición de denegación de servicio.

Tráfico sin cifrar.

En modo cluster los nodos se comunican e intercambian paquetes de datos sin ningún tipo de protección en la capa de transporte. Esto significa que evidentemente, es inseguro por defecto. Como seguramente ya sabéis, esto puede dar lugar a diferentes tipos de ataques que van desde la captura pasiva de paquetes hasta la manipulación y posterior reinyección de los mismos en ciertos escenarios. En este punto poco más merece la pena explicar, es evidente que se trata de un problema de seguridad que no es aceptable en un cluster encargado de almacenar información sensible.

¿Contramedidas?

Si el lector ha trabajado anteriormente con ES, seguramente una de las primeras cosas en las que pensará será en las características de seguridad disponibles en el módulo “X-Pack” (https://www.elastic.co/guide/en/elasticsearch/reference/current/configuring-security.html) y a continuación en la inversión que habría que realizar para adquirir y habilitar dicho módulo en la instancia de ES, ya que no es gratuito. Sin embargo, debido a la presión de la comunidad pidiendo implementar mecanismos de seguridad en la versión gratuita de ES, desde mayo del presente año todas las versiones de ES desde la 6.8 cuentan con características de seguridad incluidas en el producto y que se pueden activar si el administrador así lo desea. Dicho anuncio se ha hecho público hace unas pocas semanas a la fecha de escribir este post y se puede consultar aquí: https://www.elastic.co/es/blog/getting-started-with-elasticsearch-security

No obstante, como resulta evidente las instalaciones de ES existentes tienen que ser “reinstaladas” con las nuevas versiones disponibles en los repositorios de ES, lo cual no es precisamente una tarea fácil cuando la instancia o cluster tiene datos almacenados pero ya es algo.

Algunas de las características relativas a la seguridad en ES, que ahora se encuentran integradas por defecto y para las que no hace falta tirar de X-Pack son las siguientes.

  • Control de accesos basado en roles.
  • Comunicación segura entre nodos de la instancia.
  • Autenticación de usuarios basada en directorio activo, LDAP, Kerberos, SAML o de forma local.
  • Tráfico confiable “nodo a nodo”, habilitando filtrados basados en listas blancas.
  • Logging en eventos relacionados con la seguridad de forma transparete.

Entre muchas otras cosas más. Se trata de características que evidentemente se deben utilizar en un entorno productivo para proteger la información de accesos no autorizados y “miradas indiscretas”.

Un Saludo y Happy Hack.

Adastra.

Seguridad en ElasticSearch: búsquedas avanzadas y operaciones sobre índices – Parte III

septiembre 9, 2019 1 comentario

En el post anterior se ha hablado sobre como crear y gestionar índices así como la forma de realizar búsquedas con el endpoint “_search”, lo cual es el punto de entrada para comprender el funcionamiento de ES. Probablemente las características más complejas de este producto están precisamente relacionadas con las búsquedas, ya que como se verá en este post, existen varias maneras de aplicar filtros sobre índices y documentos.

En primer lugar, el endpoint “_search” no solamente admite peticiones GET, también es posible ejecutar una petición POST y en el cuerpo de la petición enviar filtros un poco más específicos que los que se podrían incluir en una petición GET. Por ejemplo:

POST /indice/tipo/_search
{ “query”: { “match”: { “title”: {
“query”: “palabra1 palabra2”,
“operator”: “and”}
}
}

“size”: 2,
“from”: 0,
“_source”: [ “campo1”, “campo2”, “campo3” ],
“highlight”: { “fields” : { “title” : {} } }
}

Se trata de una búsqueda más compleja, en la que se incluye el campo “query” que a su vez admite una estructura muy concreta para realizar la búsqueda. Con “match” se especifican los filtros, que en este caso aplican únicamente al campo “title”, es decir, que todos los documentos que tengan dicho campo serán objeto de búsqueda. Luego, se repite nuevamente el campo “query” pero en esta ocasión será útil para indicar un texto libre. Es posible utilizar operadores como “or” y “and”, de tal manera que dicha operación lógica se aplicará sobre las palabras especificadas en el campo “query”. En el ejemplo anterior, al aplicar el operador “and”, significa que la búsqueda devolverá solamente aquellos documentos que tenga en el campo “title” las palabras “palabra1” y “palabra2”. Luego, se puede apreciar en el cuerpo de la petición otros campos adicionales, tales como “size” y “from”, los cuales permiten devolver resultados en bloques, algo ideal para implementar búsquedas paginadas. Finalmente, los campos “_source” y “highlight” sirven para indicar aquellos campos del documento que devolverá la búsqueda, en este caso “campo1”, “campo2” y “campo3”. Si el documento tiene más campos estos no son incluidos en los resultado de la búsqueda.

El resultado de una búsqueda como la anterior es una estructura en formato JSON que contiene algunos campos interesantes, como por ejemplo “_source” y “score”. En el caso del primero, se trata de la estructura JSON con los resultados de la búsqueda, es decir, todos los documentos que han coincidido con los filtros especificados y el segundo, es el factor de coincidencia y es aquí en donde ES se complica un poco más, ya que ES internamente realiza una serie de calculos para asignar a cada resultado de las búsquedas un valor de coincidencia, esto es un indicativo que permite ubicar cada documento en un orden concreto en el listado de resultados. Pensad por ejemplo en Google, los enlaces a páginas externas que arroja cada búsqueda enseñan en las primeras posiciones aquellos que tienen mejor page rank, aquellos que pueden ser más interesantes para el usuario. ES hace lo mismo partiendo de los filtros que se incluyen en las búsquedas. Por ejemplo, en el caso anterior, cuantas más veces aparezca en un documento las palabras “palabra1” y “palabra2”, el documento tendrá mejor score y por lo tanto aparecerá en mejores posiciones dentro del resultado de la búsqueda. En la documentación oficial de ES podéis ver algunos ejemplos de búsquedas de este tipo para que quede un poco más claro, aunque desafortunadamente en mi opinión, la documentación oficial de ES es una de las más escuetas, poco claras y con más errores que me he encontrado hasta ahora en un producto de software, desafortunadamente es lo que hay y muchas veces toca pegarse con el producto para aprender realmente cómo funciona y ver las cosas que han cambiado, que ya no funcionan o que funcionan de forma diferente entre diferentes versiones. Los siguientes enlaces pueden ser útiles:

https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html https://www.elastic.co/guide/en/elasticsearch/reference/current/search-template.html

Por otro lado, algunos de los campos que se han incluido en el cuerpo de la petición (los más simples) también se pueden incluir como parámetros en la URL del endpoint “_search”, por ejemplo:

GET /_search?size=5
Enseña los 5 primeros resultados de la búsqueda.

GET /_search?size=5&from=5
Enseña los resultados del 5 al 10.

GET /_search?size=5&from=10
Enseña los resultados del 5 al 15.

como se ha explicado anteriormente, ES se encarga ordenar los resultados de las consultas antes devolverlos basándose en el campo “_score”, por lo tanto es común y recomendable utilizar los mecanismos de paginación para evitar problemas de rendimiento en las consultas.

Operaciones sobre índices y documentos.

Es importante conocer la forma en la que ElasticSearch interpreta los documentos almacenados en un índice concreto, ya que es posible que algunos de los campos no contengan la estructura esperada, tal como se ha visto en el post anterior a este, es posible crear documentos que no siguen ninguna estructura referente a los campos. Para ver el “mapeo” que tienen los documentos (parecido a la definición de una tabla en una base de datos relacional) es necesario utilizar el endpoint “_mapping” disponible en el índice.

GET /index/_mapping

A la hora de crear un índice es posible incluir el campo “mappings” y especificar cómo será la estructura de los campos que podrán ser heredados por los documentos creados en el índice, por ejemplo:

PUT my_index

{ “mappings”: { “properties”: {
“campo”: { “type”: “keyword”}
}}}

Es recomendable echarle un vistazo a lo que se explica en la documentación oficial sobre los mapeos en índices: https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-params.html

Los índices pueden estar abiertos o cerrados, lo que significa que es posible trabajar  con ellos para operaciones de lectura/escritura o no. No es posible indexar documentos o realizar búsquedas sobre índices cerrados. Cuando un índice está cerrado, ES no mantiene las estructuras de datos internas para la búsqueda, es decir, los documentos no se indexan y por lo tanto, el consumo de memoria es menor. No obstante, dependiendo del tamaño de los documentos de dicho índice, un índice cerrado puede suponer un consumo considerable de disco duro ya que como resulta evidente, la información de dichos documentos se debe guardar de forma persistentemente en disco en el caso de que el índice se abra nuevamente. Abrir o cerrar un índice es muy sencillo tal como se muestra a continuación. (obviamente, “my_index” corresponde al nombre del índice).

* Abrir un índice: POST /my_index/_open
* Cerrar un índice: POST /my_index/_close

Alias sobre índices.

Una forma rápida y sencilla de obtener todos los índices disponibles en ES es por medio del endpoint “_aliases” el cual devuelve un listado de todos los alias disponibles para cada uno de los índices. Con este endpoint también es posible crear o eliminar alias (etiquetas) sobre los índices creados.

POST /_aliases {
“actions” : [ { “add” : { “index” : “test1”, “alias” : “alias1” } },
{ “remove” : { “index” : “test1”, “alias” : “alias2” } } ] }

En el caso anterior, las acciones utilizadas son “add” y “remove”. Se ha creado un alias el nombre “alias1” sobre el indice “test1” y además, se ha eliminado el alias “alias2” sobre el índice “test1”. Un índice puede tener múltiples “alias” sin que esto afecte a los documentos o estructura del índice.
Probablemente una de las características más potentes de los alias es que permiten crear vistas sobre los índices partiendo de los filtros, por ejemplo:

POST /_aliases {
“actions” : [ {“add” : {“index” : “test1”, “alias” : “alias2”,
“filter” : { “term” : { “campo” : “valor” } } } } ] }

Como se puede apreciar, se ha creado un alias con nombre “alias2” sobre el índice “test1”. Cuando se intente consultar dicho alias, ES aplicará el filtro indicado en el campo “filter” y devolverá los documentos que coincidan con la búsqueda. Esto en el mundo de las bases de datos relacionales es similar a las vistas, lo cual simplifica mucho las consultas que se pueden realizar contra un índice concreto. Para consultar el alias, se accede directamente al endpoint “_search”, por ejemplo:

GET /alias1/_search
GET /alias2/_search

Al realizar una petición como la anterior ES se encargará de buscar dicho alias, ver el índice al que apunta y si hay algún filtro, aplicarlo.

Los alias también se pueden utilizar como vistas de escritura, es decir, una forma de simplificar la creación de documentos con el atributo “is_write_index”.

POST /_aliases
{ “actions” : [
{ “add” : {“index” : “test”, “alias” : “alias1”, “is_write_index” : true } }
]}

Como se puede apreciar, para crear un alias en modo escritura, basta simplemente con incluir el campo “is_write_index” con el valor “true” a la hora de crearlo. Para utilizar el índice en modo de escritura se podrá realizar una petición POST o PUT de la siguiente forma.

PUT /alias1/_doc/1
{
“campo”: “valor”
}

En donde “_doc” es un endpoint que le permite a ES saber que se intenta acceder a la estructura de documentos que se encuentran almacenados en el índice al que apunta el alias “alias1”, luego en el cuerpo de la petición viene el JSON con el documento propiamente dicho.

Consultas interesantes en ES

Antes de finalizar este post, es conveniente conocer algunos de los endpoints disponibles en el producto para realizar consultas directas sobre el estado del nodo o cluster. Para ello existen varios endpoints interesantes que son muy sencillos y aportan información valiosa. Por ejemplo:

GET /_cat/master?v
GET /_cat/nodes?v
GET /_cat/indices?v
GET /_cat/plugins?v
GET /_cat/shards?v
GET /_cat/health?v
GET /_cat/master?help
GET /_nodes/node1,node2
GET /_nodes/process
GET /_nodes/_all/process
GET /_nodes/node1,node2/jvm,process
GET /_nodes/plugins
GET /_nodes/stats/indices
GET /_nodes/stats/os,process
GET /_nodes/192.168.1.101/stats/process
GET /_nodes/usage
GET /_nodes/nodeId1,nodeId2/usage
GET /_nodes/hot_threads

Son peticiones fáciles de entender y que permiten extraer información relevante sobre una instancia de ES en ejecución, de hecho, complementos como “cerebro”, “elasticsearch-HQ” o el propio Kibana hacen uso de estos endpoints de forma directa para enseñar la información en un formato amigable para el usuario.

En el próximo artículo de la serie se hablará sobre configuración de una instancia de ES y algunas consideraciones de seguridad que se entenderán mucho mejor después de haber leído la parte 1 y la parte 2 de la serie.

Un saludo y Happy Hack.
Adastra.

A %d blogueros les gusta esto: