Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/couchdb/couchdb_login.rb
19813 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Exploit::Remote::HttpClient
8
include Msf::Auxiliary::Report
9
include Msf::Auxiliary::AuthBrute
10
include Msf::Auxiliary::Scanner
11
12
def initialize(info = {})
13
super(
14
update_info(
15
info,
16
'Name' => 'CouchDB Login Utility',
17
'Description' => %q{
18
This module tests CouchDB logins on a range of
19
machines and report successful logins.
20
},
21
'Author' => [
22
'espreto <robertoespreto[at]gmail.com>'
23
],
24
'License' => MSF_LICENSE,
25
'Notes' => {
26
'Stability' => [CRASH_SAFE],
27
'SideEffects' => [IOC_IN_LOGS, ACCOUNT_LOCKOUTS],
28
'Reliability' => []
29
}
30
)
31
)
32
33
register_options(
34
[
35
Opt::RPORT(5984),
36
OptString.new('TARGETURI', [false, 'TARGETURI for CouchDB. Default here is /', '/']),
37
OptPath.new('USERPASS_FILE', [
38
false, 'File containing users and passwords separated by space, one pair per line',
39
File.join(Msf::Config.data_directory, 'wordlists', 'http_default_userpass.txt')
40
]),
41
OptPath.new('USER_FILE', [
42
false, 'File containing users, one per line',
43
File.join(Msf::Config.data_directory, 'wordlists', 'http_default_users.txt')
44
]),
45
OptPath.new('PASS_FILE', [
46
false, 'File containing passwords, one per line',
47
File.join(Msf::Config.data_directory, 'wordlists', 'http_default_pass.txt')
48
]),
49
OptBool.new('USER_AS_PASS', [ false, 'Try the username as the password for all users', false]),
50
]
51
)
52
53
deregister_options('HttpUsername', 'HttpPassword')
54
end
55
56
def run_host(_ip)
57
user = datastore['HttpUsername'].to_s
58
pass = datastore['HttpPassword'].to_s
59
60
if user.nil? || user.strip == ''
61
each_user_pass do |u, p|
62
do_login(u, p)
63
end
64
return
65
end
66
67
vprint_status("#{rhost}:#{rport} - Trying to login with '#{user}' : '#{pass}'")
68
69
uri = target_uri.path
70
71
res = send_request_cgi({
72
'uri' => normalize_uri(uri, '_users/_all_docs'),
73
'method' => 'GET',
74
'authorization' => basic_auth(user, pass)
75
})
76
77
return if res.nil?
78
return if res.headers['Server'].nil? || res.headers['Server'] !~ /CouchDB/
79
return if res.code == 404
80
81
if [200, 301, 302].include?(res.code)
82
vprint_good("#{rhost}:#{rport} - Successful login with '#{user}' : '#{pass}'")
83
end
84
rescue ::Rex::ConnectionError
85
vprint_error("'#{rhost}':'#{rport}' - Failed to connect to the web server")
86
end
87
88
def report_cred(opts)
89
service_data = {
90
address: opts[:ip],
91
port: opts[:port],
92
service_name: opts[:service_name],
93
protocol: 'tcp',
94
workspace_id: myworkspace_id
95
}
96
97
credential_data = {
98
origin_type: :service,
99
module_fullname: fullname,
100
username: opts[:user],
101
private_data: opts[:password],
102
private_type: :password
103
}.merge(service_data)
104
105
login_data = {
106
core: create_credential(credential_data),
107
status: Metasploit::Model::Login::Status::UNTRIED,
108
proof: opts[:proof]
109
}.merge(service_data)
110
111
create_credential_login(login_data)
112
end
113
114
def do_login(user, pass)
115
vprint_status("Trying username:'#{user}' with password:'#{pass}'")
116
117
res = send_request_cgi({
118
'uri' => normalize_uri(target_uri.path, '_users/_all_docs'),
119
'method' => 'GET',
120
'ctype' => 'text/plain',
121
'authorization' => basic_auth(user, pass)
122
})
123
124
unless res
125
print_error('HTTP connection failed, aborting')
126
return :abort
127
end
128
129
return :skip_pass unless res.code == 200
130
131
print_good("#{peer} - Successful login with: '#{user}' : '#{pass}'")
132
133
report_cred(
134
ip: rhost,
135
port: rport,
136
service_name: 'couchdb',
137
user: user,
138
password: pass,
139
proof: res.code.to_s
140
)
141
142
:next_user
143
rescue ::Rex::ConnectionError, ::Errno::ECONNREFUSED, ::Errno::ETIMEDOUT
144
print_error('HTTP connection failed, aborting')
145
return :abort
146
rescue StandardError => e
147
print_error("Error: #{e}")
148
return nil
149
end
150
end
151
152