module Msf::DBManager::Service # Deletes a port and associated vulns matching this port def del_service(wspace, address, proto, port, comm='') host = get_host(:workspace => wspace, :address => address) return unless host ::ActiveRecord::Base.connection_pool.with_connection { host.services.where({:proto => proto, :port => port}).each { |s| s.destroy } } end # Iterates over the services table calling the supplied block with the # service instance of each entry. def each_service(wspace=workspace, &block) ::ActiveRecord::Base.connection_pool.with_connection { services(wspace).each do |service| block.call(service) end } end def find_or_create_service(opts) report_service(opts) end def get_service(wspace, host, proto, port) ::ActiveRecord::Base.connection_pool.with_connection { host = get_host(:workspace => wspace, :address => host) return if !host return host.services.find_by_proto_and_port(proto, port) } end # # Record a service in the database. # # opts MUST contain # +:host+:: the host where this service is running # +:port+:: the port where this service listens # +:proto+:: the transport layer protocol (e.g. tcp, udp) # # opts may contain # +:name+:: the application layer protocol (e.g. ssh, mssql, smb) # +:sname+:: an alias for the above # +:workspace+:: the workspace for the service # def report_service(opts) return if !active ::ActiveRecord::Base.connection_pool.with_connection { |conn| addr = opts.delete(:host) || return hname = opts.delete(:host_name) hmac = opts.delete(:mac) host = nil wspace = opts.delete(:workspace) || workspace hopts = {:workspace => wspace, :host => addr} hopts[:name] = hname if hname hopts[:mac] = hmac if hmac # Other report_* methods take :sname to mean the service name, so we # map it here to ensure it ends up in the right place despite not being # a real column. if opts[:sname] opts[:name] = opts.delete(:sname) end if addr.kind_of? ::Mdm::Host host = addr addr = host.address else host = report_host(hopts) end if opts[:port].to_i.zero? dlog("Skipping port zero for service '%s' on host '%s'" % [opts[:name],host.address]) return nil end ret = {} =begin host = get_host(:workspace => wspace, :address => addr) if host host.updated_at = host.created_at host.state = HostState::Alive host.save! end =end proto = opts[:proto] || Msf::DBManager::DEFAULT_SERVICE_PROTO service = host.services.where(port: opts[:port].to_i, proto: proto).first_or_initialize opts.each { |k,v| if (service.attribute_names.include?(k.to_s)) service[k] = ((v and k == :name) ? v.to_s.downcase : v) elsif !v.blank? dlog("Unknown attribute for Service: #{k}") end } service.state ||= Msf::ServiceState::Open service.info ||= "" if (service and service.changed?) msf_import_timestamps(opts,service) service.save! end if opts[:task] Mdm::TaskService.create( :task => opts[:task], :service => service ) end ret[:service] = service } end # Returns a list of all services in the database def services(wspace = workspace, only_up = false, proto = nil, addresses = nil, ports = nil, names = nil) ::ActiveRecord::Base.connection_pool.with_connection { conditions = {} conditions[:state] = [Msf::ServiceState::Open] if only_up conditions[:proto] = proto if proto conditions["hosts.address"] = addresses if addresses conditions[:port] = ports if ports conditions[:name] = names if names wspace.services.includes(:host).where(conditions).order("hosts.address, port") } end end