Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
goelp14
GitHub Repository: goelp14/easyctf-iv-problems
Path: blob/master/nosource/src/app.js
671 views
1
const express = require('express');
2
const crypto = require('crypto');
3
const path = require('path');
4
const logger = require('morgan');
5
const session = require('express-session');
6
const mustacheExpress = require('mustache-express');
7
const bodyParser = require('body-parser');
8
const cookieParser = require('cookie-parser');
9
const helmet = require('helmet');
10
const useragent = require('express-useragent');
11
const MemoryStore = require('memorystore')(session);
12
13
14
function generateToken() {
15
return crypto.randomBytes(32).toString('base64');
16
}
17
18
function processToken(input, init, soupify) {
19
const token = Buffer.from(input, 'base64');
20
if (token.length != 32) {
21
console.error("invalid token from input: " + input);
22
return '';
23
}
24
25
if (soupify) {
26
token.write('soupd', 32 - 5, 5, 'binary');
27
}
28
29
let k = init & 0xff;
30
for (let i = 0; i < token.length; i++) {
31
k ^= token[i];
32
token[i] = k;
33
}
34
return token.toString('base64');
35
}
36
37
const app = express();
38
app.engine('mustache', mustacheExpress());
39
app.set('views', path.join(__dirname, 'views'));
40
app.set('view engine', 'mustache');
41
42
var sess = {
43
name: 'sid',
44
secret: "i am a cat who goes mrrroowww",
45
resave: false,
46
saveUninitialized: false,
47
cookie: {
48
httpOnly: true,
49
},
50
store: new MemoryStore({
51
checkPeriod: 1000 * 60 * 60 // prune expired entries
52
}),
53
};
54
55
var helmetConfig = {
56
dnsPrefetchControl: false,
57
};
58
59
if (app.get('env') === 'production') {
60
app.set('trust proxy', 1);
61
sess.cookie.secure = true;
62
}
63
64
app.use(logger('dev'));
65
app.use(bodyParser.urlencoded({extended: false}));
66
app.use(cookieParser());
67
app.use(session(sess));
68
app.use(helmet(helmetConfig));
69
app.use(useragent.express());
70
71
72
// img and css can be cached
73
app.use('/static/css', express.static(
74
path.join(__dirname, 'public', 'css'),
75
{ lastModified: false }));
76
77
app.use('/static/img', express.static(
78
path.join(__dirname, 'public', 'img'),
79
{ lastModified: false }));
80
81
82
// nothing else should be cached
83
app.use(function (req, res, next) {
84
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate');
85
res.setHeader('Pragma', 'no-cache');
86
next();
87
});
88
89
// handle js files
90
const static_js_options = {
91
root: path.join(__dirname, 'public', 'js'),
92
cacheControl: false,
93
lastModified: false,
94
etag: false,
95
};
96
97
app.get('/static/js/bootstrap.min.js', function (req, res, next) {
98
if (req.session.token && req.session.tokenTime) {
99
console.log('serving modified bootstrap.min.js');
100
res.sendFile('mod-bootstrap.min.js', static_js_options);
101
return;
102
}
103
next();
104
});
105
106
app.get('/static/js/popper.min.js', function (req, res, next) {
107
if (req.session.successOnce) {
108
delete req.session.successOnce;
109
console.log('serving modified popper.min.js');
110
res.sendFile('mod-popper.min.js', static_js_options);
111
return;
112
}
113
next();
114
});
115
116
app.use('/static/js', express.static(
117
static_js_options.root, static_js_options));
118
119
120
// do not filter these by user agent
121
app.get('/', function (req, res) {
122
delete req.session.tokenTime;
123
const token = generateToken();
124
req.session.token = token;
125
res.render('index', { token: token });
126
});
127
128
app.get('/soupd', function (req, res) {
129
req.session.destroy();
130
if (req.cookies.token) {
131
res.clearCookie('token');
132
}
133
res.render('soupd');
134
});
135
136
app.get('/useragent', function (req, res) {
137
res.send(req.useragent);
138
});
139
140
// nosource junior!!
141
app.get('/jr/', function (req, res) {
142
res.render('jr', {noSourceJr: true});
143
});
144
145
app.get('/www.google-analytics.com/analytics.js', function (req, res) {
146
res.sendFile('fake-analytics.js', static_js_options);
147
});
148
149
// filter everything below by user agent
150
app.use(function (req, res, next) {
151
if (!req.useragent.isChrome) {
152
res.redirect('/soupd?7');
153
} else {
154
next();
155
}
156
});
157
158
app.post('/login', function (req, res) {
159
if (req.session.token) {
160
const goodToken = processToken(req.session.token, 0x20, false);
161
const receivedToken = req.body.token;
162
console.log('receivedToken:', receivedToken);
163
console.log('goodToken :', goodToken);
164
req.session.token = '';
165
166
if (receivedToken === goodToken) {
167
// generate another token, with time
168
const token = generateToken();
169
req.session.token = token;
170
req.session.tokenTime = new Date();
171
172
res.setHeader('Refresh', '2; url=/soupd?4');
173
res.render('test', {
174
token: token,
175
timeoutSoupd: true,
176
});
177
return;
178
}
179
}
180
res.redirect('/soupd?5');
181
});
182
183
app.get('/login', function (req, res) {
184
//console.log("req.session: " + JSON.stringify(req.session));
185
//console.log("req.cookies: " + JSON.stringify(req.cookies));
186
187
if (req.cookies.token && req.session.token && req.session.tokenTime) {
188
const duration = new Date() - new Date(req.session.tokenTime);
189
const soupToken = processToken(req.session.token, 20, true);
190
//const nosoupToken = processToken(req.session.token, 20, false);
191
const receivedToken = req.cookies.token;
192
193
console.log('receivedToken:', receivedToken);
194
console.log('soupToken :', soupToken);
195
//console.log('nosoupToken :', nosoupToken);
196
console.log('duration', duration);
197
198
delete req.session.token;
199
delete req.session.tokenTime;
200
res.clearCookie('token');
201
202
if (receivedToken === soupToken) {
203
if (duration < 5000) {
204
req.session.successOnce = true;
205
res.render('success', { timeoutSoupd: true });
206
return;
207
}
208
res.redirect('/soupd?8');
209
return;
210
}
211
res.redirect('/soupd?9');
212
return;
213
}
214
res.redirect('/soupd?6');
215
});
216
217
module.exports = app;
218
219
220