
Hi everyone. Uh my name is Alexa. I am an application security engineer, an independent vulnerability researcher and the native Torononian. Um I'm very excited to be giving a presentation titled uh from schema to shell uh the agentic exploitation of GraphQL. Uh I'd like to start by giving a brief overview of the discussion we'll be having today. Uh I'll start by delineating the difference between uh GraphQL APIs and standard REST APIs. Uh from there we'll move on to a case study. uh where I'll walk us through uh two vulnerability attack chain uh that allowed us to access the admin panel of uh financial dashboard that utilize GraphQL. Uh I'll talk about uh the GraphQL tooling ecosystem and the tools that
were used in the identification of this attack chain uh and how that led uh to the inception of the grape scanning agent agent. Uh from there um I'll finish uh with a discussion on agentic exploitation and how AI agents uh can be used to help us triage reports and agentically produce a proof of concept. Uh and we'll finish with the demo and leave some time for question and answer. Uh with that being said, I'd like to talk a little bit about GraphQL. Uh so GraphQL stands for graph uh graphical query language. Uh and it was developed uh uh and released by Meta in 2018. uh that allows uh web clients to specify uh the exact data uh they'd like
to uh query or operate on uh using one uh API endpoint. GraphQL has two primary operating primitives uh that being uh queries and mutations uh with queries being how you uh specify the data you'd like to retrieve and mutations being how you specify the data you'd like to edit or mutate. uh it was designed uh to prevent uh the overfetching or underfetching of data uh that commonly occurs uh when a client uh has to fetch multiple API endpoints uh to operate on the data it requires. Now, um although a although GraphQL APIs primarily work through post requests, uh where a GraphQL query is included in the body of an HTTP request, uh GraphQL APIs also can be configured uh to work uh
with get requests in some cases. uh for the purposes of this discussion uh we'll consider the set of vulnerabilities uh that exist in GraphQL APIs uh to be equivalent to the set of vulnerabilities that exist in standard uh REST APIs. Uh and with the exception of do uh denial of service uh they can be tested for in more or less the same way. Uh with that uh I'd like to give uh an example of a two vulnerability attack chain uh that involves a high severity um SQL injection and privilege escalation attack uh that allowed us to access the administrative uh panel of a financial application. Uh so uh for this particular uh assessment uh I was tasked with uh
assessing a dashboard uh that allowed us uh to search for and run uh a various set of uh financial sub applications um and uh run them against uh the company data set. uh and in this particular case I I was able to identify a timebased uh Postgress SQL injection uh and uh that was rated critical severity and a high uh severity uh instance of broken authentication control uh that allowed us to access uh an admin panel when uh searching and querying uh for uh a number of sub applications on this administrative panel. Uh I uh noticed that there was a particular GraphQL query uh that contained uh two parameters. Uh the first being uh search
uh which allowed us to search for applications by name uh and a second parameter uh being called filter uh that allowed us to filter for a set of applications uh uh based on a certain set of attributes. I I figured that one of these two variables was passed uh to a backend database query. uh and the chances were pretty high uh that at least one of them uh were passed uh to a database query uh through direct string concatenation uh and without parameterization uh which would allow us which would allow us to achieve some kind of database injection. uh after including a single quote uh at the end of the filter parameter uh and posting
it to the GraphQL API uh I got an HTTP response uh which included a Postgress error uh which meant that the filter parameter uh was SQL injectable. Uh from there I proceeded to include a timebased payload uh which would sleep for 25 seconds uh if we had super user privileges uh over a data data database. Uh and uh the SQL injection indeed slept uh for 25 seconds indicating that we did have uh super user privileges over the database. Uh we could read data, we could write data uh and we had access to all the databases functionality. uh which meant that we could potentially use this uh SQL injection uh to achieve a remote code execution. Uh however uh
unfortunately remote code execution uh was out of scope uh for this engagement. Uh so what I did is I used the SQL injection uh to enumerate uh data from the backend database uh and see the tables, columns and column names uh of the corresponding table. uh and I use that to collect a list of valid usernames that were associated with the application. Uh with that being said, uh I'd like to talk a little bit about uh the website's administrative panel. Uh this uh particular uh financial application dashboard uh had an administrative panel that was accessible uh uh to all users uh both non-privileged and administrative users. Uh but when a user with a standard level
of privilege attempted to access uh one of the sub menus uh which allowed us to edit uh application metadata uh such as run frequency uh we got an inconvenient access denied message. So I proxied my request to the application uh dashboard uh through burp uh uh and I noticed that when attempting to access uh the administrative panel uh I saw a graphql query called brass check access uh that said sent my username as well as a user role of ABC admin uh to uh the post uh the graphql API and the graphql API responded with an as authorized value of false. What I proceeded to do was uh to pass uh a list of usernames I'd constructed
using the SQL injection uh to uh burp intruder and performed uh sniper attack against the brass check access query. Uh and from there I was able to identify a set of usernames that had had an is authorized value of true. Right? And then when accessing the admin panel, I simply substituted uh my username with that of an administrator. And I was able to access the admin panel and altered application metadata. And with that, I'd like to conclude my two vulnerability attack chain that resulted in us uh being able to access uh the admin functionality of the application. Uh I'd like to move on by discussing the GraphQL tooling ecosystem uh and uh the three uh scripts and tools that were
used to identify these vulnerabilities uh and where I felt uh the tooling ecosystem fell short. So three uh standalone scripts and tools uh were used in uh the assessment of this graphical API. Uh I started by running a modular Python based script called uh graph cobb uh which uh checks for misconfigurations uh and u uh extracts the graphical schema through an introspection query. Uh the results of the introspection query uh were uh passed to an enumeration tool uh called graph woof uh which fingerprints the corresponding implementation uh and compiles a list of uh potential associated CVEes. And uh third and final tool uh was inql uh which is a burpuite function uh that uh is able to blindly execute a brute force
attack on individual graphql queries or or mutations uh without knowledge of the underlying text stack or uh any potential CVS or the schema in general. uh and I thought that these could uh be arranged into a convenient pipeline uh in a way that uh the value of the whole is greater than the sum of its parts and if they happen to be uh equivalent at least it saves me from having to independently run uh three separate tools. Uh and that leads us uh to uh uh the inception and creation of uh the GraphQL scanning engine. Effectively what I done uh to create the graph scanning engine uh is that I converted uh the three affformentioned
tools uh graph cop graphwolf uh and inql uh into three module uh uh python packages uh that were uh aligned in a single cohesive pipeline. Uh we start with a modular version of uh graph cop uh which scans for mis misconfigurations uh and extracts the schema uh through an introspection query. Uh this has then passed a fingerprinting module uh which is able uh to uh fingerprint the underlying text stack uh and compile a list of potential CVEes. And then this is passed uh to an injection tester uh module and an authentication testing module uh which uh uses the GraphQL schema uh and information about the underlying uh uh implementation uh to uh select a series
of test cases that have been coded encoded uh as YAML rules uh and test them against the target API. Uh once uh the injection uh module and the authentication module finish uh the results of uh all modules are uh sent uh to a final reporting module uh that compiles the report uh using uh API calls to a large language model. However, uh this left me in in the same position uh that I found myself in with a lot of other vulnerability scanners. uh I had to manually triage uh a number of findings uh and attempt to produce a proof of concept exploit uh before deeming uh the finding a true positive or a false positive. And I asked myself
uh what it would look like if I used uh AI agents uh better and hopefully to speed up uh this process which led me to the creation of uh exploitation agent uh that was used uh in lie of the reporter agent. I spent some time considering uh what it meant to triage each individual finding uh produced uh uh by any given report. In this particular case, the Grape Gill scanning engine. Uh and I concluded that uh it came down to uh simple it iterative loop uh that uh could very easily be ran uh by an AI agent. Effectively what I was doing uh in each case uh is that I was taking a a vulnerability and an HTTP request uh
that was responsible for triggering this vulnerability uh and using something like a Burp extension to convert it to a Python script. Uh from there uh I'd run it uh iteratively against uh the test uh instance of the web application I was assessing. uh I would analyze the response uh and iteratively make updates to the script before deeming the finding a true positive or false positive. Uh and if I did deem the finding a true positive uh I'd end up uh with a verified uh proof of concept exploit that executes a safe payload against the target application. Um, and with that being said, I'd uh like to show everyone uh the GraphQL uh the GrapeQL scanning engine uh with
aentic exploitation uh in action. Uh so I'll finish things off with a demo. Uh here uh we have uh the grip kill scanning agent agent uh and uh the agentic exploiter um uh packaged up uh and wrapped in a web UI. Uh we'll be running a scan uh against the damn vulnerable uh web application graphql application running on port 5313 uh of localhost. Uh we'll be running it as an unauthorized user or an unauthenticated user. Uh so we won't be passing a token. Uh and we expect uh GrapeQL to extra extract the schema itself. Uh so uh we won't be passing a GraphQL schema uh as a part of the scan.
Perfect. Scan successfully completed. We'll go over to the reports page uh uh to see what was reported. Uh and uh we'll notice that we have uh 15 critical vulnerabilities identified as a part of this application. Uh there's a reason they call it the damn vulnerable graphical application. And as you can imagine, this would be a lot to triage uh during a manual pen test. I'll scroll down uh to uh a finding uh that looks interesting. Uh and I've decided to settle on uh the command injection uh in uh the system diagnostics cmd parameter. I'll click uh the generate exploit function uh which uh sends the GraphQL query uh and an HTTP request uh responsible for
triggering the query to the exploitation agent uh to create a proof of concept exploit. From there, we'll move to the exploit tab uh and quickly analyze the exploit uh to see that it is indeed safe to run. Um and uh we can download it and test it against our um dam vulnerable GraphQL application. Uh thankfully I already have this ready uh against uh my I already have this ready and saved on my desktop. Uh and uh we'll quickly execute the command. Uh as you can see uh we were successfully able to uh uh query the GraphQL API through an identically uh generated exploit. Uh we received an HTTP 2000 uh meaning uh that the GraphQL
query accepted uh the HTTP request the GraphQL API accepted the HTTP request. Uh and uh we received uh uh data uh congruent with the youame- a command. Um and the PC was thankfully confirmed. Uh and with that uh I'd like to conclude my presentation and uh thank everyone for attending.
>> Uh yes. Yeah.
>> Breaker breaker. Uh, do you plan on using first off super cool demo, love the demo. Um, when you're going and performing this and creating the exploits, have you thought about also generating countermeasures to detect and potentially block these exploits so that you're you're sort of coming to the party with the problem and the solution. >> Uh, thank you for the question. It's a great question. Uh so so far my um job has been more on the offensive side in the application security side. Uh and I really haven't thought that much about detection. Uh but uh seeing your prior presentation, I think that'd be a good use case uh for uh for agentic tools. Um
I'm a very big proponent of um building uh AI agents on top of a agentic spine on top of a deterministic spine. uh and I think uh using uh self-arning loop uh to create deterministic rules is uh the way I'll be exploring for the uh foreseeable future. Thank you.
And these sorts of things have a tendency to break when you reach high scale like when you scan one server, 10 server, 10 million servers, etc. Did you reach a point where you saw where the tool is reaching a gap where it's starting to produce false positives or incorrect results and what do you have to do in order to fix them? >> Yeah. Uh so um so far I've only used the tool uh against singular GraphQL endpoints. I haven't um used it to scan GraphQL in parallel. Uh and uh when I'm dealing with a monor repo or a very large repository, uh uh the reports happen to be quite large. Uh thankfully the scanning engine in and of itself is
quite uh robust. Uh but I have noticed that my rule set uh sometimes produces a large amount of false positives. Uh and uh that was particularly the case with um uh SQL injections. Um sometimes if uh the GraphQL uh API responds with an error uh u my tool registers that as a SQL error. Um and uh that left me with a lot of uh findings to triage which most often ended up as false positives. Uh but thankfully with the configuration of this rule um updating uh the configuration of this tool updating the rule set uh is simply a matter of updating the YAML rule. Uh so I'm going to be iterating iteratively updating uh and uh uh creating uh new YAML rules for
better detection. Thank you.