Issue
I've been using REST APIs (both as a consumer and a developer of) for many years and am just starting to work with a GraphQL API for the first time, specifically, href="https://portswigger.net/burp/extensibility/enterprise/graphql-api/" rel="nofollow noreferrer">BurpSuite's Enterprise GraphQL API. I like it but I'm definitely missing a few critical concepts.
I am trying to hit their GetScan
endpoint:
curl -k -i -H "Content-Type: application/json" -H "Authorization: <MY_API_KEY>" -X GET -d '{ "query": "query GetScan ($id: ID!) { scan(id: $id) { id status agent { id name } site_application_logins { login_credentials { label username } recorded_logins { label } } audit_items { id issue_counts { total } number_of_requests } scan_configurations { id name } } }"}' 'https://mybsee.example.com/graphql/v1'
For easier reading, that graphql query is also:
query GetScan ($id: ID!) {
scan(id: $id) {
id status
agent { id name }
site_application_logins {
login_credentials { label username }
recorded_logins { label }
}
audit_items {
id
issue_counts { total }
number_of_requests
}
scan_configurations { id name }
}
},
variables {
$agent: "Firefox"
}
Above <MY_API_KEY>
has a real value when I run it (I can't post it here, obviously). Same with the URL (I have an on-premise version of BurpSuite running off, say, mybsee.example.com
).
When I run that curl, I get the following output:
About to execute: query GetScan ($id: ID!) { scan(id: $id) { id status agent { id name } site_application_logins { login_credentials { label username } recorded_logins { label } } audit_items { id issue_counts { total } number_of_requests } scan_configurations { id name } } }
HTTP/2 200
date: Wed, 20 Oct 2021 23:33:50 GMT
x-frame-options: DENY
<lots of response headers omitted>
{"errors":[{"message":"Unexpected exception occurred. Check logs for more details.","extensions":{"code":77}}]}
I don't have access to the server logs, so I'm trying to rule out an issue on the client-side (bad call to GetScan
on my part). Anything look wrong to anybody? Should I be injecting values to any of the fields in the query, such as id
or status
, etc.? If so, how (specifically) could I change the query to be valid? I'm also not sure if I need to append a "query"
JSON field name into the actual query or not.
Thanks for any and all help here.
Update
I do realize that this is not a perfectly answerable problem, because the BurpSuite API is unfortunately proprietary and you cannot obtain an API key from them unless you purchase the product or go through a lot of rigamarole to get a free trial license.
But more importantly, I'm not looking for anyone to fish for me here, I'm hoping someone can teach me how to fish. In reality I need to integrate with a lot more GraphQL endpoints besides this one, but if someone can show me the proper way to construct one query, I can take it from there.
Solution
The safest way to do this is to use jq
to generate correctly-escaped JSON with both your query and its parameters.
Building a function to automate that:
# usage: gqlQuery http://ENDPOINT/graphql "$query" arg1=val1 arg2=val2 ...
gqlQuery() {
local endpoint query postBody
local -a jqArgs=( )
endpoint=$1; shift || return
query=$1; shift || return
while (( $# )); do
case $1 in
# the variable name "query" is used for passing in, well, the query
query=*) echo "ERROR: variable name query is reserved" >&2; return 1;;
# 'foo=JSON:["bar", "baz"]' passes ["bar", "baz"] as a list, not a string
*=JSON:*) jqArgs+=( --argjson "${1%%=*}" "${1#*=}" ) ;;
# without JSON:, everything gets passed as a string to the child
*=*) jqArgs+=( --arg "${1%%=*}" "${1#*=}" ) ;;
# arguments without a = are not recognized
*) echo "ERROR: Argument $1 not well-formed" >&2; return 1;;
esac
shift
done
postBody=$(jq -nc \
--arg query "$query" \
"${jqArgs[@]}" \
'{ "query": $query, "variables": ($ARGS.named | del(.query)) }'
) || return
curl --fail -XPOST \
-H 'Content-Type: application/json' \
-d "$postBody" "$endpoint"
}
...you might use such a function as:
getScanQuery='query GetScan ($id: ID!) { scan(id: $id) { id status agent { id name } site_application_logins { login_credentials { label username } recorded_logins { label } } audit_items { id issue_counts { total } number_of_requests } scan_configurations { id name } } }'
myUrl=https://mybsee.example.com/graphql/v1
scanIdToRetrieve=1000 # replace with whatever is appropriate
result=$(gqlQuery "$myUrl" "$getScanQuery" id="$scanIdToRetrieve")
Answered By - Charles Duffy Answer Checked By - Senaida (WPSolving Volunteer)