diff --git a/.gitignore b/.gitignore index ed756a2..6484f85 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ ehthumbs.db Thumbs.db desktop.ini .dropbox* -.idea \ No newline at end of file +.idea +vendor/ +.bundle/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b91888..f6fbb65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### 1.8 + - Added pass-the-hash feature + - Added bundler installation method + ### 1.7 - Added x64 compatibility to use Donut payloads diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..1d6ed7d --- /dev/null +++ b/Gemfile @@ -0,0 +1,6 @@ +source 'https://rubygems.org' + +gem 'winrm' +gem 'winrm-fs' +gem 'colorize' +gem 'stringio' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..239dcfc --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,47 @@ +GEM + remote: https://rubygems.org/ + specs: + builder (3.2.3) + colorize (0.8.1) + erubis (2.7.0) + ffi (1.11.1) + gssapi (1.3.0) + ffi (>= 1.0.1) + gyoku (1.3.1) + builder (>= 2.1.2) + httpclient (2.8.3) + little-plugger (1.1.4) + logging (2.2.2) + little-plugger (~> 1.1) + multi_json (~> 1.10) + multi_json (1.14.1) + nori (2.6.0) + rubyntlm (0.6.2) + rubyzip (1.3.0) + stringio (0.0.2) + winrm (2.3.2) + builder (>= 2.1.2) + erubis (~> 2.7) + gssapi (~> 1.2) + gyoku (~> 1.0) + httpclient (~> 2.2, >= 2.2.0.2) + logging (>= 1.6.1, < 3.0) + nori (~> 2.0) + rubyntlm (~> 0.6.0, >= 0.6.1) + winrm-fs (1.3.2) + erubis (~> 2.7) + logging (>= 1.6.1, < 3.0) + rubyzip (~> 1.1) + winrm (~> 2.0) + +PLATFORMS + ruby + +DEPENDENCIES + colorize + stringio + winrm + winrm-fs + +BUNDLED WITH + 2.0.2 diff --git a/README.md b/README.md index 847e05a..20504ce 100644 --- a/README.md +++ b/README.md @@ -27,12 +27,12 @@ purposes by system administrators as well but the most of its features are focus - Load x64 payloads generated with awesome [donut] technique - Colorization on output messages (can be disabled optionally) - SSL and certificates support + - Pass-the-hash support ## Help - ``` -Usage: evil-winrm -i IP -u USER [-s SCRIPTS_PATH] [-e EXES_PATH] [-P PORT] [-p PASS] [-U URL] [-S] [-c PUBLIC_KEY_PATH ] [-k PRIVATE_KEY_PATH ] - -S, --ssl Enable SSL +Usage: evil-winrm -i IP -u USER [-s SCRIPTS_PATH] [-e EXES_PATH] [-P PORT] [-p PASS] [-H HASH] [-U URL] [-S] [-c PUBLIC_KEY_PATH ] [-k PRIVATE_KEY_PATH ] + -S, --ssl Enable ssl -c, --pub-key PUBLIC_KEY_PATH Local path to public key certificate -k, --priv-key PRIVATE_KEY_PATH Local path to private key certificate -s, --scripts PS_SCRIPTS_PATH Powershell scripts local path @@ -41,6 +41,7 @@ Usage: evil-winrm -i IP -u USER [-s SCRIPTS_PATH] [-e EXES_PATH] [-P PORT] [-p P -U, --url URL Remote url endpoint (default /wsman) -u, --user USER Username (required) -p, --password PASS Password + -H, --hash HASH NTLM hash -P, --port PORT Remote host port (default 5985) -V, --version Show version -h, --help Display this help message @@ -48,24 +49,32 @@ Usage: evil-winrm -i IP -u USER [-s SCRIPTS_PATH] [-e EXES_PATH] [-P PORT] [-p P ## Requirements Ruby 2.3 or higher is needed. Some ruby gems are needed as well: `winrm >=2.3.2`, `winrm-fs >=1.3.2`, `stringio >=0.0.2` and `colorize >=0.8.1`. +Depending of your installation method (3 availables) the installation of them could be required to be done manually. -`~$ sudo gem install winrm winrm-fs colorize stringio` - -## Installation & Quick Start - - Step 1. Clone the repo: `git clone https://github.com/Hackplayers/evil-winrm.git` - - Step 2. Ready. Just launch it! `~$ cd evil-winrm && ruby evil-winrm.rb -i 192.168.1.100 -u Administrator -p 'MySuperSecr3tPass123!' -s '/home/foo/ps1_scripts/' -e '/home/foo/exe_files/'` - -If you don't want to put the password in clear text, you can optionally avoid to set `-p` argument and the password will be prompted preventing to be shown. +## Installation & Quick Start (3 methods) -To use IPv6, the address must be added to /etc/hosts. +### Method 1. Git clone and install dependencies on your system manually + - Step 1. Install dependencies manually: `~$ sudo gem install winrm winrm-fs colorize stringio` + - Step 2. Clone the repo: `git clone https://github.com/Hackplayers/evil-winrm.git` + - Step 3. Ready. Just launch it! `~$ cd evil-winrm && ruby evil-winrm.rb -i 192.168.1.100 -u Administrator -p 'MySuperSecr3tPass123!' -s '/home/foo/ps1_scripts/' -e '/home/foo/exe_files/'` -##### Alternative installation method as ruby gem +### Method 2. Using bundler (dependencies will not be installed on your system, just to use evil-winrm) + - Step 1. Install bundler: `gem install bundler:2.0.2` + - Step 2. Install dependencies with bundler: `cd evil-winrm && bundle install --path vendor/bundle` + - Step 3. Launch it with bundler: `bundle exec evil-winrm.rb -i 192.168.1.100 -u Administrator -p 'MySuperSecr3tPass123!' -s '/home/foo/ps1_scripts/' -e '/home/foo/exe_files/'` - - Step 1. Install it: `gem install evil-winrm` +### Method 3. Installation directly as ruby gem (dependencies will be installed automatically on your system) + - Step 1. Install it (it will install automatically dependencies): `gem install evil-winrm` - Step 2. Ready. Just launch it! `~$ evil-winrm -i 192.168.1.100 -u Administrator -p 'MySuperSecr3tPass123!' -s '/home/foo/ps1_scripts/' -e '/home/foo/exe_files/'` ## Documentation +#### Clear text password +If you don't want to put the password in clear text, you can optionally avoid to set `-p` argument and the password will be prompted preventing to be shown. + +#### Ipv6 +To use IPv6, the address must be added to /etc/hosts. Just put the already set name of the host after `-i` argument instead of an IP address. + #### Basic commands - **upload**: local files can be auto-completed using tab key. It is recommended to use absolute path for destination to avoid errors. Otherwise you could get uncontrolled errors due Winrm-fs limitations. - usage: `upload local_path remote_absolute_path` @@ -88,7 +97,6 @@ To use IPv6, the address must be added to /etc/hosts. ![ps1](resources/image7.png) #### Advanced commands - - Invoke-Binary: allows exes compiled from c# to be executed in memory. The name can be auto-completed using tab key and allows up to 3 parameters. The executables must be in the path set at `-e` argument. ![Invoke-Binary](resources/image3.png) @@ -138,6 +146,7 @@ Hat tip to: - [WinRb] All contributors of ruby library. - [TheWover] for his awesome donut tool. - [byt3bl33d3r] for his python library to create donut payloads. + - [Sh11td0wn] for inspiration about new features. ## Disclaimer & License This script is licensed under LGPLv3+. Direct link to [License](LICENSE). @@ -158,8 +167,9 @@ Use it at your own servers and/or with the server owner's permission. [byt3bl33d3r]: https://twitter.com/byt3bl33d3r [WinRb]: https://github.com/WinRb/WinRM/graphs/contributors [TheWover]: https://github.com/TheWover +[Sh11td0wn]: https://github.com/Sh11td0wn -[Version-shield]: https://img.shields.io/badge/version-1.7-blue.svg?style=flat-square&colorA=273133&colorB=0093ee "Latest version" +[Version-shield]: https://img.shields.io/badge/version-1.8-blue.svg?style=flat-square&colorA=273133&colorB=0093ee "Latest version" [Ruby2.3-shield]: https://img.shields.io/badge/ruby-2.3%2B-blue.svg?style=flat-square&colorA=273133&colorB=ff0000 "Ruby 2.3 or later" [License-shield]: https://img.shields.io/badge/license-LGPL%20v3%2B-blue.svg?style=flat-square&colorA=273133&colorB=bd0000 "LGPL v3+" [Gem-Version]: https://badge.fury.io/rb/evil-winrm.svg "Ruby gem" diff --git a/evil-winrm.rb b/evil-winrm.rb index 69b7633..2019df8 100755 --- a/evil-winrm.rb +++ b/evil-winrm.rb @@ -17,7 +17,7 @@ # Constants # Version -VERSION = '1.7' +VERSION = '1.8' # Msg types TYPE_INFO = 0 @@ -55,7 +55,7 @@ class EvilWinRM def arguments() options = { port:$port, url:$url } optparse = OptionParser.new do |opts| - opts.banner = "Usage: evil-winrm -i IP -u USER [-s SCRIPTS_PATH] [-e EXES_PATH] [-P PORT] [-p PASS] [-U URL] [-S] [-c PUBLIC_KEY_PATH ] [-k PRIVATE_KEY_PATH ]" + opts.banner = "Usage: evil-winrm -i IP -u USER [-s SCRIPTS_PATH] [-e EXES_PATH] [-P PORT] [-p PASS] [-H HASH] [-U URL] [-S] [-c PUBLIC_KEY_PATH ] [-k PRIVATE_KEY_PATH ]" opts.on("-S", "--ssl", "Enable ssl") do |val| $ssl = true options[:port] = "5986" @@ -68,17 +68,29 @@ def arguments() opts.on("-U", "--url URL", "Remote url endpoint (default /wsman)") { |val| options[:url] = val } opts.on("-u", "--user USER", "Username (required)") { |val| options[:user] = val } opts.on("-p", "--password PASS", "Password") { |val| options[:password] = val } + opts.on("-H", "--hash HASH", "NTLM hash") do |val| + if options[:password] != nil and val != nil + self.print_header() + self.print_message("You must choose either password or hash auth. Both at the same time are not allowed", TYPE_ERROR) + self.custom_exit(1, false) + end + if !val.match /^[a-fA-F0-9]{32}$/ + self.print_header() + self.print_message("Invalid hash format", TYPE_ERROR) + self.custom_exit(1, false) + end + options[:password] = "00000000000000000000000000000000:" + val + end opts.on("-P", "--port PORT", "Remote host port (default 5985)") { |val| options[:port] = val } opts.on("-V", "--version", "Show version") do |val| puts("v" + VERSION) - custom_exit(0, false) + self.custom_exit(0, false) end opts.on('-h', '--help', 'Display this help message') do - puts() - self.print_message("Evil-WinRM shell v" + VERSION, TYPE_INFO, false) + self.print_header() puts(opts) puts() - custom_exit(0, false) + self.custom_exit(0, false) end end @@ -90,8 +102,7 @@ def arguments() raise OptionParser::MissingArgument.new(missing.join(', ')) end rescue OptionParser::InvalidOption, OptionParser::MissingArgument - puts() - self.print_message("Evil-WinRM shell v" + VERSION, TYPE_INFO, false) + self.print_header() self.print_message($!.to_s, TYPE_ERROR) puts(optparse) puts() @@ -112,6 +123,12 @@ def arguments() $priv_key = options[:priv_key] end + # Print script header + def print_header() + puts() + self.print_message("Evil-WinRM shell v" + VERSION, TYPE_INFO, false) + end + # Generate connection object def connection_initialization() if $ssl then @@ -277,8 +294,7 @@ def main self.arguments() self.connection_initialization() file_manager = WinRM::FS::FileManager.new($conn) - puts() - self.print_message("Starting Evil-WinRM shell v" + VERSION, TYPE_INFO) + self.print_header() if !$ssl and ($pub_key or $priv_key) then self.print_message("Useless cert/s provided, SSL is not enabled", TYPE_WARNING) @@ -394,7 +410,7 @@ def main end print(output.output) rescue - self.print_message("Check file names", TYPE_ERROR) + self.print_message("Check filenames", TYPE_ERROR) end elsif command.start_with?('Donut-Loader') then @@ -412,7 +428,7 @@ def main end print(output.output) rescue - self.print_message("Check file names", TYPE_ERROR) + self.print_message("Check filenames", TYPE_ERROR) end elsif command.start_with?('services') then