CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/metasploit/framework/login_scanner/db2.rb
Views: 1904
1
require 'metasploit/framework/tcp/client'
2
require 'metasploit/framework/login_scanner/base'
3
require 'metasploit/framework/login_scanner/rex_socket'
4
5
module Metasploit
6
module Framework
7
module LoginScanner
8
# This is the LoginScanner class for dealing with DB2 Database servers.
9
# It is responsible for taking a single target, and a list of credentials
10
# and attempting them. It then saves the results.
11
class DB2
12
include Metasploit::Framework::LoginScanner::Base
13
include Metasploit::Framework::LoginScanner::RexSocket
14
include Metasploit::Framework::Tcp::Client
15
16
DEFAULT_PORT = 50000
17
DEFAULT_REALM = 'toolsdb'
18
LIKELY_PORTS = [ DEFAULT_PORT ]
19
# @todo XXX
20
LIKELY_SERVICE_NAMES = [ ]
21
PRIVATE_TYPES = [ :password ]
22
REALM_KEY = Metasploit::Model::Realm::Key::DB2_DATABASE
23
24
# @see Base#attempt_login
25
def attempt_login(credential)
26
result_options = {
27
credential: credential
28
}
29
30
begin
31
probe_data = send_probe(credential.realm)
32
33
if probe_data.empty?
34
result_options[:status] = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
35
else
36
if authenticate?(credential)
37
result_options[:status] = Metasploit::Model::Login::Status::SUCCESSFUL
38
else
39
result_options[:status] = Metasploit::Model::Login::Status::INCORRECT
40
end
41
end
42
rescue ::Rex::ConnectionError, ::Rex::Proto::DRDA::RespError, ::Timeout::Error => e
43
result_options.merge!({
44
status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT,
45
proof: e,
46
})
47
end
48
49
result = ::Metasploit::Framework::LoginScanner::Result.new(result_options)
50
result.host = host
51
result.port = port
52
result.protocol = 'tcp'
53
result.service_name = 'db2'
54
result
55
end
56
57
private
58
# This method takes the credential and actually attempts the authentication
59
# @param credential [Credential] The Credential object to authenticate with.
60
# @return [Boolean] Whether the authentication was successful
61
def authenticate?(credential)
62
# Send the login packet and get a response packet back
63
login_packet = Rex::Proto::DRDA::Utils.client_auth(:dbname => credential.realm,
64
:dbuser => credential.public,
65
:dbpass => credential.private
66
)
67
sock.put login_packet
68
response = sock.get_once
69
if valid_response?(response)
70
if successful_login?(response)
71
true
72
else
73
false
74
end
75
else
76
false
77
end
78
end
79
80
# This method opens a socket to the target DB2 server.
81
# It then sends a client probe on that socket to get information
82
# back on the server.
83
# @param database_name [String] The name of the database to probe
84
# @return [Hash] A hash containing the server information from the probe reply
85
def send_probe(database_name)
86
disconnect if self.sock
87
connect
88
89
probe_packet = Rex::Proto::DRDA::Utils.client_probe(database_name)
90
sock.put probe_packet
91
response = sock.get_once
92
93
response_data = {}
94
if valid_response?(response)
95
packet = Rex::Proto::DRDA::Packet::SERVER_PACKET.new.read(response)
96
response_data = Rex::Proto::DRDA::Utils.server_packet_info(packet)
97
end
98
response_data
99
end
100
101
# This method sets the sane defaults for things
102
# like timeouts and TCP evasion options
103
def set_sane_defaults
104
self.connection_timeout ||= 30
105
self.port ||= DEFAULT_PORT
106
self.max_send_size ||= 0
107
self.send_delay ||= 0
108
109
self.ssl = false if self.ssl.nil?
110
end
111
112
# This method takes a response packet and checks to see
113
# if the authentication was actually successful.
114
#
115
# @param response [String] The unprocessed response packet
116
# @return [Boolean] Whether the authentication was successful
117
def successful_login?(response)
118
packet = Rex::Proto::DRDA::Packet::SERVER_PACKET.new.read(response)
119
packet_info = Rex::Proto::DRDA::Utils.server_packet_info(packet)
120
if packet_info[:db_login_success]
121
true
122
else
123
false
124
end
125
end
126
127
# This method provides a simple test on whether the response
128
# packet was valid.
129
#
130
# @param response [String] The response to examine from the socket
131
# @return [Boolean] Whether the response is valid
132
def valid_response?(response)
133
response && response.length > 0
134
end
135
end
136
137
end
138
end
139
end
140
141