diceCTF에 한번 참여해봤는데 단 한 문제도 풀지 못했다. 문제 수준이 보통이 아니다. 내가 많이 부족한걸 알지만 한 문제도 못풀 줄은 몰랐다... 다름 사람의 writeup을 봐도 처음 보는 개념이 많아서 일일이 내가 찾아봐야한다. 최선을 다해 모든 문제의 write-up을 써보고자 한다. 아... 난 왤케 못하는걸까..........
첫 화면은 별거 없다. 대충 입력하고 create하면
흠 입력한 값이 그대로 출력된다. 혹시 몰라서 XSS를 해보니 된다. 그런데 쿠키값도 설정된게 없다. id, token값이 보인다. 소스코드 파일도 주어지니 코드를 살펴보자.
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 });
const express = require('express');
const app = express();
app.use(express.urlencoded({ extended: false }));
app.use(express.static('public'));
app.post('/create', (req, res) => {
const data = req.body.data ?? 'no data provided.';
const { id, token } = db.createNote({ data: data.toString() });
res.redirect(`/note?id=${id}&token=${token}`);
});
app.get('/note', (req, res) => {
const { id, token } = req.query;
const note = db.getNote({
id: parseInt(id ?? '-1'),
token: (token ?? '').toString(),
});
if (note.error) {
res.send(note.error);
} else {
res.send(note.data);
}
});
app.listen(3000, () => {
console.log('listening on port 3000');
});
코드를 대강 읽어보면 입력한 값이 id와 token과 함께 저장하는데 id는 data의 개수, token은 id값을 secret값이 'secret-${crypto.randomUUID}'인 sha-256 암호화한 값이다.
db를 만들자마자 flag를 넣는것으로 보아 id=0에 flag가 저장된다는 것을 유추할 수 있다.
여기까지가 내가 파악한 단서였다. 이 이상 뭘 알아낼 수가 없었다. 한 가지 단서를 내가 못찾았다. 그건 바로 this.secret = `secret-${crypto.randomUUID}`; 이다. 이 randomUUID에 "()"가 없다는 것... 단순 코드 오류라니... 그래서 코드를 대충 짜서 실행시켜보면 된다.
const crypto = require('crypto');
let secret = `secret-${crypto.randomUUID}`;
let id = 0;
console.log(crypto.createHmac('sha256', secret).update(id.toString()).digest('hex'));
근데 여기가 끝이 아니다. 진짜 진짜 황당한 점이 있다. 이 결과값이 nodejs 버전에 따라 다른값이 나온다. 이게 말이되나...? 출제자의 의도가 맞을까? 16.13.2. 버전이라고 한다.
solved
악랄하다