Skip to content

Instantly share code, notes, and snippets.

@iczero
Last active October 14, 2018 03:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iczero/4d4d91796deff67f6a591d0a3cea6ceb to your computer and use it in GitHub Desktop.
Save iczero/4d4d91796deff67f6a591d0a3cea6ceb to your computer and use it in GitHub Desktop.
Fills the databases of scammers with fake email/password combinations
// spam the scammers until they're gone
// dependencies: an-array-of-english-words request blessed
const request = require('request');
const words = require('an-array-of-english-words');
const blessed = require('blessed');
const http = require('http');
const EventEmitter = require('events');
const UI_UPDATE_INTERVAL = 100;
const EMAIL_DOMAINS = [
'inbox.com', 'yahoo.com', 'gmail.com', 'aol.com', 'icloud.com',
'outlook.com', 'mail.com', 'hotmail.com', 'ymail.com'
];
/* eslint-disable max-len */
const REQUEST_OPTS = {
url: 'http://not-a-real-site.not-a-real-tld/thisguy/login.php',
method: 'POST',
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate',
'Cache-Control': 'max-age=0',
'Accept-Language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,zh-TW;q=0.6,es;q=0.5',
'Origin': 'http://not-a-real-site.not-a-real-tld',
'Upgrade-Insecure-Requests': 1
},
timeout: 5000
};
/* eslint-enable max-len */
const ITER_OPTS = {
count: 100, // how many requests to perform simultaneously
reqOpts: REQUEST_OPTS,
emailDomains: EMAIL_DOMAINS,
wordList: words,
acceptCode: 302, // status code to treat as success
emailKey: 'email',
passwordKey: 'password',
additionalFormOpts: {
// additional values which may be submitted with the form
// submit: 'CONTINUE'
}
};
http.globalAgent.maxSockets = ITER_OPTS.count;
/**
* Generate a random integer
* @param {Number} high Upper limit
* @param {Number} [low = 0] Lower limit
* @return {Number} The random integer
*/
function randInt(high, low = 0) {
return Math.floor(Math.random() * (high - low)) + low;
}
/**
* Represents an iteration of requests
* @extends EventEmitter
*/
class Iteration extends EventEmitter {
/**
* Creates an Iteration
* @param {Object} opts Options for this iteration
* @param {Number} opts.count Number of requests in the iteration
* @param {Object} opts.reqOpts Options to pass to request()
* @param {Object} opts.emailDomains Acceptable email domains to be used
* @param {String[]} opts.wordList Word list to use for generating credentials
* @param {Number} [opts.acceptCode=200] Status code signifying success
* @param {String} [opts.emailKey=email] Form key for email
* @param {String} [opts.passwordKey=password] Form key for password
* @param {Object} [opts.additionalFormOpts] Additional keys to add to form
*/
constructor(opts) {
super();
this.count = opts.count;
this.reqOpts = opts.reqOpts;
this.emailDomains = opts.emailDomains;
this.wordList = opts.wordList;
this.acceptCode = opts.acceptCode || 200;
this.emailKey = opts.emailKey || 'email';
this.passwordKey = opts.passwordKey || 'password';
this.additionalFormOpts = opts.additionalFormOpts || {};
this.pending = 0;
this.totalRequests = 0;
this.lastEmail = null;
this.lastPassword = null;
this.lastError = null;
}
/**
* Generate a random password.
* @return {String} The generated password
*/
randomPassword() {
let word = this.wordList[randInt(this.wordList.length - 1)];
return word + randInt(1000);
}
/**
* Generate a random email.
* @return {String} The generated email
*/
randomEmail() {
let str = this.randomPassword();
let domain = this.emailDomains[randInt(this.emailDomains.length - 1)];
return `${str}@${domain}`;
}
/**
* Perform a request
* @return {Request} The request object
*/
doRequest() {
this.pending++;
this.totalRequests++;
this.emit('startRequest', this.totalRequests);
let email = this.randomEmail();
let password = this.randomPassword();
let opts = {
form: {
[this.emailKey]: email,
[this.passwordKey]: password,
...this.additionalFormOpts
},
...this.reqOpts
};
let req = request.post(opts, (err, response) => {
this.lastEmail = email;
this.lastPassword = password;
this.pending--;
this.emit('endRequest', this.totalRequests);
if (err || response.statusCode !== this.acceptCode) {
this.lastError = err ? err.message : response.statusCode;
this.doRequest();
} else if (this.pending <= 0) this.emit('done');
});
return req;
}
/**
* Start performing requests
*/
start() {
for (let i = 0; i < this.count; i++) this.doRequest();
}
}
/*
* Events:
* startRequest, requestId
* endRequest, requestId
* done
*/
const screen = blessed.screen({smartCSR: true});
screen.key('C-c', () => process.exit(0));
const infoBox = blessed.box({
top: 0,
left: 0,
width: '100%',
height: '100%',
content: '',
border: {
type: 'line',
}
});
screen.append(infoBox);
infoBox.focus();
let iterCount = 0;
let iter = null;
/**
* Update the display
*/
function updateDisplay() {
infoBox.setContent([
`Iteration #${iterCount}`,
`Performing ${iter.count} requests`,
`Requests performed in iteration: ${iter.totalRequests}`,
`Requests pending in iteration: ${iter.pending}`,
``,
`Last email sent: ${iter.lastEmail}`,
`Last password sent: ${iter.lastPassword}`,
`Last error: ${iter.lastError || '(none)'}`
].join('\n'));
screen.render();
}
// interval for update here
setInterval(() => updateDisplay(), UI_UPDATE_INTERVAL);
/**
* Run a new iteration
*/
function newIter() {
iterCount++;
iter = new Iteration(ITER_OPTS);
iter.on('done', () => newIter());
iter.start();
}
newIter();

Spamming scammers

Quick start

You should first find how the browser makes the request using the Network tab of the developer tools or similar

  • npm i an-array-of-english-words blessed request
  • Configure the request options (REQUEST_OPTS)
    • Change the URL and Origin header to match
    • Change the method if necessary
    • Add or remove headers as necessary
  • Configure the request manager options (ITER_OPTS)
    • Change the number of requests to perform simultaneously
    • Change email/password form fields if needed
    • Change accept status code (usually this is 302)
    • Add additional form options if needed
    • Modify the email/password generation functions if desired
  • node spam.js

Why

  • To waste the time of scammers so they don't have as much time to try out the real email/password combinations of those who fell for their trap
  • Fun
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment