librex 0.0.5 → 0.0.6
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.
- data/README.md +1 -1
- data/Rakefile +13 -0
- data/lib/rex.rb +4 -1
- data/lib/rex/assembly/nasm.rb +4 -0
- data/lib/rex/compat.rb +31 -1
- data/lib/rex/encoder/alpha2/generic.rb +11 -10
- data/lib/rex/exceptions.rb +1 -1
- data/lib/rex/exploitation/egghunter.rb +27 -0
- data/lib/rex/file.rb +13 -0
- data/lib/rex/io/stream.rb +9 -1
- data/lib/rex/io/stream_abstraction.rb +18 -7
- data/lib/rex/io/stream_server.rb +2 -2
- data/lib/rex/job_container.rb +1 -1
- data/lib/rex/mime/message.rb +5 -4
- data/lib/rex/ole.rb +83 -6
- data/lib/rex/ole/propset.rb +144 -0
- data/lib/rex/parser/ip360_aspl_xml.rb +102 -0
- data/lib/rex/parser/ip360_xml.rb +93 -0
- data/lib/rex/parser/nessus_xml.rb +118 -0
- data/lib/rex/parser/netsparker_xml.rb +94 -0
- data/lib/rex/parser/retina_xml.rb +109 -0
- data/lib/rex/post/meterpreter/channel.rb +15 -8
- data/lib/rex/post/meterpreter/client.rb +32 -3
- data/lib/rex/post/meterpreter/extensions/sniffer/sniffer.rb +1 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +14 -5
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +1 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb +3 -3
- data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb +1 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb +1 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +5 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log.rb +16 -8
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +16 -7
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/image.rb +1 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +15 -4
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/thread.rb +13 -7
- data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +20 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/webcam/webcam.rb +63 -0
- data/lib/rex/post/meterpreter/packet_dispatcher.rb +18 -7
- data/lib/rex/post/meterpreter/packet_response_waiter.rb +10 -17
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +1 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/networkpug.rb +16 -6
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/sniffer.rb +4 -5
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi.rb +2 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +4 -2
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/webcam.rb +157 -0
- data/lib/rex/proto/dhcp/server.rb +8 -4
- data/lib/rex/proto/http/client.rb +19 -45
- data/lib/rex/proto/http/packet.rb +8 -5
- data/lib/rex/proto/http/response.rb +8 -3
- data/lib/rex/proto/http/server.rb +1 -1
- data/lib/rex/proto/proxy/socks4a.rb +4 -4
- data/lib/rex/proto/rfb.rb +19 -0
- data/lib/rex/proto/rfb.rb.ut.rb +37 -0
- data/lib/rex/proto/rfb/cipher.rb +78 -0
- data/lib/rex/proto/rfb/client.rb +207 -0
- data/lib/rex/proto/rfb/constants.rb +52 -0
- data/lib/rex/proto/tftp/server.rb +20 -17
- data/lib/rex/services/local_relay.rb +1 -1
- data/lib/rex/socket.rb +69 -10
- data/lib/rex/socket/comm/local.rb +7 -4
- data/lib/rex/socket/range_walker.rb +14 -1
- data/lib/rex/text.rb +28 -3
- data/lib/rex/text.rb.ut.rb +14 -0
- data/lib/rex/thread_factory.rb +42 -0
- data/lib/rex/ui/text/input/buffer.rb +1 -1
- data/lib/rex/zip/archive.rb +74 -9
- data/lib/rex/zip/entry.rb +6 -1
- metadata +22 -7
data/lib/rex/socket.rb
CHANGED
@@ -138,9 +138,31 @@ module Socket
|
|
138
138
|
# These calls can be quite slow. This also fixes an issue with the
|
139
139
|
# Resolv.getaddress() call being non-functional on Ruby 1.9.1 (Win32).
|
140
140
|
#
|
141
|
-
def self.getaddress(addr)
|
141
|
+
def self.getaddress(addr, accept_ipv6 = true)
|
142
142
|
begin
|
143
|
-
|
143
|
+
|
144
|
+
if dotted_ip?(addr)
|
145
|
+
return addr
|
146
|
+
end
|
147
|
+
|
148
|
+
res = ::Socket.gethostbyname(addr)
|
149
|
+
return nil if not res
|
150
|
+
|
151
|
+
# Shift the first three elements out
|
152
|
+
rname = res.shift
|
153
|
+
ralias = res.shift
|
154
|
+
rtype = res.shift
|
155
|
+
|
156
|
+
# Reject IPv6 addresses if we don't accept them
|
157
|
+
if not accept_ipv6
|
158
|
+
res.reject!{|nbo| nbo.length != 4}
|
159
|
+
end
|
160
|
+
|
161
|
+
# Make sure we have at least one name
|
162
|
+
return nil if res.length == 0
|
163
|
+
|
164
|
+
# Return the first address of the result
|
165
|
+
self.addr_ntoa( res[0] )
|
144
166
|
rescue ::ArgumentError # Win32 bug
|
145
167
|
nil
|
146
168
|
end
|
@@ -441,7 +463,14 @@ module Socket
|
|
441
463
|
#
|
442
464
|
##
|
443
465
|
|
444
|
-
|
466
|
+
#
|
467
|
+
# This method does NOT send any traffic to the destination, instead, it uses a
|
468
|
+
# "bound" UDP socket to determine what source address we would use to
|
469
|
+
# communicate with the specified destination. The destination defaults to
|
470
|
+
# Google's DNS server to make the standard behavior determine which IP
|
471
|
+
# we would use to communicate with the internet.
|
472
|
+
#
|
473
|
+
def self.source_address(dest='8.8.8.8', comm = ::Rex::Socket::Comm::Local)
|
445
474
|
begin
|
446
475
|
s = self.create_udp(
|
447
476
|
'PeerHost' => dest,
|
@@ -450,11 +479,32 @@ module Socket
|
|
450
479
|
)
|
451
480
|
r = s.getsockname[1]
|
452
481
|
s.close
|
453
|
-
|
482
|
+
|
483
|
+
# Trim off the trailing interface ID for link-local IPv6
|
484
|
+
return r.split('%').first
|
454
485
|
rescue ::Exception
|
455
486
|
return '127.0.0.1'
|
456
487
|
end
|
457
488
|
end
|
489
|
+
|
490
|
+
#
|
491
|
+
# Identifies the link-local address of a given interface (if IPv6 is enabled)
|
492
|
+
#
|
493
|
+
def self.ipv6_link_address(intf)
|
494
|
+
r = source_address("FF02::1%#{intf}")
|
495
|
+
return if not (r and r =~ /^fe80/i)
|
496
|
+
r
|
497
|
+
end
|
498
|
+
|
499
|
+
#
|
500
|
+
# Identifies the mac address of a given interface (if IPv6 is enabled)
|
501
|
+
#
|
502
|
+
def self.ipv6_mac(intf)
|
503
|
+
r = ipv6_link_address(intf)
|
504
|
+
return if not r
|
505
|
+
raw = addr_aton(r)[-8, 8]
|
506
|
+
(raw[0,3] + raw[5,3]).unpack("C*").map{|c| "%.2x" % c}.join(":")
|
507
|
+
end
|
458
508
|
|
459
509
|
#
|
460
510
|
# Create a TCP socket pair.
|
@@ -463,6 +513,8 @@ module Socket
|
|
463
513
|
# on Windows where ::Socket.pair is not implemented.
|
464
514
|
# Note: OpenSSL requires native ruby sockets for its io.
|
465
515
|
#
|
516
|
+
# Note: Even though sub-threads are smashing the parent threads local, there
|
517
|
+
# is no concurrent use of the same locals and this is safe.
|
466
518
|
def self.tcp_socket_pair
|
467
519
|
lsock = nil
|
468
520
|
rsock = nil
|
@@ -471,18 +523,25 @@ module Socket
|
|
471
523
|
threads = []
|
472
524
|
mutex = ::Mutex.new
|
473
525
|
|
474
|
-
threads << ::
|
526
|
+
threads << Rex::ThreadFactory.spawn('TcpSocketPair', false) {
|
475
527
|
server = nil
|
476
528
|
mutex.synchronize {
|
477
|
-
threads << ::
|
529
|
+
threads << Rex::ThreadFactory.spawn('TcpSocketPairClient', false) {
|
478
530
|
mutex.synchronize {
|
479
531
|
rsock = ::TCPSocket.new( laddr, lport )
|
480
532
|
}
|
481
533
|
}
|
482
|
-
server = ::
|
483
|
-
server.
|
484
|
-
|
485
|
-
|
534
|
+
server = ::TCPServer.new(laddr, 0)
|
535
|
+
if (server.getsockname =~ /127\.0\.0\.1:/)
|
536
|
+
# JRuby ridiculousness
|
537
|
+
caddr, lport = server.getsockname.split(":")
|
538
|
+
caddr = caddr[1,caddr.length]
|
539
|
+
lport = lport.to_i
|
540
|
+
else
|
541
|
+
# Sane implementations where Socket#getsockname returns a
|
542
|
+
# sockaddr
|
543
|
+
lport, caddr = ::Socket.unpack_sockaddr_in( server.getsockname )
|
544
|
+
end
|
486
545
|
}
|
487
546
|
lsock, saddr = server.accept
|
488
547
|
server.close
|
@@ -193,7 +193,7 @@ class Rex::Socket::Comm::Local
|
|
193
193
|
|
194
194
|
sock.bind(Rex::Socket.to_sockaddr(param.localhost, param.localport))
|
195
195
|
|
196
|
-
rescue Errno::EADDRINUSE
|
196
|
+
rescue ::Errno::EADDRNOTAVAIL,::Errno::EADDRINUSE
|
197
197
|
sock.close
|
198
198
|
raise Rex::AddressInUse.new(param.localhost, param.localport), caller
|
199
199
|
end
|
@@ -206,7 +206,7 @@ class Rex::Socket::Comm::Local
|
|
206
206
|
|
207
207
|
# If a server TCP instance is being created...
|
208
208
|
if (param.server?)
|
209
|
-
sock.listen(
|
209
|
+
sock.listen(128)
|
210
210
|
|
211
211
|
if (param.bare? == false)
|
212
212
|
klass = Rex::Socket::TcpServer
|
@@ -242,10 +242,14 @@ class Rex::Socket::Comm::Local
|
|
242
242
|
raise ::Errno::ETIMEDOUT
|
243
243
|
end
|
244
244
|
|
245
|
-
rescue ::Errno::EHOSTUNREACH,::Errno::ENETDOWN,::Errno::ENETUNREACH,::Errno::ENETRESET,::Errno::EHOSTDOWN,::Errno::EACCES,::Errno::EINVAL
|
245
|
+
rescue ::Errno::EHOSTUNREACH,::Errno::ENETDOWN,::Errno::ENETUNREACH,::Errno::ENETRESET,::Errno::EHOSTDOWN,::Errno::EACCES,::Errno::EINVAL
|
246
246
|
sock.close
|
247
247
|
raise Rex::HostUnreachable.new(param.peerhost, param.peerport), caller
|
248
248
|
|
249
|
+
rescue ::Errno::EADDRNOTAVAIL,::Errno::EADDRINUSE
|
250
|
+
sock.close
|
251
|
+
raise Rex::AddressInUse.new(param.peerhost, param.peerport), caller
|
252
|
+
|
249
253
|
rescue Errno::ETIMEDOUT
|
250
254
|
sock.close
|
251
255
|
raise Rex::ConnectionTimeout.new(param.peerhost, param.peerport), caller
|
@@ -406,4 +410,3 @@ class Rex::Socket::Comm::Local
|
|
406
410
|
end
|
407
411
|
|
408
412
|
end
|
409
|
-
|
@@ -150,13 +150,26 @@ class RangeWalker
|
|
150
150
|
addr = Rex::Socket.addr_atoi(addr)
|
151
151
|
end
|
152
152
|
@ranges.map { |r|
|
153
|
-
if r
|
153
|
+
if r[0] <= addr and addr <= r[1]
|
154
154
|
return true
|
155
155
|
end
|
156
156
|
}
|
157
157
|
return false
|
158
158
|
end
|
159
159
|
|
160
|
+
#
|
161
|
+
# Returns true if this RangeWalker includes all of the addresses in the
|
162
|
+
# given RangeWalker
|
163
|
+
#
|
164
|
+
def include_range?(range_walker)
|
165
|
+
range_walker.ranges.all? do |start, stop|
|
166
|
+
ranges.any? do |self_start, self_stop|
|
167
|
+
r = (self_start..self_stop)
|
168
|
+
r.include?(start) and r.include?(stop)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
160
173
|
#
|
161
174
|
# Calls the given block with each address
|
162
175
|
#
|
data/lib/rex/text.rb
CHANGED
@@ -760,13 +760,15 @@ module Text
|
|
760
760
|
# Make sure there's something in sets even if we were given an explicit nil
|
761
761
|
sets ||= [ UpperAlpha, LowerAlpha, Numerals ]
|
762
762
|
|
763
|
+
# Return stupid uses
|
764
|
+
return "" if length.to_i < 1
|
765
|
+
return sets[0][0] * length if sets.size == 1 and sets[0].size == 1
|
766
|
+
|
763
767
|
sets.length.times { offsets << 0 }
|
764
768
|
|
765
769
|
until buf.length >= length
|
766
770
|
begin
|
767
771
|
buf << converge_sets(sets, 0, offsets, length)
|
768
|
-
rescue RuntimeError
|
769
|
-
break
|
770
772
|
end
|
771
773
|
end
|
772
774
|
|
@@ -778,6 +780,28 @@ module Text
|
|
778
780
|
buf[0,length]
|
779
781
|
end
|
780
782
|
|
783
|
+
# Step through an arbitrary number of sets of bytes to build up a findable pattern.
|
784
|
+
# This is mostly useful for experimentially determining offset lengths into memory
|
785
|
+
# structures. Note that the supplied sets should never contain duplicate bytes, or
|
786
|
+
# else it can become impossible to measure the offset accurately.
|
787
|
+
def self.patt2(len, sets = nil)
|
788
|
+
buf = ""
|
789
|
+
counter = []
|
790
|
+
sets ||= [ UpperAlpha, LowerAlpha, Numerals ]
|
791
|
+
len ||= len.to_i
|
792
|
+
return "" if len.zero?
|
793
|
+
|
794
|
+
sets = sets.map {|a| a.split(//)}
|
795
|
+
sets.size.times { counter << 0}
|
796
|
+
0.upto(len-1) do |i|
|
797
|
+
setnum = i % sets.size
|
798
|
+
|
799
|
+
puts counter.inspect
|
800
|
+
end
|
801
|
+
|
802
|
+
return buf
|
803
|
+
end
|
804
|
+
|
781
805
|
#
|
782
806
|
# Calculate the offset to a pattern
|
783
807
|
#
|
@@ -1029,8 +1053,9 @@ protected
|
|
1029
1053
|
# If we reached the point where the idx fell below zero, then that
|
1030
1054
|
# means we've reached the maximum threshold for permutations.
|
1031
1055
|
if (idx < 0)
|
1032
|
-
|
1056
|
+
return buf
|
1033
1057
|
end
|
1058
|
+
|
1034
1059
|
end
|
1035
1060
|
|
1036
1061
|
buf
|
data/lib/rex/text.rb.ut.rb
CHANGED
@@ -7,6 +7,20 @@ require 'rex/text'
|
|
7
7
|
require 'rex/exceptions'
|
8
8
|
class Rex::Text::UnitTest < Test::Unit::TestCase
|
9
9
|
|
10
|
+
def test_pattern_create
|
11
|
+
set1 = %w{AB ab 12}
|
12
|
+
assert_equal 'Aa1Aa2', Rex::Text.pattern_create(6,set1)
|
13
|
+
set2 = %w{ABC abc 123}
|
14
|
+
assert_equal 'Aa1Aa2Aa3Ab1Ab2Ab3', Rex::Text.pattern_create(18,set2)
|
15
|
+
assert_equal 'Zz8Zz9', Rex::Text.pattern_create(20280)[-6,6] # Bug #2952
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_pattern_create_silly
|
19
|
+
assert_equal "", Rex::Text.pattern_create(nil)
|
20
|
+
assert_equal "", Rex::Text.pattern_create(0)
|
21
|
+
assert_equal 'AAAAAAAAA', Rex::Text.pattern_create(9,['A'])
|
22
|
+
end
|
23
|
+
|
10
24
|
def test_uri_encode
|
11
25
|
srand(0)
|
12
26
|
assert_equal('A1%21', Rex::Text.uri_encode('A1!'), 'uri encode')
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Rex
|
2
|
+
|
3
|
+
###
|
4
|
+
#
|
5
|
+
# This class provides a wrapper around Thread.new that can provide
|
6
|
+
# additional features if a corresponding thread provider is set.
|
7
|
+
#
|
8
|
+
###
|
9
|
+
|
10
|
+
class ThreadFactory
|
11
|
+
|
12
|
+
@@provider = nil
|
13
|
+
|
14
|
+
def self.provider=(val)
|
15
|
+
@@provider = val
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.spawn(name, crit, *args, &block)
|
19
|
+
if @@provider
|
20
|
+
if block
|
21
|
+
return @@provider.spawn(name, crit, *args){ |*args_copy| block.call(*args_copy) }
|
22
|
+
else
|
23
|
+
return @@provider.spawn(name, crit, *args)
|
24
|
+
end
|
25
|
+
else
|
26
|
+
t = nil
|
27
|
+
if block
|
28
|
+
t = ::Thread.new(*args){ |*args_copy| block.call(*args_copy) }
|
29
|
+
else
|
30
|
+
t = ::Thread.new(*args)
|
31
|
+
end
|
32
|
+
t[:tm_name] = name
|
33
|
+
t[:tm_crit] = crit
|
34
|
+
t[:tm_time] = Time.now
|
35
|
+
t[:tm_call] = caller
|
36
|
+
return t
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/lib/rex/zip/archive.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
##
|
2
|
-
# $Id: archive.rb
|
2
|
+
# $Id: archive.rb 11175 2010-11-30 07:10:57Z egypt $
|
3
3
|
##
|
4
4
|
|
5
5
|
module Rex
|
@@ -86,6 +86,10 @@ class Archive
|
|
86
86
|
ret
|
87
87
|
end
|
88
88
|
|
89
|
+
def inspect
|
90
|
+
"#<#{self.class} entries = [#{@entries.map{|e| e.name}.join(",")}]>"
|
91
|
+
end
|
92
|
+
|
89
93
|
end
|
90
94
|
|
91
95
|
class Jar < Archive
|
@@ -93,17 +97,24 @@ class Jar < Archive
|
|
93
97
|
|
94
98
|
def build_manifest(opts={})
|
95
99
|
main_class = opts[:main_class] || nil
|
96
|
-
|
100
|
+
existing_manifest = nil
|
97
101
|
|
98
|
-
@manifest =
|
99
|
-
|
100
|
-
@manifest
|
102
|
+
@manifest = "Manifest-Version: 1.0\r\n"
|
103
|
+
@manifest << "Main-Class: #{main_class}\r\n" if main_class
|
104
|
+
@manifest << "\r\n"
|
101
105
|
@entries.each { |e|
|
102
|
-
|
103
|
-
|
106
|
+
existing_manifest = e if e.name == "META-INF/MANIFEST.MF"
|
107
|
+
next unless e.name =~ /\.class$/
|
108
|
+
@manifest << "Name: #{e.name}\r\n"
|
109
|
+
#@manifest << "SHA1-Digest: #{Digest::SHA1.base64digest(e.data)}\r\n"
|
110
|
+
@manifest << "\r\n"
|
104
111
|
}
|
105
|
-
|
106
|
-
|
112
|
+
if existing_manifest
|
113
|
+
existing_manifest.data = @manifest
|
114
|
+
else
|
115
|
+
add_file("META-INF/", '')
|
116
|
+
add_file("META-INF/MANIFEST.MF", @manifest)
|
117
|
+
end
|
107
118
|
end
|
108
119
|
|
109
120
|
def to_s
|
@@ -113,6 +124,60 @@ class Jar < Archive
|
|
113
124
|
def length
|
114
125
|
pack.length
|
115
126
|
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# Add multiple files from an array
|
130
|
+
#
|
131
|
+
# +files+ should be structured like so:
|
132
|
+
# [
|
133
|
+
# [ "path", "to", "file1" ],
|
134
|
+
# [ "path", "to", "file2" ]
|
135
|
+
# ]
|
136
|
+
# and +path+ should be the location on the file system to find the files to
|
137
|
+
# add. +base_dir+ will be prepended to the path inside the jar.
|
138
|
+
#
|
139
|
+
# Example:
|
140
|
+
# <code>
|
141
|
+
# war = Rex::Zip::Jar.new
|
142
|
+
# war.add_file("WEB-INF/", '')
|
143
|
+
# war.add_file("WEB-INF/", "web.xml", web_xml)
|
144
|
+
# war.add_file("WEB-INF/classes/", '')
|
145
|
+
# files = [
|
146
|
+
# [ "servlet", "examples", "HelloWorld.class" ],
|
147
|
+
# [ "Foo.class" ],
|
148
|
+
# [ "servlet", "Bar.class" ],
|
149
|
+
# ]
|
150
|
+
# war.add_files(files, "./class_files/", "WEB-INF/classes/")
|
151
|
+
# </code>
|
152
|
+
#
|
153
|
+
# The above code would create a jar with the following structure from files
|
154
|
+
# found in ./class_files/ :
|
155
|
+
#
|
156
|
+
# +- WEB-INF/
|
157
|
+
# +- web.xml
|
158
|
+
# +- classes/
|
159
|
+
# +- Foo.class
|
160
|
+
# +- servlet/
|
161
|
+
# +- Bar.class
|
162
|
+
# +- examples/
|
163
|
+
# +- HelloWorld.class
|
164
|
+
#
|
165
|
+
def add_files(files, path, base_dir="")
|
166
|
+
files.each do |file|
|
167
|
+
# Add all of the subdirectories if they don't already exist
|
168
|
+
1.upto(file.length - 1) do |idx|
|
169
|
+
full = base_dir + file[0,idx].join("/") + "/"
|
170
|
+
if !(entries.map{|e|e.name}.include?(full))
|
171
|
+
add_file(full, '')
|
172
|
+
end
|
173
|
+
end
|
174
|
+
# Now add the actual file, grabbing data from the filesystem
|
175
|
+
fd = File.open(File.join( path, file ), "rb")
|
176
|
+
data = fd.read(fd.stat.size)
|
177
|
+
fd.close
|
178
|
+
add_file(base_dir + file.join("/"), data)
|
179
|
+
end
|
180
|
+
end
|
116
181
|
end
|
117
182
|
|
118
183
|
end
|
data/lib/rex/zip/entry.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
##
|
2
|
-
# $Id: entry.rb
|
2
|
+
# $Id: entry.rb 11173 2010-11-30 03:52:46Z egypt $
|
3
3
|
##
|
4
4
|
|
5
5
|
module Rex
|
@@ -8,6 +8,7 @@ module Zip
|
|
8
8
|
class Entry
|
9
9
|
|
10
10
|
attr_accessor :name, :flags, :info, :xtra, :comment, :attrs
|
11
|
+
attr_reader :data
|
11
12
|
|
12
13
|
def initialize(fname, data, compmeth, timestamp=nil, attrs=nil, xtra=nil, comment=nil)
|
13
14
|
@name = fname
|
@@ -32,6 +33,10 @@ class Entry
|
|
32
33
|
@compdata ||= ''
|
33
34
|
end
|
34
35
|
|
36
|
+
def data=(val)
|
37
|
+
@data = val
|
38
|
+
compress
|
39
|
+
end
|
35
40
|
|
36
41
|
def compress
|
37
42
|
@crc = Zlib.crc32(@data, 0)
|