Tags: php web csp-bypass 

Rating: 5.0

### Baby CSP (web, 6 solves, 406 points)
> We just started our bug bounty program. Can you find anything suspicious?
>
> The website is running at https://baby-csp.web.jctf.pro/

#### The challenge
The challenge was marked as `medium` but had very little solves. The idea wasn't new to the challenge so I thought players would know it but apperantly this wasn't the case and it was proven that the challenge was rather difficult.

By visiting the main page we could see a higlighted source code of the main server code.

```php=

setInterval(
()=>user.style.color=Math.random()<0.3?'red':'black'
,100);
</script>
<center><h1> Hello <span>{$_GET['user']}</span>!!</h1>

Click here to get a flag!


EOT;
}else{
show_source(__FILE__);
}

// Found a bug? We want to hear from you! /bugbounty.php
// Check /Dockerfile
```

At the bottom we can see two comments:
* `/Dockerfile` which yields a simple `Dockerfile` of the build:
```Dockerfile
FROM php:7.4-apache
COPY src-docker/ /var/www/html/
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
EXPOSE 80
```
* `/bugbounty.php` which is basically a script used to report URLs to a bot.

From the `Dockerfile` we can notice one thing that will come important later on, and that is `php.ini-development` which hints us that this is built under the development config.

#### The solution

Only three bugs were intended to be present in the code.

**Reflected XSS**
We could quickly notice that by visiting https://baby-csp.web.jctf.pro/?user=%3Cu%3Eterjanq%3C/u%3E we get a **reflected HTML** returned.

![](https://i.imgur.com/r3bppS2.png)

We are, however, **limited to only 23 characters**. By visiting https://tinyxss.terjanq.me we can notice a payload with only 23 characters and that is:

```htmlmixed
<svg/onload=eval(name)>
```

This would normally eval the code inside the page, but unforunately this would be blocked by a **very strict, nonce-based, CSP** (Content-Security-Policy).

![](https://i.imgur.com/F2Ah7wv.png)

**PHP Warnings**
Here comes the second vulnerability in the challenge - **PHP running in development mode**

We can notice in the code that **we can choose which hashing algorithm** will be used in order to generate the nonce from 8 random bytes. By providing an invalid algorithm we will see 10 warnings.

![](https://i.imgur.com/QR2wZEY.png)

**Order matters**
Normally, in PHP, when you return any body data before `header()` is called, the call will be ignored because the response was already sent to the user and headers must be sent first. In the application there was no explicit data returned before calling `header("content-security-policy: ...");` but because warnings were displayed first, they went into the response buffer before the header had a chance to get there in time.

PHP is known for **buffering the response to 4096** bytes by default, so by providing enough data inside warnings, the response will be sent before the CSP header, causing the header to be ignored. Hence, it is possible to execute our SVG payload.

*There is also another limit for the size of the warning (1kb if I recall correctly) so it is needed to force around 4 warnings 1000 characters each.*

#### Exploit

```htmlmixed
<script>
name="fetch('?flag').then(e=>e.text()).then(alert)"

location = 'https://baby-csp.web.jctf.pro/?user=%3Csvg%20onload=eval(name)%3E&alg='+'a'.repeat('292');

</script>
```

[PoC](https://terjanq.me/justCTF2020/babycsp.html)

*Some players struggled with fetching the actual flag and this was because the admin was being authenticated through `Lax cookie`. That's why it's needed to use top window instead of iframes for instance. And also, the bot was closing the page just after the page loaded so players had to to either write blocking PoCs or stall the page for a little longer (e.g. through a long loading image).*

Original writeup (https://hackmd.io/@terjanq/justCTF2020-writeups#Baby-CSP-web-6-solves-406-points).