Module: Msf::DBManager::Vuln
- Included in:
- Msf::DBManager
- Defined in:
- lib/msf/core/db_manager/vuln.rb
Instance Method Summary collapse
-
#delete_vuln(opts) ⇒ Array
Deletes Vuln entries based on the IDs passed in.
-
#each_vuln(wspace = framework.db.workspace, &block) ⇒ Object
This method iterates the vulns table calling the supplied block with the vuln instance of each entry.
-
#find_or_create_vuln(opts) ⇒ Object
Find or create a vuln matching this service/name.
- #find_vuln_by_details(details_map, host, service = nil) ⇒ Object
- #find_vuln_by_refs(refs, host, service = nil) ⇒ Object
- #get_vuln(wspace, host, service, name, data = '') ⇒ Object
-
#has_vuln?(name) ⇒ Boolean
Find a vulnerability matching this name.
-
#report_vuln(opts) ⇒ Object
- opts MUST contain
:host
- the host where this vulnerability resides
:name
-
the friendly name for this vulnerability (title).
- the host where this vulnerability resides
- opts MUST contain
-
#update_vuln(opts) ⇒ Mdm::Vuln
Update the attributes of a Vuln entry with the values in opts.
-
#vulns(opts) ⇒ Object
This methods returns a list of all vulnerabilities in the database.
Instance Method Details
#delete_vuln(opts) ⇒ Array
Deletes Vuln entries based on the IDs passed in.
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
# File 'lib/msf/core/db_manager/vuln.rb', line 289 def delete_vuln(opts) raise ArgumentError.new("The following options are required: :ids") if opts[:ids].nil? ::ApplicationRecord.connection_pool.with_connection { deleted = [] opts[:ids].each do |vuln_id| vuln = Mdm::Vuln.find(vuln_id) begin deleted << vuln.destroy rescue # refs suck elog("Forcibly deleting #{vuln}") deleted << vuln.delete end end return deleted } end |
#each_vuln(wspace = framework.db.workspace, &block) ⇒ Object
This method iterates the vulns table calling the supplied block with the vuln instance of each entry.
6 7 8 9 10 11 12 |
# File 'lib/msf/core/db_manager/vuln.rb', line 6 def each_vuln(wspace=framework.db.workspace, &block) ::ApplicationRecord.connection_pool.with_connection { wspace.vulns.each do |vulns| block.call(vulns) end } end |
#find_or_create_vuln(opts) ⇒ Object
Find or create a vuln matching this service/name
17 18 19 |
# File 'lib/msf/core/db_manager/vuln.rb', line 17 def find_or_create_vuln(opts) report_vuln(opts) end |
#find_vuln_by_details(details_map, host, service = nil) ⇒ Object
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/msf/core/db_manager/vuln.rb', line 21 def find_vuln_by_details(details_map, host, service=nil) # Create a modified version of the criteria in order to match against # the joined version of the fields crit = {} details_map.each_pair do |k,v| crit[ "vuln_details.#{k}" ] = v end vuln = nil if service other_vulns = service.vulns.includes(:vuln_details).where(crit).to_a vuln = other_vulns.empty? ? nil : other_vulns.first end # Return if we matched based on service return vuln if vuln # Prevent matches against other services crit["vulns.service_id"] = nil if service other_vulns = host.vulns.includes(:vuln_details).where(crit).to_a other_vulns.empty? ? nil : other_vulns.first end |
#find_vuln_by_refs(refs, host, service = nil) ⇒ Object
47 48 49 50 51 52 53 54 |
# File 'lib/msf/core/db_manager/vuln.rb', line 47 def find_vuln_by_refs(refs, host, service=nil) ref_ids = refs.find_all { |ref| ref.name.starts_with? 'CVE-'} relation = host.vulns.joins(:refs) if !service.try(:id).nil? return relation.where(service_id: service.try(:id), refs: { id: ref_ids}).first end return relation.where(refs: { id: ref_ids}).first end |
#get_vuln(wspace, host, service, name, data = '') ⇒ Object
56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/msf/core/db_manager/vuln.rb', line 56 def get_vuln(wspace, host, service, name, data='') raise RuntimeError, "Not workspace safe: #{caller.inspect}" ::ApplicationRecord.connection_pool.with_connection { vuln = nil if (service) vuln = ::Mdm::Vuln.find.where("name = ? and service_id = ? and host_id = ?", name, service.id, host.id).order("vulns.id DESC").first() else vuln = ::Mdm::Vuln.find.where("name = ? and host_id = ?", name, host.id).first() end return vuln } end |
#has_vuln?(name) ⇒ Boolean
Find a vulnerability matching this name
73 74 75 76 77 |
# File 'lib/msf/core/db_manager/vuln.rb', line 73 def has_vuln?(name) ::ApplicationRecord.connection_pool.with_connection { Mdm::Vuln.find_by_name(name) } end |
#report_vuln(opts) ⇒ Object
opts MUST contain
:host
-
the host where this vulnerability resides
:name
-
the friendly name for this vulnerability (title)
opts can contain
:info
-
a human readable description of the vuln, free-form text
:refs
-
an array of Ref objects or string names of references
:details
-
a hash with :key pointed to a find criteria hash and the rest containing VulnDetail fields
:sname
-
the name of the service this vulnerability relates to, used to associate it or create it.
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'lib/msf/core/db_manager/vuln.rb', line 90 def report_vuln(opts) return if not active raise ArgumentError.new("Missing required option :host") if opts[:host].nil? raise ArgumentError.new("Deprecated data column for vuln, use .info instead") if opts[:data] name = opts[:name] || return info = opts[:info] ::ApplicationRecord.connection_pool.with_connection { wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework) opts = opts.clone() opts.delete(:workspace) exploited_at = opts[:exploited_at] || opts["exploited_at"] details = opts.delete(:details) rids = opts.delete(:ref_ids) if opts[:refs] rids ||= [] opts[:refs].each do |r| if r.instance_of?(Mdm::Module::Ref) str = r.name elsif (r.respond_to?(:ctx_id)) and (r.respond_to?(:ctx_val)) str = "#{r.ctx_id}-#{r.ctx_val}" elsif (r.is_a?(Hash) and r[:ctx_id] and r[:ctx_val]) str = "#{r[:ctx_id]}-#{r[:ctx_val]}" elsif r.is_a?(String) str = r end rids << find_or_create_ref(:name => str) unless str.nil? end end host = nil addr = nil if opts[:host].kind_of? ::Mdm::Host host = opts[:host] else host = report_host({:workspace => wspace, :host => opts[:host]}) addr = Msf::Util::Host.normalize_host(opts[:host]) end ret = {} # Truncate the info field at the maximum field length if info info = info[0,65535] end # Truncate the name field at the maximum field length name = name[0,255] # Placeholder for the vuln object vuln = nil # Identify the associated service service = opts.delete(:service) # Treat port zero as no service if service or opts[:port].to_i > 0 if not service proto = nil case opts[:proto].to_s.downcase # Catch incorrect usages, as in report_note when 'tcp','udp' proto = opts[:proto] sname = opts[:sname] when 'dns','snmp','dhcp' proto = 'udp' sname = opts[:proto] else proto = 'tcp' sname = opts[:proto] end services = host.services.where(port: opts[:port].to_i, proto: proto) services = services.where(name: sname) if sname.present? service = services.first_or_create end # Try to find an existing vulnerability with the same service & references # If there are multiple matches, choose the one with the most matches # If a match is found on a vulnerability with no associated service, # update that vulnerability with our service information. This helps # prevent dupes of the same vuln found by both local patch and # service detection. if rids and rids.length > 0 vuln = find_vuln_by_refs(rids, host, service) vuln.service = service if vuln end else # Try to find an existing vulnerability with the same host & references # If there are multiple matches, choose the one with the most matches if rids and rids.length > 0 vuln = find_vuln_by_refs(rids, host) end end # Try to match based on vuln_details records if not vuln and opts[:details_match] vuln = find_vuln_by_details(opts[:details_match], host, service) if vuln && service && vuln.service.nil? vuln.service = service end end # No matches, so create a new vuln record unless vuln if service vuln = service.vulns.find_by_name(name) else vuln = host.vulns.find_by_name(name) end unless vuln vinf = { :host_id => host.id, :name => name, :info => info } vinf[:service_id] = service.id if service vuln = Mdm::Vuln.create(vinf) begin framework.events.on_db_vuln(vuln) if vuln rescue ::Exception => e wlog("Exception in on_db_vuln event handler: #{e.class}: #{e}") wlog("Call Stack\n#{e.backtrace.join("\n")}") end end end # Set the exploited_at value if provided vuln.exploited_at = exploited_at if exploited_at # Merge the references if rids vuln.refs << (rids - vuln.refs) end # Finalize if vuln.changed? (opts, vuln) vuln.save! end # Handle vuln_details parameters report_vuln_details(vuln, details) if details vuln } end |
#update_vuln(opts) ⇒ Mdm::Vuln
Update the attributes of a Vuln entry with the values in opts. The values in opts should match the attributes to update.
273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/msf/core/db_manager/vuln.rb', line 273 def update_vuln(opts) ::ApplicationRecord.connection_pool.with_connection { wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework, false) opts = opts.clone() opts.delete(:workspace) opts[:workspace] = wspace if wspace v = Mdm::Vuln.find(opts.delete(:id)) v.update!(opts) v } end |
#vulns(opts) ⇒ Object
This methods returns a list of all vulnerabilities in the database
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'lib/msf/core/db_manager/vuln.rb', line 247 def vulns(opts) ::ApplicationRecord.connection_pool.with_connection { # If we have the ID, there is no point in creating a complex query. if opts[:id] && !opts[:id].to_s.empty? return Array.wrap(Mdm::Vuln.find(opts[:id])) end wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework) opts = opts.clone() opts.delete(:workspace) search_term = opts.delete(:search_term) if search_term && !search_term.empty? column_search_conditions = Msf::Util::DBManager.create_all_column_search_conditions(Mdm::Vuln, search_term) wspace.vulns.includes(:host).where(opts).where(column_search_conditions) else wspace.vulns.includes(:host).where(opts) end } end |