forked from rapid7/metasploit-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmsfvenom_spec.rb
267 lines (227 loc) · 7.1 KB
/
msfvenom_spec.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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
require 'spec_helper'
require 'msf/core'
# doesn't end in .rb or .so, so have to load instead of require
load File.join(Msf::Config.install_root, 'msfvenom')
shared_examples_for "nop dumper" do
it "should list known nops" do
%w!
x86/opty2
armle/simple
!.each do |name|
dump.should include(name)
end
end
end
shared_examples_for "encoder dumper" do
it "should list known encoders" do
%w!
generic/none
x86/shikata_ga_nai
x64/xor
!.each do |name|
dump.should include(name)
end
end
end
shared_examples_for "payload dumper" do
it "should list known payloads" do
# Just a representative sample of some of the important ones.
%w!
cmd/unix/reverse
java/meterpreter/reverse_tcp
java/meterpreter/reverse_https
linux/x86/shell/reverse_tcp
linux/x86/shell_reverse_tcp
linux/x64/shell/reverse_tcp
linux/x64/shell_reverse_tcp
linux/armle/shell/reverse_tcp
linux/armle/shell_reverse_tcp
linux/mipsbe/shell_reverse_tcp
php/meterpreter/reverse_tcp
windows/meterpreter/reverse_tcp
windows/meterpreter/reverse_https
!.each do |name|
dump.should include(name)
end
end
end
describe MsfVenom do
let(:stdin) { StringIO.new("", "rb") }
let(:stdout) { StringIO.new("", "wb") }
let(:stderr) { StringIO.new("", "wb") }
subject(:venom) { described_class.new(stdin, stdout, stderr, framework) }
before(:each) do
conf_dir = Metasploit::Framework.root.join('spec', 'dummy', 'framework','config')
conf_dir.mkpath
end
after(:each) do
dummy_dir = Metasploit::Framework.root.join('spec', 'dummy')
dummy_dir.rmtree
end
before(:all) do
conf_dir = Metasploit::Framework.root.join('spec', 'dummy', 'framework','config')
conf_dir.mkpath
create_opts = {
:module_types => [
::Msf::MODULE_PAYLOAD, ::Msf::MODULE_ENCODER, ::Msf::MODULE_NOP
],
'ConfigDirectory' => conf_dir.to_s,
'DisableDatabase' => true
}
@framework = ::Msf::Simple::Framework.create(create_opts)
end
let(:framework) { @framework }
describe "#dump_encoders" do
it_behaves_like "encoder dumper" do
let(:dump) { venom.dump_encoders }
end
end
describe "#dump_nops" do
it_behaves_like "nop dumper" do
let(:dump) { venom.dump_nops }
end
end
describe "#dump_payloads" do
it_behaves_like "payload dumper" do
let(:dump) { venom.dump_payloads }
end
end
describe "#parse_args" do
context "help" do
it "should raise UsageError" do
expect { venom.parse_args(%w! -h !) }.to raise_error(MsfVenom::UsageError)
expect { venom.parse_args(%w! --help !) }.to raise_error(MsfVenom::UsageError)
expect { venom.parse_args(%w! --help-formats !) }.to raise_error(MsfVenom::UsageError)
end
end
context "with bad arguments" do
it "should raise UsageError with empty arguments" do
expect { venom.parse_args([]) }.to raise_error(MsfVenom::UsageError)
end
it "should raise with unexpected options" do
expect { venom.parse_args(%w! --non-existent-option !) }.to raise_error(MsfVenom::UsageError)
end
%w! --platform -a -b -c -f -p -n -s -i -x !.each do |required_arg|
it "should raise UsageError with no arg for option #{required_arg}" do
expect { venom.parse_args([required_arg]) }.to raise_error(MsfVenom::UsageError)
end
end
end
end
describe "#generate_raw_payload" do
before do
venom.parse_args(args)
end
context "with --options" do
context "and a payload" do
let(:args) { %w! -o -p windows/meterpreter/reverse_tcp ! }
it "should print options" do
expect { venom.generate_raw_payload }.to_not raise_error
output = stderr.string
output.should include("LHOST")
output.should include("LPORT")
end
context "and some datastore options" do
it "should print options" do
venom.parse_args %w! -o -p windows/meterpreter/reverse_tcp LPORT=1234!
expect { venom.generate_raw_payload }.to_not raise_error
output = stderr.string
output.should include("LHOST")
output.should match(/LPORT\s+1234/)
end
it "should print options case-insensitively" do
venom.parse_args %w! -o -p windows/meterpreter/reverse_tcp lPoRt=1234!
expect { venom.generate_raw_payload }.to_not raise_error
output = stderr.string
output.should include("LHOST")
output.should match(/LPORT\s+1234/)
end
end
end
context "and an invalid payload" do
let(:args) { %w! -o -p asdf! }
it "should raise" do
expect { venom.generate_raw_payload }.to raise_error(MsfVenom::UsageError)
end
end
end
[
{ :format => "elf", :arch => "x86" },
{ :format => "raw", :arch => "x86" },
{ :format => "elf", :arch => "armle" },
{ :format => "raw", :arch => "armle" },
{ :format => "elf", :arch => "ppc" },
{ :format => "raw", :arch => "ppc" },
{ :format => "elf", :arch => "mipsle" },
{ :format => "raw", :arch => "mipsle" },
].each do |format_hash|
format = format_hash[:format]
arch = format_hash[:arch]
context "building #{format} with linux/#{arch}/shell_bind_tcp" do
let(:args) { %W! -f #{format} -p linux/#{arch}/shell_bind_tcp ! }
# We're not encoding, so should be testable here
it "should contain /bin/sh" do
output = venom.generate_raw_payload
# Usually push'd in two instructions, so the whole string
# isn't all together. Check for the two pieces seperately
output.should include("/sh")
output.should include("/bin")
end
end
end
end
describe "#generate" do
include_context 'Msf::Util::Exe'
before { venom.parse_args(args) }
context "with --list" do
context "with invalid module type" do
let(:args) { %w!--list asdf! }
it "should raise UsageError" do
expect { venom.generate }.to raise_error(MsfVenom::UsageError)
end
end
[ "nop", "encoder", "payload" ].each do |type|
context "#{type}s" do
let(:args) { %W!--list #{type}s! }
it_behaves_like "#{type} dumper" do
let(:dump) do
venom.generate
stderr.string
end
end
end
end
end
context "with invalid datastore option" do
let(:args) { %w!-f exe -p windows/shell_reverse_tcp LPORT=asdf! }
it "should fail validation" do
expect { venom.generate }.to raise_error(Msf::OptionValidateError)
end
end
context "without required datastore option" do
# Requires LHOST
let(:args) { %w!-f exe -p windows/shell_reverse_tcp! }
it "should fail validation" do
expect { venom.generate }.to raise_error(Msf::OptionValidateError)
end
end
@platform_format_map.each do |plat, formats|
formats.each do |format_hash|
format = format_hash[:format]
arch = format_hash[:arch]
# Need a new context for each so the let() will work correctly
context "with format=#{format} platform=#{plat} arch=#{arch}" do
# This will build executables with no payload. They won't work
# of course, but at least we can see that it is producing the
# correct file format for the given arch and platform.
let(:args) { %W! -p - -f #{format} -a #{arch} --platform #{plat} ! }
it "should print a #{format} to stdout" do
venom.generate
output = stdout.string
verify_bin_fingerprint(format_hash, output)
end
end
end
end
end
end