Skip to content

Commit 471ac6d

Browse files
committed
Use typed_enable?(type) instead of protected enablement_by_type[type]
Msf::Modules::Loader::Archive#each_module_reference_name tried to check the enabled types for the module_manager by accessing the enabledment_by_type Hash, which is protected. Instead, it should use the public type_enabled? method. Add specs to test all of Msf::Modules::Loader::Archive while testing each_module_reference_name. In order to properly test that modules could be found in archives, I had to produce a fastlib archive, so there is now a spec for FastLib.dump and FastLib.load. Some specs are marked pending as I found a bug in FastLib, which has a work-around. The bug is filed in PivotalTracker as https://www.pivotaltracker.com/story/show/38730815 and the pending tests include the URL also in their tags.
1 parent 6c11b87 commit 471ac6d

File tree

5 files changed

+527
-6
lines changed

5 files changed

+527
-6
lines changed

lib/fastlib.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,14 @@ def self.fastlib_filter_encode(lib, buff)
182182
end
183183

184184

185+
# This method provides a way to create a FASTLIB archive programatically.
185186
#
186-
# This method provides a way to create a FASTLIB archive programatically,
187-
# the key arguments are the name of the destination archive, the base
188-
# directory that should be excluded from the archived path, and finally
189-
# the list of specific files and directories to include in the archive.
190-
#
187+
# @param [String] lib the output path for the archive
188+
# @param [String] flag a string containing the hex values for the flags ({FLAG_COMPRESS} and {FLAG_ENCRYPT}).
189+
# @param [String] bdir the path to the base directory which will be stripped from all paths included in the archive
190+
# @param [Array<String>] dirs list of directories/files to pack into the archive. All dirs should be under bdir so
191+
# that the paths are stripped correctly.
192+
# @return [void]
191193
def self.dump(lib, flag, bdir, *dirs)
192194
head = ""
193195
data = ""

lib/msf/core/modules/loader/archive.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def each_module_reference_name(path)
4141
type = entry.split('/', 2)[0]
4242
type = type.singularize
4343

44-
unless module_manager.enablement_by_type[type]
44+
unless module_manager.type_enabled?(type)
4545
next
4646
end
4747

spec/lib/fastlib_spec.rb

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
require 'spec_helper'
2+
3+
require 'msf/core'
4+
5+
describe FastLib do
6+
let(:archived_paths) do
7+
[
8+
File.join('auxiliary', 'scanner', 'portscan', 'xmas.rb'),
9+
File.join('exploits', 'windows', 'smb', 'ms08_067_netapi.rb')
10+
]
11+
end
12+
13+
let(:base_path) do
14+
File.join(Msf::Config.install_root, 'modules')
15+
end
16+
17+
let(:extension) do
18+
'.fastlib'
19+
end
20+
21+
let(:flag_compress) do
22+
0x01
23+
end
24+
25+
let(:flag_encrypt) do
26+
0x02
27+
end
28+
29+
let(:unarchived_paths) do
30+
archived_paths.collect { |archived_path|
31+
File.join(base_path, archived_path)
32+
}
33+
end
34+
35+
context 'CONSTANTS' do
36+
context 'flags' do
37+
it 'should have compression' do
38+
described_class::FLAG_COMPRESS.should == flag_compress
39+
end
40+
41+
it 'should have encryption' do
42+
described_class::FLAG_ENCRYPT.should == flag_encrypt
43+
end
44+
end
45+
end
46+
47+
context 'class methods' do
48+
context 'dump' do
49+
let(:flag_string) do
50+
flags.to_s(16)
51+
end
52+
53+
before(:each) do
54+
FastLib.cache.clear
55+
end
56+
57+
around(:each) do |example|
58+
Dir.mktmpdir do |directory|
59+
@destination_path = File.join(directory, "rspec#{extension}")
60+
61+
example.run
62+
end
63+
end
64+
65+
context 'without compression and without encryption' do
66+
let(:flags) do
67+
0x0
68+
end
69+
70+
it 'should create an archive' do
71+
File.exist?(@destination_path).should be_false
72+
73+
described_class.dump(@destination_path, flag_string, base_path, *unarchived_paths)
74+
75+
File.exist?(@destination_path).should be_true
76+
end
77+
78+
context 'cache' do
79+
it 'should populate' do
80+
FastLib.cache[@destination_path].should be_nil
81+
82+
described_class.dump(@destination_path, flag_string, base_path, *unarchived_paths)
83+
84+
FastLib.cache[@destination_path].should be_a Hash
85+
end
86+
87+
it 'should include flags' do
88+
described_class.dump(@destination_path, flag_string, base_path, *unarchived_paths)
89+
90+
FastLib.cache[@destination_path][:fastlib_flags].should == flags
91+
end
92+
93+
pending "Fix https://www.pivotaltracker.com/story/show/38730815" do
94+
it 'should include header' do
95+
described_class.dump(@destination_path, flag_string, base_path, *unarchived_paths)
96+
header = FastLib.cache[@destination_path][:fastlib_header]
97+
modification_time = File.mtime(@destination_path).utc.to_i
98+
99+
header.should be_a Array
100+
# @todo figure out why 12 before header length
101+
header[0].should == 12
102+
# @todo figure out why header length is 0
103+
header[1].should == 0
104+
header[2].should == modification_time
105+
end
106+
107+
it 'should include archived paths' do
108+
described_class.dump(@destination_path, flag_string, base_path, *unarchived_paths)
109+
cache = FastLib.cache[@destination_path]
110+
111+
archived_path = File.join('exploits', 'windows', 'smb', 'ms08_067_netapi.rb')
112+
unarchived_path = File.join(base_path, archived_path)
113+
114+
# make sure that the unarchived module exists and hasn't be deleted or renamed before expecting it to be
115+
# in the archive.
116+
File.exist?(unarchived_path).should be_true
117+
cache[archived_path].should_not be_nil
118+
end
119+
end
120+
end
121+
end
122+
123+
context 'with compression and without encryption' do
124+
let(:flags) do
125+
flag_compress
126+
end
127+
128+
it 'should create an archive' do
129+
File.exist?(@destination_path).should be_false
130+
131+
described_class.dump(@destination_path, flag_string, base_path, *unarchived_paths)
132+
133+
File.exist?(@destination_path).should be_true
134+
end
135+
136+
it 'should be smaller than the uncompressed archive' do
137+
uncompressed_path = "#{@destination_path}.uncompressed"
138+
compressed_path = "#{@destination_path}.compressed"
139+
140+
File.exist?(uncompressed_path).should be_false
141+
File.exist?(compressed_path).should be_false
142+
143+
described_class.dump(uncompressed_path, '', base_path, *unarchived_paths)
144+
described_class.dump(compressed_path, flag_string, base_path, *unarchived_paths)
145+
146+
File.exist?(uncompressed_path).should be_true
147+
File.exist?(compressed_path).should be_true
148+
149+
File.size(compressed_path).should < File.size(uncompressed_path)
150+
end
151+
end
152+
153+
context 'without compression and with encryption' do
154+
let(:flags) do
155+
flag_encrypt
156+
end
157+
158+
it 'should create an archive' do
159+
File.exist?(@destination_path).should be_false
160+
161+
described_class.dump(@destination_path, flag_string, base_path, *unarchived_paths)
162+
163+
File.exist?(@destination_path).should be_true
164+
end
165+
end
166+
167+
context 'with compression and with encryption' do
168+
let(:flags) do
169+
flag_compress | flag_encrypt
170+
end
171+
172+
it 'should create an archive' do
173+
File.exist?(@destination_path).should be_false
174+
175+
described_class.dump(@destination_path, flag_string, base_path, *unarchived_paths)
176+
177+
File.exist?(@destination_path).should be_true
178+
end
179+
end
180+
end
181+
182+
context 'list' do
183+
around(:each) do |example|
184+
Dir.mktmpdir do |directory|
185+
@destination_path = File.join(directory, "rspec#{extension}")
186+
187+
FastLib.dump(@destination_path, FastLib::FLAG_COMPRESS.to_s, base_path, *unarchived_paths)
188+
189+
example.run
190+
end
191+
end
192+
193+
# ensure modules expected to be listed actually exist
194+
it 'should use existent unarchived modules' do
195+
unarchived_paths.each do |unarchived_path|
196+
File.exist?(unarchived_path).should be_true
197+
end
198+
end
199+
200+
context 'with cached dump', :pending => "Fix https://www.pivotaltracker.com/story/show/38730815" do
201+
it 'should have dump cached' do
202+
FastLib.cache[@destination_path].should_not be_nil
203+
end
204+
205+
it 'should list archived paths' do
206+
paths = FastLib.list(@destination_path)
207+
208+
paths.length.should == archived_paths.length
209+
paths.should == archived_paths
210+
end
211+
end
212+
213+
context 'without cached dump' do
214+
before(:each) do
215+
FastLib.cache.clear
216+
end
217+
218+
it 'should not have dump cache' do
219+
FastLib.cache[@destination_path].should be_nil
220+
end
221+
222+
it 'should list archived paths' do
223+
paths = FastLib.list(@destination_path)
224+
225+
paths.length.should == archived_paths.length
226+
paths.should == archived_paths
227+
end
228+
end
229+
end
230+
end
231+
end

0 commit comments

Comments
 (0)