Module: Msf::DBManager::Service

Included in:
Msf::DBManager
Defined in:
lib/msf/core/db_manager/service.rb

Instance Method Summary collapse

Instance Method Details

#delete_service(opts) ⇒ Object

Deletes a port and associated vulns matching this port

Raises:

  • (ArgumentError)

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/msf/core/db_manager/service.rb', line 3

def delete_service(opts)
  raise ArgumentError.new("The following options are required: :ids") if opts[:ids].nil?

::ApplicationRecord.connection_pool.with_connection {
  deleted = []
  opts[:ids].each do |service_id|
    service = Mdm::Service.find(service_id)
    begin
      deleted << service.destroy
    rescue
      elog("Forcibly deleting #{service.name}")
      deleted << service.delete
    end
  end

  return deleted
}
end

#each_service(wspace = framework.db.workspace, &block) ⇒ Object

Iterates over the services table calling the supplied block with the service instance of each entry.


24
25
26
27
28
29
30
# File 'lib/msf/core/db_manager/service.rb', line 24

def each_service(wspace=framework.db.workspace, &block)
::ApplicationRecord.connection_pool.with_connection {
  wspace.services.each do |service|
    block.call(service)
  end
}
end

#find_or_create_service(opts) ⇒ Object


32
33
34
# File 'lib/msf/core/db_manager/service.rb', line 32

def find_or_create_service(opts)
  report_service(opts)
end

#get_service(wspace, host, proto, port) ⇒ Object


36
37
38
39
40
41
42
# File 'lib/msf/core/db_manager/service.rb', line 36

def get_service(wspace, host, proto, port)
::ApplicationRecord.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

#report_service(opts) ⇒ Object

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)

:workspace

the workspace for the service

opts may contain

:name

the application layer protocol (e.g. ssh, mssql, smb)

:sname

an alias for the above

:info

Detailed information about the service such as name and version information

:state

The current listening state of the service (one of: open, closed, filtered, unknown)


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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
# File 'lib/msf/core/db_manager/service.rb', line 59

def report_service(opts)
  return if !active
::ApplicationRecord.connection_pool.with_connection { |conn|
  addr  = opts.delete(:host) || return
  hname = opts.delete(:host_name)
  hmac  = opts.delete(:mac)
  host  = nil
  wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework)
  opts = opts.clone()
  opts.delete(:workspace) # this may not be needed however the service creation below might complain if missing
  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
  ostate = service.state
  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  ||= ""

  begin
    framework.events.on_db_service(service) if service.new_record?
  rescue ::Exception => e
    wlog("Exception in on_db_service event handler: #{e.class}: #{e}")
    wlog("Call Stack\n#{e.backtrace.join("\n")}")
  end

  begin
    framework.events.on_db_service_state(service, service.port, ostate) if service.state != ostate
  rescue ::Exception => e
    wlog("Exception in on_db_service_state event handler: #{e.class}: #{e}")
    wlog("Call Stack\n#{e.backtrace.join("\n")}")
  end

  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

#services(opts) ⇒ Object

Returns a list of all services in the database


147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/msf/core/db_manager/service.rb', line 147

def services(opts)
  opts = opts.clone()
  search_term = opts.delete(:search_term)

  order_args = [:port]
  order_args.unshift(Mdm::Host.arel_table[:address]) if opts.key?(:hosts)

::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::Service.find(opts[:id]))
  end

  wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework)
  opts.delete(:workspace)

  if search_term && !search_term.empty?
    column_search_conditions = Msf::Util::DBManager.create_all_column_search_conditions(Mdm::Service, search_term)
    wspace.services.includes(:host).where(opts).where(column_search_conditions).order(*order_args)
  else
    wspace.services.includes(:host).where(opts).order(*order_args)
  end
}
end

#update_service(opts) ⇒ Object


172
173
174
175
176
177
178
179
180
181
182
# File 'lib/msf/core/db_manager/service.rb', line 172

def update_service(opts)
  opts = opts.clone() # it is not polite to change arguments passed from callers
  opts.delete(:workspace) # Workspace isn't used with Mdm::Service. So strip it if it's present.

::ApplicationRecord.connection_pool.with_connection {
  id = opts.delete(:id)
  service = Mdm::Service.find(id)
  service.update!(opts)
  return service
}
end