摘要:在本文中,我们将构建漏洞扫描引擎的第二个核心模块,目标是自动化地发现**反射型跨站脚本(Reflected XSS)**漏洞。我们将超越之前简单的字符串匹配,设计一个更智能的、**感知上下文(Context-Aware)**的检测引擎。这个引擎会尝试注入多种针对不同HTML上下文(如标签内部、属性内部、JavaScript脚本内部)的探测Payload,并分析这些Payload是否成功地“逃逸”或“破坏”了原有的语法结构,从而更精准地识别出XSS漏洞的存在。

关键词:Python, XSS, 反射型XSS, 漏洞扫描, Web安全, 上下文感知, Payload


正文

⚠️ 警告:仅用于授权的教育和安全测试目的

本文及配套代码用于探测真实的安全漏洞。未经授权,对任何线上系统进行漏洞扫描都是违法行为。所有读者必须在自己的本地测试环境或授权的漏洞靶场中使用本文所学知识。

1. 超越简单反射:XSS的“上下文”

在我们之前的入门课程中,我们通过检查一个字符串是否被“原样反射”来判断XSS。但在真实世界中,这种方法非常不准确。一个安全的Web应用可能会对用户输入进行HTML编码(例如,将<变为&lt;),此时虽然字符串被“反射”了,但它在浏览器中只会被当作普通文本显示,无法执行。

一个真正的XSS漏洞能否被利用,完全取决于我们的输入被反射到了HTML的哪个位置,我们称之为“上下文(Context)”。

  • HTML标签内容上下文:

    • 代码: <div>你好, <?php echo $_GET['name']; ?></div>

    • 注入点: ...name=John -> <div>你好, John</div>

    • 成功Payload: 注入完整的HTML标签,如<script>alert(1)</script>

  • HTML属性上下文:

    • 代码: <input type="text" value="<?php echo $_GET['query']; ?>">

    • 注入点: ...query=MySearch -> <input type="text" value="MySearch">

    • 成功Payload: 需要先闭合属性的引号,再插入新的HTML。例如:"><script>alert(1)</script>,这会将HTML变为<input type="text" value=""><script>alert(1)</script>">

  • JavaScript字符串上下文:

    • 代码: <script>var username = '<?php echo $_GET['user']; ?>';</script>

    • 注入点: ...user=guest -> <script>var username = 'guest';</script>

    • 成功Payload: 需要先闭合JS字符串的引号,再插入JS代码。例如:';alert(1)//,这会将JS变为<script>var username = '';alert(1)//';</script>

我们的扫描引擎必须能够模拟这几种最常见的注入场景。

2. 设计上下文感知的Payloads

我们将设计一个Payload列表,每个Payload都包含两部分:要注入的内容,以及我们期望在响应中看到的内容(用于验证)。

Python

# 一个简化的XSS Payload列表
# 格式: (注入的Payload, 验证时在响应中寻找的特征)
# 我们使用独特的、无害的标签和属性来验证,而不是alert(1)
XSS_PAYLOADS = [
    # 1. 基础的HTML标签注入
    ("<xss_test_tag>", "<xss_test_tag>"),
    
    # 2. 用于跳出HTML属性的Payload
    ("\"><xss_test_tag>", "<xss_test_tag>"),
    ("' onmouseover='xss-test-event'", "onmouseover='xss-test-event'"),
    
    # 3. 用于跳出JavaScript字符串的Payload
    ("';let xss_test_var=1;//", ";let xss_test_var=1;//"),
    ("'-_xss_test_func()-'", "-_xss_test_func()-"),
]

3. 完整代码实现 (xss_scanner.py)

我们将创建一个扫描器,它会遍历URL的所有GET参数,并对每个参数依次尝试我们Payload库中的所有Payload。

Python

# xss_scanner.py
import requests
import argparse
import sys
from urllib.parse import urlparse, parse_qs, urlencode, urlunparse

# Payload 库
XSS_PAYLOADS = [
    # (注入的Payload, 验证时在响应中寻找的特征)
    ("<scripT>alert('xss-test')</scripT>", "<scripT>alert('xss-test')</scripT>"),
    ("\"><xss_test_tag>", "<xss_test_tag>"),
    ("' onmouseover='xss-test-event'", "onmouseover='xss-test-event'"),
    ("';alert('xss-test');//", ";alert('xss-test');//"),
]

def scan_reflected_xss(url):
    """
    对给定的URL进行上下文感知的反射型XSS扫描。
    """
    print(f"[*] 正在对URL进行反射型XSS扫描: {url}")
    
    is_vulnerable = False
    parsed_url = urlparse(url)
    params = parse_qs(parsed_url.query)

    if not params:
        print("[*] URL中不含GET参数。")
        return False

    # 遍历所有GET参数
    for param in params:
        original_value = params[param][0]
        
        # 遍历所有Payload
        for payload, check_string in XSS_PAYLOADS:
            test_params = params.copy()
            test_params[param] = original_value + payload
            
            query = urlencode(test_params, doseq=True)
            test_url = urlunparse(parsed_url._replace(query=query))
            
            try:
                response = requests.get(test_url, timeout=5)
                
                # 检查Payload的“特征”是否未经编码地出现在响应中
                if check_string in response.text:
                    print("\n[+] 高危: 检测到潜在的反射型XSS漏洞!")
                    print(f"    - 目标URL: {url}")
                    print(f"    - 影响参数: {param}")
                    print(f"    - 成功Payload: {payload}")
                    is_vulnerable = True
                    # 为了全面性,我们可以选择继续测试其他payload,或在此返回
                    # return True
            except requests.RequestException:
                pass # 忽略网络错误

    if not is_vulnerable:
        print("[-] 未在GET参数中检测到反射型XSS漏洞。")
        
    return is_vulnerable

def main():
    print("="*60)
    print("!!! 警告: 本工具仅用于经授权的教育和安全测试目的 !!!")
    print("="*60 + "\n")

    parser = argparse.ArgumentParser(description="一个基于上下文感知的反射型XSS扫描器。")
    parser.add_argument("url", help="待测试的完整URL (必须包含查询参数)。例如: 'http://testphp.vulnweb.com/search.php?test=query'")
    args = parser.parse_args()
    
    scan_reflected_xss(args.url)

if __name__ == "__main__":
    main()

四、 如何使用与局限性

使用方法:

Bash

# 对一个已知的XSS测试靶场URL进行测试
python xss_scanner.py "http://testphp.vulnweb.com/search.php?test=abc"

工具会依次尝试不同的Payload注入到test参数中。如果其中一个Payload成功地在响应中留下了预期的“痕跡”,工具就会报告漏洞。

工具的局限性

  • Payloads有限:我们的Payload库非常小,真实的WAF和过滤器可以轻易地拦截它们。专业的扫描器拥有包含数千种编码和变体技巧的Payload库。

  • 未进行DOM渲染:我们的工具只能分析静态的HTML响应。它无法检测那些由页面JavaScript执行后才产生的DOM型XSS。要检测DOM-XSS,必须使用Selenium或Playwright等可以驱动真实浏览器的“无头浏览器”技术。

  • 仅支持GET请求:尚未实现对POST请求和表单的测试。

总结

我们成功地构建了一个更智能的XSS检测模块。通过设计针对不同上下文的Payload,它不再是盲目地检查字符串反射,而是开始理解XSS漏洞的本质——破坏预期的语法结构,注入可执行的代码。这个模块为我们的扫描引擎增添了发现客户端漏洞的关键能力。

反射型XSS需要攻击者诱骗受害者点击一个恶意链接。但还有一种更危险的XSS,它的Payload被永久地存储在服务器的数据库中,任何访问受感染页面的用户都会自动“中毒”。这就是存储型XSS。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐