Sp4ce 发表于 2017-3-25 01:58

对RainCMS (V2.0.1)后门简单的挖掘

本帖最后由 轩少 于 2017-3-25 02:34 编辑

在论坛看见一款PHP网络验证源码,下载下来搭建看了下,这一看看出了点问题
首先,我并没有在设置管理员信息的地方看到填写邮箱选项

然而安装完成后在数据库里发现了这个

这个邮箱什么鬼??我并没有设置啊。。
要知道,admin号同样可以通过邮箱找回
于是乎,开始了找邮箱的过程
由于这套程序基于THINKPHP5.0.3框架开发,所以程序主体都在application\目录里面
经过一番搜索,在\application\index\controller的senm.php中发现了该邮箱的踪迹

<?php
namespace app\index\controller;
use think\Session;
use think\Controller;
use think\Db;
use think\View;
use app\common\controller\Payfn;

class Sendm extends Base {
       
        public function index(){
                $res=send_mail('3718217@qq.com','raiaaan','tesfdsafdsatss','xxxxx');
               
        }

}
懂点PHP的都看出来这是干什么了,赤裸裸的发送邮件
附上完整语法
               think_send_mail(&to,&name, &subject, &body, $attachment = null){
               
                /**
* 系统邮件发送函数
* @param string $to    接收邮件者邮箱
* @param string $name接收邮件者名称
* @param string $subject 邮件主题
* @param string $body    邮件内容
* @param string $attachment 附件列表
* @Return boolean
*/
看到这里有人问了,这里没写SMTP怎么发邮件?
注意后台这个功能

看到这个功能了吗?
这个功能贴心的让你主动填写你的SMTP邮箱信息,如果不填写,那么会员找回密码功能将不可用【因为要发邮件】
填写了,那么我们继续看看他获取了哪些信息
第一处:管理员帐号信息
Myauth.php
class MyAuth extends controller {
        public function _initialize() {
      $request = Request::instance();
                $web_path=$request->root();
                $module_name=$request->module();
                $controller_name=$request->controller();
                $action_name=$request->action();          
                $loginuid=Session('uid');
                $authName=$module_name.'/'.$controller_name.'/'.$action_name;               
                $auth = new \auth\Auth();
                $res=$auth -> check(strtolower($authName), $loginuid);
                if($loginuid==1){
                        $res=TRUE;
                }                获取UID为1的用户登录状态和session
其中session在login.php里设置
{//登录成功设置session                                       
                          Session::set('username',$name); //用户名写入session
                                Session::set('password',$password);        //密码写入session
                                Session::set('uid',$uid);                //用户id写入session
                                Session::set('status',$status);                                                                       
                                $data['logintime'] = time();//取登录时间
                                $data['lastlogintime']=Db::name('member')->where('uid',$uid)->value('logintime');//取上次登录时间
                $data['loginip'] = $_SERVER["REMOTE_ADDR"];//登录IP
                                $data['lastloginip']=Db::name('member')->where('uid',$uid)->value('loginip');//上次登录IP
                                Db::name('member')->where('uid',$uid)->update($data);//登录更新数据库
                Db::name('member')->where('uid', $uid)->setInc('logincount');//等录次数加1
                if($uid != '1'){
                        $res=['msg'=>'success','code'=>2];
                        return json($res);               
                }
                               
                          $res=['msg'=>'success','code'=>1];
                        return json($res);
                  }
                }else{
                        $res=['msg'=>'error','code'=>0];
                    return json($res);       
                }                第二处:获取产品信息和激活卡
我在GetApp.php里发现这套源码存在获取产品相关信息并发送的行为
GetApp.php关键代码
class GetApp extends controller {
        public function index() {
                $opconfig=new Opconfig();
            if(input('?get.data') && input('get.data')){
              $getdata=input('get.data');
                        $json_arr=$opconfig->jsonop($getdata,'de');       
                        if($json_arr=='error'){
                                $resdata = ['code'=>444,'message'=>'error'];                               
                          return $opconfig->jsonop($resdata,'en');
                        }
            $appkey=$json_arr['app_key'];                                       
                        $appid=$json_arr['appid'];
                        if($appkey==null || $appid==null){
                                $resdata=['code'=>421,'message'=>'error'];
                                return $opconfig->jsonop($resdata,'en');                               
                        }
                        $appdata=['appid'=>$appid,'app_key'=>$appkey];
                        $resapp=Db::name('app')->where($appdata)->find($appid);                       
                        if(!$resapp){
                                $resdata=['code'=>422,'message'=>'error'];
                                return $opconfig->jsonop($resdata,'en');
                        }elseif($resapp['app_status'] < 1){
                                $resdata=['code'=>423,'message'=>'error'];                       
                                return $opconfig->jsonop($resdata,'en');
                        }else{
                                $res=[
                                  'app_name'    =>$resapp['app_name'],//应用名                                  
                                  'free'      =>$resapp['free'],//是否收费
                                  'app_data'    =>$resapp['app_data'],//应用自定议数据
                                  'announcement'=>$resapp['announcement'],//应用公告
                                  'version'   =>$resapp['version'],//应用版本号
                                  'down_url'    =>$resapp['down_url']//应用下载链接
                                ];
                                $resdata=['data'=>$res,'code'=>3,'message'=>'success'];
                                return $opconfig->jsonop($resdata,'en');
                  }   
                }else{
                        $resdata=['code'=>420,'message'=>'error'];
                  return $opconfig->jsonop($resdata,'en');
                }   比如,当你更新完程序并且通过这套程序发布时,我会在第一时间通过合法渠道获取你的程序,除此之外,我还可以通过在GetACard.php中获得的激活卡信息合法的去使用你的程序
GetAcrad.php关键部分
class GetAcard extends controller {//授权卡
        public function index() {
.......
                        if($day=='expire'){
                                $res=['expire_time'=>$expiretime,'app_free'=>'1','days'=>'0','fee_count'=>$acarddb['fee_count']];
                        $resdata=['data'=>$res,'code'=>4501,'message'=>'error'];
                                return $opconfig->jsonop($resdata,'en');       
                        }else{
                                Db::name('acard')->where('acard_number', $acard)->where('appid', $appid)->update(['loginip'=>$this->getip(),'logintime'=>time(),'sales_status'=>2]);
                                $res=['expire_time'=>$expiretime,'app_free'=>'1','days'=>$day,'fee_count'=>$acarddb['fee_count']];
                        $resdata=['data'=>$res,'code'=>7,'message'=>'success'];
                                return $opconfig->jsonop($resdata,'en');       
                        }第三处:register.php存在获取注册用户信息
register.php关键代码:
class register extends controller {
    public function index() {
........
                                Db::name('member')->insert($update);                               
                                $uid=Db::getLastInsID();
                                Db::name('auth_group_access')->insert(['uid' => $uid, 'group_id' => 3]);
                                $resdata=['username'=>$username,'uid'=>$uid];                               
                                $res=['data'=>$resdata,'code'=>2,'message'=>'success'];
                                return $opconfig->jsonop($res,'en');
                        }                               
                }如果我分发了代{过}{滤}理商,那么作者可以通过获取代{过}{滤}理商的方式生成卡密
第四处:
Fn.php存在获取网站前端公告信息
Fn extends controller
{
        //取前端菜单数据       
        public function getMenu(){
                $res=Db::name('menu')->where('status',1)->order('id asc')->select();               
                return $res;
        }
        //取最新文章
        public function newarticle($num){
                $res=Db::name('article')->where('status',1)->order('id desc')->limit($num)->select();
                return $res;
        }
   
}同获取软件信息一样,网站文章更新后作者会第一时间知晓并使用
除此之外还有很多文件都涉及用$res函数发送邮件,不一一举例,另外以外的发现了越权下载数据库BUG,这就比较坑爹了,客官看图

完整路径:网站/admin/netset/bak/tp/dowonload/name/数据库.sql
由于数据库命名方式是年月日时分秒.sql
又由于这套程序是2017年1月10日首发在精益论坛http://bbs.125.la/forum.php?mod=viewthread&tid=13975944&extra=page%3D1所以如果开发者用了这套系统并且有备份数据库的习惯,攻击者完全可以通过软件枚举出数据库地址并下载,
数据库都有了,我还愁没有卡密吗?

Sp4ce 发表于 2017-4-4 01:07

本帖最后由 轩少 于 2017-4-4 01:13 编辑

ydlds777 发表于 2017-3-29 00:07
楼主,你会不会PHP?这些API代码你要说是后门?
权限认证功能你要说是后门?
你是不是别有用心?

第一,我跟你没仇,不必用这种语气评论,第二,我没有开发任何和你产品类似的东西,因此不必用抢单说话,第三,你在数据库里留admin邮箱持续一个版本是什么意思

shy52110 发表于 2017-8-14 16:11

楼主,$res是定义的一个变量啊,$res在第一个发邮件的函数里,用于获取发送邮件的返回状态,而且在生存域之后就失效了。在后面全部就是定义一个新的变量。
而且PHP调用函数,是不带$res。总结一句话,你的php还需要学习一个呀

源总丶 发表于 2017-3-25 02:18

好帖子谢谢分享

shareolie 发表于 2017-3-25 02:25

作者留的后门还是论坛发帖的留的后门?

Sp4ce 发表于 2017-3-25 02:33

shareolie 发表于 2017-3-25 02:25
作者留的后门还是论坛发帖的留的后门?

不得而知,应该是作者预留的,论坛的那个失效了,我直接下的首发的

amscracker 发表于 2017-3-25 02:38

经典的分析哈哈!代码审计

liushuai44 发表于 2017-3-25 08:32

进来学习学习 感觉好高大上啊!

流光Streamer 发表于 2017-3-25 10:23

{:301_997:}6的不行,那么庞大的代码量 我可没有耐心

11053 发表于 2017-3-25 10:48

厉害了,分析的这么深,学习了,本来还准用穿上搭建个验证的

ssou 发表于 2017-3-25 16:15

分析的不错,连我这代码盲都看明白了

lelandyang 发表于 2017-3-25 16:50

所以说开源的软件未必安全。有商业利益在驱动。
页: [1] 2
查看完整版本: 对RainCMS (V2.0.1)后门简单的挖掘