“Bettercatalog” was a web challenge at the BSides Ahmedabad CTF 2021 that abused a bug in an old chrome version to trigger “Scroll to Text Fragment” (short: STTF) without user interaction and leak cross-origin data. More details about how STTF can be used for XS-Leaks can be found at the XS-Leaks Wiki.
Challenge description:
The catalog by bluepichu is so vulnerable, I made a secure version check this out https://bettercatalog.xyz. Please run your tests locally using docker. Source code: https://s3.amazonaws.com/bsidesahm/e9dd9cd8-b5a7-4ce9-bca1-c82e63fddcaf/bettercatalog_f4f479d06cb522dd565634479bb0dac2.tar.gz
The challenge is based on the “Catalog” challenge from Plaid CTF 2020, a detailed writeup can be found here. I’d recommend reading it before continuing to get a better overall understanding, but the main points are:
- A strict, nonce-based CSP is set at
php/src/include/utils.php:4
:
|
|
- It is possible to inject HTML via
$issue["image"]
atphp/src/issue.php:34
:
|
|
- It is possible to inject HTML via
$_POST["username"]
atphp/src/user.php:38
by trying to login with an invalid username and password, whereby the username is reflected atphp/src/include/header.php:48
:
|
|
|
|
While reading the writeup for “Catalog” and seeing “Scroll to Text Fragment” mentioned, I remembered stumbling upon this chromium issue by s1r1us. We can use this in combination with image lazy-loading to determine if a STTF was successful without requiring user interaction!
The steps are as follows:
- Create an issue that redirects to the issue with the flag. This is required to bypass the need of user interaction for STTF.
|
|
- Create another issue that redirects to our page hosting the actual script to leak the flag character by character:
|
|
- Implement the PoC from the chromium bug report by s1r1us into a script that leaks the flag.
- Submit the issue from step 2 to the admin.
Getting the script to work reliably took most of my time, for some reason STTF only triggered if there was a specific delay between changing frames[0].location
. There are probably also better ways to do it than how I did it, but here is my script that worked well enough to leak the flag:
|
|
Doing this character by character and updating the flag in the script, we get the flag: NEKO{ITS_4_5M4LL_1}