what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

PScanDetect-0.8.c

PScanDetect-0.8.c
Posted Dec 23, 2003
Authored by dodo

PScanDetect version 0.8 is a utility that will detect TCP-based portscans. Tested under FreeBSD 5.1, OpenBSD 3.3, and Slackware Linux 9.0.

tags | tool, scanner, tcp
systems | linux, unix, freebsd, slackware, openbsd
SHA-256 | 1b74539c9e0cfe25914068560f46eada7a570bd6136dcd7882274d57af719da3

PScanDetect-0.8.c

Change Mirror Download
/*
* TCP Portscan Detector v0.8
* os: Linux, FreeBSD, OpenBSD
* author: dodo <dodo@darkwired.org>
* date: 23-dec-2003
*
* description:
* this tool can detect TCP portscans and alerts them
* check -h for more info
* tested on: FreeBSD 5.1, OpenBSD 3.3, Slackware linux 9.0
*
* license:
* this code is licensed under the GNU GPL
* by compiling this, you agree to this license
*
* compilation:
* gcc PScanDetect.c -o pscandetect -lpcap
*
* todo:
* SCAN_INSPECT detection
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>

#ifndef __OpenBSD__
#include <net/ethernet.h>
#endif

#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <pcap.h>

#ifdef __Win32__
#error "you idiot, I did not code this for Win32!"
#endif

#ifdef __Linux__
#include <netinet/ether.h>
#endif

/* define the scan types */
#define SCAN_SINGLESTEP 0x1
#define SCAN_LARGESTEP 0x2
#define SCAN_INSPECT 0x3
#define SCAN_MANYHIGH 0x4

/* define boundaries */
#define MAX_BLASTERS 20
#define MAX_SCANNERS 20
#define MAX_PORTS 20
#define BOUNDARY_MANYHIGH 5000

/* define misc constants */
#define VERSION 0.8
#define NUM_TYPES 4
#define NUM_DROP_SECS 5
#define NAME_SCAN_SINGLESTEP "SCAN_SINGLESTEP"
#define NAME_SCAN_LARGESTEP "SCAN_LARGESTEP"
#define NAME_SCAN_INSPECT "SCAN_INSPECT"
#define NAME_SCAN_MANYHIGH "SCAN_MANYHIGH"

struct my_ip {
u_int8_t ip_vhl; /* header length, version */
#define IP_V(ip) (((ip)->ip_vhl & 0xf0) >> 4)
#define IP_HL(ip) ((ip)->ip_vhl & 0x0f)
u_int8_t ip_tos; /* type of service */
u_int16_t ip_len; /* total length */
u_int16_t ip_id; /* identification */
u_int16_t ip_off; /* fragment offset field */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_int8_t ip_ttl; /* time to live */
u_int8_t ip_p; /* protocol */
u_int16_t ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};

struct BlastRadius {
unsigned short id; /* identifier */
unsigned short ports[MAX_PORTS]; /* ports accessed */
unsigned short portsn; /* port pointer */
unsigned long birth; /* since when? */
unsigned long lporttime; /* time when last added port */
unsigned short active; /* recycling? */
struct in_addr host; /* the bastard */
};

struct Scanner {
unsigned short id; /* identifier */
unsigned short portsn; /* num ports accessed */
unsigned char type; /* scan type */
unsigned long lporttime; /* time when last added port */
struct in_addr host; /* the bastard */
};


/* interface attributes */
char *dev;
char *logfile = NULL;
FILE *logfd;
unsigned short int level = 3;
unsigned char promiscuous = 0;
unsigned char verbose = 0;

/* internal attributes */
char selfhost[20];
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t *handle;
struct pcap_pkthdr header;
const u_char *packet;
struct ether_header *data_ether;
const struct my_ip* data_ip;
const struct tcphdr* data_tcp;
struct BlastRadius *blasters[MAX_BLASTERS];
struct Scanner *scanners[MAX_SCANNERS];
unsigned long int blastsize = 0;
unsigned long int scanrsize = 0;
int h;

/* methods */
void initPcap();
char *getDevice();
void getDeviceIP();
void setFilter();
void openLive();
void closeLive();
void doLoop();
void nibblePacket();
void inspectBlast(struct in_addr blasthost, unsigned int port);
char addBR(struct in_addr blasthost, unsigned short int port);
void replaceBR(struct in_addr blasthost, unsigned int port);
void updateBR(struct in_addr blasthost, unsigned short int port);
char checkBR(struct in_addr blasthost);
char checkBRPort(struct BlastRadius *br, unsigned short int port);
char checkBRPortMax(struct BlastRadius *br);
void outputAlert(struct BlastRadius *br, char type);
void dumpBR();
void cleanBR();
char checkSelf(struct in_addr blasthost);
char checkScanner(struct in_addr blasthost);
char addScanner(struct in_addr blasthost, unsigned short portsn, unsigned char type);
char updateScanner(struct in_addr blasthost);
void dumpScanners();
void usage(char *self);
char parseOptions(int argc, char *argv[]);


int main(int argc, char *argv[])
{
int i;
dev = getDevice();
if(parseOptions(argc, argv)==0) usage(argv[0]);
getDeviceIP();
openLive();
setFilter();
doLoop();
closeLive();
dumpBR();
}

void usage(char *self)
{
fprintf(stdout,
"\nTCP Portscan Detector v%2.1f\n"
"http://www.darkwired.org/\n\n"
"usage: %s [options]\n"
"options:\n"
" -l <file> output to logfile\n"
" -a <level> alert when scan alert type <= then <level> (default 3)\n"
" -d <device> use this device to detect scans on\n"
" -p enable promiscuous mode (detect scans in all traffic on line)\n"
" -v enable verbose mode\n"
" -h show this\n"
"scan alert types:\n"
" 0x1 SCAN_SINGLESTEP\n"
" 0x2 SCAN_LARGESTEP\n"
" 0x3 SCAN_INSPECT\n"
" 0x4 SCAN_MANYHIGH\n",
VERSION, self);
exit(-1);
}

char parseOptions(int argc, char *argv[])
/* this will be messy :] */
{
int i;
for(i=0; argc > i; i++) {

if(argv[i][0]=='-') {
switch(argv[i][1]) {
case 'l': {
if((i+1)>=argc) return 0; /* option requires param */
logfile = argv[i+1]; i++;
break;
}

case 'd': {
if((i+1)>=argc) return 0; /* option requires param */
dev = argv[i+1]; i++;
break;
}

case 'a': {
if((i+1)>=argc) return 0; /* option requires param */
level = atoi(argv[i+1]); i++;
if(level<1 || level>NUM_TYPES) {
fprintf(stderr, "bad alert level: %d\n", level);
return 0;
}
break;
}

case 'h': {
return 0;
break;
}

case 'p': {
promiscuous = 1;
break;
}

case 'v': {
verbose = 1;
break;
}
}
}
}

if(verbose==1) {
printf("device: %s\n", dev);
if(logfile == NULL) {
printf("logfile: stdout\n");
} else {
printf("logfile: %s\n", logfile);
}

printf("alertlevel: %d\n", level);
printf("promiscuous: %d\n", promiscuous);
}
return 1;
}

char *getDevice()
{
char *dev;
dev = pcap_lookupdev(errbuf);
return dev;
}

void getDeviceIP()
{
struct sockaddr_in *ssin;
struct ifreq ifr;
unsigned long int ip;
int fd;

fd = socket(PF_INET, SOCK_DGRAM, 0);

/* ripped this peace of code somewhere using google */
memset(&ifr, 0, sizeof(ifr));
ssin = (struct sockaddr_in *)&ifr.ifr_addr;
strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
ifr.ifr_addr.sa_family = AF_INET;

if (ioctl(fd, SIOCGIFADDR, (char*) &ifr) < 0)
{
fprintf(stderr, "unable to get IP address of device: %s\n", dev);
close(fd);
exit(-1);
}

*ssin = * ( (struct sockaddr_in *)&ifr.ifr_addr);
if(verbose==1)
printf("device ip address: %s\n", inet_ntoa(ssin->sin_addr));
strncpy(selfhost, inet_ntoa(ssin->sin_addr), sizeof(selfhost));
}

void setFilter()
{
struct bpf_program filter;
char filter_app[] = "";
bpf_u_int32 mask;
bpf_u_int32 net;
pcap_lookupnet(dev, &net, &mask, errbuf);
pcap_compile(handle, &filter, filter_app, 0, net);
pcap_setfilter(handle, &filter);
}

void openLive()
{
if(dev == NULL) {
fprintf(stderr, "could not get network device (check permissions)\n");
exit(-1);
}
handle = pcap_open_live(dev, BUFSIZ, promiscuous, 0, errbuf);
}

void closeLive()
{
pcap_close(handle);
}

void nibblePacket
(
u_char *user,
struct pcap_pkthdr *phrd,
u_char *packet
)
{
data_ether = (struct ether_header *)packet;

if(ntohs(data_ether->ether_type)==ETHERTYPE_IP)
{
data_ip = (struct my_ip *)(packet+sizeof(struct ether_header));
data_tcp = (struct tcphdr *)(packet+sizeof(struct ether_header)+sizeof(struct my_ip));

#ifdef __FreeBSD__
inspectBlast(data_ip->ip_src, ntohs(data_tcp->th_dport));
#elif defined __OpenBSD__
inspectBlast(data_ip->ip_src, ntohs(data_tcp->th_dport));
#elif defined __linux__
inspectBlast(data_ip->ip_src, ntohs(data_tcp->dest));
#endif

/*printf("%s:%d -> %s:%d\n", //debugging
inet_ntoa(data_ip->ip_src),
ntohs(data_tcp->source),
inet_ntoa(data_ip->ip_dst),
ntohs(data_tcp->dest)
);
*/

}
}

void doLoop()
{
pcap_loop(handle, -1, (pcap_handler)nibblePacket, 0);
}



void inspectBlast(struct in_addr blasthost, unsigned int port)
{
if(checkSelf(blasthost)) {
return;
}


if(checkScanner(blasthost)==1) {
updateScanner(blasthost);
return;
}


if(checkBR(blasthost)==0) {
if(addBR(blasthost, port)==0) {
replaceBR(blasthost, port);
}
} else {
updateBR(blasthost, port);
}

/* now we check wether someone scanned us */
cleanBR();
}

void dumpBR()
{
int i=0, a=0;
for(i=0; blastsize>i; i++) {
printf("%d BlastRadius->host: %s (%d ports in %d secs) [%d]\n", blasters[i]->id, inet_ntoa(blasters[i]->host), blasters[i]->portsn, (int)(time(NULL) - blasters[i]->lporttime), blasters[i]->active);
for(a=0; blasters[i]->portsn>a; a++) {
printf("%d,", blasters[i]->ports[a]);
}
printf("\n");
}
}

char addBR(struct in_addr blasthost, unsigned short int port)
{
if(blastsize==MAX_BLASTERS) {
return 0;
}
blasters[blastsize] = malloc(sizeof(struct BlastRadius));
blasters[blastsize]->id = blastsize;
blasters[blastsize]->portsn = 0;
blasters[blastsize]->active = 1;
blasters[blastsize]->birth = time(NULL);
blasters[blastsize]->lporttime = time(NULL);
blasters[blastsize]->host = blasthost;
blastsize++;
return 1;
}

void replaceBR(struct in_addr blasthost, unsigned int port)
{
int i;
for(i=0; blastsize>i; i++) {
if(blasters[i]->active==0) {
blasters[i]->portsn = 0;
blasters[i]->active = 1;
blasters[i]->birth = time(NULL);
blasters[i]->lporttime = time(NULL);
blasters[i]->host = blasthost;

break;
}
}


}


void updateBR(struct in_addr blasthost, unsigned short int port)
{
char bh[20];
int i;
strncpy(bh, inet_ntoa(blasthost), (sizeof(bh)-1));
for(i=0; blastsize>i; i++) {
if(
strcmp(inet_ntoa(blasters[i]->host), bh) == 0
&&
blasters[i]->active == 1
) {
if(blasters[i]->portsn < MAX_PORTS) {
if(checkBRPort(blasters[i], port)==0) {
/* update last_portadd field */
blasters[i]->lporttime = time(NULL);
blasters[i]->ports[(blasters[i]->portsn)] = port;
blasters[i]->portsn++;
}
}
}
}
}

char checkBRPort(struct BlastRadius *br, unsigned short int port)
{
int i;
for(i=0; br->portsn > i; i++) {
if(br->ports[i] == port) {
return 1;
}
}
return 0;
}

char checkBRPortMax(struct BlastRadius *br)
{
if(br->portsn==MAX_PORTS) return 1;
return 0;
}

char checkBRPortScan(struct BlastRadius *br, char type)
{
if(type==SCAN_LARGESTEP) {

if(checkBRPortScan(br, SCAN_MANYHIGH)==1)
return 0;

if(br->portsn > 8 && checkBRPortScan(br, SCAN_MANYHIGH)==0)
return 1;
}

if(type==SCAN_SINGLESTEP) {
int i;
int cport = br->ports[0];

if(br->portsn < 8) {
return 0;
}

if(checkBRPortScan(br, SCAN_MANYHIGH)==1) {
return 0;
}

for(i=1; br->portsn > i; i++) {
if( (cport+1) == br->ports[i] ) {
cport++;
} else {
return 0;
}
}
return 1;
}

if(type==SCAN_MANYHIGH) {
int i;
if(br->portsn < 8)
return 0;

for(i=1; br->portsn > i; i++) {
if(br->ports[i] < BOUNDARY_MANYHIGH)
return 0;
}

return 1;
}

return 0;
}

char checkBR(struct in_addr blasthost)
{
char bh[20];
int i;
strncpy(bh, inet_ntoa(blasthost), (sizeof(bh)-1));
for(i=0; blastsize>i; i++) {
if(
strcmp(inet_ntoa(blasters[i]->host), bh) == 0
&&
blasters[i]->active == 1
)
return 1;
}
return 0;
}

char checkBRNoSuspect(struct BlastRadius *br)
{
if((*br).portsn < 4) {
/* thanks to ilja for reminding me :p */
if((int)(time(NULL) - br->lporttime) > NUM_DROP_SECS)
return 1;
}

return 0;
}

void cleanBR()
{
int i;
for(i=0; blastsize>i; i++) {

if(checkBRNoSuspect(blasters[i])) {
blasters[i]->active = 0;
}

if(blasters[i]->portsn > 2 && blasters[i]->active==1) {


if(checkBRPortMax(blasters[i])==1) {
blasters[i]->active = 0;
}

if(checkBRPortScan(blasters[i], SCAN_LARGESTEP)) {
blasters[i]->active = 0;
addScanner(blasters[i]->host, blasters[i]->portsn, SCAN_LARGESTEP);
outputAlert(blasters[i], SCAN_LARGESTEP);
}

if(checkBRPortScan(blasters[i], SCAN_SINGLESTEP)) {
blasters[i]->active = 0;
addScanner(blasters[i]->host, blasters[i]->portsn, SCAN_SINGLESTEP);
outputAlert(blasters[i], SCAN_SINGLESTEP);
}

if(checkBRPortScan(blasters[i], SCAN_MANYHIGH)) {
blasters[i]->active = 0;
addScanner(blasters[i]->host, blasters[i]->portsn, SCAN_MANYHIGH);
outputAlert(blasters[i], SCAN_MANYHIGH);
}
}
}
}

void outputAlert(struct BlastRadius *br, char type)
{
char *scanname;

if(type > level) return;

if(logfile == NULL) {
logfd = fopen("/dev/stdout", "a");
} else {
logfd = fopen(logfile, "a");
}
if(!logfd) {
fprintf(stderr, "unable to open logfile\n");
exit(-1);
}

switch(type) {
case SCAN_SINGLESTEP:
scanname = NAME_SCAN_SINGLESTEP;
break;
case SCAN_LARGESTEP:
scanname = NAME_SCAN_LARGESTEP;
break;
case SCAN_MANYHIGH:
scanname = NAME_SCAN_MANYHIGH;
break;
case SCAN_INSPECT:
scanname = NAME_SCAN_INSPECT;
break;
}

fprintf(logfd, "detected scan from %s, type: %s\n", inet_ntoa(br->host), scanname);
fclose(logfd);
/* good place to use debugging functions */
}

char checkSelf(struct in_addr blasthost)
{

if(
strcmp(selfhost, inet_ntoa(blasthost)) == 0
)
return 1;

return 0;
}


char checkScanner(struct in_addr blasthost)
{
char bh[20];
int i;
strncpy(bh, inet_ntoa(blasthost), (sizeof(bh)-1));
for(i=0; scanrsize>i; i++) {
if(
strcmp(inet_ntoa(scanners[i]->host), bh) == 0
)
return 1;
}

return 0;
}


char addScanner(struct in_addr blasthost, unsigned short portsn, unsigned char type)
{
if(scanrsize==MAX_SCANNERS) {
return 0;
}
scanners[scanrsize] = malloc(sizeof(struct Scanner));
scanners[scanrsize]->id = scanrsize;
scanners[scanrsize]->type = type;
scanners[scanrsize]->portsn = portsn;
scanners[scanrsize]->lporttime = time(NULL);
scanners[scanrsize]->host = blasthost;
scanrsize++;
return 1;
}



char updateScanner(struct in_addr blasthost)
{
char bh[20];
int i;
strncpy(bh, inet_ntoa(blasthost), (sizeof(bh)-1));

for(i=0; scanrsize>i; i++) {
if(
strcmp(inet_ntoa(scanners[i]->host), bh) == 0
) {
scanners[i]->lporttime = time(NULL);
return 1;
}
}



return 0;
}

void dumpScanners()
{
int i=0;
for(i=0; scanrsize>i; i++) {
printf("%d Scanner->host: %s (%d ports, last hit: %d secs)\n", scanners[i]->id, inet_ntoa(scanners[i]->host), scanners[i]->portsn, (int)(time(NULL) - scanners[i]->lporttime));
}
}

Login or Register to add favorites

File Archive:

July 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Jul 1st
    27 Files
  • 2
    Jul 2nd
    10 Files
  • 3
    Jul 3rd
    35 Files
  • 4
    Jul 4th
    27 Files
  • 5
    Jul 5th
    18 Files
  • 6
    Jul 6th
    0 Files
  • 7
    Jul 7th
    0 Files
  • 8
    Jul 8th
    28 Files
  • 9
    Jul 9th
    44 Files
  • 10
    Jul 10th
    24 Files
  • 11
    Jul 11th
    25 Files
  • 12
    Jul 12th
    11 Files
  • 13
    Jul 13th
    0 Files
  • 14
    Jul 14th
    0 Files
  • 15
    Jul 15th
    0 Files
  • 16
    Jul 16th
    0 Files
  • 17
    Jul 17th
    0 Files
  • 18
    Jul 18th
    0 Files
  • 19
    Jul 19th
    0 Files
  • 20
    Jul 20th
    0 Files
  • 21
    Jul 21st
    0 Files
  • 22
    Jul 22nd
    0 Files
  • 23
    Jul 23rd
    0 Files
  • 24
    Jul 24th
    0 Files
  • 25
    Jul 25th
    0 Files
  • 26
    Jul 26th
    0 Files
  • 27
    Jul 27th
    0 Files
  • 28
    Jul 28th
    0 Files
  • 29
    Jul 29th
    0 Files
  • 30
    Jul 30th
    0 Files
  • 31
    Jul 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close