├── Current-Standings.md ├── FAQ.md ├── LICENSE ├── README.md ├── Rules.md └── UnderhandedScriptTesting └── UnderhandedScriptTesting.psm1 /Current-Standings.md: -------------------------------------------------------------------------------- 1 | # Current Standings 2 | | Username | Confirmed Underhanded Techniques | 3 | |----------------|----------------------------------| 4 | | PetSerAl | 33 | 5 | | fmichaleczek | 31 | 6 | | jonwhitejwh | 10 | 7 | | noaml | 7 | 8 | | Emin | 6 | 9 | | test | 4 | 10 | | superbadguy | 2 | 11 | | mattifestation | 2 | 12 | | sevoroby | 1 | 13 | | foo | 1 | 14 | | proxb | 1 | 15 | | kittH | 1 | 16 | | KevinMarquette | 1 | 17 | 18 | 19 | *Generated on 5/5/2016 3:09:24 PM PST* 20 | -------------------------------------------------------------------------------- /FAQ.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerShell/underhanded-powershell/1e5f93db5445acc518816a5393d41e5ad6e1d396/FAQ.md -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 PowerShell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Underhanded PowerShell Contest 2 | 3 | - [FAQ](http://github.com/powershell/underhanded-powershell/blob/master/FAQ.md) 4 | - [RULES](http://github.com/powershell/underhanded-powershell/blob/master/Rules.md) 5 | - [TERMS OF USE](http://underhanded-powershell.azurewebsites.net/TermsOfUse.html) 6 | - [STANDINGS](http://github.com/powershell/underhanded-powershell/blob/master/Current-Standings.md) 7 | 8 | ## About This Series 9 | 10 | In an effort to improve the validation capability of PowerShell Script Analyzer, we are running a series of contests. We want you - the community members - to help us identify underhanded PowerShell scripts, and then create rules to catch them. There are specific areas where Script Analyzer rules are needed and we need your skills to help us hone them. 11 | 12 | What's underhanded PowerShell code? Basically, code that is designed to do something the user would not intend, or takes actions that are not apparent to someone who would casually read the code. 13 | 14 | We'll be running this contest in two phases: "Red Team", and "Blue Team". In the "Red Team" phase, you get to unleash your underhanded creativity in _writing_ underhanded PowerShell code. In an upcoming "Blue Team" phase, we'll be looking for creative and reliable defenses to detect underhanded PowerShell. Participation in both contests will be allowed - and in fact encouraged! 15 | 16 | ## Participating as a Red Teamer 17 | 18 | We have set up a web service that runs PowerShell Script Analyzer with a set of preliminary rules that are designed to detect underhanded script code, along with a set of commands built into the [UnderhandedScriptTesting](https://github.com/PowerShell/underhanded-powershell/tree/master/UnderhandedScriptTesting) module that will work against that service. 19 | 20 | ## Submission Guidelines and Deadlines 21 | 22 | Full [Rules](http://github.com/powershell/underhanded-powershell/blob/master/Rules.md) are posted on [GitHub](http://github.com/powershell/underhanded-powershell), along with the rest of the documents and the module code required for participating in this contest. You must read all the rules before participating. The first contest in this series is focused on finding scripts that would do the equivalent of the following PowerShell code, but not be caught by the rules we have created. 23 | 24 | ` [System.Runtime.InteropServices.Marshal]::SystemDefaultCharSize ` 25 | 26 | An example of an underhanded approach to this would be: 27 | 28 | ``` powershell 29 | $type = [Type] ("System.Runtime.InteropSe" + "rvices.Mar" + "shal") 30 | $property = "SystemDef" + "aultCharSize" 31 | $type::$property 32 | ``` 33 | or alternatively through C# and the Add-Type cmdlet, 34 | 35 | ``` powershell 36 | $code = @' 37 | public static int Getter 38 | { 39 | get { return System.Runtime.InteropServices.Marshal.SystemDefaultCharSize; } 40 | } 41 | '@ 42 | 43 | $type = Add-Type -Name "Me$(Get-Random)" -MemberDefinition $code -PassThru 44 | $type::Getter 45 | ``` 46 | 47 | Your goal is to submit your own creative approaches to underhanded scripting using the **Test-IsSuspiciousContent** command, and get a false IsSuspicious return value. 48 | 49 | We will award prizes for the largest number of unique successful underhanded techniques submitted, and will also update the contest standings regularly so you can show off to your friends. Critical dates for this contest are: 50 | 51 | | Date | Event | 52 | |------------------|---------------------------------| 53 | | **Mar 7, 2016** | Contest opens | 54 | | **May 1, 2016** | Submission deadline | 55 | | **May 15, 2016** | Results of Judging | 56 | | **May 15, 2016** | Next phase of contest announced | 57 | 58 | **Important:** Before you submit any code, read the [Rules](http://github.com/powershell/underhanded-powershell/blob/master/Rules.md). Among other things you will see that by submitting code to this contest, you are granting Microsoft the ability to reuse in any way the code or content you submit, and that we will collect contact information from you to help us run the contest. 59 | 60 | As mentioned above, we plan for this to be a series of contests. In future contests, we will share some of our rules that we want you to break, and will expand the prize rules to deal with adding support for defenders (those submitting new validation rules), and attackers (getting past the rules), etc. 61 | 62 | ## Module Usage 63 | 64 | ### Install the module 65 | 66 | ``` 67 | $profileDir = Split-Path $profile 68 | if (!(Test-Path $profileDir)) {New-Item -Type Directory $profileDir -Force} 69 | Set-Location $profileDir 70 | New-Item -Type Directory "Modules/UnderhandedScriptTesting" -Force  71 | $webRequest = @{ 72 | Uri = 'https://raw.githubusercontent.com/PowerShell/underhanded-powershell/master/UnderhandedScriptTesting/UnderhandedScriptTesting.psm1' 73 | OutFile = 'Modules/UnderhandedScriptTesting/UnderhandedScriptTesting.psm1' 74 | } 75 | Invoke-WebRequest @webRequest 76 | ``` 77 | 78 | ### Test a script 79 | 80 | ``` 81 | Test-IsUnderhandedPowerShell -ScriptBlock { Invoke-Expression "SOME_BASE64" } -Username superbadguy -ContactEmail redteam@example.com 82 | ``` 83 | -------------------------------------------------------------------------------- /Rules.md: -------------------------------------------------------------------------------- 1 | ## Underhanded PowerShell Contest 1 2 | 3 | # Contest Rules 4 | 5 | __Requirements__ 6 | 7 | * All submissions must be written in PowerShell, and submitted using the UnderhandedScriptTesting module available on GitHub at http://github.com/powershell/underhanded-powershell 8 | * The username is required with all submissions. The same username must be supplied for any submission to be counted with others towards towards the awards for this contest. The username will be displayed on the contest status page. 9 | * The email address is required with all submissions, and will be used only by Microsoft to contact submitters. 10 | * The value of Prizes for this contest will be less than $100.00. Contest prizes will not be awarded for submissions that are not associated with a valid email address. 11 | * Attacks against directed to the website are bad form, and will not aid the user in winning this contest. 12 | 13 | __Contest Scoring__ 14 | 15 | * Submissions that return a false "IsSuspicious" value will be counted towards a winning score. 16 | * Scores will be aggregated across all unique submissions made with the same username in the submission. 17 | * Uniqueness of submissions is applied for submissions from a single user. A submission will be deemed unique if the reviewers find that design considerations are required to address that submission separately from other submissions by the author. 18 | * Submissions will be reviewed by Microsoft employees, who will make all decisions regarding the applicability of the submissions. All decisions of the reviewers will be considered final. 19 | * Comments inserted in the PowerShell code should be provided to identify the specific techniques used, and if needed, why the techniques in one submission should be considered to be unique from another submission with the same username. 20 | -------------------------------------------------------------------------------- /UnderhandedScriptTesting/UnderhandedScriptTesting.psm1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Starts the Powershell ScriptAnalyzer job. 4 | #> 5 | Function Start-PssaJob 6 | { 7 | 8 | param( 9 | [Parameter(Mandatory=$true, Position=1)] 10 | [string]$serviceUrl, 11 | 12 | [Parameter(Mandatory=$true, Position=2)] 13 | [string]$content, 14 | 15 | [Parameter(Mandatory=$true, Position=3)] 16 | [string]$username, 17 | 18 | [string]$email 19 | ) 20 | 21 | $jobStartContent = "/api/Invoke" 22 | $serviceUrl = $serviceUrl + $jobStartContent; 23 | 24 | $contentBase64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($content)); 25 | 26 | $result = Invoke-WebRequest -UseBasicParsing -Method Post ` 27 | -Uri $serviceUrl ` 28 | -Body @{content=$contentBase64; 29 | username=$username; 30 | email=$email}; 31 | 32 | if($result.StatusCode -ne 201) 33 | { 34 | Throw ("Cannot create the job: {0}" -f $result) 35 | } 36 | 37 | return((ConvertFrom-Json -InputObject $result.Content).id); 38 | } 39 | 40 | <# 41 | .SYNOPSIS 42 | Returns the current status (Enqueued, Running, Finished, Failed or Cancelled) of the job. 43 | #> 44 | Function Get-PssaJobStatus 45 | { 46 | param( 47 | [string]$serviceUrl, 48 | [Guid]$id 49 | ) 50 | $jobStatus = "/api/status" 51 | $url = "{0}/{1}/{2}" -f ($serviceUrl, $jobStatus, $id) 52 | $result = Invoke-WebRequest -UseBasicParsing -Method Get ` 53 | -Uri $url 54 | return($result) 55 | } 56 | 57 | <# 58 | .SYNOPSIS 59 | Returns the result returned by the ScriptAnalyzer job. 60 | #> 61 | Function Get-PssasJobResult 62 | { 63 | param( 64 | [string]$serviceUrl, 65 | [Guid]$id 66 | ) 67 | $jobResult = "/api/result" 68 | $url = $url = "{0}/{1}/{2}" -f ($serviceUrl, $jobResult, $id) 69 | $result = Invoke-RestMethod -Method Get ` 70 | -Uri $url 71 | return($result) 72 | } 73 | 74 | <# 75 | .SYNOPSIS 76 | Stops the ScriptAnalyzer job. 77 | #> 78 | Function Stop-PssasJob 79 | { 80 | param( 81 | [string]$serviceUrl, 82 | [Guid]$id 83 | ) 84 | $jobStop = "/api/cancel" 85 | $url = $url = "{0}/{1}/{2}" -f ($serviceUrl, $jobStop, $id) 86 | $result = Invoke-WebRequest -UseBasicParsing -Method Delete ` 87 | -Uri $url 88 | return($result) 89 | } 90 | 91 | <# 92 | .SYNOPSIS 93 | Tests a script block for any suspicious code. 94 | 95 | .DESCRIPTION 96 | This function takes a script block and sends it to the remote server for analysis. The server runs an instance of ScriptAnalyzer with a special set of security rules. These rules are designed to check the ScriptBlock for any suspicious content. If it finds anything suspicious, it returns an IsSuspicous boolean flag wherein a True value indicates suspicious code and a False value indicates otherwise. 97 | 98 | .PARAMETER ScriptBlock 99 | Script block to be submitted for analysis. 100 | 101 | .PARAMETER Username 102 | Username of the entity submitting the script block. 103 | 104 | .PARAMETER ContactEmail 105 | Email address of the entity submitting the script block. (Please see the contest website for privacy related information.) 106 | 107 | .EXAMPLE 108 | PS> Test-IsUnderhandedPowerShell -ScriptBlock {.\foo.exe} -Username foo -ContactEmail foo@bar.foobar 109 | Tests the given script block for any suspicious code. 110 | 111 | #> 112 | Function Test-IsUnderhandedPowerShell 113 | { 114 | param( 115 | [Parameter(Mandatory=$true)] 116 | [ScriptBlock] $ScriptBlock, 117 | 118 | [Parameter(Mandatory=$true)] 119 | [String] $Username, 120 | 121 | [Parameter(Mandatory=$true)] 122 | [String] $ContactEmail 123 | ) 124 | 125 | $ServiceUrl = 'https://underhanded-powershell.azurewebsites.net/' 126 | $timeoutInSec = 180 127 | $pollIntervalInSec = 1 128 | 129 | $ScriptContent = $ScriptBlock.ToString() 130 | $id = Start-PssaJob -ServiceUrl $ServiceUrl ` 131 | -Content $ScriptContent ` 132 | -UserName $Username ` 133 | -email $ContactEmail 134 | $timeout = New-TimeSpan -Seconds $timeoutInSec 135 | $stopWatch = [System.Diagnostics.Stopwatch]::StartNew(); 136 | while ($stopWatch.elapsed -le $timeout) 137 | { 138 | $jobStatusReq = Get-PssaJobStatus -ServiceUrl $serviceUrl -id $id 139 | $jobStatusObj = ConvertFrom-Json $jobStatusReq 140 | $jobStatus = $jobStatusObj.status 141 | # Write-Host ("Job Status: " + $jobStatus) 142 | if ($jobStatus -in ("Enqueued", "Running")) 143 | { 144 | $percentComplete = 0 145 | if ($jobStatus -eq "Enqueued") 146 | { 147 | $percentComplete = 33 148 | } 149 | 150 | if ($jobStatus -eq "Running") 151 | { 152 | $percentComplete = 67 153 | } 154 | Write-Progress -Activity "Checking for possible underhanded code..." ` 155 | -Status $jobStatus ` 156 | -PercentComplete $percentComplete 157 | 158 | Start-Sleep -Seconds $pollIntervalInSec 159 | continue 160 | } 161 | if ($jobStatus -eq "Finished") 162 | { 163 | Write-Progress -Activity "Checking for possible underhanded code..." ` 164 | -Status $jobStatus ` 165 | -PercentComplete 100 166 | 167 | $results = Get-PssasJobResult -ServiceUrl $serviceUrl -id $id 168 | Write-Host ("IsSuspicious: " + $results.IsSuspicious.ToString()) 169 | break 170 | } 171 | if ($jobStatus -eq "Failed") 172 | { 173 | Write-Host ("Job failed because of " + $jobStatusObj.message + ".") 174 | break 175 | } 176 | if ($jobStatus -eq "Cancelled") 177 | { 178 | Write-Host "Job has been cancelled." 179 | break 180 | } 181 | } 182 | if ($stopWatch.elapsed -gt $timeout) 183 | { 184 | Write-Host "Timed out! Sorry, something isn't right. Please try again in a few minutes." 185 | } 186 | } 187 | 188 | Export-ModuleMember -Function Test-IsUnderhandedPowerShell --------------------------------------------------------------------------------