diff --git a/api.js b/api.js
index 39b35e4..8c925c4 100644
--- a/api.js
+++ b/api.js
@@ -11,11 +11,9 @@ const Users = database.Users;
const Secrets = database.Secrets;
const safeCompare = require('safe-compare');
const { Op } = require("sequelize");
-const Settings = database.Settings;
const PayloadFireResults = database.PayloadFireResults;
const CollectedPages = database.CollectedPages;
const InjectionRequests = database.InjectionRequests;
-const update_settings_value = database.update_settings_value;
const constants = require('./constants.js');
const validate = require('express-jsonschema').validate;
const get_hashed_password = require('./utils.js').get_hashed_password;
@@ -54,11 +52,7 @@ function session_wrapper_function(req, res, next) {
async function set_up_api_server(app) {
// Check for existing session secret value
- const session_secret_setting = await Settings.findOne({
- where: {
- key: constants.session_secret_key
- }
- });
+ const session_secret_setting = process.env.SESSION_SECRET_KEY;
if (!session_secret_setting) {
console.error(`No session secret is set, can't start API server (this really shouldn't happen...)!`);
@@ -118,6 +112,10 @@ async function set_up_api_server(app) {
constants.API_BASE_PATH + 'payloadfires',
constants.API_BASE_PATH + 'collected_pages',
constants.API_BASE_PATH + 'settings',
+ constants.API_BASE_PATH + 'xss-uri',
+ constants.API_BASE_PATH + 'user-path',
+ constants.API_BASE_PATH + '',
+
];
// Check if the path being accessed required authentication
@@ -486,13 +484,13 @@ async function set_up_api_server(app) {
}
}
app.post(constants.API_BASE_PATH + 'record_injection', validate({ body: RecordCorrelatedRequestSchema }), async (req, res) => {
- const correlation_key_record = await Settings.findOne({
+ const user = await Users.findOne({
where: {
- key: constants.CORRELATION_API_SECRET_SETTINGS_KEY
+ injectionCorrelationAPIKey: req.body.owner_correlation_key
}
});
- if (!safeCompare(correlation_key_record.value, req.body.owner_correlation_key)) {
+ if (! user) {
res.status(200).json({
"success": false,
"error": "Invalid authentication provided. Please provide a proper correlation API key.",
@@ -535,53 +533,18 @@ async function set_up_api_server(app) {
Returns current settings values for the UI
*/
app.get(constants.API_BASE_PATH + 'settings', async (req, res) => {
- const settings_to_retrieve = [
- {
- key: constants.CORRELATION_API_SECRET_SETTINGS_KEY,
- return_key: 'correlation_api_key',
- default: '',
- formatter: false,
- },
- {
- key: constants.CHAINLOAD_URI_SETTINGS_KEY,
- return_key: 'chainload_uri',
- default: '',
- formatter: false,
- },
- {
- key: constants.PAGES_TO_COLLECT_SETTINGS_KEY,
- return_key: 'pages_to_collect',
- default: [],
- formatter: ((value) => {
- return JSON.parse(value);
- }),
- },
- {
- key: constants.SEND_ALERT_EMAILS_KEY,
- return_key: 'send_alert_emails',
- default: true,
- formatter: ((value) => {
- return JSON.parse(value);
- }),
- },
- ];
-
- let result = {};
- let database_promises = settings_to_retrieve.map(async settings_value_metadata => {
- const db_record = await Settings.findOne({
- where: {
- key: settings_value_metadata.key
- }
- });
-
- const formatter_function = settings_value_metadata.formatter ? settings_value_metadata.formatter : (value) => value;
- result[settings_value_metadata.return_key] = db_record ? formatter_function(db_record.value) : settings_value_metadata.default;
- });
- await Promise.all(database_promises);
-
+ let returnObj = {}
+ const user = await Users.findOne({ where: { 'id': req.session.user_id } });
+ if(! user){
+ return res.send("Invalid");
+ }
+ returnObj.correlation_api_key = user.injectionCorrelationAPIKey;
+ returnObj.chainload_uri = user.additionalJS;
+ returnObj.send_alert_emails = user.sendEmailAlerts;
+
res.status(200).json({
'success': true,
- result
+ returnObj
}).end();
});
@@ -621,60 +584,25 @@ async function set_up_api_server(app) {
}
}
app.put(constants.API_BASE_PATH + 'settings', validate({ body: UpdateConfigSchema }), async (req, res) => {
-
+ const user = await Users.findOne({ where: { 'id': req.session.user_id } });
+ if(! user){
+ return res.send("Invalid");
+ }
if(req.body.correlation_api_key === true) {
- const correlation_api_key = get_secure_random_string(64);
- await update_settings_value(
- constants.CORRELATION_API_SECRET_SETTINGS_KEY,
- correlation_api_key
- );
+ user.injectionCorrelationAPIKey = req.body.correlation_api_key;
}
// Intentionally no URL validation incase people want to do
// data: for inline extra JS.
if(req.body.chainload_uri) {
- await update_settings_value(
- constants.CHAINLOAD_URI_SETTINGS_KEY,
- req.body.chainload_uri
- );
+ user.additionalJS = req.body.chainload_uri;
}
if(req.body.send_alert_emails !== undefined) {
- await update_settings_value(
- constants.SEND_ALERT_EMAILS_KEY,
- req.body.send_alert_emails.toString()
- );
+ user.sendEmailAlerts = req.body.send_alert_emails;
}
- // Immediately rotate session secret and revoke all sessions.
- if(req.body.revoke_all_sessions !== undefined) {
- const new_session_secret = get_secure_random_string(64);
- // Update session secret in database
- const session_secret_setting = await Settings.findOne({
- where: {
- key: constants.session_secret_key
- }
- });
- session_secret_setting.value = new_session_secret;
- await session_secret_setting.save();
-
- // We do this by patching the sessions middleware at runtime
- // to utilize a new HMAC secret so all previous sessions are revoked.
- const updated_session_settings = {
- ...sessions_settings_object,
- ...{
- secret: session_secret_setting.value
- }
- };
- sessions_middleware = sessions(updated_session_settings);
- }
-
- if(req.body.pages_to_collect) {
- await update_settings_value(
- constants.PAGES_TO_COLLECT_SETTINGS_KEY,
- JSON.stringify(req.body.pages_to_collect)
- );
- }
+ await user.save();
res.status(200).json({
'success': true,
diff --git a/app.js b/app.js
index b6ad568..be4c317 100644
--- a/app.js
+++ b/app.js
@@ -6,7 +6,6 @@ const path = require('path');
const asyncfs = require('fs').promises;
const uuid = require('uuid');
const database = require('./database.js');
-const Settings = database.Settings;
const PayloadFireResults = database.PayloadFireResults;
const savePayload = database.savePayload;
const Users = database.Users;
@@ -333,28 +332,17 @@ async function get_app_server() {
}
console.log(`Got xss fetch for user ${user.email}`);
- const db_promises = [
- Settings.findOne({
- where: {
- key: constants.PAGES_TO_COLLECT_SETTINGS_KEY,
- }
- }),
- Settings.findOne({
- where: {
- key: constants.CHAINLOAD_URI_SETTINGS_KEY,
- }
- }),
- ];
- const db_results = await Promise.all(db_promises);
- const pages_to_collect = (db_results[0] === null) ? [] : JSON.parse(db_results[0].value);
- const chainload_uri = (db_results[1] === null) ? '' : db_results[1].value;
+ const chainload_uri = user.additionalJS;
+ if (! chainload_uri){
+ chainload_uri = '';
+ }
res.send(XSS_PAYLOAD.replace(
/\[HOST_URL\]/g,
`https://${process.env.XSS_HOSTNAME}`
).replace(
'[COLLECT_PAGE_LIST_REPLACE_ME]',
- JSON.stringify(pages_to_collect)
+ JSON.stringify([])
).replace(
/\[USER_PATH\]/g,
userPath
diff --git a/database.js b/database.js
index e69ad8e..bedd8bb 100644
--- a/database.js
+++ b/database.js
@@ -19,46 +19,6 @@ const sequelize = new Sequelize(
const Model = Sequelize.Model;
-/*
- Storage for XSS Hunter Express settings.
-
- All settings keys must be unique.
-
- Additionally stores admin credentials for the
- single user that can authenticate.
-*/
-class Settings extends Model {}
-Settings.init({
- id: {
- allowNull: false,
- primaryKey: true,
- type: Sequelize.UUID,
- defaultValue: uuid.v4()
- },
- // Setting name
- key: {
- type: Sequelize.TEXT,
- allowNull: true,
- unique: true
- },
- // Setting value
- value: {
- type: Sequelize.TEXT,
- allowNull: true,
- },
-}, {
- sequelize,
- modelName: 'settings',
- indexes: [
- {
- unique: true,
- fields: ['key'],
- method: 'BTREE',
- }
- ]
-});
-
-
/*
Secrets found in DOMs
*/
@@ -76,10 +36,22 @@ Users.init({
unique: true
},
path: {
- type: Sequelize.TEXT,
- allowNull: true,
+ type: sequelize.text,
+ allownull: true,
+ unique: true
+ },
+ injectionCorrelationAPIKey: {
+ type: sequelize.text,
+ allownull: true,
+ unique: true
+ },
+ additionalJS: {
+ type: sequelize.text,
+ allownull: true,
unique: true
}
+
+
}, {
sequelize,
modelName: 'users',
@@ -381,57 +353,6 @@ InjectionRequests.init({
]
});
-async function initialize_configs() {
- // Check for existing session secret value
- const session_secret_setting = await Settings.findOne({
- where: {
- key: constants.session_secret_key
- }
- });
-
- // If it exists, there's nothing else to do here.
- if(session_secret_setting) {
- return
- }
-
- console.log(`No session secret set, generating one now...`);
-
- // Since it doesn't exist, generate one.
- await Settings.create({
- id: uuid.v4(),
- key: constants.session_secret_key,
- value: get_secure_random_string(64)
- });
-
- console.log(`Session secret generated successfully!`);
-}
-
-async function setup_admin_user(password) {
- // If there's an existing admin user, skip this.
- // Check for existing session secret value
- const admin_user_password = await Settings.findOne({
- where: {
- key: constants.ADMIN_PASSWORD_SETTINGS_KEY
- }
- });
-
- // If user is already set up then there's nothing
- // for us to do here, return.
- if(admin_user_password) {
- return false
- }
-
- const bcrypt_hash = await get_hashed_password(password);
-
- // Set up the admin user
- await Settings.create({
- id: uuid.v4(),
- key: constants.ADMIN_PASSWORD_SETTINGS_KEY,
- value: bcrypt_hash
- });
-
- return true;
-}
function get_default_user_created_banner(password) {
return `
@@ -444,16 +365,7 @@ function get_default_user_created_banner(password) {
╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
- An admin user (for the admin control panel) has been created
- with the following password:
-
- PASSWORD: ${password}
-
- XSS Hunter Express has only one user for the instance. Do not
- share this password with anyone who you don't trust. Save it
- in your password manager and don't change it to anything that
- is bruteforcable.
-
+ Hi. I love you.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
█████╗ ████████╗████████╗███████╗███╗ ██╗████████╗██╗ ██████╗ ███╗ ██╗
██╔══██╗╚══██╔══╝╚══██╔══╝██╔════╝████╗ ██║╚══██╔══╝██║██╔═══██╗████╗ ██║
@@ -466,60 +378,16 @@ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
`;
}
-async function initialize_users() {
- // Check if the admin user has been created.
- // If not then set it up.
-
- // Generate cryptographically-secure random
- // password for the default user we're adding.
- const new_password = get_secure_random_string(32);
-
- // Create user and add to database
- const new_user_created = await setup_admin_user(
- new_password
- );
-
- if(!new_user_created) {
- return
- }
-
- // Now we need to write these credentials to the
- // filesystem in a file so the user can retrieve
- // them.
- const banner_message = get_default_user_created_banner(
- new_password
- );
-
+async function print_banner() {
console.log(banner_message);
}
-// Set up correlation API with a randomly
-// generated API key to auth with.
-async function initialize_correlation_api() {
- const existing_correlation_key = await Settings.findOne({
- where: {
- key: constants.CORRELATION_API_SECRET_SETTINGS_KEY
- }
- });
-
- if(existing_correlation_key) {
- return
- }
-
- const api_key = get_secure_random_string(64);
- await Settings.create({
- id: uuid.v4(),
- key: constants.CORRELATION_API_SECRET_SETTINGS_KEY,
- value: api_key
- });
-}
async function database_init() {
const force = false;
// Set up database schema
await Promise.all([
- Settings.sync({ force: force }),
PayloadFireResults.sync({ force: force }),
Users.sync({ force: force }),
Secrets.sync({ force: force }),
@@ -528,45 +396,17 @@ async function database_init() {
]);
await Promise.all([
- // Set up configs if they're not already set up.
- initialize_configs(),
-
// Set up admin panel user if not already set up.
- initialize_users(),
-
- // Set up the correlation API if not already set up
- initialize_correlation_api(),
+ print_banner(),
]);
}
-async function update_settings_value(settings_key, new_value) {
- const settings_record = await Settings.findOne({
- where: {
- key: settings_key
- }
- });
-
- if(settings_record) {
- settings_record.value = new_value;
- await settings_record.save();
- return
- }
-
- await Settings.create({
- id: uuid.v4(),
- key: settings_key,
- value: new_value
- });
-}
-
module.exports = {
sequelize,
- Settings,
PayloadFireResults,
CollectedPages,
InjectionRequests,
database_init,
- update_settings_value,
savePayload,
Secrets,
Users
diff --git a/docker-compose.yml b/docker-compose.yml
index 3a941c9..f00f47c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -36,6 +36,8 @@ services:
# CLIENT ID FOR OAUTH LOGIN
- CLIENT_ID=your_client_id
- CLIENT_SECRET=your_client_secret
+ # GENERATE A RANDOM LONG STRING FOR THIS
+ - SESSION_SECRET_KEY=
# THERE IS NO NEED TO MODIFY BELOW THIS LINE
# ------------------------------------------
# FEEL FREE, BUT KNOW WHAT YOU'RE DOING.
diff --git a/front-end/src/App.vue b/front-end/src/App.vue
index 714d3ae..1b0ef56 100644
--- a/front-end/src/App.vue
+++ b/front-end/src/App.vue
@@ -7,13 +7,6 @@
XSS Hunter
-
Please login to continue.