/* pios - passive identifikation of services Attention: proof of concept code Type: Passive Port Scanner Author: Anthraxx (anthraxx@gmx.net) Date: Feb. 2001 Version: 0.8 Based on: ipl.c by loq Todo: Banner Scanning License: GPL Runs on: My Redhat 6.0 Laptop, Debian 2.2 AMD400, 100Mbit Net Greets: Kryptocrew, UNF, Oracle Page: home.datacomm.ch/prutishauser Sorry: for the bad code, and english... Bugs: Can't monitor multiple Packets at one time (i'm too lazy ;) when we left the promisc modus, he think's we are setting the promisc modus.. strange (linux sux anyway) problems with fragmented packetes (nfs) Description (German): PIOS durchsucht den Netzwerkverkehr nach SYN, SYN/ACK und ACK Packeten, die von/zu einem Host gehen. Nach diesen kann man bewerten, ob ein Port offen oder geschlossen ist. Diese Technik ist zuverlaessiger als der "fast" Modus. Im "fast" Modus sniffen wir nur nach SYN/ACK Packeten _vom_ Host. Diese Zeigen mit hoher warscheinlichkeit an, ob der Port offen ist, koennen aber auch gespooft vom Host gesendet werden. Wenn du Zugang zu einem Gateway/Router besitzt, oder am gleichen Hub (Switch) wie der zu Scannende Rechner sitzt, kannst du so absolut anonym die offenen TCP Ports dieses Hosts herausfinden. Aber leider findet dieses Prog hier nur Ports, auf die auch zugegriffen wird. Was bei WWW, FTP, POP3 oder aehnlichem noch warscheinlich ist, ist zb bei vergessene Ports (Portmap, NFS, ident usw..) eher unwarscheinlich. Hier hilft entweder: 1) Warten 2) Gespoofter SYN Scan starten (&& fast Modus benutzen) Description: (English): PIOS search's SYN, SYN/ACK and ACK Packet, who are coming from or to a Host. With this Packets, we can say where the Port is open or not. In the "fast" mode, PIOS only search for SYN/ACK Packets. If you own a Gateway, or sit on a hub, you can totally anonymly scan for open ports (ok, scan isn't right, sniff...). Usage: pios -n 192.168.1.1 - search for ports on 192.168.1.1 pios -f 192.168.1.1 - dito, but use only SYN/ACK packets pios -a - scans for all hosts If you have another device as "eth0", change it in the "STD_DEV" define. ... i hope someone improve this, or write a new one ... */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** your device **/ #define STD_DEV "eth0" /* standard host to monitor */ #define DST_ADDR "192.168.1.2" #define BUFLEN 256 #define ETHLINKHDR 14 #define F_MAX_PORTS 256 /* network socket - must be global 'cuz signal() sux */ int mysocket; /* an ethernet packet ... */ struct etherpacket { struct ethhdr eth; struct iphdr ip; struct tcphdr tcp; char data[BUFLEN]; }; /* "my" own packet */ struct mpacket { char src[17]; /* dst addr */ int port; /* dst port */ int opt; /* 0 == nothing *g* 1 == syn 2 == syn/ack 3 == ack 4 == printed out and finished 5 == fast scan; syn/ack */ }; /* knot :) */ struct Knot { struct mpacket *mypacket; struct Knot *next; }; /* head from list */ struct ListHead { struct Knot *head; struct Knot *tail; }; /* left the promisc modus, and close the socket */ void stopdevice(void) { struct ifreq ifr; strcpy(ifr.ifr_name, STD_DEV); /* interface we're gonna use */ if( ioctl(mysocket, SIOCGIFFLAGS, &ifr) < 0 ) { /* get flags */ close(mysocket); perror("Can't get flags"); exit(2); } ifr.ifr_flags ^= IFF_PROMISC; if( ioctl(mysocket, SIOCSIFFLAGS, &ifr) < 0 ) { close(mysocket); perror("Can't set flags"); exit(2); } if ( (close(mysocket)) < 0 ) { perror("Can't close socket"); exit(2); } exit(0); } /* get a socket and setting promisc modus * returns the socket */ void initdevice(void) { #define PROTO htons(0x0800) /* Ethernet code for IP protocol */ struct ifreq ifr; if ( (mysocket = socket(AF_INET, SOCK_PACKET, PROTO)) < 0 ) { perror("Can't get socket"); exit(2); } strcpy(ifr.ifr_name, STD_DEV); /* interface we're gonna use */ if( ioctl(mysocket, SIOCGIFFLAGS, &ifr) < 0 ) { /* get flags */ close(mysocket); perror("Can't get flags"); exit(2); } ifr.ifr_flags |= IFF_PROMISC; if( ioctl(mysocket, SIOCSIFFLAGS, &ifr) < 0 ) { close(mysocket); perror("Can't set flags"); exit(2); } } /* function to find a port, for the "fast" modus */ int fast_find_port(int port) { static int open_ports[F_MAX_PORTS]; static int nr_open_ports = 0; int n; if(nr_open_ports>F_MAX_PORTS) { printf("aaarghh... to many open ports... gona die..."); exit(1); } for(n=0; nmypacket=pkt; ap->next=0; if(!(hd->head)) { hd->head=hd->tail=ap; return(1); } else { hd->tail->next=ap; hd->tail=ap; return(1); } } return(0); } /* create a new packet */ int new_pkt(struct ListHead *hd, char *srcip, int prt, int md) { struct mpacket *dat=malloc(sizeof(struct mpacket)); if(dat) { strcpy(dat->src, srcip); dat->port=prt; dat->opt=md; if(add_mpkt(hd,dat)) { return(1); } else { free(dat); return(0); } } else { return(0); } } /* create a list */ struct ListHead *ListCreate(void) { struct ListHead *head=malloc(sizeof(struct ListHead)); if(head) { head->head=head->tail=0; return(head); } return(0); } /* change the mode from a packet */ int changem(struct ListHead *hd, int port, int mode) { struct Knot *cur=hd->head; /* short that thing */ if(cur) { while(cur) { if(port == cur->mypacket->port) { if(mode == 4) { return(0); } if(mode == 3) { cur->mypacket->opt=4; return(2); } cur->mypacket->opt=mode; return(1); } cur=cur->next; } } return(0); } /* find a host and port in the struct - fast scan of all hosts */ int find_fhp(struct ListHead *hd, char *host, int port) { struct Knot *cur=hd->head; /* i know, it isn't nice to have "one host - only one port", but it's easyer to code, eventually faster, and with no limit in the number of ports. so... */ if(cur) { while(cur) { if((!strcmp(cur->mypacket->src, host)) && (cur->mypacket->port == port)){ /* port is checked before */ return(0); } cur=cur->next; } } /* port is new */ /* 0 == port must not be checked 1 == port must be checked */ return(1); } /* find a port in the structs - for normal scan */ int find_port(struct ListHead *hd, int port) { struct Knot *cur=hd->head; if(cur) { while(cur) { if((cur->mypacket->port == port) && (cur->mypacket->opt > 3)) { /* port is checked before */ return(0); } cur=cur->next; } } /* port is new */ /* 0 == port must not be checked 1 == port must be checked */ return(1); } /* duh! */ void help(void) { printf("PIOS Version 0.7 - Passive Port Scanner \n"); printf("Usage: pios [options] [host]\n"); printf(" -n Normal Scan of one Host\n"); printf(" -f Fast Scan of one Host\n"); printf(" -a Fast Scan of all Hosts\n"); /* printf(" -d Device"); */ printf("\n"); printf(" [host] must be an IP\n"); printf("by Anthraxx\n"); } /* main?!! */ int main(int argc, char **argv) { struct etherpacket ep; struct sockaddr dest; struct iphdr *ip; struct tcphdr *tcp; struct timeval timeout; struct ListHead *liste; fd_set rd,wr; int mode=3; int port; int dlen; char device[7]=STD_DEV; char dip[17]; char sip[17]; char dst_ip[17]; /** param's - i know it's shit, but it's enough to work **/ if(argc > 1) { /* help */ if(!strcmp(argv[1], "-h")) { help(); exit(0); } /* device */ /* if(!strcmp(argv[1], "-d")) { if(argc>2) { if(strlen(argv[2]) < 7) { strcpy(device, argv[2]); } } else { strcpy(device, "eth0"); } } */ /* normal scan, one host */ if(!strcmp(argv[1], "-n")) { mode=1; liste=ListCreate(); if(argc>2) { strcpy(dst_ip, argv[2]); } else { strcpy(dst_ip, DST_ADDR); } } /* scan of one host, fast */ if(!strcmp(argv[1], "-f")) { mode=2; if(argc>2) { strcpy(dst_ip, argv[2]); } else { strcpy(dst_ip, DST_ADDR); } } /* scan of all hosts, fast */ if(!strcmp(argv[1], "-a")) { strcpy(dst_ip, "[all]"); liste=ListCreate(); mode=3; } } else { help(); exit(0); } /* handle ctlr-c and co */ signal (SIGINT, (void *)stopdevice); signal (SIGQUIT, (void *)stopdevice); signal (SIGTERM, (void *)stopdevice); signal (SIGKILL, (void *)stopdevice); /* init */ initdevice(); printf("Starting PIOS\n"); printf("Mode: %i Host: %s Device: %s\n", mode, dst_ip, device); for(;;) { bzero (&dest, sizeof(dest)); dlen = 0; FD_ZERO (&rd); FD_ZERO (&wr); FD_SET (mysocket, &rd); timeout.tv_sec = 0; timeout.tv_usec = 0; ip = (struct iphdr *)(((unsigned long)&ep.ip)-2); tcp = (struct tcphdr *)(((unsigned long)&ep.tcp)-2); if (FD_ISSET(mysocket, &rd)) { recvfrom(mysocket, &ep, sizeof(ep), 0, &dest, &dlen); /* tcp/ip packet? */ if(ep.eth.h_proto==ntohs(ETH_P_IP)) { bzero(dip, sizeof(dip)); bzero(sip, sizeof(sip)); strcpy(dip, (char *)(inet_ntoa(ip->daddr))); strcpy(sip, (char *)(inet_ntoa(ip->saddr))); /* 1 = normal scanning of one host 2 = fast scanning one host (only SYN/ACK) 3 = fast scanning all hosts */ switch(mode) { case 1: /** Normal scanning of ONE Host **/ /* is the DEST addr == our host? */ if(!strcmp(dip, dst_ip)) { port=(int)(ntohs(tcp->dest)); /* check where the port is open! */ if(find_port(liste, port)) { /* syn */ if(tcp->syn == 1 && tcp->ack == 0) { new_pkt(liste, dip, port, 1); } /* ack */ if(tcp->syn == 0 && tcp->ack == 1) { if((changem(liste, port, 3)) == 2) { printf("Port %i on %s is open\n", port, dip); fflush(stdout); } } } } /* is the SOURCE addr == our host */ if(!strcmp(sip, dst_ip)) { port=(int)(ntohs(tcp->source)); if(find_port(liste, port)) { if(find_port(liste, port)) { /* syn/ack */ if(tcp->syn == 1 && tcp->ack == 1) { changem(liste, port, 2); } } } } break; case 2: /** Fast scanning of ONE Host **/ /* is this our addr? */ if(!strcmp(sip, dst_ip)) { /* syn/ack packet? */ if(tcp->syn == 1 && tcp->ack == 1) { /* in wich state is the dest port? */ if(fast_find_port((int)(ntohs(tcp->source)))) { printf("Port %d on %s open\n", ntohs(tcp->source), sip); fflush(stdout); } } } break; case 3: /** Fast scanning of ALL Hosts **/ /* syn/ack packet? */ if(tcp->syn == 1 && tcp->ack == 1) { port=(int)(ntohs(tcp->source)); if(find_fhp(liste, sip, port)) { printf("Port %i on %s is open\n", port, sip); fflush(stdout); new_pkt(liste, sip, port, 0); } } break; } } } } return(0); }