├── images ├── batch.png ├── shell.png └── powershell.png ├── polyshell.txt ├── LICENSE.md └── README.md /images/batch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llamasoft/polyshell/HEAD/images/batch.png -------------------------------------------------------------------------------- /images/shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llamasoft/polyshell/HEAD/images/shell.png -------------------------------------------------------------------------------- /images/powershell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llamasoft/polyshell/HEAD/images/powershell.png -------------------------------------------------------------------------------- /polyshell.txt: -------------------------------------------------------------------------------- 1 | echo \" <<'BATCH_SCRIPT' >/dev/null ">NUL "\" \`" <#" 2 | @ECHO OFF 3 | REM ===== Batch Script Begin ===== 4 | ECHO I'm PolyShell, a batch script! 5 | REM ====== Batch Script End ====== 6 | GOTO :eof 7 | TYPE CON >NUL 8 | BATCH_SCRIPT 9 | #> | Out-Null 10 | 11 | 12 | echo \" <<'POWERSHELL_SCRIPT' >/dev/null # " | Out-Null 13 | # ===== PowerShell Script Begin ===== 14 | echo "... but also a PowerShell script!" 15 | # ====== PowerShell Script End ====== 16 | while ( ! $MyInvocation.MyCommand.Source ) { $input_line = Read-Host } 17 | exit 18 | <# 19 | POWERSHELL_SCRIPT 20 | 21 | 22 | set +o histexpand 2>/dev/null 23 | # ===== Bash Script Begin ===== 24 | echo "... and a Unix shell script!" 25 | # ====== Bash Script End ====== 26 | case $- in *"i"*) cat /dev/stdin >/dev/null ;; esac 27 | exit 28 | #> -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 llamasoft 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 | ## PolyShell: a Bash/Batch/PowerShell polyglot 2 | 3 | ## What It Is 4 | 5 | PolyShell is a script that's simultaneously valid in Bash, Windows Batch, and PowerShell (i.e. a [polyglot](https://en.wikipedia.org/wiki/Polyglot_(computing))). 6 | 7 | This makes PolyShell a useful template for penetration testing as it can be executed on most systems without the need for target-specific payloads. PolyShell is also specifically designed to be deliverable via input injection using a [USB Rubby Ducky](https://shop.hak5.org/collections/usb-rubber-ducky/products/usb-rubber-ducky-deluxe), [MalDuino](https://malduino.com/), or similar device. 8 | 9 | ![Batch demo](images/batch.png) 10 | ![Powershell demo](images/powershell.png) 11 | ![Unix shell demo](images/shell.png) 12 | 13 | 14 | ## How To Use It 15 | 16 | ### As a stand-alone script 17 | 18 | 1. Copy/rename the script so it has the correct file extension (`.sh`, `.bat`, or `.ps1`). 19 | 1. Run the script with a Unix shell, as a batch file, or with PowerShell. 20 | 21 | ### Using input injection 22 | 23 | 1. Open a terminal on the target machine. 24 | 1. Run the payload. 25 | 1. Press Ctrl-C, then run `exit`. 26 | 27 | The input injection method will behave slightly differently than the script method. When run as a script, the payload will exit immediately once a language has been processed. When delivered via injection, the payload runs a read loop instead. Without it, the payload would close the terminal window but continue typing into an unknown window instead. The Ctrl-C breaks the script out of the read loop, allowing it run without unintended side-effects. 28 | 29 | Additionally, _pasting_ the script into a terminal might fail. Once the script reaches the read loop, some terminals will treat the remaining pasted text as the read loop's input (good), but others may continue executing the script when the read loop exits (bad). 30 | 31 | 32 | ## How It Works 33 | 34 | The main trick is to get each other language to "look away" when we want to run code specific to only one of them. This is accomplished by exploiting language quirks surrounding quoting, redirection, and comments. 35 | Consider the following line: 36 | 37 | echo \" <<'BATCH_SCRIPT' >/dev/null ">NUL "\" \`" <#" 38 | 39 | Each language sees the `echo` command, but will interpret the rest of the line differently. 40 | For example, this is what each language will interpret as a string: 41 | 42 | echo \" <<'BATCH_SCRIPT' >/dev/null ">NUL "\" \`" <#" 43 | Bash [-----] [---] 44 | Batch [-----------------------------] [-] [---] 45 | PS [-----------------------------] [-] 46 | 47 | After executing the line, the bash script will be in a [here document](https://www.tldp.org/LDP/abs/html/here-docs.html), PowerShell script will be in a [multiline-comment](https://ss64.com/ps/syntax-comments.html), and the batch script will continue executing normally. After each language is done executing, we terminate it. This prevents us from needing to work around its quirks later in the script. 48 | 49 | 50 | ### Quirks 51 | 52 | Obviously, the tricks required to make this polyglot doesn't follow _normal_ coding conventions. 53 | There are quite a few quirks that were leveraged or had to be worked around: 54 | 55 | - All three languages have different escape characters: 56 | - Bash: backslash (`\`) 57 | - Batch: caret (`^`) 58 | - PowerShell: backtick (`` ` ``) 59 | - Escape characters work inside Bash and PowerShell strings, but not batch strings. 60 | - Redirects (i.e. `<` and `>`) have special meaning in all three languages unless quoted. 61 | - Redirects don't have to be at the end of a command. 62 | - This is valid Bash/Batch/PowerShell: `echo >output.txt "Hello World"` 63 | - Batch is the only language _without_ multi-line strings or comments. 64 | - Batch treats `>` as a redirect even when it directly touches a string, but PowerShell doesn't. 65 | - Batch script `GOTO` statements only work when run as a script, not when run interactively. 66 | - PowerShell's multi-line comment (`<#`) must be immediately preceded by whitespace. 67 | - Bash's here documents may begin *anywhere* so long as it's unquoted and not a comment. 68 | --------------------------------------------------------------------------------