Building.Open.Source.Network.Security.Tools.Components.And.Techniques [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Building.Open.Source.Network.Security.Tools.Components.And.Techniques [Electronic resources] - نسخه متنی

Mike D. Schiffman

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید







Sample Code–Sift

The following two source files comprise the Sift codebase. To preserve readability, we richly comment the code but do not include book-text inside the code. You can download the full source files from this book's companion Web site at http://www.wi1ey.com/compbooks/schiffman.


sift.h



/*
* $Id: sift.h.v 1.3 2002/05/17 05:55:29 route Exp $
*
* Building Open Source Network Security Tools
* sift.h - Vulnerability Scanning Technique example code
*
* Copyright (c) 2002 Mike D. Schiffman <mike@infonexus.com>
* All rights reserved.
*
*
*/
#include <libnet.h>
#include <pcap.h>
/* misc defines */
#define SNAPLEN 150 /* 150 bytes should cover us nicely */
#define PROMISC 0 /* dont need to be in promise mode */
#define TIMEOUT 0 /* no timeout, return immediately */
#define SOURCE_PORT 31337 /- we are */
tdefine FILTER "udp port 53" /* only DNS responses please */
tdefine NETWORK_TIMEOUT 3 /* 3 seconds and we're crying foul */
/* sitt return codes */
#define TIMEDOUT 0 /* no response */
fdefine NO_ANSWER 1 /* a response without an answer */
#define RESPONSE 2 /* a response with an answer */
/* DNS flags */
#define DNS_NOTIMPL 0x0004
#define DNS_SERVFAILED 0x0002
#define DNS_FORMATERR 0x0001
/*
* The chaos class query resource record:
* 07 'V' 'E' R' 'S' 'I' '0' 'N' 04 'B' 'I' 'N' 'D' 00 16 00 03
*/
u_char chaos_query[] = {0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x04, 0x62, 0x69, 0x6e,
0x64, 0x00, 0x00, 0x10, 0x00, 0x03};
#define CHAOS_QUERY_S 18 /* our chaos class RR is 18 bytes */
/* sift statistics structure */
struct sift_stats
{
u_long total_queries; /* total queries sent */
u_long total_responses; /* total responses received */
u_long valid_responses; /* real responses received */
u_long timed_out; /* total timeouts */
u_long timed_out_resolving; /* total timeouts resolving */
u_long not_implemented; /* DNS servers NI */
u_long server_failed; /* DNS server failed */
u_long format_error; /* DNS server format errors */
};
/* sift control context */
struct sift_pack
{
pcap_t *p; /* pcap descriptor */
libnet_t *1; /* libnet descriptor */
FILE *in_hosts; /* file to read hosts from */
FILE *in_db; /* file to read db from */
u_char *packet; /* everyone's favorite: packet! */
struct pcap_pkthdr h; /* pcap packet header */
libnet_ptag_t dns; /* DNS header */
libnet_ptag_t udp; /* UDP header */
libnet_ptag_t ip; /* IP header */
u_long src_ip; /* source ip */
u_long dst_ip; /* host to scan */
u_short id; /* session id */
u_char to; /* packet read timeout */
u_char cnt; /* probe count */
u_char flags; /* control flags */
struct sift_stats stats; /* statistics */
char errbuf[LIBNET_ERRBUF_SIZE];
};
struct sift_pack *sift_init(char *, char *, u_char, u_char, u_char,
char *);
void sift_destroy(struct sift_pack *);
void sift(struct sift_pack *);
void sift_stats(struct sift_pack *);
int build_packet(struct sift_pack *, char *);
int write_packet(struct sift_pack *);
int receive_packet (struct sift_pack *);
void cleanup(int);
int catch_sig(int, void(*)());
void usage(char *);
/* EOF */


sift.c




/*
* $Id: sift.c,v 1.3 2002/05/17 05:55:29 route Exp $
*
* Building Open Source Network Security Tools
* sift.c - Vulnerability Scanning Technique example code
*
* Copyright (c) 2002 Mike D. Schiffman <mike@infonexus.com>
* All rights reserved.
*
*
*/
#include "./sift.h"
int loop = 1;
int
main(int argc, char **argv)
{
int c;
u_char to, cnt, flags;
char *device;
struct sift_pack *sp;
char errbuf[LIBNET_ERRBUF_SIZE], file[64];
printf("Sift 1.0 [DNS Version scanning tool]\n");
to = 0;
cnt = 0;
flags = 0;
device = NULL;
memset (&file, NULL, sizeof (file));
while ((c = getopt(argc, argv, "hi:r:t:")) != EOF)
{
switch (c)
{
case 'h':
usage(argv[0]);
exit (EXIT_SUCCESS);
break;
case 'i':
device = optarg;
break;
case 'r':
cnt = atoi(optarg);
break;
case 't':
to = atoi(optarg);
break;
default:
usage(argv[0]);
exit(EXIT_FAILURE);
}
}
c = argc - optind;
if (c != 1)
{
usage(argv[0]);
exit (EXIT_FAILURE);
}
else
{
/* target IPs */
strncpy(file, argv[optind], sizeof (file) - 1);
}
sp = sift_init(device, file, flags, to, cnt, errbuf);
if (sp == NULL)
{
fprintf(stderr, "sift_init() failed: %s\n", errbuf);
goto done;
}
printf("<ctrl-c> to quit\n");
sift(sp);
sift_stats(sp);
done:
sift_destroy(sp);
return (EXIT_SUCCESS);
}
struct sift_pack *
sift_init(char *device, char *file, u_char flags, u_char to, u_char cnt, char *errbuf)
{
struct sift_pack *sp;
struct bpf_program filter_code;
bpf_u_int32 local_net, netmask;
int one;
/*
* We want to catch the interrupt signal so we can inform the user
* how many packets we captured before we exit.
*/
if (catch_sig(SIGINT, cleanup) == -1)
{
sprintf(errbuf, "can't catch SIGINT signal. /n");
return (NULL);
}
sp = malloc(sizeof (struct sift_pack));
if (sp == NULL)
{
snprintf(errbuf, LIBNET_ERRBUF_SIZE, strerror(errno));
return (NULL)
}
/* open the host list */
sp->in_hosts = fopen(file, "r");
if (sp->in_hosts == NULL)
{
snprintf(errbuf, LIBNET_ERRBUF_SIZE, strerror (errno));
sift_destroy(sp);
return (NULL);
}
sp->id = getpidO;
sp->flags = flags;
sp->to = to == 0 ? NETWORK_TIMEOUT : to;
sp->cnt = cnt;
sp->dns = LIBNET_PTAG_INITIALIZER;
sp->udp = LIBNET_PTAG_INITIALIZER;
sp->ip = LIBNET_PTAG_INITIALIZER;
/*
* If device is NULL, that means the user did not specify one and
* is leaving it up libpcap / libnet to find one. We'll use
* libpcap's lookup routine, but they're both from the same
* codebase so it doesn't matter... ;)
*/
if (device == NULL)
{
device = pcap_lookupaev(errbuf);
if (device == NULL)
{
sift_destroy(sp);
return (NULL);
}
}
/*
* Open the packet capturing device with the following values:
*
* SNAPLEN: We shouldn't need more than 150 bytes
* PROMISC: off
* TIMEOUT: Oms
*/ sp->p = pcap_open_live(device, SNAPLEN, PROMISC, TIMEOUT, errbuf);
if (sp->p == NULL)
{
return (NULL);
}
/*
* BPF, by default, will buffer packets inside the kernel until
* either the timer expires (which we do not use) or when the
* buffer fills up. This is not sufficient for us since we could
* miss responses to our probes. So we set BIOCIMMEDIATE to tell
* BPF to return immediately when it gets a packet. This is pretty
* much the same behavior we see with Linux which returns every
* time it sees a packet. This is less than efficient since we're
* spending more time interrupting the kernel, but hey, we gotta
* get our work done!
*
* We don't check for error here on purpose. Since we're not
* doing any robust precompilation configuration via autoconf
* we can't be sure if this system supports BPF. As such we'll
* just try the ioctl and if it fails - so be it. We'll assume
* the system does not support the ioctl(). This IS pretty naive.
* For the right way to do this, see Chapter 12. Also we do hope
* that this ioctl() won't cause unexpected side effects on non
* bpf-enabled machines.
*/
one = 1;
if (ioctl(pcap_fileno(sp- p), BIOCIMMEDIATE, &one) 0)
{
/* it's ok if this fails... */
}
/*
* We need to make sure this is Ethernet. The DLT_EN10MB specifies
* standard 10MB and higher Ethernet.
*/
if (pcap_datalink(sp- p) != DLT_EN10KB)
{
sprintf(errbuf, "Sift only works with ethernet.\n");
sift_destroy(sp);
return (NULL);
}
/* get the subnet mask of the interface */
if (pcap_lookupnet(device, &local_net, &netmask, errbuf) == -1)
{
snprintf(errbuf, LIBNET_ERRBUF_SIZE, "pcap_lookupnet()");
sift_destroy(sp);
return (NULL);
}
/* compile the BPF filter code */
if (pcap_compile(sp- p, &filter_code, FILTER, 1, netmask) == -1)
{
snprintf(sp->errbuf, LIBNET_ERRBUF_SIZE, "pcap_compile(): %s" '
pcap_geterr(sp->p));
sift_destroy(sp);
return (NULL);
}
/* apply the filter to the interface */
if (pcap_setfilter(sp- p, &filter_code) == -1)
{
snprintf(sp->errbuf, LIBNET_ERRBUF_SIZE, "pcap_setfilter(): %s" '
pcap_geterr(sp- p));
sift_destroy(sp);
return (NULL);
}
sp->l = libnet_init(LIBNET_RAW4, device, errbuf);
if (sp->l == NULL)
{
sift_destroy(sp);
return (NULL);
}
/* set the source address of our interface */
sp->src_ip = Iibnet_get_ipaddr4(sp->l);
return (sp);
}
void
sift_destroy(struct sift_pack *sp)
{
if (sp)
{
ir (sp->p)
{
pcap_close (sp->p);
}
if (sp->l)
{
libnet_destroy(sp->l);
}
if (sp->in_hosts)
{
fclose(sp->in_hosts);
}
}
}
int
catch_sig(int signo, void (*handler)())
{
struct sigaction action;
action.sa_handler = handler;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
if (sigaction(signo, &action, NULL) == -1)
{
return (-1);
}
else
{
return (1);
}
}
void
sift(struct sift_pack *sp)
{
u_char retry_cnt;
char host[128];
retry_cnt = 0;
/* pull entries from the host list and send queries */
while (fgets(host, sizeof (host) - 1, sp->in_hosts) && loop)
{
if (host[0] == '#')
{
/* ignore comments */
continue;
}
/* remove the newline */
host[strlen(host) - 1] = 0;
/* build a chaos query packet using host as the destination */
if (build_packet(sp, host) == -1)
{
fprintf(stderr, "build_packet(): %s", sp- errbuf);
continue;
}
/* set retry counter, accounting for the probe just sent */
sp->cnt ? retry_cnt = sp->cnt - 1 : 0;
retry:
/* write query the network */
if (write_packet(sp) == -1)
{
fprintf(stderr, "write_packet(): %s", sp->errbuf);
continue;
}
else
{
sp->stats. total_queries++;
fprintf(stderr, "Chaos class query to %s: t",
libnet_addr2name4(sp- dst_ip, 0));
}
/* read the response handling timeouts if so configured */
if (receive__packet (sp) == TIMEDOUT)
{
/* timed out, check for retry */
if (retry_cnt)
{
retry_cnt--;
goto retry;
}
}
}
}
int
build_packet(struct sift_pack *sp, char *host)
{
u_long packet_size;
packet_size = LIBNET_IPV4_H + LI3NET_UDP_H + LIBNET_DNSV4_H +
CHAOS_QUERY_S;
/*
* Increment the session id per packet. We do this in case a DNS
* server happened to respond late to a query we had already deemed
* expired. If we used the same transaction id for every query,
* these late comers could give us false results.
*/
+ + sp->id;
/*
* Build a dns chaos class query request packet. As before, we
* save the ptag after the first usage so future calls will modify
* this packet header template rather than build a new one.
*/
sp->dns = Iibnet_build_dnsv4(
sp->id, /* transaction id */
0x0100, /* flags (request) */
1, /* 1 question RR */
0, /* no answer RR */
0, /* no authority RR */
0, /* no additional RR */
chaos_query, /* payload */
CHAOS_QUERY_S, /* payload size */
sp->l, /* libnet context */
sp->dns); /* ptag */
if (sp->dns == -1)
{
sprintf(sp->errbuf, "Can't build DNS header: %s /n",
libnet_geterror(sp->l));
return (-1);
}
/*
* The UDP header only has to be built once. Checksums will have
* to be recomputed everytime since the DNS header is changing
* but we don't need to modify the header explicitly after it's
* built.
*/
if (sp->udp == LIBNET_PTAG_INITIALIZER)
{
sp->udp = libnet_build_udp(
SOURCE_PORT, /* source port */
53, /* destination port */
LIBNET_UDP_H + LIBNET_DNSV4_H + CHAOS_QUERY_S,
0, /* checksum */
NULL, /* payload */
0, /* payload size */
sp->l, /* libnet context */
sp->udp); /* ptag */
if (sp->udp == -1)
{
sprintf(sp->errbuf, "Can't build UDP header: %s /n",
libnet_geterror(sp->l));
return (-1);
}
}
/* resolve the host in a big endian number */
if ((sp->dst_ip = libnet_name2addr4(sp->l, host,
LIBNET_RESOLVE)) == -1)
{
sprintf(sp->errbuf, "%s (%s)\n", libnet_geterror(sp->l), host);
fp->stats.timed_out_resolving++;
return (-1);
}
/*
* After building it, we'll need to update the IP header every time
* with the new address.
*/
sp->ip = Iibnet_build_ipv4(
packet_size, /* total packet size */
0, /* type of service */
242, /* identification */
0, /* fragmentation */
64, /* time to live */
IPPROTO_UDP, /* protocol */
0, /* checksum */
sp->src_ip, /* source */
sp- dst_ip, /* destination */
NULL, /* payload */
0, /* payload size */
sp->l, /* libnet context */
sp->ip); /* ptag */
if (sp->ip == -1)
{
sprintf(sp->errbuf, "Can't build IP header: %s\n",
libnet_geterror(sp->l)};
return (-1);
}
return (-1);
}
int
write_packet(struct sift_pack *sp)
{
int c;
c = libnet_write(sp->l);
if (c == -1)
{
sprintf(sp->errbuf, "libnet_write(): %s /n",
libnet_geterror(sp->l));
}
return (c);
}
int
receive_pacKec(btrucu sift_pack *sp;
{
u_short ip_hl;
u_char *payload;
char version[128];
fd_set read_set;
u_short count, offset;
struct timeval timeout;
struct Iibnet_ipv4_hdr *ip;
struct Iibnet_dnsv4_hdr *dns;
int c, j, 1, m, timed_out, pcap_fd;
timeout.tv_sec = sp->to;
timeout.tv_usec = 0;
pcap_fd = pcap_fileno(sp->p);
FD_ZERO(&read_set);
FD_SET(pcap_fd, &read_set);
/* run through the packet capturing loop until a timeout or ctrl-c */
for (timed_out = 0; !timed_out && loop; )
{
/* synchronous I/O multiplexing */
c = select(pcap_fd + 1, &read_set, 0, 0, fctimeout);
switch (c)
{
case -1:
snprintf(sp->errbuf, LIBNET_ERRBUF_SIZE,
"select() %s", strerror(errno));
return (-1);
case 0:
timed_out = 1;
continue;
default:
if (FD_ISSET(pcap_fd, &read_set) == 0)
{
timed_out = 1;
continue;
}
/* fall through to read the packet */
}
sp->packet = (u_char *)pcap_next(sp->p, &sp->h);
if (sp->packet == NULL)
{
/*
* We have to be careful here as pcap_next() can return
* NULL if the timer expires with no data in the packet
* buffer or under some special circumstances under linux.
*/
continue;
}
ip = (struct Iibnet_ipv4_hdr *)(sp- packet + LIBNET_ETH_H);
if (ip->ip_src.s_addr == sp->src_ip)
{
/* packets we send are of no interest to us here. */
continue;
}
ip_hl = ip->ip_hl << 2;
dns = (struct Iibnet_dnsv4_hdr *)(sp- packet + LIBNET_ETH_H +
ip_hl + LIBNET_UDP_H);
/* check to see if this is a response to our query */
if (ntohs(dns->id) == sp->id)
{
/* check to see if the CHAOS class is implemented */
if ((ntohs(dns- flags) & DNS_NOTIMPL))
{
fprintf(stderr, "not implemented /n");
sp->stats.total_responses++;
sp->stats.not_implemented++;
return (NO_ANSWER);
}
/* check to see if the server failed */
if ((ntohs(dns- flags) & DNS_SERVFAILED))
{
fprintf(stderr, "server failed /n");
sp->stats.total_responses++;
sp->stats. server_failed++;
return (NO_ANSWER);
}
/* check to see if there was a format error */
if ((ntohs(dns- flags) & DNS_FORMATERR))
{
fprintf (stderr, "format error\n");
sp->stats.total_responses++;
sp->stats.format_error++;
return (NO_ANSWER);
}
/*
* Every response to our chaos class query should have our
* original uncompressed question in it. As such we can
* safely point payload past that query rr directly to
* the answer rr which is what we want to parse.
*/
payload = (u_char *)(sp- packet + LIBNET_ETH_H + ip_hl +
LIBNET_UDP_H + LIBNET_DNSV4_H + CHAOS_QUERY_S);
/*
* Some DNS servers will be smart and compress their
* response to our query. We check for that case here.
*/
if (payload[0] & 0xcO)
{
/*
* When the two high-order bits are set (values
* 192 - 255) it indicates the response is compressed.
* Shave off the low-order 14 bits to determine the
* offset. It's pretty bitwise code but unfortunately
* we have no use for it in this version.
*/
offset = (payload[0j << 0x08 | payloadfl]) & 0x3fff;
/*
* The llth and 12th bytes will contain the count
* (number of bytes) of the answer.
*/
count = payload[10] << 0x08 | payload[11];
j = 12;
}
else
{
/*
* If we're not compressed step over the 24 bytes of
* answer stuff we don't care about.
*/
count = payload[22] << 0x08 | payload[23] ;
j = 24;
}
/*
* Our buffer to hold the version info is only 128 bytes
* and we need to account for the terminating NULL.
*/
count > 127 ? count =127 : count ;
memset (version, 0, 128);
/*
* Run through the payload pulling out only the printable
* ASCII characters which are between 0x21 (!) and 0x7e
* (~).
*/
for (1 = 0, m = 0; 1 < count; 1++)
{
if (payload[j + 1] = 0x21 && payloadtj + 1] = 0x7e)
{
version[m] = payload[j + 1];
m++;
}
}
/* report the version to the user */
fprintf(stderr, "%s /n", version);
sp->stats.valid_responses++;
sp->stats.total_responses++;
return (RESPONSE);
}
}
/* we timed out waiting for a response */
fprintf(stderr, "*\n");
sp->stats.timed_out++;
return (TIMEDOUT);
}
void
cleanup(int signo)
{
loop = 0;
printf("Interrupt signal caught... /n");
}
void
sift_stats(struct sift_pack *sp)
{
printf("Sift statistics: /n"
"total queries sent:\t\t%41d\n"
"total responses received:\t%41d\n"
"total valid responses received:\t%41d\n"
"total timeouts:\t\t\t%41d\n"
"total timeouts resolving:\t%41d\n"
"total not implemented:\t\t%41d\n"
"total server failed:\t\t%41d\n"
"total format errors:\t\t%41d\n",
sp->stats.total_gueries, sp->stats.total_responses,
sp->stats.valid_responses, sp->stats.timed_out,
sp->stats.not_implemented, sp->stats.server_failed,
sp->stats. forma error);
}
void
usage(char *name)
{
printf("usage %s [options] host_file\n"
"-h\t\tthis blurb you see right here\n"
"-i device\tspecify a device\n"
"-r count\tnumber of times to retry the guery\n"
"-t timeout\tseconds to wait for a response\n", name);
}
/* EOF */

/ 135