librex 0.0.32 → 0.0.33

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,10 +1,13 @@
1
1
  ##
2
- # $Id: entry.rb 11173 2010-11-30 03:52:46Z egypt $
2
+ # $Id: entry.rb 12718 2011-05-25 16:45:20Z egypt $
3
3
  ##
4
4
 
5
5
  module Rex
6
6
  module Zip
7
7
 
8
+ #
9
+ # An Entry represents a logical file or directory to be stored in an Archive
10
+ #
8
11
  class Entry
9
12
 
10
13
  attr_accessor :name, :flags, :info, :xtra, :comment, :attrs
@@ -38,6 +41,10 @@ class Entry
38
41
  compress
39
42
  end
40
43
 
44
+ #
45
+ # Compress the #data and store it for later use. If this entry's compression method
46
+ # produces a larger blob than the original data, the method is changed to CM_STORE.
47
+ #
41
48
  def compress
42
49
  @crc = Zlib.crc32(@data, 0)
43
50
  case @flags.compmeth
@@ -73,6 +80,9 @@ class Entry
73
80
  end
74
81
 
75
82
 
83
+ #
84
+ # Return the compressed data in a format suitable for adding to an Archive
85
+ #
76
86
  def pack
77
87
  ret = ''
78
88
 
@@ -0,0 +1,224 @@
1
+
2
+ require 'rex/zip/archive'
3
+
4
+ module Rex
5
+ module Zip
6
+
7
+ #
8
+ # A Jar is a zip archive containing Java class files and a MANIFEST.MF listing
9
+ # those classes. Several variations exist based on the same idea of class
10
+ # files inside a zip, most notably:
11
+ # - WAR files store XML files, Java classes, JSPs and other stuff for
12
+ # servlet-based webservers (e.g.: Tomcat and Glassfish)
13
+ # - APK files are Android Package files
14
+ #
15
+ class Jar < Archive
16
+ attr_accessor :manifest
17
+
18
+ #
19
+ # Create a MANIFEST.MF file based on the current Archive#entries.
20
+ #
21
+ # See http://download.oracle.com/javase/1.4.2/docs/guide/jar/jar.html for
22
+ # some explanation of the format.
23
+ #
24
+ # Example MANIFEST.MF
25
+ # Manifest-Version: 1.0
26
+ # Main-Class: metasploit.Payload
27
+ #
28
+ # Name: metasploit.dat
29
+ # SHA1-Digest: WJ7cUVYUryLKfQFmH80/ADfKmwM=
30
+ #
31
+ # Name: metasploit/Payload.class
32
+ # SHA1-Digest: KbAIMttBcLp1zCewA2ERYkcnRU8=
33
+ #
34
+ # The SHA1-Digest lines are optional unless the jar is signed (see #sign).
35
+ #
36
+ def build_manifest(opts={})
37
+ main_class = opts[:main_class] || nil
38
+ existing_manifest = nil
39
+
40
+ @manifest = "Manifest-Version: 1.0\r\n"
41
+ @manifest << "Main-Class: #{main_class}\r\n" if main_class
42
+ @manifest << "\r\n"
43
+ @entries.each { |e|
44
+ next if e.name =~ %r|/$|
45
+ if e.name == "META-INF/MANIFEST.MF"
46
+ existing_manifest = e
47
+ next
48
+ end
49
+ #next unless e.name =~ /\.class$/
50
+ @manifest << "Name: #{e.name}\r\n"
51
+ #@manifest << "SHA1-Digest: #{Digest::SHA1.base64digest(e.data)}\r\n"
52
+ @manifest << "\r\n"
53
+ }
54
+ if existing_manifest
55
+ existing_manifest.data = @manifest
56
+ else
57
+ add_file("META-INF/", '')
58
+ add_file("META-INF/MANIFEST.MF", @manifest)
59
+ end
60
+ end
61
+
62
+ def to_s
63
+ pack
64
+ end
65
+
66
+ #
67
+ # Length of the *compressed* blob
68
+ #
69
+ def length
70
+ pack.length
71
+ end
72
+
73
+ #
74
+ # Add multiple files from an array
75
+ #
76
+ # +files+ should be structured like so:
77
+ # [
78
+ # [ "path", "to", "file1" ],
79
+ # [ "path", "to", "file2" ]
80
+ # ]
81
+ # and +path+ should be the location on the file system to find the files to
82
+ # add. +base_dir+ will be prepended to the path inside the jar.
83
+ #
84
+ # Example:
85
+ # war = Rex::Zip::Jar.new
86
+ # war.add_file("WEB-INF/", '')
87
+ # war.add_file("WEB-INF/web.xml", web_xml)
88
+ # war.add_file("WEB-INF/classes/", '')
89
+ # files = [
90
+ # [ "servlet", "examples", "HelloWorld.class" ],
91
+ # [ "Foo.class" ],
92
+ # [ "servlet", "Bar.class" ],
93
+ # ]
94
+ # war.add_files(files, "./class_files/", "WEB-INF/classes/")
95
+ #
96
+ # The above code would create a jar with the following structure from files
97
+ # found in ./class_files/ :
98
+ #
99
+ # +- WEB-INF/
100
+ # +- web.xml
101
+ # +- classes/
102
+ # +- Foo.class
103
+ # +- servlet/
104
+ # +- Bar.class
105
+ # +- examples/
106
+ # +- HelloWorld.class
107
+ #
108
+ def add_files(files, path, base_dir="")
109
+ files.each do |file|
110
+ # Add all of the subdirectories if they don't already exist
111
+ 1.upto(file.length - 1) do |idx|
112
+ full = base_dir + file[0,idx].join("/") + "/"
113
+ if !(entries.map{|e|e.name}.include?(full))
114
+ add_file(full, '')
115
+ end
116
+ end
117
+ # Now add the actual file, grabbing data from the filesystem
118
+ fd = File.open(File.join( path, file ), "rb")
119
+ data = fd.read(fd.stat.size)
120
+ fd.close
121
+ add_file(base_dir + file.join("/"), data)
122
+ end
123
+ end
124
+
125
+ #
126
+ # Add a signature to this jar given a +key+ and a +cert+. +cert+ should be
127
+ # an instance of OpenSSL::X509::Certificate and +key+ is expected to be an
128
+ # instance of one of OpenSSL::PKey::DSA or OpenSSL::PKey::RSA.
129
+ #
130
+ # This method aims to create signature files compatible with the jarsigner
131
+ # tool destributed with the JDK and any JVM should accept the resulting
132
+ # jar.
133
+ #
134
+ # === Signature contents
135
+ # Modifies the META-INF/MANIFEST.MF entry adding SHA1-Digest attributes in
136
+ # each Name section. The signature consists of two files, a .SF and a .DSA
137
+ # (or .RSA if signing with an RSA key). The .SF file is similar to the
138
+ # manifest with Name sections but the SHA1-Digest is not optional. The
139
+ # difference is in what gets hashed for the SHA1-Digest line -- in the
140
+ # manifest, it is the file's contents, in the .SF, it is the file's section
141
+ # in the manifest (including trailing newline!). The .DSA/.RSA file is a
142
+ # PKCS7 signature of the .SF file contents.
143
+ #
144
+ # === Links
145
+ # A short description of the format:
146
+ # http://download.oracle.com/javase/1.4.2/docs/guide/jar/jar.html#Signed%20JAR%20File
147
+ #
148
+ # Some info on importing a private key into a keystore which is not
149
+ # directly supported by keytool for some unfathomable reason
150
+ # http://www.agentbob.info/agentbob/79-AB.html
151
+ #
152
+ def sign(key, cert)
153
+ m = self.entries.find { |e| e.name == "META-INF/MANIFEST.MF" }
154
+ raise RuntimeError.new("Jar has no manifest") unless m
155
+ new_manifest = ''
156
+ sigdata = "Signature-Version: 1.0\r\n"
157
+ sigdata << "Created-By: 1.6.0_18 (Sun Microsystems Inc.)\r\n"
158
+ sigdata << "\r\n"
159
+
160
+ # Grab the sections of the manifest
161
+ files = m.data.split(/\r?\n\r?\n/)
162
+ if files[0] =~ /Manifest-Version/
163
+ # keep the header as is
164
+ new_manifest << files[0]
165
+ new_manifest << "\r\n\r\n"
166
+ files = files[1,files.length]
167
+ end
168
+
169
+ # The file sections should now look like this:
170
+ # "Name: metasploit/Payload.class\r\nSHA1-Digest: KbAIMttBcLp1zCewA2ERYkcnRU8=\r\n\r\n"
171
+ files.each do |f|
172
+ next unless f =~ /Name: (.*)/
173
+ name = $1
174
+ e = self.entries.find { |e| e.name == name }
175
+ if e
176
+ digest = OpenSSL::Digest::SHA1.digest(e.data)
177
+ manifest_section = "Name: #{name}\r\n"
178
+ manifest_section << "SHA1-Digest: #{[digest].pack('m').strip}\r\n"
179
+ manifest_section << "\r\n"
180
+
181
+ manifest_digest = OpenSSL::Digest::SHA1.digest(manifest_section)
182
+
183
+ sigdata << "Name: #{name}\r\n"
184
+ sigdata << "SHA1-Digest: #{[manifest_digest].pack('m')}\r\n"
185
+ new_manifest << manifest_section
186
+ end
187
+ end
188
+
189
+ # Now overwrite with the new manifest
190
+ m.data = new_manifest
191
+
192
+ flags = 0
193
+ flags |= OpenSSL::PKCS7::BINARY
194
+ flags |= OpenSSL::PKCS7::DETACHED
195
+ # SMIME and ATTRs are technically valid in the signature but they both
196
+ # screw up the java verifier, so don't include them.
197
+ flags |= OpenSSL::PKCS7::NOSMIMECAP
198
+ flags |= OpenSSL::PKCS7::NOATTR
199
+
200
+ signature = OpenSSL::PKCS7.sign(cert, key, sigdata, [cert], flags)
201
+ sigalg = case key
202
+ when OpenSSL::PKey::RSA; "RSA"
203
+ when OpenSSL::PKey::DSA; "DSA"
204
+ # Don't really know what to do if it's not DSA or RSA. Can
205
+ # OpenSSL::PKCS7 actually sign stuff with it in that case?
206
+ # Regardless, the java spec says signatures can only be RSA, DSA,
207
+ # or PGP, so just assume it's PGP and hope for the best
208
+ else; "PGP"
209
+ end
210
+
211
+ # SIGNFILE is the default name in documentation. MYKEY is probably
212
+ # more common, though because that's what keytool defaults to. We can
213
+ # probably randomize this with no ill effects.
214
+ add_file("META-INF/SIGNFILE.SF", sigdata)
215
+ add_file("META-INF/SIGNFILE.#{sigalg}", signature.to_der)
216
+
217
+ return true
218
+ end
219
+
220
+ end
221
+
222
+ end
223
+ end
224
+
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: librex
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.32
5
+ version: 0.0.33
6
6
  platform: ruby
7
7
  authors:
8
8
  - Metasploit Development Team
@@ -11,11 +11,11 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2011-05-13 00:00:00 -05:00
14
+ date: 2011-05-25 00:00:00 -05:00
15
15
  default_executable:
16
16
  dependencies: []
17
17
 
18
- description: Rex provides a variety of classes useful for security testing and exploit development. Based on SVN Revision 12612
18
+ description: Rex provides a variety of classes useful for security testing and exploit development. Based on SVN Revision 12724
19
19
  email:
20
20
  - hdm@metasploit.com
21
21
  - jacob.hammack@hammackj.com
@@ -107,6 +107,7 @@ files:
107
107
  - lib/rex/io/bidirectional_pipe.rb
108
108
  - lib/rex/io/datagram_abstraction.rb
109
109
  - lib/rex/io/ring_buffer.rb
110
+ - lib/rex/io/ring_buffer.rb.ut.rb
110
111
  - lib/rex/io/stream.rb
111
112
  - lib/rex/io/stream_abstraction.rb
112
113
  - lib/rex/io/stream_server.rb
@@ -159,7 +160,9 @@ files:
159
160
  - lib/rex/parser/nessus_xml.rb
160
161
  - lib/rex/parser/netsparker_xml.rb
161
162
  - lib/rex/parser/nexpose_xml.rb
163
+ - lib/rex/parser/nmap_nokogiri.rb
162
164
  - lib/rex/parser/nmap_xml.rb
165
+ - lib/rex/parser/nokogiri_doc_mixin.rb
163
166
  - lib/rex/parser/retina_xml.rb
164
167
  - lib/rex/payloads/win32/common.rb
165
168
  - lib/rex/payloads/win32/kernel/common.rb
@@ -242,8 +245,10 @@ files:
242
245
  - lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb.ut.rb
243
246
  - lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb
244
247
  - lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb.ut.rb
248
+ - lib/rex/post/meterpreter/extensions/stdapi/railgun/mock_magic.rb
245
249
  - lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb
246
250
  - lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb
251
+ - lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb.ut.rb
247
252
  - lib/rex/post/meterpreter/extensions/stdapi/railgun/tlv.rb
248
253
  - lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb
249
254
  - lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb
@@ -458,6 +463,7 @@ files:
458
463
  - lib/rex/zip/archive.rb
459
464
  - lib/rex/zip/blocks.rb
460
465
  - lib/rex/zip/entry.rb
466
+ - lib/rex/zip/jar.rb
461
467
  - lib/rex/zip/samples/comment.rb
462
468
  - lib/rex/zip/samples/mkwar.rb
463
469
  - lib/rex/zip/samples/mkzip.rb