127 lines
3.2 KiB
Ruby
127 lines
3.2 KiB
Ruby
# -*- coding: binary -*-
|
|
|
|
module Msf
|
|
module Exploit::Remote::Asterisk
|
|
include Msf::Exploit::Remote::Tcp
|
|
include Msf::Auxiliary::Report
|
|
|
|
def initialize(info = {})
|
|
super
|
|
|
|
register_options(
|
|
[
|
|
Opt::RPORT(5038),
|
|
OptString.new('USERNAME', [true, 'The username for Asterisk Access', '']),
|
|
OptString.new('PASSWORD', [true, 'The password for the specified username', '']),
|
|
], self.class
|
|
)
|
|
end
|
|
|
|
#
|
|
# Handler for sending AMI commands
|
|
#
|
|
# @param cmd [String] command to send
|
|
#
|
|
# @return [String] response from the server
|
|
def send_command(cmd = '')
|
|
sock.put cmd
|
|
|
|
res = ''
|
|
timeout = 15
|
|
Timeout.timeout(timeout) do
|
|
res << sock.get_once while res !~ /\r?\n\r?\n/
|
|
end
|
|
|
|
res
|
|
rescue Timeout::Error
|
|
print_error "Timeout (#{timeout} seconds)"
|
|
rescue StandardError => e
|
|
print_error e.message
|
|
end
|
|
|
|
#
|
|
# Attempt to get the asterisk version number
|
|
#
|
|
#
|
|
# @return [Gem::Version] version response from the server. False on error
|
|
def get_asterisk_version
|
|
vprint_status 'Checking Asterisk version'
|
|
|
|
req = "action: command\r\n"
|
|
req << "command: core show version\r\n"
|
|
req << "\r\n"
|
|
res = send_command req
|
|
|
|
return false if res =~ /Response: Error/
|
|
|
|
# example output
|
|
# Response: Success
|
|
# Message: Command output follows
|
|
# Output: Asterisk 19.8.0 built by mockbuild @ jenkins7 on a x86_64 running Linux on 2023-01-16 07:07:49 UTC
|
|
|
|
# https://rubular.com/r/e2LvocVBeKaiVo
|
|
if res =~ /^Output: Asterisk (.*?) built/
|
|
return ::Regexp.last_match(1)
|
|
end
|
|
|
|
false
|
|
end
|
|
|
|
#
|
|
# Handler for logging in to AMI
|
|
#
|
|
# @param username [String] username of the user
|
|
# @param password [String] password of the user
|
|
#
|
|
# @return [Boolean] true on success, false on failure
|
|
def login(username, password)
|
|
vprint_status "Authenticating as '#{username}'"
|
|
|
|
req = "action: login\r\n"
|
|
req << "username: #{username}\r\n"
|
|
req << "secret: #{password}\r\n"
|
|
req << "events: off\r\n"
|
|
req << "\r\n"
|
|
res = send_command req
|
|
|
|
return false unless res =~ /Response: Success/
|
|
|
|
report_cred user: username,
|
|
password: password,
|
|
proof: 'Response: Success'
|
|
|
|
report_service host: rhost,
|
|
port: rport,
|
|
proto: 'tcp',
|
|
name: 'asterisk'
|
|
true
|
|
end
|
|
|
|
def report_cred(opts)
|
|
service_data = {
|
|
address: rhost,
|
|
port: rport,
|
|
service_name: 'asterisk_manager',
|
|
protocol: 'tcp',
|
|
workspace_id: myworkspace_id
|
|
}
|
|
|
|
credential_data = {
|
|
origin_type: :service,
|
|
module_fullname: fullname,
|
|
username: opts[:username],
|
|
private_data: opts[:password],
|
|
private_type: :password
|
|
}.merge service_data
|
|
|
|
login_data = {
|
|
core: create_credential(credential_data),
|
|
status: Metasploit::Model::Login::Status::UNTRIED,
|
|
proof: opts[:proof]
|
|
}.merge service_data
|
|
|
|
create_credential_login login_data
|
|
end
|
|
end
|
|
end
|