Merge pull request #73 from PowerShellEmpire/powerview2.0_update

Powerview2.0 update
1.6
HarmJ0y 2015-10-27 15:19:15 -04:00
commit e08625b919
44 changed files with 9797 additions and 23012 deletions

View File

@ -102,4 +102,4 @@
8/6/2015
-----------
-Initial release. All components released
-Commited path fix to correct bug in certain modules
-Commited path fix to correct bug in certain modules

File diff suppressed because it is too large Load Diff

View File

@ -1,142 +0,0 @@
function Invoke-FileSearch {
<#
.SYNOPSIS
Searches a given server/path for files with specific terms in the name.
.DESCRIPTION
This function recursively searches a given UNC path for files with
specific keywords in the name (default of pass, sensitive, secret, admin,
login and unattend*.xml). The output can be piped out to a csv with the
-OutFile flag. By default, hidden files/folders are included in search results.
.PARAMETER Path
UNC/local path to recursively search.
.PARAMETER Terms
Terms to search for.
.PARAMETER OfficeDocs
Search for office documents (*.doc*, *.xls*, *.ppt*)
.PARAMETER FreshEXES
Find .EXEs accessed within the last week.
.PARAMETER AccessDateLimit
Only return files with a LastAccessTime greater than this date value.
.PARAMETER WriteDateLimit
Only return files with a LastWriteTime greater than this date value.
.PARAMETER CreateDateLimit
Only return files with a CreationDate greater than this date value.
.PARAMETER ExcludeFolders
Exclude folders from the search results.
.PARAMETER ExcludeHidden
Exclude hidden files and folders from the search results.
.PARAMETER CheckWriteAccess
Only returns files the current user has write access to.
.PARAMETER OutFile
Output results to a specified csv output file.
.OUTPUTS
The full path, owner, lastaccess time, lastwrite time, and size for
each found file.
.EXAMPLE
> Invoke-FileSearch -Path \\WINDOWS7\Users\
Returns any files on the remote path \\WINDOWS7\Users\ that have 'pass',
'sensitive', or 'secret' in the title.
.EXAMPLE
> Invoke-FileSearch -Path \\WINDOWS7\Users\ -Terms salaries,email -OutFile out.csv
Returns any files on the remote path \\WINDOWS7\Users\ that have 'salaries'
or 'email' in the title, and writes the results out to a csv file
named 'out.csv'
.EXAMPLE
> Invoke-FileSearch -Path \\WINDOWS7\Users\ -AccessDateLimit 6/1/2014
Returns all files accessed since 6/1/2014.
.LINK
http://www.harmj0y.net/blog/redteaming/file-server-triage-on-red-team-engagements/
#>
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$True)]
[string]
$Path = '.\',
[string[]]
$Terms,
[Switch]
$OfficeDocs,
[Switch]
$FreshEXES,
[string]
$AccessDateLimit = '1/1/1970',
[string]
$WriteDateLimit = '1/1/1970',
[string]
$CreateDateLimit = '1/1/1970',
[Switch]
$ExcludeFolders,
[Switch]
$ExcludeHidden,
[Switch]
$CheckWriteAccess,
[string]
$OutFile
)
begin {
# default search terms
$SearchTerms = @('pass', 'sensitive', 'admin', 'login', 'secret', 'unattend*.xml', '.vmdk', 'creds', 'credential', '.config')
# check if custom search terms were passed
if ($Terms){
if($Terms -isnot [system.array]){
$Terms = @($Terms)
}
$SearchTerms = $Terms
}
# append wildcards to the front and back of all search terms
for ($i = 0; $i -lt $SearchTerms.Count; $i++) {
$SearchTerms[$i] = "*$($SearchTerms[$i])*"
}
# search just for office documents if specified
if ($OfficeDocs){
$SearchTerms = @('*.doc', '*.docx', '*.xls', '*.xlsx', '*.ppt', '*.pptx')
}
# find .exe's accessed within the last 7 days
if($FreshEXES){
# get an access time limit of 7 days ago
$AccessDateLimit = (get-date).AddDays(-7).ToString('MM/dd/yyyy')
$SearchTerms = '*.exe'
}
}
process {
# build our giant recursive search command w/ conditional options
$cmd = "get-childitem $Path -rec $(if(-not $ExcludeHidden){`"-Force`"}) -ErrorAction SilentlyContinue -include $($SearchTerms -join `",`") | where{ $(if($ExcludeFolders){`"(-not `$_.PSIsContainer) -and`"}) (`$_.LastAccessTime -gt `"$AccessDateLimit`") -and (`$_.LastWriteTime -gt `"$WriteDateLimit`") -and (`$_.CreationTime -gt `"$CreateDateLimit`")} | select-object FullName,@{Name='Owner';Expression={(Get-Acl `$_.FullName).Owner}},LastAccessTime,LastWriteTime,Length $(if($CheckWriteAccess){`"| where { `$_.FullName } | where { Invoke-CheckWrite -Path `$_.FullName }`"}) $(if($OutFile){`"| export-csv -Append -notypeinformation -path $OutFile`"})"
# execute the command
Invoke-Expression $cmd
}
}

View File

@ -1,324 +0,0 @@
<#
.Synopsis
This module will query Active Directory for the hostname, OS version, and service pack level
for each computer account. That information is then cross-referenced against a list of common
Metasploit exploits that can be used during penetration testing.
.DESCRIPTION
This module will query Active Directory for the hostname, OS version, and service pack level
for each computer account. That information is then cross-referenced against a list of common
Metasploit exploits that can be used during penetration testing. The script filters out disabled
domain computers and provides the computer's last logon time to help determine if it's been
decommissioned. Also, since the script uses data tables to output affected systems the results
can be easily piped to other commands such as test-connection or a Export-Csv.
.EXAMPLE
The example below shows the standard command usage. Disabled system are excluded by default, but
the "LastLgon" column can be used to determine which systems are live. Usually, if a system hasn't
logged on for two or more weeks it's been decommissioned.
PS C:\> Get-ExploitableSystems -DomainController 192.168.1.1 -Credential demo.com\user | Format-Table -AutoSize
[*] Grabbing computer accounts from Active Directory...
[*] Loading exploit list for critical missing patches...
[*] Checking computers for vulnerable OS and SP levels...
[+] Found 5 potentially vulnerabile systems!
ComputerName OperatingSystem ServicePack LastLogon MsfModule CVE
------------ --------------- ----------- --------- --------- ---
ADS.demo.com Windows Server 2003 Service Pack 2 4/8/2015 5:46:52 PM exploit/windows/dcerpc/ms07_029_msdns_zonename http://www.cvedetails....
ADS.demo.com Windows Server 2003 Service Pack 2 4/8/2015 5:46:52 PM exploit/windows/smb/ms08_067_netapi http://www.cvedetails....
ADS.demo.com Windows Server 2003 Service Pack 2 4/8/2015 5:46:52 PM exploit/windows/smb/ms10_061_spoolss http://www.cvedetails....
LVA.demo.com Windows Server 2003 Service Pack 2 4/8/2015 1:44:46 PM exploit/windows/dcerpc/ms07_029_msdns_zonename http://www.cvedetails....
LVA.demo.com Windows Server 2003 Service Pack 2 4/8/2015 1:44:46 PM exploit/windows/smb/ms08_067_netapi http://www.cvedetails....
LVA.demo.com Windows Server 2003 Service Pack 2 4/8/2015 1:44:46 PM exploit/windows/smb/ms10_061_spoolss http://www.cvedetails....
assess-xppro.demo.com Windows XP Professional Service Pack 3 4/1/2014 11:11:54 AM exploit/windows/smb/ms08_067_netapi http://www.cvedetails....
assess-xppro.demo.com Windows XP Professional Service Pack 3 4/1/2014 11:11:54 AM exploit/windows/smb/ms10_061_spoolss http://www.cvedetails....
HVA.demo.com Windows Server 2003 Service Pack 2 11/5/2013 9:16:31 PM exploit/windows/dcerpc/ms07_029_msdns_zonename http://www.cvedetails....
HVA.demo.com Windows Server 2003 Service Pack 2 11/5/2013 9:16:31 PM exploit/windows/smb/ms08_067_netapi http://www.cvedetails....
HVA.demo.com Windows Server 2003 Service Pack 2 11/5/2013 9:16:31 PM exploit/windows/smb/ms10_061_spoolss http://www.cvedetails....
DB1.demo.com Windows Server 2003 Service Pack 2 3/22/2012 5:05:34 PM exploit/windows/dcerpc/ms07_029_msdns_zonename http://www.cvedetails....
DB1.demo.com Windows Server 2003 Service Pack 2 3/22/2012 5:05:34 PM exploit/windows/smb/ms08_067_netapi http://www.cvedetails....
DB1.demo.com Windows Server 2003 Service Pack 2 3/22/2012 5:05:34 PM exploit/windows/smb/ms10_061_spoolss http://www.cvedetails....
.EXAMPLE
The example below shows how to write the output to a csv file.
PS C:\> Get-ExploitableSystems -DomainController 192.168.1.1 -Credential demo.com\user | Export-Csv c:\temp\output.csv -NoTypeInformation
.EXAMPLE
The example below shows how to pipe the resultant list of computer names into the test-connection to determine if they response to ping
requests.
PS C:\> Get-ExploitableSystems -DomainController 192.168.1.1 -Credential demo.com\user | Test-Connection
.LINK
http://www.netspi.com
.NOTES
Author: Scott Sutherland - 2015, NetSPI
Version: Get-ExploitableSystems.psm1 v1.0
Comments: The technique used to query LDAP was based on the "Get-AuditDSComputerAccount"
function found in Carols Perez's PoshSec-Mod project. The general idea is based off of
Will Schroeder's "Invoke-FindVulnSystems" function from the PowerView toolkit.
#>
function Get-ExploitableSystems
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$false,
HelpMessage="Credentials to use when connecting to a Domain Controller.")]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty,
[Parameter(Mandatory=$false,
HelpMessage="Domain controller for Domain and Site that you want to query against.")]
[string]$DomainController,
[Parameter(Mandatory=$false,
HelpMessage="Maximum number of Objects to pull from AD, limit is 1,000.")]
[int]$Limit = 1000,
[Parameter(Mandatory=$false,
HelpMessage="scope of a search as either a base, one-level, or subtree search, default is subtree.")]
[ValidateSet("Subtree","OneLevel","Base")]
[string]$SearchScope = "Subtree",
[Parameter(Mandatory=$false,
HelpMessage="Distinguished Name Path to limit search to.")]
[string]$SearchDN
)
Begin
{
if ($DomainController -and $Credential.GetNetworkCredential().Password)
{
$objDomain = New-Object System.DirectoryServices.DirectoryEntry "LDAP://$($DomainController)", $Credential.UserName,$Credential.GetNetworkCredential().Password
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher $objDomain
}
else
{
$objDomain = [ADSI]""
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher $objDomain
}
}
Process
{
# Status user
Write-Host "[*] Grabbing computer accounts from Active Directory..."
# ----------------------------------------------------------------
# Setup data table for domain computer information
# ----------------------------------------------------------------
# Create data table for hostnames, os, and service packs from LDAP
$TableAdsComputers = New-Object System.Data.DataTable
$TableAdsComputers.Columns.Add('Hostname') | Out-Null
$TableAdsComputers.Columns.Add('OperatingSystem') | Out-Null
$TableAdsComputers.Columns.Add('ServicePack') | Out-Null
$TableAdsComputers.Columns.Add('LastLogon') | Out-Null
# ----------------------------------------------------------------
# Grab computer account information from Active Directory via LDAP
# ----------------------------------------------------------------
$CompFilter = "(&(objectCategory=Computer))"
$ObjSearcher.PageSize = $Limit
$ObjSearcher.Filter = $CompFilter
$ObjSearcher.SearchScope = "Subtree"
if ($SearchDN)
{
$objSearcher.SearchDN = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$($SearchDN)")
}
$ObjSearcher.FindAll() | ForEach-Object {
# Setup fields
$CurrentHost = $($_.properties['dnshostname'])
$CurrentOs = $($_.properties['operatingsystem'])
$CurrentSp = $($_.properties['operatingsystemservicepack'])
$CurrentLast = $($_.properties['lastlogon'])
$CurrentUac = $($_.properties['useraccountcontrol'])
# Convert useraccountcontrol to binary so flags can be checked
# http://support.microsoft.com/en-us/kb/305144
# http://blogs.technet.com/b/askpfeplat/archive/2014/01/15/understanding-the-useraccountcontrol-attribute-in-active-directory.aspx
$CurrentUacBin = [convert]::ToString($CurrentUac,2)
# Check the 2nd to last value to determine if its disabled
$DisableOffset = $CurrentUacBin.Length - 2
$CurrentDisabled = $CurrentUacBin.Substring($DisableOffset,1)
# Add computer to list if it's enabled
if ($CurrentDisabled -eq 0){
# Add domain computer to data table
$TableAdsComputers.Rows.Add($CurrentHost,$CurrentOS,$CurrentSP,$CurrentLast) | Out-Null
}
}
# Status user
Write-Host "[*] Loading exploit list for critical missing patches..."
# ----------------------------------------------------------------
# Setup data table for list of msf exploits
# ----------------------------------------------------------------
# Create data table for list of patches levels with a MSF exploit
$TableExploits = New-Object System.Data.DataTable
$TableExploits.Columns.Add('OperatingSystem') | Out-Null
$TableExploits.Columns.Add('ServicePack') | Out-Null
$TableExploits.Columns.Add('MsfModule') | Out-Null
$TableExploits.Columns.Add('CVE') | Out-Null
# Add exploits to data table
$TableExploits.Rows.Add("Windows 7","","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Server Pack 1","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Server Pack 1","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Server Pack 1","exploit/windows/iis/ms03_007_ntdll_webdav","http://www.cvedetails.com/cve/2003-0109") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Server Pack 1","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 2","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 2","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 2","exploit/windows/iis/ms03_007_ntdll_webdav","http://www.cvedetails.com/cve/2003-0109") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 2","exploit/windows/smb/ms04_011_lsass","http://www.cvedetails.com/cve/2003-0533/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 2","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 3","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 3","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 3","exploit/windows/iis/ms03_007_ntdll_webdav","http://www.cvedetails.com/cve/2003-0109") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 3","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/dcerpc/ms07_029_msdns_zonename","http://www.cvedetails.com/cve/2007-1748") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/smb/ms04_011_lsass","http://www.cvedetails.com/cve/2003-0533/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/smb/ms06_066_nwapi","http://www.cvedetails.com/cve/2006-4688") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/smb/ms06_070_wkssvc","http://www.cvedetails.com/cve/2006-4691") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","","exploit/windows/iis/ms03_007_ntdll_webdav","http://www.cvedetails.com/cve/2003-0109") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","","exploit/windows/smb/ms05_039_pnp","http://www.cvedetails.com/cve/2005-1983") | Out-Null
$TableExploits.Rows.Add("Windows Server 2000","","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2003","Server Pack 1","exploit/windows/dcerpc/ms07_029_msdns_zonename","http://www.cvedetails.com/cve/2007-1748") | Out-Null
$TableExploits.Rows.Add("Windows Server 2003","Server Pack 1","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439") | Out-Null
$TableExploits.Rows.Add("Windows Server 2003","Server Pack 1","exploit/windows/smb/ms06_066_nwapi","http://www.cvedetails.com/cve/2006-4688") | Out-Null
$TableExploits.Rows.Add("Windows Server 2003","Server Pack 1","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250") | Out-Null
$TableExploits.Rows.Add("Windows Server 2003","Server Pack 1","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2003","Service Pack 2","exploit/windows/dcerpc/ms07_029_msdns_zonename","http://www.cvedetails.com/cve/2007-1748") | Out-Null
$TableExploits.Rows.Add("Windows Server 2003","Service Pack 2","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250") | Out-Null
$TableExploits.Rows.Add("Windows Server 2003","Service Pack 2","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729") | Out-Null
$TableExploits.Rows.Add("Windows Server 2003","","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2003","","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439") | Out-Null
$TableExploits.Rows.Add("Windows Server 2003","","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250") | Out-Null
$TableExploits.Rows.Add("Windows Server 2003","","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2003 R2","","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2003 R2","","exploit/windows/smb/ms04_011_lsass","http://www.cvedetails.com/cve/2003-0533/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2003 R2","","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439") | Out-Null
$TableExploits.Rows.Add("Windows Server 2003 R2","","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/") | Out-Null
$TableExploits.Rows.Add("Windows Server 2008","Service Pack 2","exploit/windows/smb/ms09_050_smb2_negotiate_func_index","http://www.cvedetails.com/cve/2009-3103") | Out-Null
$TableExploits.Rows.Add("Windows Server 2008","Service Pack 2","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729") | Out-Null
$TableExploits.Rows.Add("Windows Server 2008","","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250") | Out-Null
$TableExploits.Rows.Add("Windows Server 2008","","exploit/windows/smb/ms09_050_smb2_negotiate_func_index","http://www.cvedetails.com/cve/2009-3103") | Out-Null
$TableExploits.Rows.Add("Windows Server 2008","","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729") | Out-Null
$TableExploits.Rows.Add("Windows Server 2008 R2","","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729") | Out-Null
$TableExploits.Rows.Add("Windows Vista","Server Pack 1","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250") | Out-Null
$TableExploits.Rows.Add("Windows Vista","Server Pack 1","exploit/windows/smb/ms09_050_smb2_negotiate_func_index","http://www.cvedetails.com/cve/2009-3103") | Out-Null
$TableExploits.Rows.Add("Windows Vista","Server Pack 1","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729") | Out-Null
$TableExploits.Rows.Add("Windows Vista","Service Pack 2","exploit/windows/smb/ms09_050_smb2_negotiate_func_index","http://www.cvedetails.com/cve/2009-3103") | Out-Null
$TableExploits.Rows.Add("Windows Vista","Service Pack 2","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729") | Out-Null
$TableExploits.Rows.Add("Windows Vista","","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250") | Out-Null
$TableExploits.Rows.Add("Windows Vista","","exploit/windows/smb/ms09_050_smb2_negotiate_func_index","http://www.cvedetails.com/cve/2009-3103") | Out-Null
$TableExploits.Rows.Add("Windows XP","Server Pack 1","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/") | Out-Null
$TableExploits.Rows.Add("Windows XP","Server Pack 1","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059") | Out-Null
$TableExploits.Rows.Add("Windows XP","Server Pack 1","exploit/windows/smb/ms04_011_lsass","http://www.cvedetails.com/cve/2003-0533/") | Out-Null
$TableExploits.Rows.Add("Windows XP","Server Pack 1","exploit/windows/smb/ms05_039_pnp","http://www.cvedetails.com/cve/2005-1983") | Out-Null
$TableExploits.Rows.Add("Windows XP","Server Pack 1","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439") | Out-Null
$TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059") | Out-Null
$TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439") | Out-Null
$TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/smb/ms06_066_nwapi","http://www.cvedetails.com/cve/2006-4688") | Out-Null
$TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/smb/ms06_070_wkssvc","http://www.cvedetails.com/cve/2006-4691") | Out-Null
$TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250") | Out-Null
$TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729") | Out-Null
$TableExploits.Rows.Add("Windows XP","Service Pack 3","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250") | Out-Null
$TableExploits.Rows.Add("Windows XP","Service Pack 3","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729") | Out-Null
$TableExploits.Rows.Add("Windows XP","","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/") | Out-Null
$TableExploits.Rows.Add("Windows XP","","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059") | Out-Null
$TableExploits.Rows.Add("Windows XP","","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439") | Out-Null
$TableExploits.Rows.Add("Windows XP","","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250") | Out-Null
# Status user
Write-Host "[*] Checking computers for vulnerable OS and SP levels..."
# ----------------------------------------------------------------
# Setup data table to store vulnerable systems
# ----------------------------------------------------------------
# Create data table to house vulnerable server list
$TableVulnComputers = New-Object System.Data.DataTable
$TableVulnComputers.Columns.Add('ComputerName') | Out-Null
$TableVulnComputers.Columns.Add('OperatingSystem') | Out-Null
$TableVulnComputers.Columns.Add('ServicePack') | Out-Null
$TableVulnComputers.Columns.Add('LastLogon') | Out-Null
$TableVulnComputers.Columns.Add('MsfModule') | Out-Null
$TableVulnComputers.Columns.Add('CVE') | Out-Null
# Iterate through each exploit
$TableExploits |
ForEach-Object {
$ExploitOS = $_.OperatingSystem
$ExploitSP = $_.ServicePack
$ExploitMsf = $_.MsfModule
$ExploitCve = $_.CVE
# Iterate through each ADS computer
$TableAdsComputers |
ForEach-Object {
$AdsHostname = $_.Hostname
$AdsOS = $_.OperatingSystem
$AdsSP = $_.ServicePack
$AdsLast = $_.LastLogon
# Add exploitable systems to vul computers data table
if ($AdsOS -like "$ExploitOS*" -and $AdsSP -like "$ExploitSP" ){
# Add domain computer to data table
$TableVulnComputers.Rows.Add($AdsHostname,$AdsOS,$AdsSP,[dateTime]::FromFileTime($AdsLast),$ExploitMsf,$ExploitCve) | Out-Null
}
}
}
# Display results
$VulnComputer = $TableVulnComputers | select ComputerName -Unique | measure
$vulnComputerCount = $VulnComputer.Count
If ($VulnComputer.Count -gt 0){
# Return vulnerable server list order with some hack date casting
Write-Host "[+] Found $vulnComputerCount potentially vulnerabile systems!"
$TableVulnComputers | Sort-Object { $_.lastlogon -as [datetime]} -Descending
}else{
Write-Host "[-] No vulnerable systems were found."
}
}
End
{
}
}

View File

@ -1,311 +0,0 @@
function Test-Server {
<#
.SYNOPSIS
Tests a connection to a remote server.
.DESCRIPTION
This function uses either ping (test-connection) or RPC
(through WMI) to test connectivity to a remote server.
.PARAMETER Server
The hostname/IP to test connectivity to.
.OUTPUTS
$True/$False
.EXAMPLE
> Test-Server -Server WINDOWS7
Tests ping connectivity to the WINDOWS7 server.
.EXAMPLE
> Test-Server -RPC -Server WINDOWS7
Tests RPC connectivity to the WINDOWS7 server.
.LINK
http://gallery.technet.microsoft.com/scriptcenter/Enhanced-Remote-Server-84c63560
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$True,ValueFromPipeline=$true)]
[String]
$Server,
[Switch]
$RPC
)
process {
if ($RPC){
$WMIParameters = @{
namespace = 'root\cimv2'
Class = 'win32_ComputerSystem'
ComputerName = $Name
ErrorAction = 'Stop'
}
if ($Credential -ne $null)
{
$WMIParameters.Credential = $Credential
}
try
{
Get-WmiObject @WMIParameters
}
catch {
Write-Verbose -Message 'Could not connect via WMI'
}
}
# otherwise, use ping
else{
Test-Connection -ComputerName $Server -count 1 -Quiet
}
}
}
function Get-NetDomainController {
<#
.SYNOPSIS
Return the current domain controllers for the active domain.
.PARAMETER Domain
The domain to query for domain controllers. If not supplied, the
current domain is used.
.EXAMPLE
> Get-NetDomainController
Returns the domain controllers for the current computer's domain.
Approximately equivialent to the hostname given in the LOGONSERVER
environment variable.
.EXAMPLE
> Get-NetDomainController -Domain test
Returns the domain controllers for the domain "test".
#>
[CmdletBinding()]
param(
[string]
$Domain
)
$d = Get-NetDomain -Domain $Domain
if($d){
$d.DomainControllers
}
}
function Get-NetDomain {
<#
.SYNOPSIS
Returns the name of the current user's domain.
.PARAMETER Domain
The domain to query return. If not supplied, the
current domain is used.
.EXAMPLE
> Get-NetDomain
Return the current domain.
.LINK
http://social.technet.microsoft.com/Forums/scriptcenter/en-US/0c5b3f83-e528-4d49-92a4-dee31f4b481c/finding-the-dn-of-the-the-domain-without-admodule-in-powershell?forum=ITCG
#>
[CmdletBinding()]
param(
[String]
$Domain
)
if($Domain -and ($Domain -ne "")){
$DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain)
try {
[System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
}
catch{
Write-Warning "The specified domain $Domain does not exist, could not be contacted, or there isn't an existing trust."
$Null
}
}
else{
[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
}
}
function Get-NetComputer {
<#
.SYNOPSIS
Gets an array of all current computers objects in a domain.
.DESCRIPTION
This function utilizes adsisearcher to query the current AD context
for current computer objects. Based off of Carlos Perez's Audit.psm1
script in Posh-SecMod (link below).
.PARAMETER HostName
Return computers with a specific name, wildcards accepted.
.PARAMETER SPN
Return computers with a specific service principal name, wildcards accepted.
.PARAMETER OperatingSystem
Return computers with a specific operating system, wildcards accepted.
.PARAMETER ServicePack
Return computers with a specific service pack, wildcards accepted.
.PARAMETER Ping
Ping each host to ensure it's up before enumerating.
.PARAMETER FullData
Return full user computer objects instead of just system names (the default).
.PARAMETER Domain
The domain to query for computers.
.OUTPUTS
System.Array. An array of found system objects.
.EXAMPLE
> Get-NetComputer
Returns the current computers in current domain.
.EXAMPLE
> Get-NetComputer -SPN mssql*
Returns all MS SQL servers on the domain.
.EXAMPLE
> Get-NetComputer -Domain testing
Returns the current computers in 'testing' domain.
> Get-NetComputer -Domain testing -FullData
Returns full computer objects in the 'testing' domain.
.LINK
https://github.com/darkoperator/Posh-SecMod/blob/master/Audit/Audit.psm1
#>
[CmdletBinding()]
Param (
[Parameter(ValueFromPipeline=$True)]
[string]
$HostName = '*',
[string]
$SPN = '*',
[string]
$OperatingSystem = '*',
[string]
$ServicePack = '*',
[Switch]
$Ping,
[Switch]
$FullData,
[string]
$Domain
)
process {
# if a domain is specified, try to grab that domain
if ($Domain){
# try to grab the primary DC for the current domain
try{
$PrimaryDC = ([Array](Get-NetDomainController))[0].Name
}
catch{
$PrimaryDC = $Null
}
try {
# reference - http://blogs.msdn.com/b/javaller/archive/2013/07/29/searching-across-active-directory-domains-in-powershell.aspx
$dn = "DC=$($Domain.Replace('.', ',DC='))"
# if we could grab the primary DC for the current domain, use that for the query
if($PrimaryDC){
$CompSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$PrimaryDC/$dn")
}
else{
# otherwise try to connect to the DC for the target domain
$CompSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$dn")
}
# create the searcher object with our specific filters
if ($ServicePack -ne '*'){
$CompSearcher.filter="(&(objectClass=Computer)(dnshostname=$HostName)(operatingsystem=$OperatingSystem)(operatingsystemservicepack=$ServicePack)(servicePrincipalName=$SPN))"
}
else{
# server 2012 peculiarity- remove any mention to service pack
$CompSearcher.filter="(&(objectClass=Computer)(dnshostname=$HostName)(operatingsystem=$OperatingSystem)(servicePrincipalName=$SPN))"
}
}
catch{
Write-Warning "The specified domain $Domain does not exist, could not be contacted, or there isn't an existing trust."
}
}
else{
# otherwise, use the current domain
if ($ServicePack -ne '*'){
$CompSearcher = [adsisearcher]"(&(objectClass=Computer)(dnshostname=$HostName)(operatingsystem=$OperatingSystem)(operatingsystemservicepack=$ServicePack)(servicePrincipalName=$SPN))"
}
else{
# server 2012 peculiarity- remove any mention to service pack
$CompSearcher = [adsisearcher]"(&(objectClass=Computer)(dnshostname=$HostName)(operatingsystem=$OperatingSystem)(servicePrincipalName=$SPN))"
}
}
if ($CompSearcher){
# eliminate that pesky 1000 system limit
$CompSearcher.PageSize = 200
$CompSearcher.FindAll() | ? {$_} | ForEach-Object {
$up = $true
if($Ping){
$up = Test-Server -Server $_.properties.dnshostname
}
if($up){
# return full data objects
if ($FullData){
$properties = $_.Properties
$out = New-Object psobject
$properties.PropertyNames | % {
if ($_ -eq "objectsid"){
# convert the SID to a string
$out | Add-Member Noteproperty $_ ((New-Object System.Security.Principal.SecurityIdentifier($properties[$_][0],0)).Value)
}
elseif($_ -eq "objectguid"){
# convert the GUID to a string
$out | Add-Member Noteproperty $_ (New-Object Guid (,$properties[$_][0])).Guid
}
elseif( ($_ -eq "lastlogon") -or ($_ -eq "lastlogontimestamp") -or ($_ -eq "pwdlastset") ){
$out | Add-Member Noteproperty $_ ([datetime]::FromFileTime(($properties[$_][0])))
}
else {
$out | Add-Member Noteproperty $_ $properties[$_][0]
}
}
$out | Out-String
}
else{
# otherwise we're just returning the DNS host name
$_.properties.dnshostname + "`n"
}
}
}
}
}
}

View File

@ -1,526 +0,0 @@
function Convert-SidToName {
<#
.SYNOPSIS
Converts a security identifier (SID) to a group/user name.
.PARAMETER SID
The SID to convert.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$True,ValueFromPipeline=$True)]
[String]
$SID
)
process {
try {
$obj = (New-Object System.Security.Principal.SecurityIdentifier($SID))
$obj.Translate( [System.Security.Principal.NTAccount]).Value
}
catch {
Write-Warning "invalid SID"
}
}
}
function Get-NetGroup {
<#
.SYNOPSIS
Gets a list of all current users in a specified domain group.
.DESCRIPTION
This function users [ADSI] and LDAP to query the current AD context
or trusted domain for users in a specified group. If no GroupName is
specified, it defaults to querying the "Domain Admins" group.
This is a replacement for "net group 'name' /domain"
.PARAMETER GroupName
The group name to query for users. If not given, it defaults to "Domain Admins"
.PARAMETER Domain
The domain to query for group users.
.PARAMETER FullData
Switch. Returns full data objects instead of just group/users.
.PARAMETER Recurse
Switch. If the group member is a group, recursively try to query its members as well.
.EXAMPLE
> Get-NetGroup
Returns the usernames that of members of the "Domain Admins" domain group.
.EXAMPLE
> Get-NetGroup -Domain testing -GroupName "Power Users"
Returns the usernames that of members of the "Power Users" group
in the 'testing' domain.
.LINK
http://www.powershellmagazine.com/2013/05/23/pstip-retrieve-group-membership-of-an-active-directory-group-recursively/
#>
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$true)]
[string]
$GroupName = 'Domain Admins',
[Switch]
$FullData,
[Switch]
$Recurse,
[string]
$Domain,
[string]
$PrimaryDC
)
process {
# if a domain is specified, try to grab that domain
if ($Domain){
# try to grab the primary DC for the current domain
try{
$PrimaryDC = ([Array](Get-NetDomainControllers))[0].Name
}
catch{
$PrimaryDC = $Null
}
try {
# reference - http://blogs.msdn.com/b/javaller/archive/2013/07/29/searching-across-active-directory-domains-in-powershell.aspx
$dn = "DC=$($Domain.Replace('.', ',DC='))"
# if we could grab the primary DC for the current domain, use that for the query
if($PrimaryDC){
$GroupSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$PrimaryDC/$dn")
}
else{
# otherwise try to connect to the DC for the target domain
$GroupSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$dn")
}
# samAccountType=805306368 indicates user objects
$GroupSearcher.filter = "(&(objectClass=group)(name=$GroupName))"
}
catch{
Write-Warning "The specified domain $Domain does not exist, could not be contacted, or there isn't an existing trust."
}
}
else{
$Domain = (Get-NetDomain).Name
# otherwise, use the current domain
$GroupSearcher = [adsisearcher]"(&(objectClass=group)(name=$GroupName))"
}
if ($GroupSearcher){
$GroupSearcher.PageSize = 200
$GroupSearcher.FindAll() | % {
try{
$GroupFoundName = $_.properties.name[0]
$_.properties.member | ForEach-Object {
# for each user/member, do a quick adsi object grab
if ($PrimaryDC){
$properties = ([adsi]"LDAP://$PrimaryDC/$_").Properties
}
else {
$properties = ([adsi]"LDAP://$_").Properties
}
# check if the result is a user account- if not assume it's a group
if ($properties.samAccountType -ne "805306368"){
$isGroup = $True
}
else{
$isGroup = $False
}
$out = New-Object psobject
$out | add-member Noteproperty 'GroupDomain' $Domain
$out | Add-Member Noteproperty 'GroupName' $GroupFoundName
if ($FullData){
$properties.PropertyNames | % {
# TODO: errors on cross-domain users?
if ($_ -eq "objectsid"){
# convert the SID to a string
$out | Add-Member Noteproperty $_ ((New-Object System.Security.Principal.SecurityIdentifier($properties[$_][0],0)).Value)
}
elseif($_ -eq "objectguid"){
# convert the GUID to a string
$out | Add-Member Noteproperty $_ (New-Object Guid (,$properties[$_][0])).Guid
}
else {
if ($properties[$_].count -eq 1) {
$out | Add-Member Noteproperty $_ $properties[$_][0]
}
else {
$out | Add-Member Noteproperty $_ $properties[$_]
}
}
}
}
else {
$MemberDN = $properties.distinguishedName[0]
# extract the FQDN from the Distinguished Name
$MemberDomain = $MemberDN.subString($MemberDN.IndexOf("DC=")) -replace 'DC=','' -replace ',','.'
if ($properties.samAccountType -ne "805306368"){
$isGroup = $True
}
else{
$isGroup = $False
}
if ($properties.samAccountName){
# forest users have the samAccountName set
$MemberName = $properties.samAccountName[0]
}
else {
# external trust users have a SID, so convert it
try {
$MemberName = Convert-SidToName $properties.cn[0]
}
catch {
# if there's a problem contacting the domain to resolve the SID
$MemberName = $properties.cn
}
}
$out | add-member Noteproperty 'MemberDomain' $MemberDomain
$out | add-member Noteproperty 'MemberName' $MemberName
$out | add-member Noteproperty 'IsGroup' $IsGroup
$out | add-member Noteproperty 'MemberDN' $MemberDN
}
$out
if($Recurse) {
# if we're recursiving and the returned value isn't a user account, assume it's a group
if($IsGroup){
if($FullData){
Get-NetGroup -Domain $Domain -PrimaryDC $PrimaryDC -FullData -Recurse -GroupName $properties.SamAccountName[0]
}
else {
Get-NetGroup -Domain $Domain -PrimaryDC $PrimaryDC -Recurse -GroupName $properties.SamAccountName[0]
}
}
}
}
}
catch {
write-verbose $_
}
}
}
}
}
function Get-NetDomain {
<#
.SYNOPSIS
Returns the name of the current user's domain.
.PARAMETER Domain
The domain to query return. If not supplied, the
current domain is used.
.EXAMPLE
> Get-NetDomain
Return the current domain.
.LINK
http://social.technet.microsoft.com/Forums/scriptcenter/en-US/0c5b3f83-e528-4d49-92a4-dee31f4b481c/finding-the-dn-of-the-the-domain-without-admodule-in-powershell?forum=ITCG
#>
[CmdletBinding()]
param(
[String]
$Domain
)
if($Domain -and ($Domain -ne "")){
$DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain)
try {
[System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
}
catch{
Write-Warning "The specified domain $Domain does not exist, could not be contacted, or there isn't an existing trust."
$Null
}
}
else{
[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
}
}
function Convert-SidToName {
<#
.SYNOPSIS
Converts a security identifier (SID) to a group/user name.
.PARAMETER SID
The SID to convert.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$True,ValueFromPipeline=$True)]
[String]
$SID
)
process {
try {
$obj = (New-Object System.Security.Principal.SecurityIdentifier($SID))
$obj.Translate( [System.Security.Principal.NTAccount]).Value
}
catch {
Write-Warning "invalid SID"
}
}
}
function Translate-NT4Name {
<#
.SYNOPSIS
Converts a user/group NT4 name (i.e. dev/john) to canonical format.
Based on Bill Stewart's code from this article:
http://windowsitpro.com/active-directory/translating-active-directory-object-names-between-formats
.PARAMETER DomainObject
The user/groupname to convert
.PARAMETER DomainObject
The user/groupname to convert
.LINK
http://windowsitpro.com/active-directory/translating-active-directory-object-names-between-formats
#>
[CmdletBinding()]
param(
[String] $DomainObject,
[String] $Domain
)
if (-not $Domain) {
$domain = (Get-NetDomain).name
}
$DomainObject = $DomainObject -replace "/","\"
# Accessor functions to simplify calls to NameTranslate
function Invoke-Method([__ComObject] $object, [String] $method, $parameters) {
$output = $object.GetType().InvokeMember($method, "InvokeMethod", $NULL, $object, $parameters)
if ( $output ) { $output }
}
function Set-Property([__ComObject] $object, [String] $property, $parameters) {
[Void] $object.GetType().InvokeMember($property, "SetProperty", $NULL, $object, $parameters)
}
$Translate = new-object -comobject NameTranslate
try {
Invoke-Method $Translate "Init" (1, $Domain)
}
catch [System.Management.Automation.MethodInvocationException] { }
Set-Property $Translate "ChaseReferral" (0x60)
try {
Invoke-Method $Translate "Set" (3, $DomainObject)
(Invoke-Method $Translate "Get" (2))
}
catch [System.Management.Automation.MethodInvocationException] { }
}
function Get-NetLocalGroup {
<#
.SYNOPSIS
Gets a list of all current users in a specified local group.
.PARAMETER HostName
The hostname or IP to query for local group users.
.PARAMETER HostList
List of hostnames/IPs to query for local group users.
.PARAMETER GroupName
The local group name to query for users. If not given, it defaults to "Administrators"
.PARAMETER Recurse
Switch. If the local member member is a domain group, recursively try to resolve its members to get a list of domain users who can access this machine.
.EXAMPLE
> Get-NetLocalGroup
Returns the usernames that of members of localgroup "Administrators" on the local host.
.EXAMPLE
> Get-NetLocalGroup -HostName WINDOWSXP
Returns all the local administrator accounts for WINDOWSXP
.EXAMPLE
> Get-NetLocalGroup -HostName WINDOWS7 -Resurse
Returns all effective local/domain users/groups that can access WINDOWS7 with
local administrative privileges.
.LINK
http://stackoverflow.com/questions/21288220/get-all-local-members-and-groups-displayed-together
http://msdn.microsoft.com/en-us/library/aa772211(VS.85).aspx
#>
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$True)]
[string]
$HostName = 'localhost',
[string]
$HostList,
[string]
$GroupName,
[switch]
$Recurse
)
process {
$Servers = @()
# if we have a host list passed, grab it
if($HostList){
if (Test-Path -Path $HostList){
$Servers = Get-Content -Path $HostList
}
else{
Write-Warning "[!] Input file '$HostList' doesn't exist!"
$null
}
}
else{
# otherwise assume a single host name
$Servers += $HostName
}
if (-not $GroupName){
# resolve the SID for the local admin group - this should usually default to "Administrators"
$objSID = New-Object System.Security.Principal.SecurityIdentifier('S-1-5-32-544')
$objgroup = $objSID.Translate( [System.Security.Principal.NTAccount])
$GroupName = ($objgroup.Value).Split('\')[1]
}
# query the specified group using the WINNT provider, and
# extract fields as appropriate from the results
foreach($Server in $Servers)
{
try{
$members = @($([ADSI]"WinNT://$server/$groupname").psbase.Invoke('Members'))
$members | ForEach-Object {
$out = New-Object psobject
$out | Add-Member Noteproperty 'Server' $Server
$AdsPath = ($_.GetType().InvokeMember('Adspath', 'GetProperty', $null, $_, $null)).Replace('WinNT://', '')
# try to translate the NT4 domain to a FQDN if possible
$name = Translate-NT4Name $AdsPath
if($name) {
$fqdn = $name.split("/")[0]
$objName = $AdsPath.split("/")[-1]
$name = "$fqdn/$objName"
$IsDomain = $True
}
else {
$name = $AdsPath
$IsDomain = $False
}
$out | Add-Member Noteproperty 'AccountName' $name
# translate the binary sid to a string
$out | Add-Member Noteproperty 'SID' ((New-Object System.Security.Principal.SecurityIdentifier($_.GetType().InvokeMember('ObjectSID', 'GetProperty', $null, $_, $null),0)).Value)
# if the account is local, check if it's disabled, if it's domain, always print $false
# TODO: fix this error?
$out | Add-Member Noteproperty 'Disabled' $( if(-not $IsDomain) { try { $_.GetType().InvokeMember('AccountDisabled', 'GetProperty', $null, $_, $null) } catch { 'ERROR' } } else { $False } )
# check if the member is a group
$IsGroup = ($_.GetType().InvokeMember('Class', 'GetProperty', $Null, $_, $Null) -eq 'group')
$out | Add-Member Noteproperty 'IsGroup' $IsGroup
$out | Add-Member Noteproperty 'IsDomain' $IsDomain
if($IsGroup){
$out | Add-Member Noteproperty 'LastLogin' ""
}
else{
try {
$out | Add-Member Noteproperty 'LastLogin' ( $_.GetType().InvokeMember('LastLogin', 'GetProperty', $null, $_, $null))
}
catch {
$out | Add-Member Noteproperty 'LastLogin' ""
}
}
$out
# if the result is a group domain object and we're recursing,
# try to resolve all the group member results
if($Recurse -and $IsDomain -and $IsGroup){
Write-Verbose "recurse!"
$FQDN = $name.split("/")[0]
$GroupName = $name.split("/")[1]
Get-NetGroup $GroupName -FullData -Recurse | % {
$out = New-Object psobject
$out | Add-Member Noteproperty 'Server' $name
$MemberDN = $_.distinguishedName
# extract the FQDN from the Distinguished Name
$MemberDomain = $MemberDN.subString($MemberDN.IndexOf("DC=")) -replace 'DC=','' -replace ',','.'
if ($_.samAccountType -ne "805306368"){
$MemberIsGroup = $True
}
else{
$MemberIsGroup = $False
}
if ($_.samAccountName){
# forest users have the samAccountName set
$MemberName = $_.samAccountName
}
else {
# external trust users have a SID, so convert it
try {
$MemberName = Convert-SidToName $_.cn
}
catch {
# if there's a problem contacting the domain to resolve the SID
$MemberName = $_.cn
}
}
$out | Add-Member Noteproperty 'AccountName' "$MemberDomain/$MemberName"
$out | Add-Member Noteproperty 'SID' $_.objectsid
$out | Add-Member Noteproperty 'Disabled' $False
$out | Add-Member Noteproperty 'IsGroup' $MemberIsGroup
$out | Add-Member Noteproperty 'IsDomain' $True
$out | Add-Member Noteproperty 'LastLogin' ''
$out
}
}
}
}
catch {
Write-Warning "[!] Error: $_"
}
}
}
}

View File

@ -1,247 +0,0 @@
function Get-NetDomainController {
<#
.SYNOPSIS
Return the current domain controllers for the active domain.
.PARAMETER Domain
The domain to query for domain controllers. If not supplied, the
current domain is used.
.EXAMPLE
> Get-NetDomainController
Returns the domain controllers for the current computer's domain.
Approximately equivialent to the hostname given in the LOGONSERVER
environment variable.
.EXAMPLE
> Get-NetDomainController -Domain test
Returns the domain controllers for the domain "test".
#>
[CmdletBinding()]
param(
[string]
$Domain
)
$d = Get-NetDomain -Domain $Domain
if($d){
$d.DomainControllers
}
}
function Get-NetDomain {
<#
.SYNOPSIS
Returns the name of the current user's domain.
.PARAMETER Domain
The domain to query return. If not supplied, the
current domain is used.
.EXAMPLE
> Get-NetDomain
Return the current domain.
.LINK
http://social.technet.microsoft.com/Forums/scriptcenter/en-US/0c5b3f83-e528-4d49-92a4-dee31f4b481c/finding-the-dn-of-the-the-domain-without-admodule-in-powershell?forum=ITCG
#>
[CmdletBinding()]
param(
[String]
$Domain
)
if($Domain -and ($Domain -ne "")){
$DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain)
try {
[System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
}
catch{
Write-Warning "The specified domain $Domain does not exist, could not be contacted, or there isn't an existing trust."
$Null
}
}
else{
[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
}
}
function Get-NetUser {
<#
.SYNOPSIS
Query information for a given user or users in the domain.
.DESCRIPTION
This function users [ADSI] and LDAP to query the current
domain for all users. Another domain can be specified to
query for users across a trust.
This is a replacement for "net users /domain"
.PARAMETER UserName
Username filter string, wildcards accepted.
.PARAMETER Domain
The domain to query for users. If not supplied, the
current domain is used.
.PARAMETER OU
The OU to pull users from.
.PARAMETER Filter
The complete LDAP query string to use to query for users.
.EXAMPLE
> Get-NetUser
Returns the member users of the current domain.
.EXAMPLE
> Get-NetUser -Domain testing
Returns all the members in the "testing" domain.
#>
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$True)]
[string]
$UserName,
[string]
$OU,
[string]
$Filter,
[string]
$Domain
)
process {
# if a domain is specified, try to grab that domain
if ($Domain){
# try to grab the primary DC for the current domain
try{
$PrimaryDC = ([Array](Get-NetDomainController))[0].Name
}
catch{
$PrimaryDC = $Null
}
try {
# reference - http://blogs.msdn.com/b/javaller/archive/2013/07/29/searching-across-active-directory-domains-in-powershell.aspx
$dn = "DC=$($Domain.Replace('.', ',DC='))"
# if we have an OU specified, be sure to through it in
if($OU){
$dn = "OU=$OU,$dn"
}
# if we could grab the primary DC for the current domain, use that for the query
if ($PrimaryDC){
$UserSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$PrimaryDC/$dn")
}
else{
# otherwise try to connect to the DC for the target domain
$UserSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$dn")
}
# check if we're using a username filter or not
if($UserName){
# samAccountType=805306368 indicates user objects
$UserSearcher.filter="(&(samAccountType=805306368)(samAccountName=$UserName))"
}
elseif($Filter){
# filter is something like (samAccountName=*blah*)
$UserSearcher.filter="(&(samAccountType=805306368)$Filter)"
}
else{
$UserSearcher.filter='(&(samAccountType=805306368))'
}
$UserSearcher.PageSize = 200
$UserSearcher.FindAll() | ForEach-Object {
# for each user/member, do a quick adsi object grab
$properties = $_.Properties
$out = New-Object psobject
$properties.PropertyNames | % {
if ($_ -eq "objectsid"){
# convert the SID to a string
$out | Add-Member Noteproperty $_ ((New-Object System.Security.Principal.SecurityIdentifier($properties[$_][0],0)).Value)
}
elseif($_ -eq "objectguid"){
# convert the GUID to a string
$out | Add-Member Noteproperty $_ (New-Object Guid (,$properties[$_][0])).Guid
}
elseif( ($_ -eq "lastlogon") -or ($_ -eq "lastlogontimestamp") -or ($_ -eq "pwdlastset") ){
$out | Add-Member Noteproperty $_ ([datetime]::FromFileTime(($properties[$_][0])))
}
else {
if ($properties[$_].count -eq 1) {
$out | Add-Member Noteproperty $_ $properties[$_][0]
}
else {
$out | Add-Member Noteproperty $_ $properties[$_]
}
}
}
$out
}
}
catch{
Write-Warning "The specified domain $Domain does not exist, could not be contacted, or there isn't an existing trust."
}
}
else{
# otherwise, use the current domain
if($UserName){
$UserSearcher = [adsisearcher]"(&(samAccountType=805306368)(samAccountName=*$UserName*))"
}
# if we're specifying an OU
elseif($OU){
$dn = "OU=$OU," + ([adsi]'').distinguishedname
$UserSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$dn")
$UserSearcher.filter='(&(samAccountType=805306368))'
}
# if we're specifying a specific LDAP query string
elseif($Filter){
# filter is something like (samAccountName=*blah*)
$UserSearcher = [adsisearcher]"(&(samAccountType=805306368)$Filter)"
}
else{
$UserSearcher = [adsisearcher]'(&(samAccountType=805306368))'
}
$UserSearcher.PageSize = 200
$UserSearcher.FindAll() | ForEach-Object {
# for each user/member, do a quick adsi object grab
$properties = $_.Properties
$out = New-Object psobject
$properties.PropertyNames | % {
if ($_ -eq "objectsid"){
# convert the SID to a string
$out | Add-Member Noteproperty $_ ((New-Object System.Security.Principal.SecurityIdentifier($properties[$_][0],0)).Value)
}
elseif($_ -eq "objectguid"){
# convert the GUID to a string
$out | Add-Member Noteproperty $_ (New-Object Guid (,$properties[$_][0])).Guid
}
elseif( ($_ -eq "lastlogon") -or ($_ -eq "lastlogontimestamp") -or ($_ -eq "pwdlastset") ){
$out | Add-Member Noteproperty $_ ([datetime]::FromFileTime(($properties[$_][0])))
}
else {
if ($properties[$_].count -eq 1) {
$out | Add-Member Noteproperty $_ $properties[$_][0]
}
else {
$out | Add-Member Noteproperty $_ $properties[$_]
}
}
}
$out
}
}
}
}

View File

@ -1,308 +0,0 @@
# Invoke-MapDomainTrusts.ps1
# part of PowerView in Veil's PowerTools
# https://github.com/Veil-Framework/PowerTools/
function Get-NetDomain {
<#
.SYNOPSIS
Returns the name of the current user's domain.
.PARAMETER Domain
The domain to query return. If not supplied, the
current domain is used.
.EXAMPLE
> Get-NetDomain
Return the current domain.
.LINK
http://social.technet.microsoft.com/Forums/scriptcenter/en-US/0c5b3f83-e528-4d49-92a4-dee31f4b481c/finding-the-dn-of-the-the-domain-without-admodule-in-powershell?forum=ITCG
#>
[CmdletBinding()]
param(
[String]
$Domain
)
if($Domain -and ($Domain -ne "")){
$DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain)
try {
[System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
}
catch{
Write-Warning "The specified domain $Domain does not exist, could not be contacted, or there isn't an existing trust."
$Null
}
}
else{
[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
}
}
function Get-NetDomainTrusts {
<#
.SYNOPSIS
Return all domain trusts for the current domain or
a specified domain.
.PARAMETER Domain
The domain whose trusts to enumerate. If not given,
uses the current domain.
.EXAMPLE
> Get-NetDomainTrusts
Return domain trusts for the current domain.
.EXAMPLE
> Get-NetDomainTrusts -Domain "test"
Return domain trusts for the "test" domain.
#>
[CmdletBinding()]
param(
[string]
$Domain
)
$d = Get-NetDomain -Domain $Domain
if($d){
$d.GetAllTrustRelationships()
}
}
function Get-NetDomainTrustsLDAP {
<#
.SYNOPSIS
Return all domain trusts for the current domain or
a specified domain using LDAP queries. This is potentially
less accurate than the Get-NetDomainTrusts function, but
can be relayed through your current domain controller
in cases where you can't reach a remote domain directly.
.PARAMETER Domain
The domain whose trusts to enumerate. If not given,
uses the current domain.
.EXAMPLE
> Get-NetDomainTrustsLDAP
Return domain trusts for the current domain.
.EXAMPLE
> Get-NetDomainTrustsLDAP -Domain "test"
Return domain trusts for the "test" domain.
#>
[CmdletBinding()]
param(
[string]
$Domain
)
$TrustSearcher = $Null
# if a domain is specified, try to grab that domain
if ($Domain){
# try to grab the primary DC for the current domain
try{
$PrimaryDC = ([Array](Get-NetDomainControllers))[0].Name
}
catch{
$PrimaryDC = $Null
}
try {
# reference - http://blogs.msdn.com/b/javaller/archive/2013/07/29/searching-across-active-directory-domains-in-powershell.aspx
$dn = "DC=$($Domain.Replace('.', ',DC='))"
# if we could grab the primary DC for the current domain, use that for the query
if ($PrimaryDC){
$TrustSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$PrimaryDC/$dn")
}
else{
# otherwise default to connecting to the DC for the target domain
$TrustSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$dn")
}
$TrustSearcher.filter = '(&(objectClass=trustedDomain))'
$TrustSearcher.PageSize = 200
}
catch{
Write-Warning "The specified domain $Domain does not exist, could not be contacted, or there isn't an existing trust."
$TrustSearcher = $Null
}
}
else{
$Domain = (Get-NetDomain).Name
$TrustSearcher = [adsisearcher]'(&(objectClass=trustedDomain))'
$TrustSearcher.PageSize = 200
}
if($TrustSearcher){
$TrustSearcher.FindAll() | ForEach-Object {
$props = $_.Properties
$out = New-Object psobject
Switch ($props.trustattributes)
{
4 { $attrib = "External"}
16 { $attrib = "CrossLink"}
32 { $attrib = "ParentChild"}
64 { $attrib = "External"}
68 { $attrib = "ExternalQuarantined"}
Default { $attrib = "unknown trust attribute number: $($props.trustattributes)" }
}
Switch ($props.trustdirection){
0 {$direction = "Disabled"}
1 {$direction = "Inbound"}
2 {$direction = "Outbound"}
3 {$direction = "Bidirectional"}
}
$out | Add-Member Noteproperty 'SourceName' $domain
$out | Add-Member Noteproperty 'TargetName' $props.name[0]
$out | Add-Member Noteproperty 'TrustType' "$attrib"
$out | Add-Member Noteproperty 'TrustDirection' "$direction"
$out
}
}
}
function Invoke-MapDomainTrusts {
<#
.SYNOPSIS
Try to map all transitive domain trust relationships.
.DESCRIPTION
This function gets all trusts for the current domain,
and tries to get all trusts for each domain it finds.
.EXAMPLE
> Invoke-MapDomainTrusts
Return a "domain1,domain2,trustType,trustDirection" list
.LINK
http://blog.harmj0y.net/
#>
# keep track of domains seen so we don't hit infinite recursion
$seenDomains = @{}
# our domain status tracker
$domains = New-Object System.Collections.Stack
# get the current domain and push it onto the stack
$currentDomain = (([adsi]'').distinguishedname -replace 'DC=','' -replace ',','.')[0]
$domains.push($currentDomain)
while($domains.Count -ne 0){
$d = $domains.Pop()
# if we haven't seen this domain before
if (-not $seenDomains.ContainsKey($d)) {
# mark it as seen in our list
$seenDomains.add($d, "") | out-null
try{
# get all the trusts for this domain
$trusts = Get-NetDomainTrusts -Domain $d
if ($trusts){
# enumerate each trust found
foreach ($trust in $trusts){
$source = $trust.SourceName
$target = $trust.TargetName
$type = $trust.TrustType
$direction = $trust.TrustDirection
# make sure we process the target
$domains.push($target) | out-null
# build the nicely-parsable custom output object
$out = new-object psobject
$out | add-member Noteproperty 'SourceDomain' $source
$out | add-member Noteproperty 'TargetDomain' $target
$out | add-member Noteproperty 'TrustType' "$type"
$out | add-member Noteproperty 'TrustDirection' "$direction"
$out
}
}
}
catch{
Write-Warning "[!] Error: $_"
}
}
}
}
function Invoke-MapDomainTrustsLDAP {
<#
.SYNOPSIS
Try to map all transitive domain trust relationships
through LDAP queries.
.EXAMPLE
> Invoke-MapDomainTrustsLDAP
Return a "domain1,domain2,trustType,trustDirection" list
.LINK
http://blog.harmj0y.net/
#>
# keep track of domains seen so we don't hit infinite recursion
$seenDomains = @{}
# our domain status tracker
$domains = New-Object System.Collections.Stack
# get the current domain and push it onto the stack
$currentDomain = (([adsi]'').distinguishedname -replace 'DC=','' -replace ',','.')[0]
$domains.push($currentDomain)
while($domains.Count -ne 0){
$d = $domains.Pop()
# if we haven't seen this domain before
if (-not $seenDomains.ContainsKey($d)) {
# mark it as seen in our list
$seenDomains.add($d, "") | out-null
try{
# get all the trusts for this domain through LDAP queries
$trusts = Get-NetDomainTrustsLDAP -Domain $d
if ($trusts){
# enumerate each trust found
foreach ($trust in $trusts){
$source = $trust.SourceName
$target = $trust.TargetName
$type = $trust.TrustType
$direction = $trust.TrustDirection
# make sure we process the target
$domains.push($target) | out-null
# build the nicely-parsable custom output object
$out = new-object psobject
$out | add-member Noteproperty 'SourceDomain' $source
$out | add-member Noteproperty 'TargetDomain' $target
$out | add-member Noteproperty 'TrustType' $type
$out | add-member Noteproperty 'TrustDirection' $direction
$out
}
}
}
catch{
Write-Warning "[!] Error: $_"
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@ menu loops.
"""
# make version for Empire
VERSION = "1.2.1"
VERSION = "1.3.0"
from pydispatch import dispatcher

View File

@ -197,6 +197,119 @@ def strip_powershell_comments(data):
return strippedCode
# PowerView dynamic helpers
def get_powerview_psreflect_overhead(script):
"""
Helper to extract some of the psreflect overhead for PowerView.
"""
pattern = re.compile(r'\n\$Mod =.*\[\'wtsapi32\'\]', re.DOTALL)
try:
return strip_powershell_comments(pattern.findall(script)[0])
except:
print color("[!] Error extracting psreflect overhead from powerview.ps1 !")
return ""
def get_dependent_functions(code, functionNames):
"""
Helper that takes a chunk of PowerShell code and a set of function
names and returns the unique set of function names within the script block.
"""
dependentFunctions = set()
for functionName in functionNames:
# find all function names that aren't followed by another alpha character
if re.search(functionName+"[^A-Za-z]+", code, re.IGNORECASE):
dependentFunctions.add(functionName)
if re.search(functionName+"|\$Netapi32|\$Advapi32|\$Kernel32\$Wtsapi32", code, re.IGNORECASE):
dependentFunctions |= set(["New-InMemoryModule", "func", "Add-Win32Type", "psenum", "struct"])
return dependentFunctions
def find_all_dependent_functions(functions, functionsToProcess, resultFunctions=[]):
"""
Takes a dictionary of "[functionName] -> functionCode" and a set of functions
to process, and recursively returns all nested functions that may be required.
Used to map the dependent functions for nested script dependencies like in
PowerView.
"""
if isinstance(functionsToProcess, str):
functionsToProcess = [functionsToProcess]
while len(functionsToProcess) != 0:
# pop the next function to process off the stack
requiredFunction = functionsToProcess.pop()
if requiredFunction not in resultFunctions:
resultFunctions.append(requiredFunction)
# get the dependencies for the function we're currently processing
try:
functionDependencies = get_dependent_functions(functions[requiredFunction], functions.keys())
except:
functionDependencies = []
print color("[!] Error in retrieving dependencies for function %s !" %(requiredFunction))
for functionDependency in functionDependencies:
if functionDependency not in resultFunctions and functionDependency not in functionsToProcess:
# for each function dependency, if we haven't already seen it
# add it to the stack for processing
functionsToProcess.append(functionDependency)
resultFunctions.append(functionDependency)
resultFunctions = find_all_dependent_functions(functions, functionsToProcess, resultFunctions)
return resultFunctions
def generate_dynamic_powershell_script(script, functionName):
"""
Takes a PowerShell script and a function name, generates a dictionary
of "[functionName] -> functionCode", and recurisvely maps all
dependent functions for the specified function name.
A script is returned with only the code necessary for the given
functionName, stripped of comments and whitespace.
Note: for PowerView, it will also dynamically detect if psreflect
overhead is needed and add it to the result script.
"""
newScript = ""
psreflect_functions = ["New-InMemoryModule", "func", "Add-Win32Type", "psenum", "struct"]
# build a mapping of functionNames -> stripped function code
functions = {}
pattern = re.compile(r'\nfunction.*?{.*?\n}\n', re.DOTALL)
for match in pattern.findall(script):
name = match[:40].split()[1]
functions[name] = strip_powershell_comments(match)
# recursively enumerate all possible function dependencies and
# start building the new result script
functionDependencies = find_all_dependent_functions(functions, functionName)
for functionDependency in functionDependencies:
try:
newScript += functions[functionDependency] + "\n"
except:
print color("[!] Key error with function %s !" %(functionDependency))
# if any psreflect methods are needed, add in the overhead at the end
if any(el in set(psreflect_functions) for el in functionDependencies):
newScript += get_powerview_psreflect_overhead(script)
return newScript + "\n"
###############################################################
#
# Parsers
@ -232,7 +345,7 @@ def parse_credentials(data):
return [("plaintext", domain, username, password, "", "")]
else:
print helpers.color("[!] Error in parsing prompted credential output.")
print color("[!] Error in parsing prompted credential output.")
return None
else:
@ -566,4 +679,3 @@ def complete_path(text, line, arg=False):
completions.append(f+'/')
return completions

View File

@ -35,23 +35,18 @@ class Module:
'Required' : True,
'Value' : ''
},
'Hosts' : {
'Description' : "Host array to enumerate.",
'ComputerName' : {
'Description' : 'Hosts to enumerate.',
'Required' : False,
'Value' : ''
},
'HostList' : {
'Description' : "List of hostnames/IPs to search.",
'Required' : False,
'Value' : ''
},
'HostFilter' : {
'Description' : "Host filter name to query AD for, wildcards accepted.",
'ComputerFilter' : {
'Description' : 'Host filter name to query AD for, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'ShareList' : {
'Description' : "List if \\HOST\shares to search through.",
'Description' : "List of '\\\\HOST\shares' (on the target) to search through.",
'Required' : False,
'Value' : ''
},
@ -70,6 +65,21 @@ class Module:
'Required' : False,
'Value' : ''
},
'LastAccessTime' : {
'Description' : "Only return files with a LastAccessTime greater than this date value.",
'Required' : False,
'Value' : ''
},
'CreationTime' : {
'Description' : "Only return files with a CreationDate greater than this date value.",
'Required' : False,
'Value' : ''
},
'FreshEXES' : {
'Description' : "Switch. Find .EXEs accessed in the last week.",
'Required' : False,
'Value' : ''
},
'ExcludeHidden' : {
'Description' : "Switch. Exclude hidden files and folders from the search results.",
'Required' : False,
@ -80,16 +90,6 @@ class Module:
'Required' : False,
'Value' : ''
},
'AccessDateLimit' : {
'Description' : "Only return files with a LastAccessTime greater than this date value.",
'Required' : False,
'Value' : ''
},
'CreateDateLimit' : {
'Description' : "Only return files with a CreationDate greater than this date value.",
'Required' : False,
'Value' : ''
},
'NoPing' : {
'Description' : "Switch. Don't ping each host to ensure it's up before enumerating.",
'Required' : False,
@ -104,6 +104,16 @@ class Module:
'Description' : "Domain to query for machines.",
'Required' : False,
'Value' : ''
},
'SearchSYSVOL' : {
'Description' : "Switch. Search for login scripts on the SYSVOL of the primary DCs for each specified domain.",
'Required' : False,
'Value' : ''
},
'Threads' : {
'Description' : "The maximum concurrent threads to execute.",
'Required' : False,
'Value' : ''
}
}
@ -120,8 +130,10 @@ class Module:
def generate(self):
# read in the common module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/collection/Invoke-FileFinder.ps1"
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
@ -132,15 +144,20 @@ class Module:
moduleCode = f.read()
f.close()
script = moduleCode
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += "Invoke-FileFinder "
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
script += " -" + str(option) + " " + str(values['Value'])
script += " | Out-String"
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -5,12 +5,11 @@ class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Invoke-Filesearch',
'Name': 'Find-InterestingFile',
'Author': ['@harmj0y'],
'Description': ('Recurively searches a given file path for files with '
'specified terms in their names.'),
'Description': ('Finds sensitive files on the domain.'),
'Background' : True,
@ -37,10 +36,10 @@ class Module:
'Value' : ''
},
'Path' : {
'Description' : "Path to search, defaults to current dir.",
'Required' : False,
'Description' : 'UNC/local path to recursively search.',
'Required' : True,
'Value' : ''
},
},
'Terms' : {
'Description' : "Comma-separated terms to search for (overrides defaults).",
'Required' : False,
@ -56,6 +55,21 @@ class Module:
'Required' : False,
'Value' : ''
},
'LastAccessTime' : {
'Description' : "Only return files with a LastAccessTime greater than this date value.",
'Required' : False,
'Value' : ''
},
'CreationTime' : {
'Description' : "Only return files with a CreationDate greater than this date value.",
'Required' : False,
'Value' : ''
},
'FreshEXES' : {
'Description' : "Switch. Find .EXEs accessed in the last week.",
'Required' : False,
'Value' : ''
},
'ExcludeHidden' : {
'Description' : "Switch. Exclude hidden files and folders from the search results.",
'Required' : False,
@ -65,28 +79,13 @@ class Module:
'Description' : "Switch. Only returns files the current user has write access to.",
'Required' : False,
'Value' : ''
},
'AccessDateLimit' : {
'Description' : "Only return files with a LastAccessTime greater than this date value.",
'Required' : False,
'Value' : ''
},
'CreateDateLimit' : {
'Description' : "Only return files with a CreationDate greater than this date value.",
'Required' : False,
'Value' : ''
},
'FreshEXES' : {
'Description' : "Switch. Find .EXEs accessed within the last week.",
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
@ -96,8 +95,10 @@ class Module:
def generate(self):
# read in the common module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/collection/Invoke-Filesearch.ps1"
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
@ -108,9 +109,10 @@ class Module:
moduleCode = f.read()
f.close()
script = moduleCode
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += "Invoke-Filesearch "
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
@ -119,8 +121,8 @@ class Module:
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += " | Out-String"
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -44,7 +44,7 @@ class Module:
'Value' : ''
},
'Groups' : {
'Description' : 'Groups/users to add to the sidhistory of the target user (space-separated).',
'Description' : 'Groups/users to add to the sidhistory of the target user (COMMA-separated).',
'Required' : True,
'Value' : ''
}
@ -77,8 +77,11 @@ class Module:
script = moduleCode
# ridiculous escape format
groups = " ".join(['"\\""'+group.strip().strip("'\"")+'"""' for group in self.options["Groups"]['Value'].split(",")])
# build the custom command with whatever options we want
command = "misc::addsid "+self.options["User"]['Value'] + " " + self.options["Groups"]['Value']
command = '""misc::addsid '+self.options["User"]['Value'] + ' ' + groups
# base64 encode the command to pass to Invoke-Mimikatz
script += "Invoke-Mimikatz -Command '\"" + command + "\"';"

View File

@ -1,108 +0,0 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Get-NetDomainController',
'Author': ['@harmj0y'],
'Description': ('Returns the domain controllers for the current domain or '
'the specified domain.'),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain to query for domain controllers.',
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
script = """
function Get-NetDomain {
[CmdletBinding()]
param(
[String]
$Domain
)
if($Domain -and ($Domain -ne "")){
$DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain)
try {
[System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
}
catch{
Write-Warning "The specified domain $Domain does not exist, could not be contacted, or there isn't an existing trust."
$Null
}
}
else{
[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
}
}
function Get-NetDomainController {
[CmdletBinding()]
param(
[string]
$Domain
)
$d = Get-NetDomain -Domain $Domain
if($d){
$d.DomainControllers
}
}
"""
script += "Get-NetDomainController "
for option,values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
return script

View File

@ -1,83 +0,0 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Get-NetDomainTrusts',
'Author': ['@harmj0y'],
'Description': ('Return all domain trusts for the current domain or '
'a specified domain. Part of PowerView.'),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'Domain' : {
'Description' : 'Specific domain to query for trusts, defaults to current.',
'Required' : False,
'Value' : ''
},
'LDAP' : {
'Description' : 'Switch. Use LDAP for domain queries (less accurate).',
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
# read in the common module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/Invoke-MapDomainTrusts.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
script = moduleCode
if self.options['LDAP']['Value'].lower() == "true":
script += "Get-NetDomainTrustsLDAP | Out-String | %{$_ + \"`n\"};"
else:
script += "Get-NetDomainTrusts | Out-String | %{$_ + \"`n\"};"
return script

View File

@ -0,0 +1,114 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Get-ExploitableSystem',
'Author': ['Scott Sutherland (@_nullbind)'],
'Description': ('Queries Active Directory for systems likely vulnerable to various '
'Metasploit exploits.'),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'https://github.com/nullbind/Powershellery/blob/master/Stable-ish/ADS/Get-ExploitableSystems.psm1'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'ComputerName' : {
'Description' : 'Return computers with a specific name, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'SPN' : {
'Description' : 'Return computers with a specific service principal name, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'OperatingSystem' : {
'Description' : 'Return computers with a specific operating system, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'Filter' : {
'Description' : 'A customized ldap filter string to use, e.g. "(description=*admin*)"',
'Required' : False,
'Value' : ''
},
'Ping' : {
'Description' : "Switch. Ping each host to ensure it's up before enumerating.",
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain to query for computers, defaults to the current domain.',
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -1,79 +0,0 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Invoke-MapDomainTrusts',
'Author': ['@harmj0y'],
'Description': ('Maps all reachable domain trusts with .CSV output. Part of PowerView.'),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'LDAP' : {
'Description' : 'Switch. Use LDAP for domain queries (less accurate).',
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
# read in the common module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/Invoke-MapDomainTrusts.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
script = moduleCode
if self.options['LDAP']['Value'].lower() == "true":
script += "Invoke-MapDomainTrustsLDAP | ConvertTo-Csv -NoTypeInformation"
script += '| Out-String | %{$_ + \"`n\"};"`nInvoke-MapDomainTrustsLDAP completed"'
else:
script += "Invoke-MapDomainTrusts | ConvertTo-Csv -NoTypeInformation"
script += '| Out-String | %{$_ + \"`n\"};"`nInvoke-MapDomainTrusts completed"'
return script

View File

@ -0,0 +1,104 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Find-ComputerField',
'Author': ['@obscuresec', '@harmj0y'],
'Description': ("Searches computer object fields for a given word (default *pass*). Default field being searched is 'description'. Part of PowerView."),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'http://obscuresecurity.blogspot.com/2014/04/ADSISearcher.html',
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'SearchTerm' : {
'Description' : 'Term to search for, default of "pass".',
'Required' : False,
'Value' : ''
},
'SearchField' : {
'Description' : 'Field to search in, default of "description".',
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -0,0 +1,98 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Find-ForeignGroup',
'Author': ['@harmj0y'],
'Description': ("Enumerates all the members of a given domain's groups and finds users that are not in the queried domain. Part of PowerView."),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'GroupName' : {
'Description' : 'Groupname to filter results for, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -5,11 +5,11 @@ class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Get-NetUser',
'Name': 'Find-ForeignUser',
'Author': ['@harmj0y'],
'Description': ('Query information for a given user or users in the specified domain.'),
'Description': ("Enumerates users who are in groups outside of their principal domain. Part of PowerView."),
'Background' : True,
@ -35,23 +35,18 @@ class Module:
'Required' : True,
'Value' : ''
},
'OU' : {
'Description' : 'The OU to pull users from.',
'Required' : False,
'Value' : ''
},
'UserName' : {
'Description' : 'Username filter string, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'Filter' : {
'Description' : 'The complete LDAP query string to use to query for users.',
'Description' : 'Username to filter results for, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain to query for computers.',
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
}
@ -70,8 +65,10 @@ class Module:
def generate(self):
# read in the common module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/Get-NetUser.ps1"
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
@ -82,9 +79,10 @@ class Module:
moduleCode = f.read()
f.close()
script = moduleCode
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += "Get-NetUser "
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
@ -94,7 +92,7 @@ class Module:
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += " | Out-String"
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -0,0 +1,113 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Find-GPOComputerAdmin',
'Author': ['@harmj0y'],
'Description': ('Takes a computer (or GPO) object and determines what users/groups have administrative access over it. Part of PowerView.'),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'ComputerName' : {
'Description' : 'The computer to determine local administrative access to.',
'Required' : False,
'Value' : ''
},
'OUName' : {
'Description' : 'OU name to determine who has local adminisrtative acess to computers within it.',
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
},
'Recurse' : {
'Description' : 'Switch. If a returned member is a group, recurse and get all members.',
'Required' : False,
'Value' : ''
},
'LocalGroup' : {
'Description' : 'The local group to check access against, "Administrators", "RDP/Remote Desktop Users", or a custom SID. Defaults to "Administrators".',
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -0,0 +1,108 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Find-GPOLocation',
'Author': ['@harmj0y'],
'Description': ('Takes a user/group name and optional domain, and determines the computers in the domain the user/group has local admin (or RDP) rights to. Part of PowerView.'),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'UserName' : {
'Description' : 'A (single) user name name to query for access.',
'Required' : False,
'Value' : ''
},
'GroupName' : {
'Description' : 'A (single) group name name to query for access.',
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
},
'LocalGroup' : {
'Description' : 'The local group to check access against, "Administrators", "RDP/Remote Desktop Users", or a custom SID. Defaults to "Administrators".',
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -5,12 +5,12 @@ class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Invoke-FindLocalAdminAccess',
'Name': 'Find-LocalAdminAccess',
'Author': ['@harmj0y'],
'Description': ('Finds machines on the local domain where the current user has '
'local administrator access.'),
'local administrator access. Part of PowerView.'),
'Background' : True,
@ -36,23 +36,18 @@ class Module:
'Required' : True,
'Value' : ''
},
'Hosts' : {
'Description' : 'Hosts to enumerate.',
'ComputerName' : {
'Description' : 'Hosts to enumerate, comma separated.',
'Required' : False,
'Value' : ''
},
'HostList' : {
'Description' : 'Hostlist to enumerate.',
'Required' : False,
'Value' : ''
},
'HostFilter' : {
'ComputerFilter' : {
'Description' : 'Host filter name to query AD for, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'NoPing' : {
'Description' : 'Don\'t ping each host to ensure it\'s up before enumerating.',
'Description' : "Don't ping each host to ensure it's up before enumerating.",
'Required' : False,
'Value' : ''
},
@ -62,7 +57,17 @@ class Module:
'Value' : ''
},
'Domain' : {
'Description' : 'Domain to enumerate for hosts.',
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
},
'Threads' : {
'Description' : 'The maximum concurrent threads to execute.',
'Required' : False,
'Value' : ''
}
@ -81,8 +86,10 @@ class Module:
def generate(self):
# read in the common module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/Invoke-FindLocalAdminAccess.ps1"
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
@ -93,9 +100,10 @@ class Module:
moduleCode = f.read()
f.close()
script = moduleCode
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += "Invoke-FindLocalAdminAccess "
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
@ -106,6 +114,6 @@ class Module:
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`nInvoke-FindLocalAdminAccess completed"'
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -0,0 +1,104 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Find-ComputerField',
'Author': ['@obscuresec', '@harmj0y'],
'Description': ("Searches user object fields for a given word (default *pass*). Default field being searched is 'description'."),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'http://obscuresecurity.blogspot.com/2014/04/ADSISearcher.html',
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'SearchTerm' : {
'Description' : 'Term to search for, default of "pass".',
'Required' : False,
'Value' : ''
},
'SearchField' : {
'Description' : 'Field to search in, default of "description".',
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
},
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -0,0 +1,128 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Get-NetComputer',
'Author': ['@harmj0y'],
'Description': ('Queries the domain for current computer objects. Part of PowerView.'),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'ComputerName' : {
'Description' : 'Return computers with a specific name, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'SPN' : {
'Description' : 'Return computers with a specific service principal name, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'OperatingSystem' : {
'Description' : 'Return computers with a specific operating system, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'Filter' : {
'Description' : 'A customized ldap filter string to use, e.g. "(description=*admin*)"',
'Required' : False,
'Value' : ''
},
'Printers' : {
'Description' : 'Switch. Return only printers.',
'Required' : False,
'Value' : ''
},
'Ping' : {
'Description' : "Switch. Ping each host to ensure it's up before enumerating.",
'Required' : False,
'Value' : ''
},
'FullData' : {
'Description' : "Switch. Return full computer objects instead of just system names (the default).",
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -0,0 +1,99 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Get-NetDomainController',
'Author': ['@harmj0y'],
'Description': ('Returns the domain controllers for the current domain or '
'the specified domain. Part of PowerView.'),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain to query for domain controllers.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
},
'LDAP' : {
'Description' : 'Switch. Use LDAP queries to determine the domain controllers.',
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -0,0 +1,99 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Get-NetDomainTrust',
'Author': ['@harmj0y'],
'Description': ('Return all domain trusts for the current domain or '
'a specified domain. Part of PowerView.'),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain whose trusts to enumerate, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
},
'LDAP' : {
'Description' : 'Switch. Use LDAP queries to enumerate the trusts instead of direct domain connections.',
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -0,0 +1,88 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Get-NetForestDomain',
'Author': ['@harmj0y'],
'Description': ('Return all domains for a given forest. Part of PowerView.'),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'Forest' : {
'Description' : 'The forest name to query domain for, defaults to the current forest.',
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -5,11 +5,11 @@ class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Get-NetComputer',
'Name': 'Get-NetGPO',
'Author': ['@harmj0y'],
'Description': ('Queries the domain for current computer objects.'),
'Description': ('Gets a list of all current GPOs in a domain.'),
'Background' : True,
@ -35,28 +35,28 @@ class Module:
'Required' : True,
'Value' : ''
},
'FullData' : {
'Description' : 'Switch. Return full user computer objects instead of just system names.',
'GPOname' : {
'Description' : 'The GPO name to query for, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'Ping' : {
'Description' : 'Switch. Only return hosts that respond to ping.',
'Required' : False,
'Value' : ''
},
'HostName' : {
'Description' : 'Return computers with a specific name, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'OperatingSystem' : {
'Description' : 'Return computers with a specific operating system, wildcards accepted.',
'DisplayName' : {
'Description' : 'The GPO display name to query for, wildcards accepted. ',
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain to query for computers.',
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
},
'ADSpath' : {
'Description' : 'The LDAP source to search through.',
'Required' : False,
'Value' : ''
}
@ -75,8 +75,10 @@ class Module:
def generate(self):
# read in the common module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/Get-NetComputer.ps1"
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
@ -87,9 +89,10 @@ class Module:
moduleCode = f.read()
f.close()
script = moduleCode
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += "Get-NetComputer "
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
@ -99,5 +102,7 @@ class Module:
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -0,0 +1,118 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Get-NetGroup',
'Author': ['@harmj0y'],
'Description': ('Gets a list of all current groups in a domain, or all the groups a given user/group object belongs to. Part of PowerView.'),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'GroupName' : {
'Description' : 'The group name to query for, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'SID' : {
'Description' : 'The group SID to query for.',
'Required' : False,
'Value' : ''
},
'UserName' : {
'Description' : 'The user name (or group name) to query for all effective groups of.',
'Required' : False,
'Value' : ''
},
'Filter' : {
'Description' : 'A customized ldap filter string to use, e.g. "(description=*admin*)"',
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
},
'FullData' : {
'Description' : 'Return full group objects instead of just object names (the default).',
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -0,0 +1,118 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Get-NetGroupMember',
'Author': ['@harmj0y'],
'Description': ('Returns the members of a given group, with the option to "Recurse" to find all effective group members. Part of PowerView.'),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'GroupName' : {
'Description' : 'The group name to query for users.',
'Required' : True,
'Value' : ''
},
'SID' : {
'Description' : 'The Group SID to query for users.',
'Required' : False,
'Value' : ''
},
'Filter' : {
'Description' : 'A customized ldap filter string to use, e.g. "(description=*admin*)"',
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
},
'FullData' : {
'Description' : 'Return full group objects instead of just object names (the default).',
'Required' : False,
'Value' : ''
},
'Recurse' : {
'Description' : 'Switch. If the group member is a group, recursively try to query its members as well.',
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -10,7 +10,7 @@ class Module:
'Author': ['@harmj0y'],
'Description': ('Returns a list of all current users in a specified local group '
'on a local or remote machine.'),
'on a local or remote machine. Part of PowerView.'),
'Background' : True,
@ -34,16 +34,21 @@ class Module:
'Required' : True,
'Value' : ''
},
'HostName' : {
'ComputerName' : {
'Description' : 'The hostname or IP to query for local group users.',
'Required' : False,
'Value' : 'localhost'
},
'GroupName' : {
'Description' : 'The local group name to query for users.',
'Description' : 'The local group name to query for users, defaults to "Administrators".',
'Required' : False,
'Value' : 'Administrators'
},
'ListGroups' : {
'Description' : 'Switch. List all the local groups instead of their members.',
'Required' : False,
'Value' : ''
},
'Recurse' : {
'Description' : 'Switch. If the local member member is a domain group, recursively try to resolve its members to get a list of domain users who can access this machine.',
'Required' : False,
@ -64,8 +69,10 @@ class Module:
def generate(self):
# read in the common module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/Get-NetLocalgroup.ps1"
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
@ -76,9 +83,10 @@ class Module:
moduleCode = f.read()
f.close()
script = moduleCode
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += "Get-NetLocalGroup "
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
@ -87,8 +95,8 @@ class Module:
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += "| Out-String"
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -0,0 +1,133 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Get-ObjectAcl',
'Author': ['@harmj0y', '@pyrotek3'],
'Description': ('Returns the ACLs associated with a specific active directory object. Part of PowerView.'),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'SamAccountName' : {
'Description' : 'Object SamAccountName to filter for.',
'Required' : False,
'Value' : ''
},
'Name' : {
'Description' : 'Object Name to filter for.',
'Required' : False,
'Value' : ''
},
'DistinguishedName' : {
'Description' : 'Object distinguished name to filter for.',
'Required' : False,
'Value' : ''
},
'ResolveGUIDs' : {
'Description' : 'Switch. Resolve GUIDs to their display names.',
'Required' : False,
'Value' : 'True'
},
'Filter' : {
'Description' : 'A customized ldap filter string to use, e.g. "(description=*admin*)"',
'Required' : False,
'Value' : ''
},
'ADSpath' : {
'Description' : 'The LDAP source to search through, e.g. "LDAP://OU=secret,DC=testlab,DC=local"',
'Required' : False,
'Value' : ''
},
'ADSprefix' : {
'Description' : 'Prefix to set for the searcher (like "CN=Sites,CN=Configuration")',
'Required' : False,
'Value' : ''
},
'RightsFilter' : {
'Description' : 'Only return results with the associated rights, "All", "ResetPassword","ChangePassword","WriteMembers"',
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -5,12 +5,11 @@ class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Invoke-Netview',
'Name': 'Get-NetOU',
'Author': ['@harmj0y'],
'Description': ('Queries the domain for all hosts, and retrieves open shares, '
'sessions, and logged on users for each host. Part of PowerView.'),
'Description': ('Gets a list of all current OUs in a domain. Part of PowerView.'),
'Background' : True,
@ -23,8 +22,7 @@ class Module:
'MinPSVersion' : '2',
'Comments': [
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView',
'https://github.com/mubix/netview'
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
@ -37,38 +35,33 @@ class Module:
'Required' : True,
'Value' : ''
},
'Hosts' : {
'Description' : 'Hosts to enumerate.',
'OUName' : {
'Description' : 'The OU name to query for, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'HostList' : {
'Description' : 'Hostlist to enumerate.',
'Required' : False,
'Value' : ''
},
'HostFilter' : {
'Description' : 'Host filter name to query AD for, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'NoPing' : {
'Description' : 'Don\'t ping each host to ensure it\'s up before enumerating.',
'Required' : False,
'Value' : ''
},
'CheckShareAccess' : {
'Description' : 'Switch. Only display found shares that the local user has access to.',
'Required' : False,
'Value' : ''
},
'Delay' : {
'Description' : 'Delay between enumerating hosts, defaults to 0.',
'GUID' : {
'Description' : 'Only return OUs with the specified GUID in their gplink property.',
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'Domain to enumerate for hosts.',
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
},
'ADSpath' : {
'Description' : 'The LDAP source to search through.',
'Required' : False,
'Value' : ''
},
'FullData' : {
'Description' : 'Switch. Return full OU objects instead of just object names (the default).',
'Required' : False,
'Value' : ''
}
@ -87,8 +80,10 @@ class Module:
def generate(self):
# read in the common module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/Invoke-Netview.ps1"
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
@ -99,9 +94,10 @@ class Module:
moduleCode = f.read()
f.close()
script = moduleCode
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += "Invoke-NetView "
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
@ -111,7 +107,7 @@ class Module:
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += '| Out-String | %{$_ + \"`n\"};"`nInvoke-Netview completed"'
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -0,0 +1,113 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Get-NetUser',
'Author': ['@harmj0y'],
'Description': ('Query information for a given user or users in the specified domain. Part of PowerView.'),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : True,
'MinPSVersion' : '2',
'Comments': [
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'UserName' : {
'Description' : 'Username filter string, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
},
'ADSpath' : {
'Description' : 'The LDAP source to search through, e.g. "LDAP://OU=secret,DC=testlab,DC=local"',
'Required' : False,
'Value' : ''
},
'Filter' : {
'Description' : 'A customized ldap filter string to use, e.g. "(description=*admin*)"',
'Required' : False,
'Value' : ''
},
'SPN' : {
'Description' : 'Switch. Only return user objects with non-null service principal names.',
'Required' : False,
'Value' : ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -5,12 +5,11 @@ class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Get-ExploitableSystems',
'Name': 'Invoke-MapDomainTrust',
'Author': ['Scott Sutherland (@_nullbind)'],
'Author': ['@harmj0y'],
'Description': ('Queries Active Directory for systems likely vulnerable to various '
'Metasploit exploits.'),
'Description': ('Maps all reachable domain trusts with .CSV output. Part of PowerView.'),
'Background' : True,
@ -23,7 +22,7 @@ class Module:
'MinPSVersion' : '2',
'Comments': [
'https://github.com/nullbind/Powershellery/blob/master/Stable-ish/ADS/Get-ExploitableSystems.psm1'
'https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerView'
]
}
@ -36,13 +35,13 @@ class Module:
'Required' : True,
'Value' : ''
},
'DomainController' : {
'Description' : 'Specific domain controller to query against.',
'LDAP' : {
'Description' : 'Switch. Use LDAP for domain queries (less accurate).',
'Required' : False,
'Value' : ''
},
'SearchDN' : {
'Description' : 'Distinguished Name Path to limit search to.',
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
}
@ -51,7 +50,7 @@ class Module:
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
@ -60,9 +59,11 @@ class Module:
def generate(self):
# read in the common module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/Get-ExploitableSystems.psm1"
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
@ -73,9 +74,10 @@ class Module:
moduleCode = f.read()
f.close()
script = moduleCode
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += "Get-ExploitableSystems "
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
@ -84,8 +86,8 @@ class Module:
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += " -" + str(option) + " " + str(values['Value'])
script += " | ft -autosize | Out-String | %{$_ + \"`n\"}"
script += '| ConvertTo-Csv -NoTypeInformation | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -5,13 +5,11 @@ class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Invoke-StealthUserHunter',
'Name': 'Invoke-ProcessHunter',
'Author': ['@harmj0y'],
'Description': ('Finds which machines users of a specified group are logged into by '
'querying AD for servers likely to have high traffic (file servers, DCs, etc.) '
'and enumerating sessions again each. Part of PowerView.'),
'Description': ('Query the process lists of remote machines, searching for processes with a specific name or owned by a specific user.'),
'Background' : True,
@ -37,13 +35,28 @@ class Module:
'Required' : True,
'Value' : ''
},
'Hosts' : {
'ComputerName' : {
'Description' : 'Hosts to enumerate.',
'Required' : False,
'Value' : ''
},
'HostList' : {
'Description' : 'Hostlist to enumerate.',
'ComputerFilter' : {
'Description' : 'Host filter name to query AD for, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'ProcessName' : {
'Description' : 'The name of the process to hunt, or a comma separated list of names.',
'Required' : False,
'Value' : ''
},
'GroupName' : {
'Description' : 'Group name to query for target users.',
'Required' : False,
'Value' : ''
},
'TargetServer' : {
'Description' : 'Hunt for users who are effective local admins on a target server.',
'Required' : False,
'Value' : ''
},
@ -52,28 +65,18 @@ class Module:
'Required' : False,
'Value' : ''
},
'GroupName' : {
'Description' : 'Group to query for user names.',
'Required' : False,
'Value' : ''
},
'UserList' : {
'Description' : 'List of usernames to search for.',
'UserFilter' : {
'Description' : 'A customized ldap filter string to use for user enumeration, e.g. "(description=*admin*)"',
'Required' : False,
'Value' : ''
},
'StopOnSuccess' : {
'Description' : 'Switch. Stop when a target user is found.',
'Required' : False,
'Value' : ''
},
'NoPing' : {
'Description' : 'Don\'t ping each host to ensure it\'s up before enumerating.',
'Description' : 'Switch. Stop hunting after finding after finding a target user.',
'Required' : False,
'Value' : ''
},
'CheckAccess' : {
'Description' : 'Switch. Check if the current user has local admin access to found machines.',
'NoPing' : {
'Description' : "Don't ping each host to ensure it's up before enumerating.",
'Required' : False,
'Value' : ''
},
@ -82,13 +85,18 @@ class Module:
'Required' : False,
'Value' : ''
},
'ShowAll' : {
'Description' : 'Switch. Show all result output.',
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'Domain to enumerate for hosts.',
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
},
'Threads' : {
'Description' : 'The maximum concurrent threads to execute.',
'Required' : False,
'Value' : ''
}
@ -107,8 +115,10 @@ class Module:
def generate(self):
# read in the common module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/Invoke-UserHunter.ps1"
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
@ -119,9 +129,10 @@ class Module:
moduleCode = f.read()
f.close()
script = moduleCode
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += "Invoke-StealthUserHunter "
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
@ -131,9 +142,7 @@ class Module:
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
script += "| Select-Object TargetUser, Computer, IP, SessionFrom, LocalAdmin | ft -autosize | Out-String | %{$_ + \"`n\"}"
script += ';"`nInvoke-StealthUserHunter completed"'
return script

View File

@ -9,7 +9,7 @@ class Module:
'Author': ['@harmj0y'],
'Description': ('Finds shares on machines in the domain.'),
'Description': ('Finds shares on machines in the domain. Part of PowerView.'),
'Background' : True,
@ -35,38 +35,43 @@ class Module:
'Required' : True,
'Value' : ''
},
'Hosts' : {
'ComputerName' : {
'Description' : 'Hosts to enumerate.',
'Required' : False,
'Value' : ''
},
'HostList' : {
'Description' : 'Hostlist to enumerate.',
'Required' : False,
'Value' : ''
},
'HostFilter' : {
'ComputerFilter' : {
'Description' : 'Host filter name to query AD for, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'NoPing' : {
'Description' : 'Don\'t ping each host to ensure it\'s up before enumerating.',
'Required' : False,
'Value' : ''
},
'CheckShareAccess' : {
'Description' : 'Switch. Only display found shares that the local user has access to.',
'Required' : False,
'Value' : ''
},
'NoPing' : {
'Description' : "Don't ping each host to ensure it's up before enumerating.",
'Required' : False,
'Value' : ''
},
'Delay' : {
'Description' : 'Delay between enumerating hosts, defaults to 0.',
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'Domain to enumerate for hosts.',
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
},
'Threads' : {
'Description' : 'The maximum concurrent threads to execute.',
'Required' : False,
'Value' : ''
}
@ -85,8 +90,10 @@ class Module:
def generate(self):
# read in the common module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/Invoke-ShareFinder.ps1"
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
@ -97,9 +104,10 @@ class Module:
moduleCode = f.read()
f.close()
script = moduleCode
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += "Invoke-ShareFinder "
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
@ -109,7 +117,7 @@ class Module:
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += '| Out-String | %{$_ + \"`n\"};"`nInvoke-ShareFinder completed"'
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
return script

View File

@ -36,18 +36,23 @@ class Module:
'Required' : True,
'Value' : ''
},
'Hosts' : {
'ComputerName' : {
'Description' : 'Hosts to enumerate.',
'Required' : False,
'Value' : ''
},
'HostList' : {
'Description' : 'Hostlist to enumerate.',
'ComputerFilter' : {
'Description' : 'Host filter name to query AD for, wildcards accepted.',
'Required' : False,
'Value' : ''
},
'HostFilter' : {
'Description' : 'Host filter name to query AD for, wildcards accepted.',
'GroupName' : {
'Description' : 'Group name to query for target users.',
'Required' : False,
'Value' : ''
},
'TargetServer' : {
'Description' : 'Hunt for users who are effective local admins on a target server.',
'Required' : False,
'Value' : ''
},
@ -56,23 +61,18 @@ class Module:
'Required' : False,
'Value' : ''
},
'GroupName' : {
'Description' : 'Group to query for user names.',
'Required' : False,
'Value' : ''
},
'UserList' : {
'Description' : 'List of usernames to search for.',
'UserFilter' : {
'Description' : 'A customized ldap filter string to use for user enumeration, e.g. "(description=*admin*)"',
'Required' : False,
'Value' : ''
},
'StopOnSuccess' : {
'Description' : 'Switch. Stop when a target user is found.',
'Description' : 'Switch. Stop hunting after finding after finding a target user.',
'Required' : False,
'Value' : ''
},
},
'NoPing' : {
'Description' : 'Don\'t ping each host to ensure it\'s up before enumerating.',
'Description' : "Don't ping each host to ensure it's up before enumerating.",
'Required' : False,
'Value' : ''
},
@ -86,13 +86,28 @@ class Module:
'Required' : False,
'Value' : ''
},
'ShowAll' : {
'Description' : 'Switch. Show all result output.',
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'Domain to enumerate for hosts.',
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
'Value' : ''
},
'DomainController' : {
'Description' : 'Domain controller to reflect LDAP queries through.',
'Required' : False,
'Value' : ''
},
'ShowAll' : {
'Description' : 'Switch. Return all user location results without filtering.',
'Required' : False,
'Value' : ''
},
'Stealth' : {
'Description' : 'Switch. Only enumerate sessions from connonly used target servers.',
'Required' : False,
'Value' : ''
},
'Threads' : {
'Description' : 'The maximum concurrent threads to execute.',
'Required' : False,
'Value' : ''
}
@ -111,8 +126,10 @@ class Module:
def generate(self):
# read in the common module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/Invoke-UserHunter.ps1"
moduleName = self.info["Name"]
# read in the common powerview.ps1 module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/situational_awareness/network/powerview.ps1"
try:
f = open(moduleSource, 'r')
@ -123,9 +140,10 @@ class Module:
moduleCode = f.read()
f.close()
script = moduleCode
# get just the code needed for the specified function
script = helpers.generate_dynamic_powershell_script(moduleCode, moduleName)
script += "Invoke-UserHunter "
script += moduleName + " "
for option,values in self.options.iteritems():
if option.lower() != "agent":
@ -135,9 +153,7 @@ class Module:
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
script += ' | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
script += "| Select-Object TargetUser, Computer, IP, SessionFrom, LocalAdmin | ft -autosize | Out-String | %{$_ + \"`n\"}"
script += ';"`nInvoke-UserHunter completed"'
return script