· 7 years ago · Oct 31, 2018, 02:50 PM
1#requires -version 2
2function New-InMemoryModule
3{
4 Param
5 (
6 [Parameter(Position = 0)]
7 [ValidateNotNullOrEmpty()]
8 [String]
9 $ModuleName = [Guid]::NewGuid().ToString()
10 )
11
12 $LoadedAssemblies = [AppDomain]::CurrentDomain.GetAssemblies()
13
14 ForEach ($Assembly in $LoadedAssemblies) {
15 if ($Assembly.FullName -and ($Assembly.FullName.Split(',')[0] -eq $ModuleName)) {
16 return $Assembly
17 }
18 }
19
20 $DynAssembly = New-Object Reflection.AssemblyName($ModuleName)
21 $Domain = [AppDomain]::CurrentDomain
22 $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, 'Run')
23 $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule($ModuleName, $False)
24
25 return $ModuleBuilder
26}
27
28function func
29{
30 Param
31 (
32 [Parameter(Position = 0, Mandatory = $True)]
33 [String]
34 $DllName,
35
36 [Parameter(Position = 1, Mandatory = $True)]
37 [String]
38 $FunctionName,
39
40 [Parameter(Position = 2, Mandatory = $True)]
41 [Type]
42 $ReturnType,
43
44 [Parameter(Position = 3)]
45 [Type[]]
46 $ParameterTypes,
47
48 [Parameter(Position = 4)]
49 [Runtime.InteropServices.CallingConvention]
50 $NativeCallingConvention,
51
52 [Parameter(Position = 5)]
53 [Runtime.InteropServices.CharSet]
54 $Charset,
55
56 [Switch]
57 $SetLastError
58 )
59
60 $Properties = @{
61 DllName = $DllName
62 FunctionName = $FunctionName
63 ReturnType = $ReturnType
64 }
65
66 if ($ParameterTypes) { $Properties['ParameterTypes'] = $ParameterTypes }
67 if ($NativeCallingConvention) { $Properties['NativeCallingConvention'] = $NativeCallingConvention }
68 if ($Charset) { $Properties['Charset'] = $Charset }
69 if ($SetLastError) { $Properties['SetLastError'] = $SetLastError }
70
71 New-Object PSObject -Property $Properties
72}
73function Add-Win32Type
74{
75
76
77 [OutputType([Hashtable])]
78 Param(
79 [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
80 [String]
81 $DllName,
82
83 [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
84 [String]
85 $FunctionName,
86
87 [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
88 [Type]
89 $ReturnType,
90
91 [Parameter(ValueFromPipelineByPropertyName = $True)]
92 [Type[]]
93 $ParameterTypes,
94
95 [Parameter(ValueFromPipelineByPropertyName = $True)]
96 [Runtime.InteropServices.CallingConvention]
97 $NativeCallingConvention = [Runtime.InteropServices.CallingConvention]::StdCall,
98
99 [Parameter(ValueFromPipelineByPropertyName = $True)]
100 [Runtime.InteropServices.CharSet]
101 $Charset = [Runtime.InteropServices.CharSet]::Auto,
102
103 [Parameter(ValueFromPipelineByPropertyName = $True)]
104 [Switch]
105 $SetLastError,
106
107 [Parameter(Mandatory = $True)]
108 [ValidateScript({($_ -is [Reflection.Emit.ModuleBuilder]) -or ($_ -is [Reflection.Assembly])})]
109 $Module,
110
111 [ValidateNotNull()]
112 [String]
113 $Namespace = ''
114 )
115
116 BEGIN
117 {
118 $TypeHash = @{}
119 }
120
121 PROCESS
122 {
123 if ($Module -is [Reflection.Assembly])
124 {
125 if ($Namespace)
126 {
127 $TypeHash[$DllName] = $Module.GetType("$Namespace.$DllName")
128 }
129 else
130 {
131 $TypeHash[$DllName] = $Module.GetType($DllName)
132 }
133 }
134 else
135 {
136 # Define one type for each DLL
137 if (!$TypeHash.ContainsKey($DllName))
138 {
139 if ($Namespace)
140 {
141 $TypeHash[$DllName] = $Module.DefineType("$Namespace.$DllName", 'Public,BeforeFieldInit')
142 }
143 else
144 {
145 $TypeHash[$DllName] = $Module.DefineType($DllName, 'Public,BeforeFieldInit')
146 }
147 }
148
149 $Method = $TypeHash[$DllName].DefineMethod(
150 $FunctionName,
151 'Public,Static,PinvokeImpl',
152 $ReturnType,
153 $ParameterTypes)
154
155 # Make each ByRef parameter an Out parameter
156 $i = 1
157 ForEach($Parameter in $ParameterTypes)
158 {
159 if ($Parameter.IsByRef)
160 {
161 [void] $Method.DefineParameter($i, 'Out', $Null)
162 }
163
164 $i++
165 }
166
167 $DllImport = [Runtime.InteropServices.DllImportAttribute]
168 $SetLastErrorField = $DllImport.GetField('SetLastError')
169 $CallingConventionField = $DllImport.GetField('CallingConvention')
170 $CharsetField = $DllImport.GetField('CharSet')
171 if ($SetLastError) { $SLEValue = $True } else { $SLEValue = $False }
172
173 # Equivalent to C# version of [DllImport(DllName)]
174 $Constructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor([String])
175 $DllImportAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($Constructor,
176 $DllName, [Reflection.PropertyInfo[]] @(), [Object[]] @(),
177 [Reflection.FieldInfo[]] @($SetLastErrorField, $CallingConventionField, $CharsetField),
178 [Object[]] @($SLEValue, ([Runtime.InteropServices.CallingConvention] $NativeCallingConvention), ([Runtime.InteropServices.CharSet] $Charset)))
179
180 $Method.SetCustomAttribute($DllImportAttribute)
181 }
182 }
183
184 END
185 {
186 if ($Module -is [Reflection.Assembly])
187 {
188 return $TypeHash
189 }
190
191 $ReturnTypes = @{}
192
193 ForEach ($Key in $TypeHash.Keys)
194 {
195 $Type = $TypeHash[$Key].CreateType()
196
197 $ReturnTypes[$Key] = $Type
198 }
199
200 return $ReturnTypes
201 }
202}
203function psenum
204{
205 [OutputType([Type])]
206 Param
207 (
208 [Parameter(Position = 0, Mandatory = $True)]
209 [ValidateScript({($_ -is [Reflection.Emit.ModuleBuilder]) -or ($_ -is [Reflection.Assembly])})]
210 $Module,
211
212 [Parameter(Position = 1, Mandatory = $True)]
213 [ValidateNotNullOrEmpty()]
214 [String]
215 $FullName,
216
217 [Parameter(Position = 2, Mandatory = $True)]
218 [Type]
219 $Type,
220
221 [Parameter(Position = 3, Mandatory = $True)]
222 [ValidateNotNullOrEmpty()]
223 [Hashtable]
224 $EnumElements,
225
226 [Switch]
227 $Bitfield
228 )
229
230 if ($Module -is [Reflection.Assembly])
231 {
232 return ($Module.GetType($FullName))
233 }
234
235 $EnumType = $Type -as [Type]
236
237 $EnumBuilder = $Module.DefineEnum($FullName, 'Public', $EnumType)
238
239 if ($Bitfield)
240 {
241 $FlagsConstructor = [FlagsAttribute].GetConstructor(@())
242 $FlagsCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($FlagsConstructor, @())
243 $EnumBuilder.SetCustomAttribute($FlagsCustomAttribute)
244 }
245
246 ForEach ($Key in $EnumElements.Keys)
247 {
248 # Apply the specified enum type to each element
249 $Null = $EnumBuilder.DefineLiteral($Key, $EnumElements[$Key] -as $EnumType)
250 }
251
252 $EnumBuilder.CreateType()
253}
254
255function field
256{
257 Param
258 (
259 [Parameter(Position = 0, Mandatory = $True)]
260 [UInt16]
261 $Position,
262
263 [Parameter(Position = 1, Mandatory = $True)]
264 [Type]
265 $Type,
266
267 [Parameter(Position = 2)]
268 [UInt16]
269 $Offset,
270
271 [Object[]]
272 $MarshalAs
273 )
274
275 @{
276 Position = $Position
277 Type = $Type -as [Type]
278 Offset = $Offset
279 MarshalAs = $MarshalAs
280 }
281}
282
283function struct
284{
285
286
287 [OutputType([Type])]
288 Param
289 (
290 [Parameter(Position = 1, Mandatory = $True)]
291 [ValidateScript({($_ -is [Reflection.Emit.ModuleBuilder]) -or ($_ -is [Reflection.Assembly])})]
292 $Module,
293
294 [Parameter(Position = 2, Mandatory = $True)]
295 [ValidateNotNullOrEmpty()]
296 [String]
297 $FullName,
298
299 [Parameter(Position = 3, Mandatory = $True)]
300 [ValidateNotNullOrEmpty()]
301 [Hashtable]
302 $StructFields,
303
304 [Reflection.Emit.PackingSize]
305 $PackingSize = [Reflection.Emit.PackingSize]::Unspecified,
306
307 [Switch]
308 $ExplicitLayout
309 )
310
311 if ($Module -is [Reflection.Assembly])
312 {
313 return ($Module.GetType($FullName))
314 }
315
316 [Reflection.TypeAttributes] $StructAttributes = 'AnsiClass,
317 Class,
318 Public,
319 Sealed,
320 BeforeFieldInit'
321
322 if ($ExplicitLayout)
323 {
324 $StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::ExplicitLayout
325 }
326 else
327 {
328 $StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::SequentialLayout
329 }
330
331 $StructBuilder = $Module.DefineType($FullName, $StructAttributes, [ValueType], $PackingSize)
332 $ConstructorInfo = [Runtime.InteropServices.MarshalAsAttribute].GetConstructors()[0]
333 $SizeConst = @([Runtime.InteropServices.MarshalAsAttribute].GetField('SizeConst'))
334
335 $Fields = New-Object Hashtable[]($StructFields.Count)
336
337 # Sort each field according to the orders specified
338 # Unfortunately, PSv2 doesn't have the luxury of the
339 # hashtable [Ordered] accelerator.
340 ForEach ($Field in $StructFields.Keys)
341 {
342 $Index = $StructFields[$Field]['Position']
343 $Fields[$Index] = @{FieldName = $Field; Properties = $StructFields[$Field]}
344 }
345
346 ForEach ($Field in $Fields)
347 {
348 $FieldName = $Field['FieldName']
349 $FieldProp = $Field['Properties']
350
351 $Offset = $FieldProp['Offset']
352 $Type = $FieldProp['Type']
353 $MarshalAs = $FieldProp['MarshalAs']
354
355 $NewField = $StructBuilder.DefineField($FieldName, $Type, 'Public')
356
357 if ($MarshalAs)
358 {
359 $UnmanagedType = $MarshalAs[0] -as ([Runtime.InteropServices.UnmanagedType])
360 if ($MarshalAs[1])
361 {
362 $Size = $MarshalAs[1]
363 $AttribBuilder = New-Object Reflection.Emit.CustomAttributeBuilder($ConstructorInfo,
364 $UnmanagedType, $SizeConst, @($Size))
365 }
366 else
367 {
368 $AttribBuilder = New-Object Reflection.Emit.CustomAttributeBuilder($ConstructorInfo, [Object[]] @($UnmanagedType))
369 }
370
371 $NewField.SetCustomAttribute($AttribBuilder)
372 }
373
374 if ($ExplicitLayout) { $NewField.SetOffset($Offset) }
375 }
376
377 # Make the struct aware of its own size.
378 # No more having to call [Runtime.InteropServices.Marshal]::SizeOf!
379 $SizeMethod = $StructBuilder.DefineMethod('GetSize',
380 'Public, Static',
381 [Int],
382 [Type[]] @())
383 $ILGenerator = $SizeMethod.GetILGenerator()
384 # Thanks for the help, Jason Shirk!
385 $ILGenerator.Emit([Reflection.Emit.OpCodes]::Ldtoken, $StructBuilder)
386 $ILGenerator.Emit([Reflection.Emit.OpCodes]::Call,
387 [Type].GetMethod('GetTypeFromHandle'))
388 $ILGenerator.Emit([Reflection.Emit.OpCodes]::Call,
389 [Runtime.InteropServices.Marshal].GetMethod('SizeOf', [Type[]] @([Type])))
390 $ILGenerator.Emit([Reflection.Emit.OpCodes]::Ret)
391
392 # Allow for explicit casting from an IntPtr
393 # No more having to call [Runtime.InteropServices.Marshal]::PtrToStructure!
394 $ImplicitConverter = $StructBuilder.DefineMethod('op_Implicit',
395 'PrivateScope, Public, Static, HideBySig, SpecialName',
396 $StructBuilder,
397 [Type[]] @([IntPtr]))
398 $ILGenerator2 = $ImplicitConverter.GetILGenerator()
399 $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Nop)
400 $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Ldarg_0)
401 $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Ldtoken, $StructBuilder)
402 $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Call,
403 [Type].GetMethod('GetTypeFromHandle'))
404 $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Call,
405 [Runtime.InteropServices.Marshal].GetMethod('PtrToStructure', [Type[]] @([IntPtr], [Type])))
406 $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Unbox_Any, $StructBuilder)
407 $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Ret)
408
409 $StructBuilder.CreateType()
410}
411
412function Get-NameField {
413 # function that attempts to extract the appropriate field name
414 # from various passed objects. This is so functions can have
415 # multiple types of objects passed on the pipeline.
416 [CmdletBinding()]
417 param(
418 [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
419 $Object
420 )
421 process {
422 if($Object) {
423 if ( [bool]($Object.PSobject.Properties.name -match "dnshostname") ) {
424 # objects from Get-NetComputer
425 $Object.dnshostname
426 }
427 elseif ( [bool]($Object.PSobject.Properties.name -match "name") ) {
428 # objects from Get-NetDomainController
429 $Object.name
430 }
431 else {
432 # strings and catch alls
433 $Object
434 }
435 }
436 else {
437 return $Null
438 }
439 }
440}
441
442function Export-PViewCSV {
443
444 Param(
445 [Parameter(Mandatory=$True, ValueFromPipeline=$True,
446 ValueFromPipelineByPropertyName=$True)]
447 [System.Management.Automation.PSObject]
448 $InputObject,
449
450 [Parameter(Mandatory=$True, Position=0)]
451 [Alias('PSPath')]
452 [String]
453 $OutFile
454 )
455
456 process {
457
458 $ObjectCSV = $InputObject | ConvertTo-Csv -NoTypeInformation
459
460 # mutex so threaded code doesn't stomp on the output file
461 $Mutex = New-Object System.Threading.Mutex $False,'CSVMutex';
462 $Null = $Mutex.WaitOne()
463
464 if (Test-Path -Path $OutFile) {
465 # hack to skip the first line of output if the file already exists
466 $ObjectCSV | Foreach-Object {$Start=$True}{if ($Start) {$Start=$False} else {$_}} | Out-File -Encoding 'ASCII' -Append -FilePath $OutFile
467 }
468 else {
469 $ObjectCSV | Out-File -Encoding 'ASCII' -Append -FilePath $OutFile
470 }
471
472 $Mutex.ReleaseMutex()
473 }
474}
475function Get-DomainPolicy {
476
477 [CmdletBinding()]
478 Param (
479 [String]
480 [ValidateSet("Domain","DC")]
481 $Source ="Domain",
482
483 [String]
484 $Domain,
485
486 [String]
487 $DomainController,
488
489 [Switch]
490 $ResolveSids,
491
492 [Switch]
493 $UsePSDrive
494 )
495
496 if($Source -eq "Domain") {
497 # query the given domain for the default domain policy object
498 $GPO = Get-NetGPO -Domain $Domain -DomainController $DomainController -GPOname "{31B2F340-016D-11D2-945F-00C04FB984F9}"
499
500 if($GPO) {
501 # grab the GptTmpl.inf file and parse it
502 $GptTmplPath = $GPO.gpcfilesyspath + "\MACHINE\Microsoft\Windows NT\SecEdit\GptTmpl.inf"
503
504 $ParseArgs = @{
505 'GptTmplPath' = $GptTmplPath
506 'UsePSDrive' = $UsePSDrive
507 }
508
509 # parse the GptTmpl.inf
510 Get-GptTmpl @ParseArgs
511 }
512
513 }
514 elseif($Source -eq "DC") {
515 # query the given domain/dc for the default domain controller policy object
516 $GPO = Get-NetGPO -Domain $Domain -DomainController $DomainController -GPOname "{6AC1786C-016F-11D2-945F-00C04FB984F9}"
517
518 if($GPO) {
519 # grab the GptTmpl.inf file and parse it
520 $GptTmplPath = $GPO.gpcfilesyspath + "\MACHINE\Microsoft\Windows NT\SecEdit\GptTmpl.inf"
521
522 $ParseArgs = @{
523 'GptTmplPath' = $GptTmplPath
524 'UsePSDrive' = $UsePSDrive
525 }
526
527 # parse the GptTmpl.inf
528 Get-GptTmpl @ParseArgs | Foreach-Object {
529 if($ResolveSids) {
530 # if we're resolving sids in PrivilegeRights to names
531 $Policy = New-Object PSObject
532 $_.psobject.properties | Foreach-Object {
533 if( $_.Name -eq 'PrivilegeRights') {
534
535 $PrivilegeRights = New-Object PSObject
536 # for every nested SID member of PrivilegeRights, try to
537 # unpack everything and resolve the SIDs as appropriate
538 $_.Value.psobject.properties | Foreach-Object {
539
540 $Sids = $_.Value | Foreach-Object {
541 try {
542 if($_ -isnot [System.Array]) {
543 Convert-SidToName $_
544 }
545 else {
546 $_ | Foreach-Object { Convert-SidToName $_ }
547 }
548 }
549 catch {
550 Write-Debug "Error resolving SID : $_"
551 }
552 }
553
554 $PrivilegeRights | Add-Member Noteproperty $_.Name $Sids
555 }
556
557 $Policy | Add-Member Noteproperty 'PrivilegeRights' $PrivilegeRights
558 }
559 else {
560 $Policy | Add-Member Noteproperty $_.Name $_.Value
561 }
562 }
563 $Policy
564 }
565 else { $_ }
566 }
567 }
568 }
569}
570function Get-NetShare {
571
572 [CmdletBinding()]
573 param(
574 [Parameter(ValueFromPipeline=$True)]
575 [Alias('HostName')]
576 [String]
577 $ComputerName = 'localhost'
578 )
579
580 begin {
581 if ($PSBoundParameters['Debug']) {
582 $DebugPreference = 'Continue'
583 }
584 }
585
586 process {
587
588 # process multiple host object types from the pipeline
589 $ComputerName = Get-NameField -Object $ComputerName
590
591 # arguments for NetShareEnum
592 $QueryLevel = 1
593 $PtrInfo = [IntPtr]::Zero
594 $EntriesRead = 0
595 $TotalRead = 0
596 $ResumeHandle = 0
597
598 # get the share information
599 $Result = $Netapi32::NetShareEnum($ComputerName, $QueryLevel, [ref]$PtrInfo, -1, [ref]$EntriesRead, [ref]$TotalRead, [ref]$ResumeHandle)
600
601 # Locate the offset of the initial intPtr
602 $Offset = $PtrInfo.ToInt64()
603
604 Write-Debug "Get-NetShare result: $Result"
605
606 # 0 = success
607 if (($Result -eq 0) -and ($Offset -gt 0)) {
608
609 # Work out how mutch to increment the pointer by finding out the size of the structure
610 $Increment = $SHARE_INFO_1::GetSize()
611
612 # parse all the result structures
613 for ($i = 0; ($i -lt $EntriesRead); $i++) {
614 # create a new int ptr at the given offset and cast
615 # the pointer as our result structure
616 $NewIntPtr = New-Object System.Intptr -ArgumentList $Offset
617 $Info = $NewIntPtr -as $SHARE_INFO_1
618 # return all the sections of the structure
619 $Info | Select-Object *
620 $Offset = $NewIntPtr.ToInt64()
621 $Offset += $Increment
622 }
623
624 # free up the result buffer
625 $Null = $Netapi32::NetApiBufferFree($PtrInfo)
626 }
627 else
628 {
629 switch ($Result) {
630 (5) {Write-Debug 'The user does not have access to the requested information.'}
631 (124) {Write-Debug 'The value specified for the level parameter is not valid.'}
632 (87) {Write-Debug 'The specified parameter is not valid.'}
633 (234) {Write-Debug 'More entries are available. Specify a large enough buffer to receive all entries.'}
634 (8) {Write-Debug 'Insufficient memory is available.'}
635 (2312) {Write-Debug 'A session does not exist with the computer name.'}
636 (2351) {Write-Debug 'The computer name is not valid.'}
637 (2221) {Write-Debug 'Username not found.'}
638 (53) {Write-Debug 'Hostname could not be found'}
639 }
640 }
641 }
642}
643function Get-NetDomain {
644 [CmdletBinding()]
645 param(
646 [Parameter(ValueFromPipeline=$True)]
647 [String]
648 $Domain
649 )
650
651 process {
652 if($Domain) {
653 $DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain)
654 try {
655 [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
656 }
657 catch {
658 Write-Warning "The specified domain $Domain does not exist, could not be contacted, or there isn't an existing trust."
659 $Null
660 }
661 }
662 else {
663 [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
664 }
665 }
666}
667function Invoke-FileFinder {
668
669 [CmdletBinding()]
670 param(
671 [Parameter(Position=0,ValueFromPipeline=$True)]
672 [Alias('Hosts')]
673 [String[]]
674 $ComputerName,
675
676 [ValidateScript({Test-Path -Path $_ })]
677 [Alias('HostList')]
678 [String]
679 $ComputerFile,
680
681 [String]
682 $ComputerFilter,
683
684 [String]
685 $ComputerADSpath,
686
687 [ValidateScript({Test-Path -Path $_ })]
688 [String]
689 $ShareList,
690
691 [Switch]
692 $OfficeDocs,
693
694 [Switch]
695 $FreshEXEs,
696
697 [String[]]
698 $Terms,
699
700 [ValidateScript({Test-Path -Path $_ })]
701 [String]
702 $TermList,
703
704 [String]
705 $LastAccessTime,
706
707 [String]
708 $LastWriteTime,
709
710 [String]
711 $CreationTime,
712
713 [Switch]
714 $IncludeC,
715
716 [Switch]
717 $IncludeAdmin,
718
719 [Switch]
720 $ExcludeFolders,
721
722 [Switch]
723 $ExcludeHidden,
724
725 [Switch]
726 $CheckWriteAccess,
727
728 [String]
729 $OutFile,
730
731 [Switch]
732 $NoClobber,
733
734 [Switch]
735 $NoPing,
736
737 [UInt32]
738 $Delay = 0,
739
740 [Double]
741 $Jitter = .3,
742
743 [String]
744 $Domain,
745
746 [String]
747 $DomainController,
748
749 [Switch]
750 $SearchForest,
751
752 [Switch]
753 $SearchSYSVOL,
754
755 [ValidateRange(1,100)]
756 [Int]
757 $Threads,
758
759 [Switch]
760 $UsePSDrive,
761
762 [System.Management.Automation.PSCredential]
763 $Credential = [System.Management.Automation.PSCredential]::Empty
764 )
765
766 begin {
767 if ($PSBoundParameters['Debug']) {
768 $DebugPreference = 'Continue'
769 }
770
771 # random object for delay
772 $RandNo = New-Object System.Random
773
774 Write-Verbose "[*] Running Invoke-FileFinder with delay of $Delay"
775
776 $Shares = @()
777
778 # figure out the shares we want to ignore
779 [String[]] $ExcludedShares = @("C$", "ADMIN$")
780
781 # see if we're specifically including any of the normally excluded sets
782 if ($IncludeC) {
783 if ($IncludeAdmin) {
784 $ExcludedShares = @()
785 }
786 else {
787 $ExcludedShares = @("ADMIN$")
788 }
789 }
790
791 if ($IncludeAdmin) {
792 if ($IncludeC) {
793 $ExcludedShares = @()
794 }
795 else {
796 $ExcludedShares = @("C$")
797 }
798 }
799
800 # delete any existing output file if it already exists
801 if(!$NoClobber) {
802 if ($OutFile -and (Test-Path -Path $OutFile)) { Remove-Item -Path $OutFile }
803 }
804
805 # if there's a set of terms specified to search for
806 if ($TermList) {
807 ForEach ($Term in Get-Content -Path $TermList) {
808 if (($Term -ne $Null) -and ($Term.trim() -ne '')) {
809 $Terms += $Term
810 }
811 }
812 }
813
814 if($Domain) {
815 $TargetDomains = @($Domain)
816 }
817 elseif($SearchForest) {
818 # get ALL the domains in the forest to search
819 $TargetDomains = Get-NetForestDomain | ForEach-Object { $_.Name }
820 }
821 else {
822 # use the local domain
823 $TargetDomains = @( (Get-NetDomain).name )
824 }
825
826 # if we're hard-passed a set of shares
827 if($ShareList) {
828 ForEach ($Item in Get-Content -Path $ShareList) {
829 if (($Item -ne $Null) -and ($Item.trim() -ne '')) {
830 # exclude any "[tab]- commants", i.e. the output from Invoke-ShareFinder
831 $Share = $Item.Split("`t")[0]
832 $Shares += $Share
833 }
834 }
835 }
836 if($SearchSYSVOL) {
837 ForEach ($Domain in $TargetDomains) {
838 $DCSearchPath = "\\$Domain\SYSVOL\"
839 Write-Verbose "[*] Adding share search path $DCSearchPath"
840 $Shares += $DCSearchPath
841 }
842 if(!$Terms) {
843 # search for interesting scripts on SYSVOL
844 $Terms = @('.vbs', '.bat', '.ps1')
845 }
846 }
847 else {
848 # if we're using a host list, read the targets in and add them to the target list
849 if($ComputerFile) {
850 $ComputerName = Get-Content -Path $ComputerFile
851 }
852 else {
853 [array]$ComputerName = @()
854 ForEach ($Domain in $TargetDomains) {
855 Write-Verbose "[*] Querying domain $Domain for hosts"
856 $ComputerName += Get-NetComputer -Filter $ComputerFilter -ADSpath $ComputerADSpath -Domain $Domain -DomainController $DomainController
857 }
858 }
859
860 # remove any null target hosts, uniquify the list and shuffle it
861 $ComputerName = $ComputerName | Where-Object { $_ } | Sort-Object -Unique | Sort-Object { Get-Random }
862 if($($ComputerName.Count) -eq 0) {
863 throw "No hosts found!"
864 }
865 }
866
867 # script block that enumerates shares and files on a server
868 $HostEnumBlock = {
869 param($ComputerName, $Ping, $ExcludedShares, $Terms, $ExcludeFolders, $OfficeDocs, $ExcludeHidden, $FreshEXEs, $CheckWriteAccess, $OutFile, $UsePSDrive, $Credential)
870
871 Write-Verbose "ComputerName: $ComputerName"
872 Write-Verbose "ExcludedShares: $ExcludedShares"
873 $SearchShares = @()
874
875 if($ComputerName.StartsWith("\\")) {
876 # if a share is passed as the server
877 $SearchShares += $ComputerName
878 }
879 else {
880 # if we're enumerating the shares on the target server first
881 $Up = $True
882 if($Ping) {
883 $Up = Test-Connection -Count 1 -Quiet -ComputerName $ComputerName
884 }
885 if($Up) {
886 # get the shares for this host and display what we find
887 $Shares = Get-NetShare -ComputerName $ComputerName
888 ForEach ($Share in $Shares) {
889
890 $NetName = $Share.shi1_netname
891 $Path = '\\'+$ComputerName+'\'+$NetName
892
893 # make sure we get a real share name back
894 if (($NetName) -and ($NetName.trim() -ne '')) {
895
896 # skip this share if it's in the exclude list
897 if ($ExcludedShares -NotContains $NetName.ToUpper()) {
898 # check if the user has access to this path
899 try {
900 $Null = [IO.Directory]::GetFiles($Path)
901 $SearchShares += $Path
902 }
903 catch {
904 Write-Debug "[!] No access to $Path"
905 }
906 }
907 }
908 }
909 }
910 }
911
912 ForEach($Share in $SearchShares) {
913 $SearchArgs = @{
914 'Path' = $Share
915 'Terms' = $Terms
916 'OfficeDocs' = $OfficeDocs
917 'FreshEXEs' = $FreshEXEs
918 'LastAccessTime' = $LastAccessTime
919 'LastWriteTime' = $LastWriteTime
920 'CreationTime' = $CreationTime
921 'ExcludeFolders' = $ExcludeFolders
922 'ExcludeHidden' = $ExcludeHidden
923 'CheckWriteAccess' = $CheckWriteAccess
924 'OutFile' = $OutFile
925 'UsePSDrive' = $UsePSDrive
926 'Credential' = $Credential
927 }
928
929 Find-InterestingFile @SearchArgs
930 }
931 }
932 }
933
934 process {
935
936 if($Threads) {
937 Write-Verbose "Using threading with threads = $Threads"
938
939 # if we're using threading, kick off the script block with Invoke-ThreadedFunction
940 $ScriptParams = @{
941 'Ping' = $(-not $NoPing)
942 'ExcludedShares' = $ExcludedShares
943 'Terms' = $Terms
944 'ExcludeFolders' = $ExcludeFolders
945 'OfficeDocs' = $OfficeDocs
946 'ExcludeHidden' = $ExcludeHidden
947 'FreshEXEs' = $FreshEXEs
948 'CheckWriteAccess' = $CheckWriteAccess
949 'OutFile' = $OutFile
950 'UsePSDrive' = $UsePSDrive
951 'Credential' = $Credential
952 }
953
954 # kick off the threaded script block + arguments
955 if($Shares) {
956 # pass the shares as the hosts so the threaded function code doesn't have to be hacked up
957 Invoke-ThreadedFunction -ComputerName $Shares -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams
958 }
959 else {
960 Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams
961 }
962 }
963
964 else {
965 if($Shares){
966 $ComputerName = $Shares
967 }
968 elseif(-not $NoPing -and ($ComputerName.count -gt 1)) {
969 # ping all hosts in parallel
970 $Ping = {param($ComputerName) if(Test-Connection -ComputerName $ComputerName -Count 1 -Quiet -ErrorAction Stop){$ComputerName}}
971 $ComputerName = Invoke-ThreadedFunction -NoImports -ComputerName $ComputerName -ScriptBlock $Ping -Threads 100
972 }
973
974 Write-Verbose "[*] Total number of active hosts: $($ComputerName.count)"
975 $Counter = 0
976
977 $ComputerName | Where-Object {$_} | ForEach-Object {
978 Write-Verbose "Computer: $_"
979 $Counter = $Counter + 1
980
981 # sleep for our semi-randomized interval
982 Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay)
983
984 Write-Verbose "[*] Enumerating server $_ ($Counter of $($ComputerName.count))"
985
986 Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $_, $False, $ExcludedShares, $Terms, $ExcludeFolders, $OfficeDocs, $ExcludeHidden, $FreshEXEs, $CheckWriteAccess, $OutFile, $UsePSDrive, $Credential
987 }
988 }
989 }
990}
991
992function Invoke-ShareFinder {
993
994 [CmdletBinding()]
995 param(
996 [Parameter(Position=0,ValueFromPipeline=$True)]
997 [Alias('Hosts')]
998 [String[]]
999 $ComputerName,
1000
1001 [ValidateScript({Test-Path -Path $_ })]
1002 [Alias('HostList')]
1003 [String]
1004 $ComputerFile,
1005
1006 [String]
1007 $ComputerFilter,
1008
1009 [String]
1010 $ComputerADSpath,
1011
1012 [Switch]
1013 $ExcludeStandard,
1014
1015 [Switch]
1016 $ExcludePrint,
1017
1018 [Switch]
1019 $ExcludeIPC,
1020
1021 [Switch]
1022 $NoPing,
1023
1024 [Switch]
1025 $CheckShareAccess,
1026
1027 [Switch]
1028 $CheckAdmin,
1029
1030 [UInt32]
1031 $Delay = 0,
1032
1033 [Double]
1034 $Jitter = .3,
1035
1036 [String]
1037 $Domain,
1038
1039 [String]
1040 $DomainController,
1041
1042 [Switch]
1043 $SearchForest,
1044
1045 [ValidateRange(1,100)]
1046 [Int]
1047 $Threads
1048 )
1049
1050 begin {
1051 if ($PSBoundParameters['Debug']) {
1052 $DebugPreference = 'Continue'
1053 }
1054
1055 # random object for delay
1056 $RandNo = New-Object System.Random
1057
1058 Write-Verbose "[*] Running Invoke-ShareFinder with delay of $Delay"
1059
1060 # figure out the shares we want to ignore
1061 [String[]] $ExcludedShares = @('')
1062
1063 if ($ExcludePrint) {
1064 $ExcludedShares = $ExcludedShares + "PRINT$"
1065 }
1066 if ($ExcludeIPC) {
1067 $ExcludedShares = $ExcludedShares + "IPC$"
1068 }
1069 if ($ExcludeStandard) {
1070 $ExcludedShares = @('', "ADMIN$", "IPC$", "C$", "PRINT$")
1071 }
1072
1073 if(!$ComputerName) {
1074
1075 if($Domain) {
1076 $TargetDomains = @($Domain)
1077 }
1078 elseif($SearchForest) {
1079 # get ALL the domains in the forest to search
1080 $TargetDomains = Get-NetForestDomain | ForEach-Object { $_.Name }
1081 }
1082 else {
1083 # use the local domain
1084 $TargetDomains = @( (Get-NetDomain).name )
1085 }
1086
1087 # if we're using a host file list, read the targets in and add them to the target list
1088 if($ComputerFile) {
1089 $ComputerName = Get-Content -Path $ComputerFile
1090 }
1091 else {
1092 [array]$ComputerName = @()
1093 ForEach ($Domain in $TargetDomains) {
1094 Write-Verbose "[*] Querying domain $Domain for hosts"
1095 $ComputerName += Get-NetComputer -Domain $Domain -DomainController $DomainController -Filter $ComputerFilter -ADSpath $ComputerADSpath
1096 }
1097 }
1098
1099 # remove any null target hosts, uniquify the list and shuffle it
1100 $ComputerName = $ComputerName | Where-Object { $_ } | Sort-Object -Unique | Sort-Object { Get-Random }
1101 if($($ComputerName.count) -eq 0) {
1102 throw "No hosts found!"
1103 }
1104 }
1105
1106 # script block that enumerates a server
1107 $HostEnumBlock = {
1108 param($ComputerName, $Ping, $CheckShareAccess, $ExcludedShares, $CheckAdmin)
1109
1110 # optionally check if the server is up first
1111 $Up = $True
1112 if($Ping) {
1113 $Up = Test-Connection -Count 1 -Quiet -ComputerName $ComputerName
1114 }
1115 if($Up) {
1116 # get the shares for this host and check what we find
1117 $Shares = Get-NetShare -ComputerName $ComputerName
1118 ForEach ($Share in $Shares) {
1119 Write-Debug "[*] Server share: $Share"
1120 $NetName = $Share.shi1_netname
1121 $Remark = $Share.shi1_remark
1122 $Path = '\\'+$ComputerName+'\'+$NetName
1123
1124 # make sure we get a real share name back
1125 if (($NetName) -and ($NetName.trim() -ne '')) {
1126 # if we're just checking for access to ADMIN$
1127 if($CheckAdmin) {
1128 if($NetName.ToUpper() -eq "ADMIN$") {
1129 try {
1130 $Null = [IO.Directory]::GetFiles($Path)
1131 "\\$ComputerName\$NetName `t- $Remark"
1132 }
1133 catch {
1134 Write-Debug "Error accessing path $Path : $_"
1135 }
1136 }
1137 }
1138 # skip this share if it's in the exclude list
1139 elseif ($ExcludedShares -NotContains $NetName.ToUpper()) {
1140 # see if we want to check access to this share
1141 if($CheckShareAccess) {
1142 # check if the user has access to this path
1143 try {
1144 $Null = [IO.Directory]::GetFiles($Path)
1145 "\\$ComputerName\$NetName `t- $Remark"
1146 }
1147 catch {
1148 Write-Debug "Error accessing path $Path : $_"
1149 }
1150 }
1151 else {
1152 "\\$ComputerName\$NetName `t- $Remark"
1153 }
1154 }
1155 }
1156 }
1157 }
1158 }
1159
1160 }
1161
1162 process {
1163
1164 if($Threads) {
1165 Write-Verbose "Using threading with threads = $Threads"
1166
1167 # if we're using threading, kick off the script block with Invoke-ThreadedFunction
1168 $ScriptParams = @{
1169 'Ping' = $(-not $NoPing)
1170 'CheckShareAccess' = $CheckShareAccess
1171 'ExcludedShares' = $ExcludedShares
1172 'CheckAdmin' = $CheckAdmin
1173 }
1174
1175 # kick off the threaded script block + arguments
1176 Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams
1177 }
1178
1179 else {
1180 if(-not $NoPing -and ($ComputerName.count -ne 1)) {
1181 # ping all hosts in parallel
1182 $Ping = {param($ComputerName) if(Test-Connection -ComputerName $ComputerName -Count 1 -Quiet -ErrorAction Stop){$ComputerName}}
1183 $ComputerName = Invoke-ThreadedFunction -NoImports -ComputerName $ComputerName -ScriptBlock $Ping -Threads 100
1184 }
1185
1186 Write-Verbose "[*] Total number of active hosts: $($ComputerName.count)"
1187 $Counter = 0
1188
1189 ForEach ($Computer in $ComputerName) {
1190
1191 $Counter = $Counter + 1
1192
1193 # sleep for our semi-randomized interval
1194 Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay)
1195
1196 Write-Verbose "[*] Enumerating server $Computer ($Counter of $($ComputerName.count))"
1197 Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $Computer, $False, $CheckShareAccess, $ExcludedShares, $CheckAdmin
1198 }
1199 }
1200
1201 }
1202}
1203
1204function Get-ExploitableSystem {
1205 [CmdletBinding()]
1206 Param(
1207 [Parameter(ValueFromPipeline=$True)]
1208 [Alias('HostName')]
1209 [String]
1210 $ComputerName = '*',
1211
1212 [String]
1213 $SPN,
1214
1215 [String]
1216 $OperatingSystem = '*',
1217
1218 [String]
1219 $ServicePack = '*',
1220
1221 [String]
1222 $Filter,
1223
1224 [Switch]
1225 $Ping,
1226
1227 [String]
1228 $Domain,
1229
1230 [String]
1231 $DomainController,
1232
1233 [String]
1234 $ADSpath,
1235
1236 [Switch]
1237 $Unconstrained,
1238
1239 [ValidateRange(1,10000)]
1240 [Int]
1241 $PageSize = 200
1242 )
1243
1244 Write-Verbose "[*] Grabbing computer accounts from Active Directory..."
1245
1246 # Create data table for hostnames, os, and service packs from LDAP
1247 $TableAdsComputers = New-Object System.Data.DataTable
1248 $Null = $TableAdsComputers.Columns.Add('Hostname')
1249 $Null = $TableAdsComputers.Columns.Add('OperatingSystem')
1250 $Null = $TableAdsComputers.Columns.Add('ServicePack')
1251 $Null = $TableAdsComputers.Columns.Add('LastLogon')
1252
1253 Get-NetComputer -FullData @PSBoundParameters | ForEach-Object {
1254
1255 $CurrentHost = $_.dnshostname
1256 $CurrentOs = $_.operatingsystem
1257 $CurrentSp = $_.operatingsystemservicepack
1258 $CurrentLast = $_.lastlogon
1259 $CurrentUac = $_.useraccountcontrol
1260
1261 $CurrentUacBin = [convert]::ToString($_.useraccountcontrol,2)
1262
1263 # Check the 2nd to last value to determine if its disabled
1264 $DisableOffset = $CurrentUacBin.Length - 2
1265 $CurrentDisabled = $CurrentUacBin.Substring($DisableOffset,1)
1266
1267 # Add computer to list if it's enabled
1268 if ($CurrentDisabled -eq 0) {
1269 # Add domain computer to data table
1270 $Null = $TableAdsComputers.Rows.Add($CurrentHost,$CurrentOS,$CurrentSP,$CurrentLast)
1271 }
1272 }
1273
1274 # Status user
1275 Write-Verbose "[*] Loading exploit list for critical missing patches..."
1276
1277 # ----------------------------------------------------------------
1278 # Setup data table for list of msf exploits
1279 # ----------------------------------------------------------------
1280
1281 # Create data table for list of patches levels with a MSF exploit
1282 $TableExploits = New-Object System.Data.DataTable
1283 $Null = $TableExploits.Columns.Add('OperatingSystem')
1284 $Null = $TableExploits.Columns.Add('ServicePack')
1285 $Null = $TableExploits.Columns.Add('MsfModule')
1286 $Null = $TableExploits.Columns.Add('CVE')
1287
1288 # Add exploits to data table
1289 $Null = $TableExploits.Rows.Add("Windows 7","","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1290 $Null = $TableExploits.Rows.Add("Windows Server 2000","Server Pack 1","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1291 $Null = $TableExploits.Rows.Add("Windows Server 2000","Server Pack 1","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059")
1292 $Null = $TableExploits.Rows.Add("Windows Server 2000","Server Pack 1","exploit/windows/iis/ms03_007_ntdll_webdav","http://www.cvedetails.com/cve/2003-0109")
1293 $Null = $TableExploits.Rows.Add("Windows Server 2000","Server Pack 1","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/")
1294 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 2","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1295 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 2","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059")
1296 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 2","exploit/windows/iis/ms03_007_ntdll_webdav","http://www.cvedetails.com/cve/2003-0109")
1297 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 2","exploit/windows/smb/ms04_011_lsass","http://www.cvedetails.com/cve/2003-0533/")
1298 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 2","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/")
1299 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 3","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1300 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 3","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059")
1301 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 3","exploit/windows/iis/ms03_007_ntdll_webdav","http://www.cvedetails.com/cve/2003-0109")
1302 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 3","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/")
1303 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1304 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059")
1305 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/dcerpc/ms07_029_msdns_zonename","http://www.cvedetails.com/cve/2007-1748")
1306 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/smb/ms04_011_lsass","http://www.cvedetails.com/cve/2003-0533/")
1307 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439")
1308 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/smb/ms06_066_nwapi","http://www.cvedetails.com/cve/2006-4688")
1309 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/smb/ms06_070_wkssvc","http://www.cvedetails.com/cve/2006-4691")
1310 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1311 $Null = $TableExploits.Rows.Add("Windows Server 2000","Service Pack 4","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/")
1312 $Null = $TableExploits.Rows.Add("Windows Server 2000","","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1313 $Null = $TableExploits.Rows.Add("Windows Server 2000","","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059")
1314 $Null = $TableExploits.Rows.Add("Windows Server 2000","","exploit/windows/iis/ms03_007_ntdll_webdav","http://www.cvedetails.com/cve/2003-0109")
1315 $Null = $TableExploits.Rows.Add("Windows Server 2000","","exploit/windows/smb/ms05_039_pnp","http://www.cvedetails.com/cve/2005-1983")
1316 $Null = $TableExploits.Rows.Add("Windows Server 2000","","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/")
1317 $Null = $TableExploits.Rows.Add("Windows Server 2003","Server Pack 1","exploit/windows/dcerpc/ms07_029_msdns_zonename","http://www.cvedetails.com/cve/2007-1748")
1318 $Null = $TableExploits.Rows.Add("Windows Server 2003","Server Pack 1","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439")
1319 $Null = $TableExploits.Rows.Add("Windows Server 2003","Server Pack 1","exploit/windows/smb/ms06_066_nwapi","http://www.cvedetails.com/cve/2006-4688")
1320 $Null = $TableExploits.Rows.Add("Windows Server 2003","Server Pack 1","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1321 $Null = $TableExploits.Rows.Add("Windows Server 2003","Server Pack 1","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/")
1322 $Null = $TableExploits.Rows.Add("Windows Server 2003","Service Pack 2","exploit/windows/dcerpc/ms07_029_msdns_zonename","http://www.cvedetails.com/cve/2007-1748")
1323 $Null = $TableExploits.Rows.Add("Windows Server 2003","Service Pack 2","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1324 $Null = $TableExploits.Rows.Add("Windows Server 2003","Service Pack 2","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1325 $Null = $TableExploits.Rows.Add("Windows Server 2003","","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1326 $Null = $TableExploits.Rows.Add("Windows Server 2003","","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439")
1327 $Null = $TableExploits.Rows.Add("Windows Server 2003","","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1328 $Null = $TableExploits.Rows.Add("Windows Server 2003","","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/")
1329 $Null = $TableExploits.Rows.Add("Windows Server 2003 R2","","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1330 $Null = $TableExploits.Rows.Add("Windows Server 2003 R2","","exploit/windows/smb/ms04_011_lsass","http://www.cvedetails.com/cve/2003-0533/")
1331 $Null = $TableExploits.Rows.Add("Windows Server 2003 R2","","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439")
1332 $Null = $TableExploits.Rows.Add("Windows Server 2003 R2","","exploit/windows/wins/ms04_045_wins","http://www.cvedetails.com/cve/2004-1080/")
1333 $Null = $TableExploits.Rows.Add("Windows Server 2008","Service Pack 2","exploit/windows/smb/ms09_050_smb2_negotiate_func_index","http://www.cvedetails.com/cve/2009-3103")
1334 $Null = $TableExploits.Rows.Add("Windows Server 2008","Service Pack 2","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1335 $Null = $TableExploits.Rows.Add("Windows Server 2008","","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1336 $Null = $TableExploits.Rows.Add("Windows Server 2008","","exploit/windows/smb/ms09_050_smb2_negotiate_func_index","http://www.cvedetails.com/cve/2009-3103")
1337 $Null = $TableExploits.Rows.Add("Windows Server 2008","","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1338 $Null = $TableExploits.Rows.Add("Windows Server 2008 R2","","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1339 $Null = $TableExploits.Rows.Add("Windows Vista","Server Pack 1","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1340 $Null = $TableExploits.Rows.Add("Windows Vista","Server Pack 1","exploit/windows/smb/ms09_050_smb2_negotiate_func_index","http://www.cvedetails.com/cve/2009-3103")
1341 $Null = $TableExploits.Rows.Add("Windows Vista","Server Pack 1","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1342 $Null = $TableExploits.Rows.Add("Windows Vista","Service Pack 2","exploit/windows/smb/ms09_050_smb2_negotiate_func_index","http://www.cvedetails.com/cve/2009-3103")
1343 $Null = $TableExploits.Rows.Add("Windows Vista","Service Pack 2","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1344 $Null = $TableExploits.Rows.Add("Windows Vista","","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1345 $Null = $TableExploits.Rows.Add("Windows Vista","","exploit/windows/smb/ms09_050_smb2_negotiate_func_index","http://www.cvedetails.com/cve/2009-3103")
1346 $Null = $TableExploits.Rows.Add("Windows XP","Server Pack 1","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1347 $Null = $TableExploits.Rows.Add("Windows XP","Server Pack 1","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059")
1348 $Null = $TableExploits.Rows.Add("Windows XP","Server Pack 1","exploit/windows/smb/ms04_011_lsass","http://www.cvedetails.com/cve/2003-0533/")
1349 $Null = $TableExploits.Rows.Add("Windows XP","Server Pack 1","exploit/windows/smb/ms05_039_pnp","http://www.cvedetails.com/cve/2005-1983")
1350 $Null = $TableExploits.Rows.Add("Windows XP","Server Pack 1","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439")
1351 $Null = $TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059")
1352 $Null = $TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439")
1353 $Null = $TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/smb/ms06_066_nwapi","http://www.cvedetails.com/cve/2006-4688")
1354 $Null = $TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/smb/ms06_070_wkssvc","http://www.cvedetails.com/cve/2006-4691")
1355 $Null = $TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1356 $Null = $TableExploits.Rows.Add("Windows XP","Service Pack 2","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1357 $Null = $TableExploits.Rows.Add("Windows XP","Service Pack 3","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1358 $Null = $TableExploits.Rows.Add("Windows XP","Service Pack 3","exploit/windows/smb/ms10_061_spoolss","http://www.cvedetails.com/cve/2010-2729")
1359 $Null = $TableExploits.Rows.Add("Windows XP","","exploit/windows/dcerpc/ms03_026_dcom","http://www.cvedetails.com/cve/2003-0352/")
1360 $Null = $TableExploits.Rows.Add("Windows XP","","exploit/windows/dcerpc/ms05_017_msmq","http://www.cvedetails.com/cve/2005-0059")
1361 $Null = $TableExploits.Rows.Add("Windows XP","","exploit/windows/smb/ms06_040_netapi","http://www.cvedetails.com/cve/2006-3439")
1362 $Null = $TableExploits.Rows.Add("Windows XP","","exploit/windows/smb/ms08_067_netapi","http://www.cvedetails.com/cve/2008-4250")
1363
1364 # Status user
1365 Write-Verbose "[*] Checking computers for vulnerable OS and SP levels..."
1366
1367 # ----------------------------------------------------------------
1368 # Setup data table to store vulnerable systems
1369 # ----------------------------------------------------------------
1370
1371 # Create data table to house vulnerable server list
1372 $TableVulnComputers = New-Object System.Data.DataTable
1373 $Null = $TableVulnComputers.Columns.Add('ComputerName')
1374 $Null = $TableVulnComputers.Columns.Add('OperatingSystem')
1375 $Null = $TableVulnComputers.Columns.Add('ServicePack')
1376 $Null = $TableVulnComputers.Columns.Add('LastLogon')
1377 $Null = $TableVulnComputers.Columns.Add('MsfModule')
1378 $Null = $TableVulnComputers.Columns.Add('CVE')
1379
1380 # Iterate through each exploit
1381 $TableExploits | ForEach-Object {
1382
1383 $ExploitOS = $_.OperatingSystem
1384 $ExploitSP = $_.ServicePack
1385 $ExploitMsf = $_.MsfModule
1386 $ExploitCVE = $_.CVE
1387
1388 # Iterate through each ADS computer
1389 $TableAdsComputers | ForEach-Object {
1390
1391 $AdsHostname = $_.Hostname
1392 $AdsOS = $_.OperatingSystem
1393 $AdsSP = $_.ServicePack
1394 $AdsLast = $_.LastLogon
1395
1396 # Add exploitable systems to vul computers data table
1397 if ($AdsOS -like "$ExploitOS*" -and $AdsSP -like "$ExploitSP" ) {
1398 # Add domain computer to data table
1399 $Null = $TableVulnComputers.Rows.Add($AdsHostname,$AdsOS,$AdsSP,$AdsLast,$ExploitMsf,$ExploitCVE)
1400 }
1401 }
1402 }
1403
1404 # Display results
1405 $VulnComputer = $TableVulnComputers | Select-Object ComputerName -Unique | Measure-Object
1406 $VulnComputerCount = $VulnComputer.Count
1407 if ($VulnComputer.Count -gt 0) {
1408 # Return vulnerable server list order with some hack date casting
1409 Write-Verbose "[+] Found $VulnComputerCount potentially vulnerable systems!"
1410 $TableVulnComputers | Sort-Object { $_.lastlogon -as [datetime]} -Descending
1411 }
1412 else {
1413 Write-Verbose "[-] No vulnerable systems were found."
1414 }
1415}
1416
1417function Get-NetFileServer {
1418
1419
1420 [CmdletBinding()]
1421 param(
1422 [String]
1423 $Domain,
1424
1425 [String]
1426 $DomainController,
1427
1428 [String[]]
1429 $TargetUsers,
1430
1431 [ValidateRange(1,10000)]
1432 [Int]
1433 $PageSize = 200
1434 )
1435
1436 function SplitPath {
1437 # short internal helper to split UNC server paths
1438 param([String]$Path)
1439
1440 if ($Path -and ($Path.split("\\").Count -ge 3)) {
1441 $Temp = $Path.split("\\")[2]
1442 if($Temp -and ($Temp -ne '')) {
1443 $Temp
1444 }
1445 }
1446 }
1447
1448 Get-NetUser -Domain $Domain -DomainController $DomainController -PageSize $PageSize | Where-Object {$_} | Where-Object {
1449 # filter for any target users
1450 if($TargetUsers) {
1451 $TargetUsers -Match $_.samAccountName
1452 }
1453 else { $True }
1454 } | Foreach-Object {
1455 # split out every potential file server path
1456 if($_.homedirectory) {
1457 SplitPath($_.homedirectory)
1458 }
1459 if($_.scriptpath) {
1460 SplitPath($_.scriptpath)
1461 }
1462 if($_.profilepath) {
1463 SplitPath($_.profilepath)
1464 }
1465
1466 } | Where-Object {$_} | Sort-Object -Unique
1467}
1468
1469function Get-NetUser {
1470
1471
1472 [CmdletBinding()]
1473 param(
1474 [Parameter(ValueFromPipeline=$True)]
1475 [String]
1476 $UserName,
1477
1478 [String]
1479 $Domain,
1480
1481 [String]
1482 $DomainController,
1483
1484 [String]
1485 $ADSpath,
1486
1487 [String]
1488 $Filter,
1489
1490 [Switch]
1491 $SPN,
1492
1493 [Switch]
1494 $AdminCount,
1495
1496 [Switch]
1497 $Unconstrained,
1498
1499 [Switch]
1500 $AllowDelegation,
1501
1502 [ValidateRange(1,10000)]
1503 [Int]
1504 $PageSize = 200
1505 )
1506
1507 begin {
1508 # so this isn't repeated if users are passed on the pipeline
1509 $UserSearcher = Get-DomainSearcher -Domain $Domain -ADSpath $ADSpath -DomainController $DomainController -PageSize $PageSize
1510 }
1511
1512 process {
1513 if($UserSearcher) {
1514
1515 # if we're checking for unconstrained delegation
1516 if($Unconstrained) {
1517 Write-Verbose "Checking for unconstrained delegation"
1518 $Filter += "(userAccountControl:1.2.840.113556.1.4.803:=524288)"
1519 }
1520 if($AllowDelegation) {
1521 Write-Verbose "Checking for users who can be delegated"
1522 # negation of "Accounts that are sensitive and not trusted for delegation"
1523 $Filter += "(!(userAccountControl:1.2.840.113556.1.4.803:=1048574))"
1524 }
1525 if($AdminCount) {
1526 Write-Verbose "Checking for adminCount=1"
1527 $Filter += "(admincount=1)"
1528 }
1529
1530 # check if we're using a username filter or not
1531 if($UserName) {
1532 # samAccountType=805306368 indicates user objects
1533 $UserSearcher.filter="(&(samAccountType=805306368)(samAccountName=$UserName)$Filter)"
1534 }
1535 elseif($SPN) {
1536 $UserSearcher.filter="(&(samAccountType=805306368)(servicePrincipalName=*)$Filter)"
1537 }
1538 else {
1539 # filter is something like "(samAccountName=*blah*)" if specified
1540 $UserSearcher.filter="(&(samAccountType=805306368)$Filter)"
1541 }
1542
1543 $UserSearcher.FindAll() | Where-Object {$_} | ForEach-Object {
1544 # convert/process the LDAP fields for each result
1545 Convert-LDAPProperty -Properties $_.Properties
1546 }
1547 }
1548 }
1549}
1550
1551function Get-NetComputer {
1552
1553
1554 [CmdletBinding()]
1555 Param (
1556 [Parameter(ValueFromPipeline=$True)]
1557 [Alias('HostName')]
1558 [String]
1559 $ComputerName = '*',
1560
1561 [String]
1562 $SPN,
1563
1564 [String]
1565 $OperatingSystem,
1566
1567 [String]
1568 $ServicePack,
1569
1570 [String]
1571 $Filter,
1572
1573 [Switch]
1574 $Printers,
1575
1576 [Switch]
1577 $Ping,
1578
1579 [Switch]
1580 $FullData,
1581
1582 [String]
1583 $Domain,
1584
1585 [String]
1586 $DomainController,
1587
1588 [String]
1589 $ADSpath,
1590
1591 [Switch]
1592 $Unconstrained,
1593
1594 [ValidateRange(1,10000)]
1595 [Int]
1596 $PageSize = 200
1597 )
1598
1599 begin {
1600 # so this isn't repeated if users are passed on the pipeline
1601 $CompSearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -ADSpath $ADSpath -PageSize $PageSize
1602 }
1603
1604 process {
1605
1606 if ($CompSearcher) {
1607
1608 # if we're checking for unconstrained delegation
1609 if($Unconstrained) {
1610 Write-Verbose "Searching for computers with for unconstrained delegation"
1611 $Filter += "(userAccountControl:1.2.840.113556.1.4.803:=524288)"
1612 }
1613 # set the filters for the seracher if it exists
1614 if($Printers) {
1615 Write-Verbose "Searching for printers"
1616 # $CompSearcher.filter="(&(objectCategory=printQueue)$Filter)"
1617 $Filter += "(objectCategory=printQueue)"
1618 }
1619 if($SPN) {
1620 Write-Verbose "Searching for computers with SPN: $SPN"
1621 $Filter += "(servicePrincipalName=$SPN)"
1622 }
1623 if($OperatingSystem) {
1624 $Filter += "(operatingsystem=$OperatingSystem)"
1625 }
1626 if($ServicePack) {
1627 $Filter += "(operatingsystemservicepack=$ServicePack)"
1628 }
1629
1630 $CompSearcher.filter = "(&(sAMAccountType=805306369)(dnshostname=$ComputerName)$Filter)"
1631
1632 try {
1633
1634 $CompSearcher.FindAll() | Where-Object {$_} | ForEach-Object {
1635 $Up = $True
1636 if($Ping) {
1637 # TODO: how can these results be piped to ping for a speedup?
1638 $Up = Test-Connection -Count 1 -Quiet -ComputerName $_.properties.dnshostname
1639 }
1640 if($Up) {
1641 # return full data objects
1642 if ($FullData) {
1643 # convert/process the LDAP fields for each result
1644 Convert-LDAPProperty -Properties $_.Properties
1645 }
1646 else {
1647 # otherwise we're just returning the DNS host name
1648 $_.properties.dnshostname
1649 }
1650 }
1651 }
1652 }
1653 catch {
1654 Write-Warning "Error: $_"
1655 }
1656 }
1657 }
1658}
1659
1660function Get-NetGPO {
1661
1662 [CmdletBinding()]
1663 Param (
1664 [Parameter(ValueFromPipeline=$True)]
1665 [String]
1666 $GPOname = '*',
1667
1668 [String]
1669 $DisplayName,
1670
1671 [String]
1672 $Domain,
1673
1674 [String]
1675 $DomainController,
1676
1677 [String]
1678 $ADSpath,
1679
1680 [ValidateRange(1,10000)]
1681 [Int]
1682 $PageSize = 200
1683
1684 )
1685
1686 begin {
1687 $GPOSearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -ADSpath $ADSpath -PageSize $PageSize
1688 }
1689
1690 process {
1691 if ($GPOSearcher) {
1692 if($DisplayName) {
1693 $GPOSearcher.filter="(&(objectCategory=groupPolicyContainer)(displayname=$DisplayName))"
1694 }
1695 else {
1696 $GPOSearcher.filter="(&(objectCategory=groupPolicyContainer)(name=$GPOname))"
1697 }
1698
1699 $GPOSearcher.FindAll() | Where-Object {$_} | ForEach-Object {
1700 # convert/process the LDAP fields for each result
1701 Convert-LDAPProperty -Properties $_.Properties
1702 }
1703 }
1704 }
1705}
1706function Get-DomainSearcher {
1707<#
1708 .SYNOPSIS
1709
1710 Helper used by various functions that takes an ADSpath and
1711 domain specifier and builds the correct ADSI searcher object.
1712
1713 .PARAMETER Domain
1714
1715 The domain to use for the query, defaults to the current domain.
1716
1717 .PARAMETER DomainController
1718
1719 Domain controller to reflect LDAP queries through.
1720
1721 .PARAMETER ADSpath
1722
1723 The LDAP source to search through, e.g. "LDAP://OU=secret,DC=testlab,DC=local"
1724 Useful for OU queries.
1725
1726 .PARAMETER ADSprefix
1727
1728 Prefix to set for the searcher (like "CN=Sites,CN=Configuration")
1729
1730 .PARAMETER PageSize
1731
1732 The PageSize to set for the LDAP searcher object.
1733
1734 .EXAMPLE
1735
1736 PS C:\> Get-DomainSearcher -Domain testlab.local
1737
1738 .EXAMPLE
1739
1740 PS C:\> Get-DomainSearcher -Domain testlab.local -DomainController SECONDARY.dev.testlab.local
1741#>
1742
1743 [CmdletBinding()]
1744 param(
1745 [String]
1746 $Domain,
1747
1748 [String]
1749 $DomainController,
1750
1751 [String]
1752 $ADSpath,
1753
1754 [String]
1755 $ADSprefix,
1756
1757 [ValidateRange(1,10000)]
1758 [Int]
1759 $PageSize = 200
1760 )
1761
1762 if(!$Domain) {
1763 $Domain = (Get-NetDomain).name
1764 }
1765 else {
1766 if(!$DomainController) {
1767 try {
1768 # if there's no -DomainController specified, try to pull the primary DC
1769 # to reflect queries through
1770 $DomainController = ((Get-NetDomain).PdcRoleOwner).Name
1771 }
1772 catch {
1773 throw "Get-DomainSearcher: Error in retrieving PDC for current domain"
1774 }
1775 }
1776 }
1777
1778 $SearchString = "LDAP://"
1779
1780 if($DomainController) {
1781 $SearchString += $DomainController + "/"
1782 }
1783 if($ADSprefix) {
1784 $SearchString += $ADSprefix + ","
1785 }
1786
1787 if($ADSpath) {
1788 if($ADSpath -like "GC://*") {
1789 # if we're searching the global catalog
1790 $DistinguishedName = $AdsPath
1791 $SearchString = ""
1792 }
1793 else {
1794 if($ADSpath -like "LDAP://*") {
1795 $ADSpath = $ADSpath.Substring(7)
1796 }
1797 $DistinguishedName = $ADSpath
1798 }
1799 }
1800 else {
1801 $DistinguishedName = "DC=$($Domain.Replace('.', ',DC='))"
1802 }
1803
1804 $SearchString += $DistinguishedName
1805 Write-Verbose "Get-DomainSearcher search string: $SearchString"
1806
1807 $Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$SearchString)
1808 $Searcher.PageSize = $PageSize
1809 $Searcher
1810}
1811function Convert-LDAPProperty {
1812 # helper to convert specific LDAP property result fields
1813 param(
1814 [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
1815 [ValidateNotNullOrEmpty()]
1816 $Properties
1817 )
1818
1819 $ObjectProperties = @{}
1820
1821 $Properties.PropertyNames | ForEach-Object {
1822 if (($_ -eq "objectsid") -or ($_ -eq "sidhistory")) {
1823 # convert the SID to a string
1824 $ObjectProperties[$_] = (New-Object System.Security.Principal.SecurityIdentifier($Properties[$_][0],0)).Value
1825 }
1826 elseif($_ -eq "objectguid") {
1827 # convert the GUID to a string
1828 $ObjectProperties[$_] = (New-Object Guid (,$Properties[$_][0])).Guid
1829 }
1830 elseif( ($_ -eq "lastlogon") -or ($_ -eq "lastlogontimestamp") -or ($_ -eq "pwdlastset") -or ($_ -eq "lastlogoff") -or ($_ -eq "badPasswordTime") ) {
1831 # convert timestamps
1832 if ($Properties[$_][0] -is [System.MarshalByRefObject]) {
1833 # if we have a System.__ComObject
1834 $Temp = $Properties[$_][0]
1835 [Int32]$High = $Temp.GetType().InvokeMember("HighPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null)
1836 [Int32]$Low = $Temp.GetType().InvokeMember("LowPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null)
1837 $ObjectProperties[$_] = ([datetime]::FromFileTime([Int64]("0x{0:x8}{1:x8}" -f $High, $Low)))
1838 }
1839 else {
1840 $ObjectProperties[$_] = ([datetime]::FromFileTime(($Properties[$_][0])))
1841 }
1842 }
1843 elseif($Properties[$_][0] -is [System.MarshalByRefObject]) {
1844 # convert misc com objects
1845 $Prop = $Properties[$_]
1846 try {
1847 $Temp = $Prop[$_][0]
1848 Write-Verbose $_
1849 [Int32]$High = $Temp.GetType().InvokeMember("HighPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null)
1850 [Int32]$Low = $Temp.GetType().InvokeMember("LowPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null)
1851 $ObjectProperties[$_] = [Int64]("0x{0:x8}{1:x8}" -f $High, $Low)
1852 }
1853 catch {
1854 $ObjectProperties[$_] = $Prop[$_]
1855 }
1856 }
1857 elseif($Properties[$_].count -eq 1) {
1858 $ObjectProperties[$_] = $Properties[$_][0]
1859 }
1860 else {
1861 $ObjectProperties[$_] = $Properties[$_]
1862 }
1863 }
1864
1865 New-Object -TypeName PSObject -Property $ObjectProperties
1866}
1867function Get-GptTmpl {
1868
1869 [CmdletBinding()]
1870 Param (
1871 [Parameter(Mandatory=$True, ValueFromPipeline=$True)]
1872 [String]
1873 $GptTmplPath,
1874
1875 [Switch]
1876 $UsePSDrive
1877 )
1878
1879 begin {
1880 if($UsePSDrive) {
1881 # if we're PSDrives, create a temporary mount point
1882 $Parts = $GptTmplPath.split('\')
1883 $FolderPath = $Parts[0..($Parts.length-2)] -join '\'
1884 $FilePath = $Parts[-1]
1885 $RandDrive = ("abcdefghijklmnopqrstuvwxyz".ToCharArray() | Get-Random -Count 7) -join ''
1886
1887 Write-Verbose "Mounting path $GptTmplPath using a temp PSDrive at $RandDrive"
1888
1889 try {
1890 $Null = New-PSDrive -Name $RandDrive -PSProvider FileSystem -Root $FolderPath -ErrorAction Stop
1891 }
1892 catch {
1893 Write-Debug "Error mounting path $GptTmplPath : $_"
1894 return $Null
1895 }
1896
1897 # so we can cd/dir the new drive
1898 $GptTmplPath = $RandDrive + ":\" + $FilePath
1899 }
1900 }
1901
1902 process {
1903 $SectionName = ''
1904 $SectionsTemp = @{}
1905 $SectionsFinal = @{}
1906
1907 try {
1908
1909 if(Test-Path $GptTmplPath) {
1910
1911 Write-Verbose "Parsing $GptTmplPath"
1912
1913 Get-Content $GptTmplPath -ErrorAction Stop | Foreach-Object {
1914 if ($_ -match '\[') {
1915 # this signifies that we're starting a new section
1916 $SectionName = $_.trim('[]') -replace ' ',''
1917 }
1918 elseif($_ -match '=') {
1919 $Parts = $_.split('=')
1920 $PropertyName = $Parts[0].trim()
1921 $PropertyValues = $Parts[1].trim()
1922
1923 if($PropertyValues -match ',') {
1924 $PropertyValues = $PropertyValues.split(',')
1925 }
1926
1927 if(!$SectionsTemp[$SectionName]) {
1928 $SectionsTemp.Add($SectionName, @{})
1929 }
1930
1931 # add the parsed property into the relevant Section name
1932 $SectionsTemp[$SectionName].Add( $PropertyName, $PropertyValues )
1933 }
1934 }
1935
1936 ForEach ($Section in $SectionsTemp.keys) {
1937 # transform each nested hash table into a custom object
1938 $SectionsFinal[$Section] = New-Object PSObject -Property $SectionsTemp[$Section]
1939 }
1940
1941 # transform the parent hash table into a custom object
1942 New-Object PSObject -Property $SectionsFinal
1943 }
1944 }
1945 catch {
1946 Write-Debug "Error parsing $GptTmplPath : $_"
1947 }
1948 }
1949
1950 end {
1951 if($UsePSDrive -and $RandDrive) {
1952 Write-Verbose "Removing temp PSDrive $RandDrive"
1953 Get-PSDrive -Name $RandDrive -ErrorAction SilentlyContinue | Remove-PSDrive
1954 }
1955 }
1956}
1957function Invoke-ThreadedFunction {
1958 # Helper used by any threaded host enumeration functions
1959 [CmdletBinding()]
1960 param(
1961 [Parameter(Position=0,Mandatory=$True)]
1962 [String[]]
1963 $ComputerName,
1964
1965 [Parameter(Position=1,Mandatory=$True)]
1966 [System.Management.Automation.ScriptBlock]
1967 $ScriptBlock,
1968
1969 [Parameter(Position=2)]
1970 [Hashtable]
1971 $ScriptParameters,
1972
1973 [Int]
1974 $Threads = 20,
1975
1976 [Switch]
1977 $NoImports
1978 )
1979
1980 begin {
1981
1982 if ($PSBoundParameters['Debug']) {
1983 $DebugPreference = 'Continue'
1984 }
1985
1986 Write-Verbose "[*] Total number of hosts: $($ComputerName.count)"
1987
1988 # Adapted from:
1989 # http://powershell.org/wp/forums/topic/invpke-parallel-need-help-to-clone-the-current-runspace/
1990 $SessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
1991 $SessionState.ApartmentState = [System.Threading.Thread]::CurrentThread.GetApartmentState()
1992
1993 # import the current session state's variables and functions so the chained PowerView
1994 # functionality can be used by the threaded blocks
1995 if(!$NoImports) {
1996
1997 # grab all the current variables for this runspace
1998 $MyVars = Get-Variable -Scope 2
1999
2000 # these Variables are added by Runspace.Open() Method and produce Stop errors if you add them twice
2001 $VorbiddenVars = @("?","args","ConsoleFileName","Error","ExecutionContext","false","HOME","Host","input","InputObject","MaximumAliasCount","MaximumDriveCount","MaximumErrorCount","MaximumFunctionCount","MaximumHistoryCount","MaximumVariableCount","MyInvocation","null","PID","PSBoundParameters","PSCommandPath","PSCulture","PSDefaultParameterValues","PSHOME","PSScriptRoot","PSUICulture","PSVersionTable","PWD","ShellId","SynchronizedHash","true")
2002
2003 # Add Variables from Parent Scope (current runspace) into the InitialSessionState
2004 ForEach($Var in $MyVars) {
2005 if($VorbiddenVars -NotContains $Var.Name) {
2006 $SessionState.Variables.Add((New-Object -TypeName System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList $Var.name,$Var.Value,$Var.description,$Var.options,$Var.attributes))
2007 }
2008 }
2009
2010 # Add Functions from current runspace to the InitialSessionState
2011 ForEach($Function in (Get-ChildItem Function:)) {
2012 $SessionState.Commands.Add((New-Object -TypeName System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList $Function.Name, $Function.Definition))
2013 }
2014 }
2015
2016 # threading adapted from
2017 # https://github.com/darkoperator/Posh-SecMod/blob/master/Discovery/Discovery.psm1#L407
2018 # Thanks Carlos!
2019
2020 # create a pool of maxThread runspaces
2021 $Pool = [runspacefactory]::CreateRunspacePool(1, $Threads, $SessionState, $Host)
2022 $Pool.Open()
2023
2024 $Jobs = @()
2025 $PS = @()
2026 $Wait = @()
2027
2028 $Counter = 0
2029 }
2030
2031 process {
2032
2033 ForEach ($Computer in $ComputerName) {
2034
2035 # make sure we get a server name
2036 if ($Computer -ne '') {
2037 # Write-Verbose "[*] Enumerating server $Computer ($($Counter+1) of $($ComputerName.count))"
2038
2039 While ($($Pool.GetAvailableRunspaces()) -le 0) {
2040 Start-Sleep -MilliSeconds 500
2041 }
2042
2043 # create a "powershell pipeline runner"
2044 $PS += [powershell]::create()
2045
2046 $PS[$Counter].runspacepool = $Pool
2047
2048 # add the script block + arguments
2049 $Null = $PS[$Counter].AddScript($ScriptBlock).AddParameter('ComputerName', $Computer)
2050 if($ScriptParameters) {
2051 ForEach ($Param in $ScriptParameters.GetEnumerator()) {
2052 $Null = $PS[$Counter].AddParameter($Param.Name, $Param.Value)
2053 }
2054 }
2055
2056 # start job
2057 $Jobs += $PS[$Counter].BeginInvoke();
2058
2059 # store wait handles for WaitForAll call
2060 $Wait += $Jobs[$Counter].AsyncWaitHandle
2061 }
2062 $Counter = $Counter + 1
2063 }
2064 }
2065
2066 end {
2067
2068 Write-Verbose "Waiting for scanning threads to finish..."
2069
2070 $WaitTimeout = Get-Date
2071
2072 # set a 60 second timeout for the scanning threads
2073 while ($($Jobs | Where-Object {$_.IsCompleted -eq $False}).count -gt 0 -or $($($(Get-Date) - $WaitTimeout).totalSeconds) -gt 60) {
2074 Start-Sleep -MilliSeconds 500
2075 }
2076
2077 # end async call
2078 for ($y = 0; $y -lt $Counter; $y++) {
2079
2080 try {
2081 # complete async job
2082 $PS[$y].EndInvoke($Jobs[$y])
2083
2084 } catch {
2085 Write-Warning "error: $_"
2086 }
2087 finally {
2088 $PS[$y].Dispose()
2089 }
2090 }
2091
2092 $Pool.Dispose()
2093 Write-Verbose "All threads completed!"
2094 }
2095}
2096function Find-InterestingFile {
2097
2098
2099 [CmdletBinding()]
2100 param(
2101 [Parameter(ValueFromPipeline=$True)]
2102 [String]
2103 $Path = '.\',
2104
2105 [String[]]
2106 $Terms,
2107
2108 [Switch]
2109 $OfficeDocs,
2110
2111 [Switch]
2112 $FreshEXEs,
2113
2114 [String]
2115 $LastAccessTime,
2116
2117 [String]
2118 $LastWriteTime,
2119
2120 [String]
2121 $CreationTime,
2122
2123 [Switch]
2124 $ExcludeFolders,
2125
2126 [Switch]
2127 $ExcludeHidden,
2128
2129 [Switch]
2130 $CheckWriteAccess,
2131
2132 [String]
2133 $OutFile,
2134
2135 [Switch]
2136 $UsePSDrive,
2137
2138 [System.Management.Automation.PSCredential]
2139 $Credential = [System.Management.Automation.PSCredential]::Empty
2140 )
2141
2142 begin {
2143 # default search terms
2144 $SearchTerms = @('pass', 'sensitive', 'admin', 'login', 'secret', 'unattend*.xml', '.vmdk', 'creds', 'credential', '.config')
2145
2146 if(!$Path.EndsWith('\')) {
2147 $Path = $Path + '\'
2148 }
2149 if($Credential -ne [System.Management.Automation.PSCredential]::Empty) { $UsePSDrive = $True }
2150
2151 # check if custom search terms were passed
2152 if ($Terms) {
2153 if($Terms -isnot [system.array]) {
2154 $Terms = @($Terms)
2155 }
2156 $SearchTerms = $Terms
2157 }
2158
2159 if(-not $SearchTerms[0].startswith("*")) {
2160 # append wildcards to the front and back of all search terms
2161 for ($i = 0; $i -lt $SearchTerms.Count; $i++) {
2162 $SearchTerms[$i] = "*$($SearchTerms[$i])*"
2163 }
2164 }
2165
2166 # search just for office documents if specified
2167 if ($OfficeDocs) {
2168 $SearchTerms = @('*.doc', '*.docx', '*.xls', '*.xlsx', '*.ppt', '*.pptx')
2169 }
2170
2171 # find .exe's accessed within the last 7 days
2172 if($FreshEXEs) {
2173 # get an access time limit of 7 days ago
2174 $LastAccessTime = (get-date).AddDays(-7).ToString('MM/dd/yyyy')
2175 $SearchTerms = '*.exe'
2176 }
2177
2178 if($UsePSDrive) {
2179 # if we're PSDrives, create a temporary mount point
2180 $Parts = $Path.split('\')
2181 $FolderPath = $Parts[0..($Parts.length-2)] -join '\'
2182 $FilePath = $Parts[-1]
2183 $RandDrive = ("abcdefghijklmnopqrstuvwxyz".ToCharArray() | Get-Random -Count 7) -join ''
2184
2185 Write-Verbose "Mounting path $Path using a temp PSDrive at $RandDrive"
2186
2187 try {
2188 $Null = New-PSDrive -Name $RandDrive -Credential $Credential -PSProvider FileSystem -Root $FolderPath -ErrorAction Stop
2189 }
2190 catch {
2191 Write-Debug "Error mounting path $Path : $_"
2192 return $Null
2193 }
2194
2195 # so we can cd/dir the new drive
2196 $Path = $RandDrive + ":\" + $FilePath
2197 }
2198 }
2199
2200 process {
2201
2202 Write-Verbose "[*] Search path $Path"
2203
2204 function Invoke-CheckWrite {
2205 # short helper to check is the current user can write to a file
2206 [CmdletBinding()]param([String]$Path)
2207 try {
2208 $Filetest = [IO.FILE]::OpenWrite($Path)
2209 $Filetest.Close()
2210 $True
2211 }
2212 catch {
2213 Write-Verbose -Message $Error[0]
2214 $False
2215 }
2216 }
2217
2218 $SearchArgs = @{
2219 'Path' = $Path
2220 'Recurse' = $True
2221 'Force' = $(-not $ExcludeHidden)
2222 'Include' = $SearchTerms
2223 'ErrorAction' = 'SilentlyContinue'
2224 }
2225
2226 Get-ChildItem @SearchArgs | ForEach-Object {
2227 Write-Verbose $_
2228 # check if we're excluding folders
2229 if(!$ExcludeFolders -or !$_.PSIsContainer) {$_}
2230 } | ForEach-Object {
2231 if($LastAccessTime -or $LastWriteTime -or $CreationTime) {
2232 if($LastAccessTime -and ($_.LastAccessTime -gt $LastAccessTime)) {$_}
2233 elseif($LastWriteTime -and ($_.LastWriteTime -gt $LastWriteTime)) {$_}
2234 elseif($CreationTime -and ($_.CreationTime -gt $CreationTime)) {$_}
2235 }
2236 else {$_}
2237 } | ForEach-Object {
2238 # filter for write access (if applicable)
2239 if((-not $CheckWriteAccess) -or (Invoke-CheckWrite -Path $_.FullName)) {$_}
2240 } | Select-Object FullName,@{Name='Owner';Expression={(Get-Acl $_.FullName).Owner}},LastAccessTime,LastWriteTime,CreationTime,Length | ForEach-Object {
2241 # check if we're outputting to the pipeline or an output file
2242 if($OutFile) {Export-PowerViewCSV -InputObject $_ -OutFile $OutFile}
2243 else {$_}
2244 }
2245 }
2246
2247 end {
2248 if($UsePSDrive -and $RandDrive) {
2249 Write-Verbose "Removing temp PSDrive $RandDrive"
2250 Get-PSDrive -Name $RandDrive -ErrorAction SilentlyContinue | Remove-PSDrive
2251 }
2252 }
2253}
2254
2255$Mod = New-InMemoryModule -ModuleName Win32
2256
2257# all of the Win32 API functions we need
2258$FunctionDefinitions = @(
2259 (func netapi32 NetShareEnum ([Int]) @([String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
2260 (func netapi32 NetWkstaUserEnum ([Int]) @([String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
2261 (func netapi32 NetSessionEnum ([Int]) @([String], [String], [String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
2262 (func netapi32 NetApiBufferFree ([Int]) @([IntPtr])),
2263 (func advapi32 OpenSCManagerW ([IntPtr]) @([String], [String], [Int])),
2264 (func advapi32 CloseServiceHandle ([Int]) @([IntPtr])),
2265 (func wtsapi32 WTSOpenServerEx ([IntPtr]) @([String])),
2266 (func wtsapi32 WTSEnumerateSessionsEx ([Int]) @([IntPtr], [Int32].MakeByRefType(), [Int], [IntPtr].MakeByRefType(), [Int32].MakeByRefType())),
2267 (func wtsapi32 WTSQuerySessionInformation ([Int]) @([IntPtr], [Int], [Int], [IntPtr].MakeByRefType(), [Int32].MakeByRefType())),
2268 (func wtsapi32 WTSFreeMemoryEx ([Int]) @([Int32], [IntPtr], [Int32])),
2269 (func wtsapi32 WTSFreeMemory ([Int]) @([IntPtr])),
2270 (func wtsapi32 WTSCloseServer ([Int]) @([IntPtr])),
2271 (func kernel32 GetLastError ([Int]) @())
2272)
2273
2274# enum used by $WTS_SESSION_INFO_1 below
2275$WTSConnectState = psenum $Mod WTS_CONNECTSTATE_CLASS UInt16 @{
2276 Active = 0
2277 Connected = 1
2278 ConnectQuery = 2
2279 Shadow = 3
2280 Disconnected = 4
2281 Idle = 5
2282 Listen = 6
2283 Reset = 7
2284 Down = 8
2285 Init = 9
2286}
2287
2288# the WTSEnumerateSessionsEx result structure
2289$WTS_SESSION_INFO_1 = struct $Mod WTS_SESSION_INFO_1 @{
2290 ExecEnvId = field 0 UInt32
2291 State = field 1 $WTSConnectState
2292 SessionId = field 2 UInt32
2293 pSessionName = field 3 String -MarshalAs @('LPWStr')
2294 pHostName = field 4 String -MarshalAs @('LPWStr')
2295 pUserName = field 5 String -MarshalAs @('LPWStr')
2296 pDomainName = field 6 String -MarshalAs @('LPWStr')
2297 pFarmName = field 7 String -MarshalAs @('LPWStr')
2298}
2299
2300# the particular WTSQuerySessionInformation result structure
2301$WTS_CLIENT_ADDRESS = struct $mod WTS_CLIENT_ADDRESS @{
2302 AddressFamily = field 0 UInt32
2303 Address = field 1 Byte[] -MarshalAs @('ByValArray', 20)
2304}
2305
2306# the NetShareEnum result structure
2307$SHARE_INFO_1 = struct $Mod SHARE_INFO_1 @{
2308 shi1_netname = field 0 String -MarshalAs @('LPWStr')
2309 shi1_type = field 1 UInt32
2310 shi1_remark = field 2 String -MarshalAs @('LPWStr')
2311}
2312
2313# the NetWkstaUserEnum result structure
2314$WKSTA_USER_INFO_1 = struct $Mod WKSTA_USER_INFO_1 @{
2315 wkui1_username = field 0 String -MarshalAs @('LPWStr')
2316 wkui1_logon_domain = field 1 String -MarshalAs @('LPWStr')
2317 wkui1_oth_domains = field 2 String -MarshalAs @('LPWStr')
2318 wkui1_logon_server = field 3 String -MarshalAs @('LPWStr')
2319}
2320
2321# the NetSessionEnum result structure
2322$SESSION_INFO_10 = struct $Mod SESSION_INFO_10 @{
2323 sesi10_cname = field 0 String -MarshalAs @('LPWStr')
2324 sesi10_username = field 1 String -MarshalAs @('LPWStr')
2325 sesi10_time = field 2 UInt32
2326 sesi10_idle_time = field 3 UInt32
2327}
2328
2329
2330$Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32'
2331$Netapi32 = $Types['netapi32']
2332$Advapi32 = $Types['advapi32']
2333$Kernel32 = $Types['kernel32']
2334$Wtsapi32 = $Types['wtsapi32']
2335
2336
2337# aliases to help the PowerView 2.0 transition
2338Set-Alias Get-NetForestDomains Get-NetForestDomain
2339Set-Alias Get-NetDomainControllers Get-NetDomainController
2340Set-Alias Get-NetUserSPNs Get-NetUser
2341Set-Alias Invoke-NetUserAdd Add-NetUser
2342Set-Alias Invoke-NetGroupUserAdd Add-NetGroupUser
2343Set-Alias Get-NetComputers Get-NetComputer
2344Set-Alias Get-NetOUs Get-NetOU
2345Set-Alias Get-NetGUIDOUs Get-NetOU
2346Set-Alias Get-NetFileServers Get-NetFileServer
2347Set-Alias Get-NetSessions Get-NetSession
2348Set-Alias Get-NetRDPSessions Get-NetRDPSession
2349Set-Alias Get-NetProcesses Get-NetProcess
2350Set-Alias Get-UserLogonEvents Get-UserEvent
2351Set-Alias Get-UserTGTEvents Get-UserEvent
2352Set-Alias Get-UserProperties Get-UserProperty
2353Set-Alias Get-ComputerProperties Get-ComputerProperty
2354Set-Alias Invoke-UserHunterThreaded Invoke-UserHunter
2355Set-Alias Invoke-ProcessHunterThreaded Invoke-ProcessHunter
2356Set-Alias Invoke-ShareFinderThreaded Invoke-ShareFinder
2357Set-Alias Invoke-SearchFiles Find-InterestingFile
2358Set-Alias Invoke-UserFieldSearch Find-UserField
2359Set-Alias Invoke-ComputerFieldSearch Find-ComputerField
2360Set-Alias Invoke-FindLocalAdminAccess Find-LocalAdminAccess
2361Set-Alias Invoke-FindLocalAdminAccessThreaded Find-LocalAdminAccess
2362Set-Alias Get-NetDomainTrusts Get-NetDomainTrust
2363Set-Alias Get-NetForestTrusts Get-NetForestTrust
2364Set-Alias Invoke-MapDomainTrusts Invoke-MapDomainTrust
2365Set-Alias Invoke-FindUserTrustGroups Find-ForeignUser
2366Set-Alias Invoke-FindGroupTrustUsers Find-ForeignGroup
2367Set-Alias Invoke-EnumerateLocalTrustGroups Invoke-EnumerateLocalAdmin
2368Set-Alias Invoke-EnumerateLocalAdmins Invoke-EnumerateLocalAdmin
2369Set-Alias Invoke-EnumerateLocalAdminsThreaded Invoke-EnumerateLocalAdmin
2370Set-Alias Invoke-FindAllUserTrustGroups Find-ForeignUser
2371Set-Alias Find-UserTrustGroup Find-ForeignUser
2372Set-Alias Invoke-FindAllGroupTrustUsers Find-ForeignGroup