Skip to content
This repository was archived by the owner on Oct 22, 2020. It is now read-only.

Commit 16dd168

Browse files
committed
Add support for custom modules in home directory
1 parent 5f6006f commit 16dd168

File tree

4 files changed

+78
-8
lines changed

4 files changed

+78
-8
lines changed

lib/wpxf/cli/module_cache.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def rebuild_cache
4545
print_warning 'Refreshing the module cache...'
4646

4747
Wpxf::Models::Module.truncate
48+
Wpxf.load_custom_modules
4849

4950
create_module_models 'exploit'
5051
create_module_models 'auxiliary'

lib/wpxf/modules.rb

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,36 @@
11
# frozen_string_literal: true
22

33
module Wpxf
4-
def self.build_module_list(namespace, folder_name = '')
4+
def self.modules_path
5+
File.join(Wpxf.app_path, 'lib', 'wpxf', 'modules')
6+
end
7+
8+
def self.custom_modules_path
9+
File.join(Wpxf.home_directory, 'modules')
10+
end
11+
12+
def self.payloads_path
13+
File.join(Wpxf.app_path, 'lib', 'wpxf', 'payloads')
14+
end
15+
16+
def self.build_module_list(namespace, source_folders = [])
517
modules = namespace.constants.select do |c|
618
namespace.const_get(c).is_a? Class
719
end
820

9-
modules_directory = File.join(Wpxf.app_path, 'lib', 'wpxf', folder_name)
10-
1121
modules.map do |m|
1222
klass = namespace.const_get(m)
1323
filename = klass.new.method(:initialize).source_location[0]
24+
25+
# Remove any source folders from the path and store the
26+
# relative path that will be used in the CLI.
27+
source_folders.each do |source_folder|
28+
filename = filename.sub(source_folder, '')
29+
end
30+
1431
{
1532
class: klass,
16-
name: filename.sub(modules_directory, '').sub(/^\//, '').sub(/\.rb$/, '')
33+
name: filename.sub(/^\//, '').sub(/\.rb$/, '')
1734
}
1835
end
1936
end
@@ -24,15 +41,20 @@ def self.load_module(path)
2441
Object.const_get(mod.class_name).new
2542
end
2643

44+
def self.load_custom_modules
45+
custom_modules_path = File.join(Wpxf.home_directory, 'modules', '**', '*.rb')
46+
Dir.glob(custom_modules_path).each { |p| load p }
47+
end
48+
2749
module Auxiliary
2850
def self.module_list
29-
Wpxf.build_module_list(Wpxf::Auxiliary, 'modules')
51+
Wpxf.build_module_list(Wpxf::Auxiliary, [Wpxf.modules_path, Wpxf.custom_modules_path])
3052
end
3153
end
3254

3355
module Exploit
3456
def self.module_list
35-
Wpxf.build_module_list(Wpxf::Exploit, 'modules')
57+
Wpxf.build_module_list(Wpxf::Exploit, [Wpxf.modules_path, Wpxf.custom_modules_path])
3658
end
3759
end
3860

@@ -46,7 +68,7 @@ def self.payload_count
4668
end
4769

4870
def self.payload_list
49-
@@payloads ||= Wpxf.build_module_list(Wpxf::Payloads, 'payloads')
71+
@@payloads ||= Wpxf.build_module_list(Wpxf::Payloads, [Wpxf.payloads_path])
5072
end
5173

5274
def self.load_payload(name)
@@ -60,3 +82,5 @@ def self.load_payload(name)
6082
require_rel 'modules/auxiliary'
6183
require_rel 'modules/exploit'
6284
require_rel 'payloads'
85+
86+
Wpxf.load_custom_modules

spec/lib/wpxf/cli/module_cache_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ def initialize
140140
expect(Wpxf::Models::Module.first(name: 'test')).to be_nil
141141
end
142142

143+
it 'should reload the custom modules' do
144+
allow(Wpxf).to receive(:load_custom_modules).and_call_original
145+
subject.rebuild_cache
146+
expect(Wpxf).to have_received(:load_custom_modules).exactly(1).times
147+
end
148+
143149
it 'should create a {Models::Module} for each class in the Wpxf::Exploit namespace' do
144150
modules = Wpxf::Exploit.constants.select do |c|
145151
Wpxf::Exploit.const_get(c).is_a? Class

spec/lib/wpxf/modules_spec.rb

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,53 @@
66
describe Wpxf do
77
describe '.build_module_list' do
88
it 'builds an array of hashes containing the modules for the specified namespace' do
9-
result = Wpxf.build_module_list(Wpxf::Exploit, 'modules')
9+
result = Wpxf.build_module_list(Wpxf::Exploit, [Wpxf.modules_path])
1010
expect(result[0]).to include(:class, :name)
1111

1212
mod = result.find { |m| m[:name] == 'exploit/shell/admin_shell_upload' }
1313
expect(mod).to_not be_nil
1414
expect(mod[:class]).to be Wpxf::Exploit::AdminShellUpload
1515
end
1616
end
17+
18+
describe '.modules_path' do
19+
it 'should return the path to the standard modules directory' do
20+
path = Wpxf.modules_path
21+
expect(path).to eql(File.join(Wpxf.app_path, 'lib', 'wpxf', 'modules'))
22+
end
23+
end
24+
25+
describe '.payloads_path' do
26+
it 'should return the path to the payloads directory' do
27+
path = Wpxf.payloads_path
28+
expect(path).to eql(File.join(Wpxf.app_path, 'lib', 'wpxf', 'payloads'))
29+
end
30+
end
31+
32+
describe '.custom_modules_path' do
33+
it 'should return the path to the custom modules directory' do
34+
path = Wpxf.custom_modules_path
35+
expect(path).to eql(File.join(Wpxf.home_directory, 'modules'))
36+
end
37+
end
38+
39+
describe '.load_custom_modules' do
40+
it 'should load all modules found in the home directory of the current user' do
41+
allow(Wpxf).to receive(:load)
42+
allow(Dir).to receive(:glob)
43+
.with(File.join(Wpxf.home_directory, 'modules', '**', '*.rb'))
44+
.and_return %w[/path1.rb /path2.rb]
45+
46+
Wpxf.load_custom_modules
47+
expect(Wpxf).to have_received(:load)
48+
.with('/path1.rb')
49+
.exactly(1).times
50+
51+
expect(Wpxf).to have_received(:load)
52+
.with('/path2.rb')
53+
.exactly(1).times
54+
end
55+
end
1756
end
1857

1958
describe 'Wpxf::Auxiliary' do

0 commit comments

Comments
 (0)