Skip to content

How to get started with writing an exploit

sinn3r edited this page Mar 14, 2016 · 31 revisions

The real kung-fu behind exploit development isn't actually about which language you choose to build it, it's about your precise understanding of how an input is processed by the application you're debugging, and how to gain control by manipulating it. That's right, the keyword is "debugging." Your binjitsu (reverse-engineering) is where the real kung-fu is. However, if your goal isn't just about popping a calculator, but actually want to weaponize, to maintain, and to provide use in the practical world, you need a development framework. And this is where Metasploit comes in. It's a framework that's free and open-source, actively contributed by researchers around the world. So when you write a Metasploit exploit, you don't have to worry about any dependency issues, or having the wrong version, or not having enough payloads for different pentesting scenarios to choose from, etc. The idea is all you need to do is focus on building that exploit, and nothing more.

Plan your module

Unlike writing a proof-of-concept, when you write a Metasploit module you need to think about how users might use it in the real world. Stealth is usually an important element to think about. Can your exploit achieve code execution without dropping a file? Can the input look more random so it's more difficult to detect? How about obfuscation? Is it generating unnecessary traffic? Can it be more stable without crashing the system so much, etc, etc.

Also, try to be precise about exploitable requirements. Usually, a bug is specific to a range of versions, or even builds. If you can't automatically check that, you need to at least mention it in the description somewhere. Some of your exploit's techniques might also be application-specific. For example, you can take advantage of a specific behavior in the application to generate heap allocations the way you want, but maybe it's more noisy in the newer version so that gives you some stability issues. Does it need a 3rd-party component to work that may not even be installed by everyone? Even if it is, is the component revised often that could make your exploit less reliable?

Know that in the real world, your exploit can break or fail in a lot of different ways. You should try to find out and fix it during the development and testing phase before learning the hard way.

Ranking

As you can see, reliability is important to Metasploit, and we try to be more friendly about this for the users. I know what you're thinking: "Well, if they're using the exploit they should understand how it works, so they know what they're getting themselves into." In the perfect world, yes. Knowing how a vulnerability works or how an exploit works will only benefit the user, but you see, we don't live in the perfect world. If you're in the middle of a penetration test, it's very unlikely to always find the time to recreate the vulnerable environment, strip the exploit to the most basic form to debug what's going on, and then do testing. Chances are you have a tight schedule to break into a large network, so you need to use your time carefully. Because of this, it's important to at least have a good description and good references for the module. And of course, a ranking system that can be trusted.

The Metasploit Framework has seven different rankings to indicate how good an exploit is:

Ranking Description
ExcellentRanking The exploit will never crash the service. This is the case for SQL Injection, CMD execution, RFI, LFI, etc. No typical memory corruption exploits should be given this ranking unless there are extraordinary circumstances (WMF Escape()).
GreatRanking The exploit has a default target AND either auto-detects the appropriate target or uses an application-specific return address AFTER a version check.
GoodRanking The exploit has a default target and it is the "common case" for this type of software (English, Windows XP for a desktop app, 2003 for server, etc).
NormalRanking The exploit is otherwise reliable, but depends on a specific version and can't (or doesn't) reliably autodetect.
AverageRanking The exploit is generally unreliable or difficult to exploit.
LowRanking The exploit is nearly impossible to exploit (or under 50%) for common platforms.
ManualRanking The exploit is unstable or difficult to exploit and is basically a DoS. This ranking is also used when the module has no use unless specifically configured by the user (e.g.: php_eval).

Template

If you have read this far, we think you are pretty impressive because it's a lot to digest. You are probably wondering why we haven't had a single line of code to share in the write-up. Well, as you recall, exploit development is mostly about your reversing skills. If you have all that, we shouldn't be telling you how to write an exploit. What we've done so far is hopefully get your mindset dialed-in correctly about what it means to become a Metasploit exploit developer for the security community, the rest is more about how to use our mixins to build that exploit. Well, there are A LOT of mixins so it's impossible to go over all of them in a single page, so you must either read the API documentation, existing code examples, or look for more wiki pages we've written to cover specific mixins.

For example, if you're looking for a writeup about how to interact with an HTTP server, you might be interested in: How to send an HTTP Request Using HTTPClient. If you're interested in browser exploit writing, definitely check out: How to write a browser exploit using BrowserExploitServer, etc.

But of course, to begin you most likely need a template to work with, and here it is. We'll also explain how to fill out the required fields:

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'

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

  def initialize(info={})
    super(update_info(info,
      'Name'           => "[Vendor] [Software] [Root Cause] [Vulnerability type]",
      'Description'    => %q{
        Say something that the user might need to know
      },
      'License'        => MSF_LICENSE,
      'Author'         => [ 'Name' ],
      'References'     =>
        [
          [ 'URL', '' ]
        ],
      'Platform'       => 'win',
      'Targets'        =>
        [
          [ 'System or software version', { 'Ret' => 0x41414141 } ]
        ],
      'Payload'        =>
        {
          'BadChars' => "\x00"
        },
      'Privileged'     => false,
      'DisclosureDate' => "",
      'DefaultTarget'  => 0))
  end

  def check
    # For the check command
  end

  def exploit
    # Main function
  end

end

The Name field should begin with the name of the vendor, followed by the software. Ideally the "Root Cause" field means which component or function the bug is found. And finally, the type of vulnerability the module is exploiting.

The Description field should explain what the module does, things to watch out for, specific requirements, the more the better. The goal is to let the user understand what he's using without the need to actually read the module's source and figure things out. And trust me, most of them don't.

The Author field is where you put your name. The format should be "Name ". If you want to have your Twitter handle there, leave it as a comment, for example: "Name # handle"

The References field is an array of references related to the vulnerability or the exploit. For example: an advisory, a blog post, etc. Make sure you use these identifiers: OSVDB, CVE, CWE, BID, MSB, EDB, WVE, US-CERT-VU, BPS, ZDI, or URL.

The Platform field indicates what platforms are supported, for example: win, linux, osx, unix, bsd.

The Targets field is an array of systems, applications, setups, or specific versions your exploit is targeting. The second element or each target array is where you store specific metadta about that target, for example: a specific offset, a gadget, a ret address, etc. When a target is selected by the user, the metadata is loaded and tracked by a "target index", and can be retrieved by using the target method.

The Payloads field specifies how the payload should be encoded and generated. You can specify: Space, SaveRegisters, Prepend, PrependEncoder, BadChars, Append, AppendEncoder, MaxNops, MinNops, Encoder, Nop, EncoderType, EncoderOptions, ExtendedOptions, EncoderDontFallThrough.

The DisclosureDate is about when the vulnerability was disclosed in public, in the format of: "M D Y". For example: "Apr 04 2014"

Your exploit should also have a check method to support the check command, but this is optional in case it's not possible.

And finally, the exploit method is like your main method. Start writing your code there.

Basic git commands

Metasploit no longer uses svn for source code management, instead we use git, so knowing some tricks with git go a long way. We're not here to lecture you about how awesome git is, we know it has a learning curve and it's not surprising to find new users making mistakes. Every once a while, your git "rage" will kick in, and we understand. However, it's important for you to take advantage of branching.

Every time you make a module, or make some changes to existing code, you should not do so on the default master branch. Why? Because when you do a msfupdate, which is Metasploit's utility for updating your repository, it will do a git reset before merging the changes, and all your code go bye-bye.

Another mistake people tend to do is have all the changes on master before submitting a pull request. This is a bad idea, because most likely you're submitting other crap you don't intend to change, and/or you're probably asking us to merge other unnecessary commit history when there only needs to be one commit. Thanks for contributing your module to the community, but no thanks to your crazy commit history.

So as a habit, when you want to make something new, or change something, begin with a new branch that's up to date to master. First off, make sure you're on master. If you do a git status it will tell you what branch you're currently on:

$ git status
# On branch upstream-master
nothing to commit, working directory clean

Ok, now do a git pull to download the latest changes from Metasploit:

$ git pull
Already up-to-date.

At this point, you're ready to start a new branch. In this case, we'll name our new branch "my_awesome_branch":

$ git checkout -b my_awesome_module
Switched to a new branch 'my_awesome_module'

And then you can go ahead and add that module. Make sure it's in the appropriate path:

$ git add [module path]

When you decide to save the changes, commit (if there's only one module, you can do git commit -a too so you don't have to type the module path. Note -a really means EVERYTHING):

$ git commit [module path]

When you're done, push your changes, which will upload your code to your remote branch "my_awesome_branch". You must push your changes in order to submit the pull request, or share it with others on the Internet.

$ git push origin my_awesome_branch

References

https://github.com/rapid7/metasploit-framework/blob/master/lib/msf/core/exploit.rb

Metasploit Wiki Pages


Clone this wiki locally