当前位置: 首页 > news >正文

DVWA 存储型XSS实战:从Low到Impossible的攻防博弈

1. 初识存储型XSS:为什么它比“一次性”攻击更可怕?

大家好,我是老张,在安全圈里摸爬滚打了十来年,今天咱们不聊那些虚头巴脑的理论,直接上手开干。咱们的目标是DVWA这个经典的靶场,来一场从“入门”到“放弃”的存储型XSS攻防实战。你可能听说过XSS,知道它能弹个窗,但存储型XSS才是真正让开发者头疼的“牛皮癣”——一旦沾上,后患无穷。

简单来说,XSS就是攻击者想方设法在别人的网页里插入并执行自己的恶意JavaScript代码。而存储型XSS,顾名思义,就是这个恶意代码会被存到网站的数据库里。比如一个论坛的留言板、一个博客的评论系统,或者一个用户昵称的展示处。攻击者提交一段带毒的留言,这段毒代码就被存进了服务器。之后,任何一个普通用户,只要打开这个留言页面,他的浏览器就会自动执行那段恶意代码。想想看,这可比那种需要诱骗用户点击特定链接的“反射型XSS”厉害多了,它是一次投毒,持续感染,所有访客自动中招。

在DVWA里,存储型XSS的关卡设计得非常经典,从Low到Impossible,完美模拟了一个网站安全防护从“裸奔”到“铜墙铁壁”的进化过程。我们作为攻击方,要做的就是利用每一关的弱点,把我们的“炮弹”(恶意脚本)打进去。而作为防御方(或者说学习防御),我们更要明白,每一关的防护为什么会被绕过,以及如何才能真正堵上漏洞。这就像一场博弈,攻防双方的技术都在对抗中不断升级。准备好了吗?咱们先从最简单的“新手村”开始。

2. Low级别:门户大开,脚本长驱直入

2.1 环境准备与目标确认

首先,你得把DVWA环境搭起来。这个过程我就不赘述了,网上教程一大堆,无非是配个PHP环境,把DVWA源码放进去,修改一下数据库配置。记得把DVWA的安全级别调到Low,这是我们所有实验的起点。

进入DVWA左侧菜单的“XSS (Stored)”模块。映入眼帘的是一个非常简单的留言板界面:有两个输入框,一个是“Name”,一个是“Message”,下面有个“Sign Guestbook”的提交按钮。提交之后,你的名字和留言内容就会显示在页面上方。这个场景太常见了,几乎所有的用户交互功能都可能存在类似的问题。

我们的攻击目标是什么?最直接的证明,就是让浏览器执行我们输入的JavaScript代码。最经典的测试语句就是弹出一个警告框。这不仅能证明漏洞存在,还能通过alert(document.cookie)来演示如何窃取用户的会话Cookie,这是XSS攻击中最危险的后果之一——拿到Cookie,攻击者很可能就能直接登录你的账户。

2.2 第一次攻击:毫无过滤的“裸奔”现场

在Low级别下,我们不需要任何技巧。直接在“Message”框里输入以下代码:

<script>alert('Hey,你的网站有漏洞!')</script>

点击提交。瞬间,一个弹窗就会出现在你面前。这说明什么?说明我们输入的<script>标签被浏览器当成真正的HTML脚本标签给解析并执行了。服务器端没有对我们的输入做任何检查、过滤或转义,原封不动地存进数据库,又原封不动地输出到网页上。

我们再来点更“危险”的演示,在“Name”框里输入:

<script>alert(document.cookie)</script>

提交后,弹窗里显示的就是你当前浏览器的Cookie信息。如果这是一个真实的网站,并且这个Cookie是登录凭证,那么攻击者就可以利用这个漏洞,把这段窃取Cookie的代码存进去。之后每个查看留言的用户,他们的Cookie都会被悄无声息地发送到攻击者指定的服务器上。防御方在这一关可以说是完全失守,代码就像不设防的城市,任由攻击者书写。这种级别的漏洞现在在正规网站上已经很少见了,但它是一切学习的起点,让我们明白最原始的漏洞形态是什么样的。

3. Medium级别:初设防线,但漏洞百出

3.1 防护升级与初步探测

将DVWA的安全级别切换到Medium,再次进入存储型XSS页面。直觉告诉我们,事情没那么简单了。我们重复Low级别的操作,在“Message”框里提交同样的弹窗脚本。你会发现,这次脚本没有执行,页面上老老实实地把我们输入的<script>alert('x')</script>当作普通文本显示出来了。

这时候,有经验的安全测试者第一反应就是:查看网页源代码。按F12打开开发者工具,找到我们提交的留言部分。你很可能会看到类似这样的输出:

Name: 张三<br /> Message: &lt;script&gt;alert(&#x27;x&#x27;)&lt;/script&gt;<br />

注意看“Message”部分,我们输入的尖括号<>被转换成了&lt;&gt;,单引号也被转换成了&#x27;。这是PHP中htmlspecialchars()函数的典型效果。这个函数会把HTML中的特殊字符(如<, >, “, ‘, &)转换成HTML实体,这样浏览器就不会把它们解析为HTML标签或属性,而是当作纯文本显示。至此,“Message”输入框的XSS漏洞基本被堵死了。

3.2 绕过策略:寻找薄弱点与前端限制

但是,防御往往不是均匀的。我们再看“Name”字段的源代码,发现它只是被简单地输出,没有看到明显的转义。尝试在“Name”框输入<script>alert(document.cookie)</script>。哎?怎么输不完?页面提示字符数超了。原来,开发者在“Name”输入框加了一个前端的长度限制,比如maxlength="10"。这是很多新手开发者会犯的错误:在前端做校验,却在后端不做或做不全校验。前端的一切限制,对于攻击者来说都是形同虚设。

我们有两种经典的绕过思路。第一种,针对代码过滤。查看Medium级别的后端源码(DVWA提供了源码查看功能),你会发现它对“Name”的处理用了str_replace(‘<script>’, ‘’, $input)。这行代码的意思是,把输入中的<script>这个字符串替换成空字符串。很天真,对不对?它只匹配了小写。那我们直接用大写的<SCRIPT>标签不就绕过了吗?提交<SCRIPT>alert(document.cookie)</SCRIPT>,成功弹窗!

第二种,针对这种简单的字符串替换,还有一个好玩的技巧:嵌套混淆。比如输入<scr<script>ipt>alert(document.cookie)</script>。当后端代码执行时,它首先查找<script>并删除,于是中间的<script>被删掉,剩下的部分恰好又拼接成了一个完整的<script>标签!这就是“拆字法”绕过。

3.3 实战突破:使用代理工具修改数据包

不过,我们刚才遇到了前端长度限制。怎么突破?这就需要请出渗透测试中的瑞士军刀——Burp Suite这类代理工具了。它的原理很简单:让你的浏览器流量都经过它转发,你就能在中间截获、查看并修改任何发送给服务器的请求。

具体操作步骤:

  1. 配置浏览器代理(比如127.0.0.1:8080指向Burp Suite)。
  2. 在Burp Suite中开启代理拦截(Intercept is on)。
  3. 回到DVWA页面,在“Name”框随便输入个短名字(比如test),在“Message”框输入任意内容,点击提交。
  4. 此时请求会被Burp Suite截获。你会在Raw标签页看到一串HTTP请求数据,其中就有txtName=test&mtxMessage=hello这样的参数。
  5. txtName的值修改为我们精心构造的Payload,比如<scr<script>ipt>alert(document.cookie)</script>。注意,这里直接改,完全不受浏览器前端10个字符的限制。
  6. 点击“Forward”放行这个被修改过的数据包。

回到浏览器页面,你会发现攻击成功了!弹窗如约而至。这一关告诉我们,防御不能只做一半。后端虽然做了过滤,但逻辑太简单(大小写敏感、简单替换);前端做了限制,却忘了攻击者根本可以不走前端。真正的安全,必须建立在服务器端对用户输入进行严格的、彻底的、上下文相关的验证和净化之上。

4. High级别:道高一尺,魔高一丈

4.1 更严格的过滤与新的攻击向量

将安全级别调到High。我们故技重施,首先尝试在“Name”框使用大写<SCRIPT>标签。发现失败了。查看后端源码,发现防护升级了:它使用了preg_replace(‘/<script>/i’, ‘’, $input)。这里的/i修饰符代表正则表达式匹配时不区分大小写。也就是说,无论<SCRIPT><Script>还是<sCrIpT>,都会被匹配并删除。看来,单纯靠改变<script>标签的大小写已经行不通了。

前端依然有长度限制,所以我们依然需要Burp Suite。但<script>标签的路被堵死了,我们该怎么办?这就需要拓宽思路:XSS不一定非要<script>标签。HTML里能触发JavaScript执行的地方多了去了。一个非常常用且经典的替代品是<img>标签的onerror事件。

原理是这样的:我们插入一个图片标签<img src=”…”>,但是把图片的地址(src)设成一个肯定不存在的路径(比如1)。浏览器尝试加载这个图片时,必然会失败,一旦加载失败,就会触发onerror这个事件处理器。而onerror后面可以跟JavaScript代码!于是,一个完美的XSS Payload就诞生了。

4.2 构造非脚本标签Payload

我们在Burp Suite里截获提交留言的请求,然后将txtName参数修改为:

<img src=1 onerror=alert(document.cookie)>

这个Payload的意思是:插入一张图片,图片地址是“1”(一个无效地址),当图片加载错误时,执行alert(document.cookie)。放行数据包后,回到浏览器,你会看到弹窗再次出现,而页面上可能会显示一个破碎的图片图标。

这里有几个技术细节值得深究。首先,为什么可以不用引号?在HTML中,如果属性值不包含空格或特殊字符,引号经常是可选的。写成src=1src=”1″效果一样。这种写法有时能绕过一些基于字符串匹配的简单过滤。其次,事件处理器是XSS的宝库,除了onerror,还有onloadonmouseoveronclick等等,它们都可以在特定条件下执行JS代码。最后,能执行JS的标签也不止<img>,还有<svg><iframe><body><input>等等,甚至一些非常冷门的标签,这为攻击提供了广阔的“攻击面”。

High级别的防护,试图通过更完善的正则表达式封死<script>标签,但它犯了一个关键错误:只防一点,不防一面。它没有对用户输入进行全面的HTML标签和属性白名单过滤,也没有对事件处理器这样的危险属性进行特殊处理。这给了攻击者利用其他HTML特性进行绕过空间。防御开始变得复杂,需要考虑到各种可能的HTML和JS注入场景。

5. Impossible级别:真正的铜墙铁壁是如何炼成的?

5.1 终极防御方案剖析

终于,我们来到了Impossible级别。顾名思义,在这一级别,开发者试图实现一种近乎不可能被绕过的防御。我们直接查看源码,会发现关键所在:无论是“Name”还是“Message”字段,在输出到页面之前,都毫无例外地使用了htmlspecialchars()函数,并且使用了正确的标志位

在PHP中,htmlspecialchars($string, ENT_QUOTES, ‘UTF-8’)是最安全的用法之一。ENT_QUOTES标志意味着同时转换单引号和双引号,防止它们在HTML属性中被利用。UTF-8编码指定可以避免一些编码绕过问题。经过这个函数处理,用户输入中的所有特殊字符都会被转换为对应的HTML实体:

  • <变成&lt;
  • >变成&gt;
  • 变成&quot;
  • 变成&#039;(或&apos;)
  • &变成&amp;

这样一来,无论用户输入什么,到了浏览器那里,都只是一段无害的纯文本。<script>会原样显示为“

http://www.jsqmd.com/news/464385/

相关文章:

  • 趣题
  • 快递鸟API实战:如何用Python快速集成物流查询与电子面单(附完整代码)
  • EtherCAT深度解析——从“火车模型”到工业实践
  • nanopb(一)——从零到一:在资源受限的嵌入式世界构建高效数据通道
  • Docker+Minio实战:5分钟搞定私有云存储搭建(附Java SDK接入指南)
  • SWAT模型实战 | ArcSWAT常见数据库写入错误排查与修复指南
  • HiKey960开发板ptable分区刷写失败排查与修复指南
  • VSCode+ROS2 Foxy环境配置全攻略:从零开始搭建机器人开发环境(含常见错误解决)
  • Libvio访问异常?5分钟搞定403/502错误码的终极排查手册
  • 基于Jenkins与阿里云k8s的CI/CD流水线优化实战
  • 告别虚拟机!Win10+CentOS7双系统性能优化指南(含SSD分区技巧)
  • Cyclone IV引脚连接避坑指南:从CLK到PLL的5个常见错误配置
  • 探索Lorem Picsum:如何高效获取与定制随机图片的完整指南
  • TMC2660驱动步进电机实战:从SPI配置到精准定位控制(附避坑指南)
  • FMCW雷达信号处理全解析:从混频到距离估计
  • 500k波特率下CAN总线负载率避坑指南:为什么你的实际负载总比计算值高20%?
  • Linux MMC驱动实战:从零开始调试SD卡初始化(附5.4内核源码分析)
  • STM32F429实战:用FreeRTOS+CLI打造机器人控制台(含DMA优化技巧)
  • 安装15.3版本单实例PostgreSQL
  • TBOX(Telematics Box)在智能网联汽车中的核心功能与应用场景解析
  • ArcGIS10.2 许可服务启动失败:从端口占用到服务修复的完整排错指南
  • WPF开发实战:HandyControl控件库的快速集成与应用
  • 从国产化替代到电路优化:基于Xilinx 7系列FPGA的INIT_B引脚实战解析
  • 避免蓝牙耳机A2DP连接冲突:IOT设备与手机同时发起start请求的解决方案
  • 从零到一:MicroPython实战入门之环境搭建、LED闪烁与固件部署
  • 动态规划在图像拼接中的最佳缝合线优化策略
  • 组合导航中的舒勒效应:为什么你的无人机总在84分钟后偏离航线?
  • Keil5环境下STM32F103C8T6工程搭建全攻略:从文件夹结构到编译调试
  • BUCK电源环路设计避坑指南:从PLECS仿真到DSP实现的5个关键点
  • 海思开发板+FFmpeg+Nginx搭建RTMP推流环境:从编译到播放的完整避坑指南