rex-socket 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/README.md +32 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/rex/socket.rb +798 -0
- data/lib/rex/socket/comm.rb +120 -0
- data/lib/rex/socket/comm/local.rb +529 -0
- data/lib/rex/socket/ip.rb +132 -0
- data/lib/rex/socket/parameters.rb +372 -0
- data/lib/rex/socket/range_walker.rb +470 -0
- data/lib/rex/socket/ssh_factory.rb +46 -0
- data/lib/rex/socket/ssl_tcp.rb +374 -0
- data/lib/rex/socket/ssl_tcp_server.rb +220 -0
- data/lib/rex/socket/subnet_walker.rb +76 -0
- data/lib/rex/socket/switch_board.rb +289 -0
- data/lib/rex/socket/tcp.rb +79 -0
- data/lib/rex/socket/tcp_server.rb +70 -0
- data/lib/rex/socket/udp.rb +165 -0
- data/lib/rex/socket/version.rb +5 -0
- data/lib/rex/socket/x509_certificate.rb +92 -0
- data/rex-socket.gemspec +30 -0
- metadata +205 -0
- metadata.gz.sig +2 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
require 'rex/socket'
|
3
|
+
|
4
|
+
module Rex
|
5
|
+
module Socket
|
6
|
+
|
7
|
+
###
|
8
|
+
#
|
9
|
+
# This class provides an interface to enumerating a subnet with a supplied
|
10
|
+
# netmask.
|
11
|
+
#
|
12
|
+
###
|
13
|
+
class SubnetWalker
|
14
|
+
|
15
|
+
#
|
16
|
+
# Initializes a subnet walker instance using the supplied subnet
|
17
|
+
# information.
|
18
|
+
#
|
19
|
+
def initialize(subnet, netmask)
|
20
|
+
self.subnet = Socket.resolv_to_dotted(subnet)
|
21
|
+
self.netmask = Socket.resolv_to_dotted(netmask)
|
22
|
+
|
23
|
+
reset
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Resets the subnet walker back to its original state.
|
28
|
+
#
|
29
|
+
def reset
|
30
|
+
self.curr_ip = self.subnet.split('.')
|
31
|
+
self.num_ips = (1 << (32 - Socket.net2bitmask(self.netmask).to_i))
|
32
|
+
self.curr_ip_idx = 0
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Returns the next IP address.
|
37
|
+
#
|
38
|
+
def next_ip
|
39
|
+
if (curr_ip_idx >= num_ips)
|
40
|
+
return nil
|
41
|
+
end
|
42
|
+
|
43
|
+
if (curr_ip_idx > 0)
|
44
|
+
self.curr_ip[3] = (curr_ip[3].to_i + 1) % 256
|
45
|
+
self.curr_ip[2] = (curr_ip[2].to_i + 1) % 256 if (curr_ip[3] == 0)
|
46
|
+
self.curr_ip[1] = (curr_ip[1].to_i + 1) % 256 if (curr_ip[2] == 0)
|
47
|
+
self.curr_ip[0] = (curr_ip[0].to_i + 1) % 256 if (curr_ip[1] == 0)
|
48
|
+
end
|
49
|
+
|
50
|
+
self.curr_ip_idx += 1
|
51
|
+
|
52
|
+
self.curr_ip.join('.')
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# The subnet that is being enumerated.
|
57
|
+
#
|
58
|
+
attr_reader :subnet
|
59
|
+
#
|
60
|
+
# The netmask of the subnet.
|
61
|
+
#
|
62
|
+
attr_reader :netmask
|
63
|
+
#
|
64
|
+
# The total number of IPs within the subnet.
|
65
|
+
#
|
66
|
+
attr_reader :num_ips
|
67
|
+
|
68
|
+
protected
|
69
|
+
|
70
|
+
attr_writer :subnet, :netmask, :num_ips # :nodoc:
|
71
|
+
attr_accessor :curr_ip, :curr_ip_idx # :nodoc:
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,289 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
require 'singleton'
|
3
|
+
require 'thread'
|
4
|
+
require 'rex/socket'
|
5
|
+
|
6
|
+
module Rex
|
7
|
+
module Socket
|
8
|
+
|
9
|
+
###
|
10
|
+
#
|
11
|
+
# This class provides a global routing table that associates subnets with Comm
|
12
|
+
# classes. Comm classes are used to instantiate objects that are tied to
|
13
|
+
# remote network entities. For example, the Local Comm class is used to
|
14
|
+
# building network connections directly from the local machine whereas, for
|
15
|
+
# instance, a Meterpreter Comm would build a local socket pair that is
|
16
|
+
# associated with a connection established by a remote entity. This can be
|
17
|
+
# seen as a uniform way of communicating with hosts through arbitrary
|
18
|
+
# channels.
|
19
|
+
#
|
20
|
+
###
|
21
|
+
class SwitchBoard
|
22
|
+
|
23
|
+
include Singleton
|
24
|
+
include Enumerable
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
@_initialized = false
|
28
|
+
end
|
29
|
+
|
30
|
+
###
|
31
|
+
#
|
32
|
+
# This class represents a logical switch board route.
|
33
|
+
# TODO: Enable this to work with IPv6 addresses
|
34
|
+
#
|
35
|
+
###
|
36
|
+
class Route
|
37
|
+
def initialize(subnet, netmask, comm)
|
38
|
+
self.subnet = subnet
|
39
|
+
self.netmask = netmask
|
40
|
+
self.comm = comm
|
41
|
+
self.subnet_nbo = Socket.resolv_nbo_i(subnet)
|
42
|
+
self.netmask_nbo = Socket.resolv_nbo_i(netmask)
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# Sort according to bitmask
|
47
|
+
#
|
48
|
+
def <=>(other)
|
49
|
+
self.bitmask <=> other.bitmask
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Convert the netmask to a bitmask and cache it.
|
54
|
+
#
|
55
|
+
def bitmask
|
56
|
+
@_bitmask = Socket.net2bitmask(self.netmask) if (@_bitmask == nil)
|
57
|
+
@_bitmask
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_reader :subnet, :netmask, :comm
|
61
|
+
attr_reader :subnet_nbo, :netmask_nbo
|
62
|
+
protected
|
63
|
+
attr_writer :subnet, :netmask, :comm
|
64
|
+
attr_writer :subnet_nbo, :netmask_nbo
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
#
|
69
|
+
# Class method wrappers
|
70
|
+
#
|
71
|
+
##
|
72
|
+
|
73
|
+
#
|
74
|
+
# Adds a route to the switch board routing table using the supplied Comm
|
75
|
+
# instance.
|
76
|
+
#
|
77
|
+
def self.add_route(subnet, mask, comm)
|
78
|
+
ret = self.instance.add_route(subnet, mask, comm)
|
79
|
+
if ret && comm.respond_to?(:routes) && comm.routes.kind_of?(Array)
|
80
|
+
comm.routes << "#{subnet}/#{mask}"
|
81
|
+
end
|
82
|
+
ret
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Removes a route from the switch board routing table for the supplied
|
87
|
+
# subnet routing through the supplied Comm instance.
|
88
|
+
#
|
89
|
+
def self.remove_route(subnet, mask, comm)
|
90
|
+
ret = self.instance.remove_route(subnet, mask, comm)
|
91
|
+
if ret && comm.respond_to?(:routes) && comm.routes.kind_of?(Array)
|
92
|
+
comm.routes.delete "#{subnet}/#{mask}"
|
93
|
+
end
|
94
|
+
ret
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# Flush all the routes from the switch board routing table.
|
99
|
+
#
|
100
|
+
def self.flush_routes
|
101
|
+
ret = self.instance.flush_routes
|
102
|
+
end
|
103
|
+
|
104
|
+
#
|
105
|
+
# Enumerate each route in the routing table.
|
106
|
+
#
|
107
|
+
def self.each(&block)
|
108
|
+
self.instance.each(&block)
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# Returns the array of routes.
|
113
|
+
#
|
114
|
+
def self.routes
|
115
|
+
self.instance.routes
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.route_exists?(subnet, mask)
|
119
|
+
self.instance.route_exists?(subnet, mask)
|
120
|
+
end
|
121
|
+
|
122
|
+
#
|
123
|
+
# Returns the Comm instance that should be used for the supplied address.
|
124
|
+
# If no comm can be found, the default Local Comm is returned.
|
125
|
+
#
|
126
|
+
def self.best_comm(addr)
|
127
|
+
self.instance.best_comm(addr)
|
128
|
+
end
|
129
|
+
|
130
|
+
#
|
131
|
+
# Removes all routes that go through the supplied Comm.
|
132
|
+
#
|
133
|
+
def self.remove_by_comm(comm)
|
134
|
+
self.instance.remove_by_comm(comm)
|
135
|
+
end
|
136
|
+
|
137
|
+
##
|
138
|
+
#
|
139
|
+
# Instance methods
|
140
|
+
#
|
141
|
+
##
|
142
|
+
|
143
|
+
#
|
144
|
+
# Adds a route for a given subnet and netmask destined through a given comm
|
145
|
+
# instance.
|
146
|
+
#
|
147
|
+
def add_route(subnet, mask, comm)
|
148
|
+
# If a bitmask was supplied, convert it.
|
149
|
+
netmask = (mask.to_s =~ /^\d+$/) ? Rex::Socket.bit2netmask(mask.to_i) : mask
|
150
|
+
rv = true
|
151
|
+
|
152
|
+
_init
|
153
|
+
|
154
|
+
mutex.synchronize {
|
155
|
+
# If the route already exists, return false to the caller.
|
156
|
+
if (route_exists?(subnet, netmask) == false)
|
157
|
+
self.routes << Route.new(subnet, netmask, comm)
|
158
|
+
else
|
159
|
+
rv = false
|
160
|
+
end
|
161
|
+
}
|
162
|
+
|
163
|
+
rv
|
164
|
+
end
|
165
|
+
|
166
|
+
#
|
167
|
+
# Removes a route for a given subnet and netmask destined through a given
|
168
|
+
# comm instance.
|
169
|
+
#
|
170
|
+
def remove_route(subnet, mask, comm)
|
171
|
+
# If a bitmask was supplied, convert it.
|
172
|
+
netmask = (mask.to_s =~ /^\d+$/) ? Rex::Socket.bit2netmask(mask.to_i) : mask
|
173
|
+
rv = false
|
174
|
+
|
175
|
+
_init
|
176
|
+
|
177
|
+
mutex.synchronize {
|
178
|
+
self.routes.delete_if { |route|
|
179
|
+
if (route.subnet == subnet and route.netmask == netmask and route.comm == comm)
|
180
|
+
rv = true
|
181
|
+
else
|
182
|
+
false
|
183
|
+
end
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
rv
|
188
|
+
end
|
189
|
+
|
190
|
+
#
|
191
|
+
# Flushes all established routes.
|
192
|
+
#
|
193
|
+
def flush_routes
|
194
|
+
_init
|
195
|
+
|
196
|
+
# Remove each of the individual routes so the comms don't think they're
|
197
|
+
# still routing after a flush.
|
198
|
+
self.routes.each { |r|
|
199
|
+
if r.comm.respond_to? :routes
|
200
|
+
r.comm.routes.delete("#{r.subnet}/#{r.netmask}")
|
201
|
+
end
|
202
|
+
}
|
203
|
+
# Re-initialize to an empty array
|
204
|
+
self.routes = Array.new
|
205
|
+
end
|
206
|
+
|
207
|
+
#
|
208
|
+
# Checks to see if a route already exists for the supplied subnet and
|
209
|
+
# netmask.
|
210
|
+
#
|
211
|
+
def route_exists?(subnet, netmask)
|
212
|
+
each { |route|
|
213
|
+
return true if (route.subnet == subnet and route.netmask == netmask)
|
214
|
+
}
|
215
|
+
|
216
|
+
false
|
217
|
+
end
|
218
|
+
|
219
|
+
#
|
220
|
+
# Enumerates each entry in the routing table.
|
221
|
+
#
|
222
|
+
def each(&block)
|
223
|
+
_init
|
224
|
+
|
225
|
+
routes.each(&block)
|
226
|
+
end
|
227
|
+
|
228
|
+
#
|
229
|
+
# Finds the best possible comm for the supplied target address.
|
230
|
+
#
|
231
|
+
def best_comm(addr)
|
232
|
+
|
233
|
+
addr_nbo = Socket.resolv_nbo_i(addr)
|
234
|
+
comm = nil
|
235
|
+
msb = 0
|
236
|
+
|
237
|
+
each { |route|
|
238
|
+
if ((route.subnet_nbo & route.netmask_nbo) ==
|
239
|
+
(addr_nbo & route.netmask_nbo))
|
240
|
+
if (route.bitmask >= msb)
|
241
|
+
comm = route.comm
|
242
|
+
msb = route.bitmask
|
243
|
+
end
|
244
|
+
end
|
245
|
+
}
|
246
|
+
|
247
|
+
comm
|
248
|
+
end
|
249
|
+
|
250
|
+
#
|
251
|
+
# Remove all routes that go through the supplied comm.
|
252
|
+
#
|
253
|
+
def remove_by_comm(comm)
|
254
|
+
_init
|
255
|
+
mutex.synchronize {
|
256
|
+
routes.delete_if { |route|
|
257
|
+
route.comm == comm
|
258
|
+
}
|
259
|
+
}
|
260
|
+
end
|
261
|
+
|
262
|
+
#
|
263
|
+
# The routes array.
|
264
|
+
#
|
265
|
+
attr_reader :routes
|
266
|
+
#
|
267
|
+
# The mutex protecting the routes array.
|
268
|
+
#
|
269
|
+
attr_reader :mutex
|
270
|
+
|
271
|
+
protected
|
272
|
+
|
273
|
+
attr_writer :routes, :mutex # :nodoc:
|
274
|
+
|
275
|
+
#
|
276
|
+
# Initializes the underlying stuff.
|
277
|
+
#
|
278
|
+
def _init
|
279
|
+
if (@_initialized != true)
|
280
|
+
@_initialized = true
|
281
|
+
self.routes = Array.new
|
282
|
+
self.mutex = Mutex.new
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
end
|
287
|
+
|
288
|
+
end
|
289
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
require 'rex/socket'
|
3
|
+
require 'rex/io/stream'
|
4
|
+
|
5
|
+
###
|
6
|
+
#
|
7
|
+
# This class provides methods for interacting with a TCP client connection.
|
8
|
+
#
|
9
|
+
###
|
10
|
+
module Rex::Socket::Tcp
|
11
|
+
|
12
|
+
include Rex::Socket
|
13
|
+
include Rex::IO::Stream
|
14
|
+
|
15
|
+
##
|
16
|
+
#
|
17
|
+
# Factory
|
18
|
+
#
|
19
|
+
##
|
20
|
+
|
21
|
+
#
|
22
|
+
# Creates the client using the supplied hash.
|
23
|
+
#
|
24
|
+
# @see create_param
|
25
|
+
# @see Rex::Socket::Parameters.from_hash
|
26
|
+
def self.create(hash = {})
|
27
|
+
hash['Proto'] = 'tcp'
|
28
|
+
self.create_param(Rex::Socket::Parameters.from_hash(hash))
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# Wrapper around the base socket class' creation method that automatically
|
33
|
+
# sets the parameter's protocol to TCP.
|
34
|
+
#
|
35
|
+
def self.create_param(param)
|
36
|
+
param.proto = 'tcp'
|
37
|
+
Rex::Socket.create_param(param)
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
#
|
42
|
+
# Stream mixin implementations
|
43
|
+
#
|
44
|
+
##
|
45
|
+
|
46
|
+
#
|
47
|
+
# Calls shutdown on the TCP connection.
|
48
|
+
#
|
49
|
+
def shutdown(how = ::Socket::SHUT_RDWR)
|
50
|
+
begin
|
51
|
+
return (super(how) == 0)
|
52
|
+
rescue ::Exception
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Returns peer information (host + port) in host:port format.
|
58
|
+
#
|
59
|
+
def peerinfo
|
60
|
+
if (pi = getpeername_as_array)
|
61
|
+
return pi[1] + ':' + pi[2].to_s
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# Returns local information (host + port) in host:port format.
|
67
|
+
#
|
68
|
+
def localinfo
|
69
|
+
if (pi = getlocalname)
|
70
|
+
return pi[1] + ':' + pi[2].to_s
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# returns socket type
|
75
|
+
def type?
|
76
|
+
return 'tcp'
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
require 'rex/socket'
|
3
|
+
require 'rex/socket/tcp'
|
4
|
+
require 'rex/io/stream_server'
|
5
|
+
|
6
|
+
###
|
7
|
+
#
|
8
|
+
# This class provides methods for interacting with a TCP server. It
|
9
|
+
# implements the Rex::IO::StreamServer interface.
|
10
|
+
#
|
11
|
+
###
|
12
|
+
module Rex::Socket::TcpServer
|
13
|
+
|
14
|
+
include Rex::Socket
|
15
|
+
include Rex::IO::StreamServer
|
16
|
+
|
17
|
+
##
|
18
|
+
#
|
19
|
+
# Factory
|
20
|
+
#
|
21
|
+
##
|
22
|
+
|
23
|
+
#
|
24
|
+
# Creates the server using the supplied hash.
|
25
|
+
#
|
26
|
+
def self.create(hash = {})
|
27
|
+
hash['Proto'] = 'tcp'
|
28
|
+
hash['Server'] = true
|
29
|
+
self.create_param(Rex::Socket::Parameters.from_hash(hash))
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Wrapper around the base class' creation method that automatically sets
|
34
|
+
# the parameter's protocol to TCP and sets the server flag to true.
|
35
|
+
#
|
36
|
+
def self.create_param(param)
|
37
|
+
param.proto = 'tcp'
|
38
|
+
param.server = true
|
39
|
+
Rex::Socket.create_param(param)
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Accepts a child connection.
|
44
|
+
#
|
45
|
+
def accept(opts = {})
|
46
|
+
t = super()
|
47
|
+
|
48
|
+
# jRuby compatibility
|
49
|
+
if t.respond_to?('[]')
|
50
|
+
t = t[0]
|
51
|
+
end
|
52
|
+
|
53
|
+
if (t)
|
54
|
+
t.extend(Rex::Socket::Tcp)
|
55
|
+
t.context = self.context
|
56
|
+
|
57
|
+
pn = t.getpeername_as_array
|
58
|
+
|
59
|
+
# We hit a "getpeername(2)" from Ruby
|
60
|
+
return nil unless pn
|
61
|
+
|
62
|
+
t.peerhost = pn[1]
|
63
|
+
t.peerport = pn[2]
|
64
|
+
end
|
65
|
+
|
66
|
+
t
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|