Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/tools/modules/verify_datastore.rb
Views: 11619
#!/usr/bin/env ruby12#3# This script parses a Metasploit module's use of the datastore to4# ensure that all datastore elements are both declared and used. Adding5# arbitrary elements to the datastore without first declaring them won't6# throw an error at runtime, but can occasionally be the cause of bugs and7# make troubleshooting more difficult.8#9# This script could use more serious option parsing, and a batch mode beyond10# bash's "for i in path/to/modules/*.rb; do verify_datastore.rb $i; done" Also,11# it assumes Metasploit's msf/core is in the load path.12#1314infile = ARGV[0]15unless(infile && File.readable?(infile))16puts "Usage: #{$0} /path/to/module.rb"17exit(1)18end1920verbose = false2122mod = File.open(infile, "rb") {|f| f.read(f.stat.size)}2324regex = {}25regex[:datastore] = /[^\x2e](datastore\x5b[\x22\x27]([^\x22\x27]+))/26regex[:comment] = /^[\s]*#/27regex[:opts] = /register_options/28regex[:opts_end] = /^[\s]*def[\s]+/29regex[:is_opt] = /^[\s]*(Opt[A-Z][^\x2e]+)\x2enew[\s]*\x28?[\x22\x27]([^\x22\x27]+)/30regex[:mixin] = /^[\s]*include[\s]+([^\s]+)/31regex[:class] = /^[\s]*class[\s]+Metasploit3[\s]*<[\s]*([A-Z][^\s]+)/32# regex[:require] = /^[\s]*require[\s]+[\x22\x27]([^\x22\x27]+)[\x22\x27]/3334referenced_datastores = []35declared_datastores = {}36undeclared_datastores = []37unused_datastores = []3839# Declared datastore finder40mod.each_line do |line|41next if line.match regex[:comment]42datastores = line.scan regex[:datastore]43datastores.each {|ds| referenced_datastores << ds[1]}44end4546# Referenced datastore finder47in_opts = false48mod.each_line do |line|49in_opts = true if line.match regex[:opts]50in_opts = false if line.match regex[:opts_end]51next unless in_opts52if line.match regex[:is_opt]53# Assumes only one!54declared_datastores[$2] ||= $155end56end5758# Class and Mixin finder59$mixins = []60$class = nil6162mod.each_line do |line|63if line.match regex[:class]64$class = ObjectSpace.class_eval($1)65elsif line.match regex[:mixin]66mixin = $167begin68$mixins << ObjectSpace.module_eval(mixin)69rescue70puts "[-] Error including mixin: #{mixin}"71next72end73end74end7576class Fakemod < $class77$mixins.each {|m| include m}78end79fakemod = Fakemod.new80inhereted_datastores = fakemod.options.keys8182undeclared_datastores = referenced_datastores - (declared_datastores.keys + inhereted_datastores)8384# It's common to not use some inhereted datastores, don't bother talking about them85unused_datastores = declared_datastores.keys - referenced_datastores8687if verbose88puts "[+] --- Referenced datastore keys for #{infile}"89referenced_datastores.uniq.sort.each {|ds| puts ds}90puts "[+] --- Declared datastore keys for #{infile}"91declared_datastores.keys.sort.each {|opt| puts "%-30s%s" % [opt, declared_datastores[opt]] }92end9394unless undeclared_datastores.empty?95puts "[-] %-60s : fail (undeclared)" % [infile]96puts "[-] The following datastore elements are undeclared" if verbose97undeclared_datastores.uniq.sort.each {|opt| puts " \e[31m#{opt}\e[0m" }98end99100unless unused_datastores.empty?101puts "[*] %-60s : warn (unused)" % [infile]102puts "[*] The following datastore elements are unused" if verbose103unused_datastores.uniq.sort.each {|opt| puts " \e[33m#{opt}\e[0m" }104end105106if undeclared_datastores.empty? && unused_datastores.empty?107puts "[+] %-60s : okay" % [infile]108end109110111