|
/*
* $Id: spoofscan.c,v 0.9 2004/03/06 17:29:17 sviat Exp $
* <spoofed stealth portscanner>
*
* Copyright (c) 2002 Luigi Pizzirani <l.pizzira@virgilio.it>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
are
* met: 1. Redistributions of source code must retain the above
copyright
* notice, this list of conditions and the following disclaimer. 2.
* Redistributions in binary form must reproduce the above copyright
notice,
* this list of conditions and the following disclaimer in the
documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF
* SUCH DAMAGE.
*
*
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#ifndef __USE_BSD
#define __USE_BSD
#endif
#include <netinet/ip.h>
#ifndef __FAVOR_BSD
#define __FAVOR_BSD
#endif
#include <netinet/tcp.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAXNUMPORTS 65535
/* pseudotcp structure to calculate tcp checksum as specified in RFC 793
*/
struct pseudo {
uint32_t saddr;
uint32_t daddr;
char unused;
char proto;
uint16_t length;
};
char packet[256], packet2[256], packet3[256], buf[256];
struct ip *ip = (struct ip *) packet;
struct tcphdr *tcp = (struct tcphdr *) (packet + sizeof(struct ip));
struct pseudo *pseudo = (struct pseudo *) packet3;
struct ip *ip2 = (struct ip *) packet2;
struct icmp *icmp = (struct icmp *) (packet2 + sizeof(struct ip));
char *data = packet + sizeof(struct ip) + sizeof(struct tcphdr);
char *data2 = packet2 + sizeof(struct ip) + sizeof(struct icmp);
struct ip *iprecv = (struct ip *) buf;
void usage(char *);
void print_service(uint16_t);
uint16_t checksum(uint16_t*, int);
uint16_t send_icmp(int, int, struct ip*, struct sockaddr_in,
struct sockaddr_in);
void send_tcp(int, struct ip*, struct sockaddr_in,
struct sockaddr_in, int);
int check_traffic(int, int, struct sockaddr_in,
struct sockaddr_in, int, char*);
int
main(int argc, char **argv)
{
int s, s2, s3, ch, open_ports[MAXNUMPORTS];
register int i, j, h, k;
uint16_t id[100], a[100], b[100];
int on = 1;
int *p = open_ports;
register int t = 0;
const int *optval = &on;
char *target_host, *silent_host, *low_port, *high_port, *num_packets,
*timeout;
struct hostent *hostent, *hostent2;
struct sockaddr_in sin, sin2, sin3;
/* Security */
if (getuid() != geteuid()) {
puts("Stealth Scan doesn't run with +s bit set.");
exit(1);
}
if (getuid() != 0) {
puts("Stealth Scan must run as root.");
exit(1);
}
puts("\nStealth Scan by Luigi Pizzirani.\n");
puts("Warning!!! This is a stealth portscanner based on the
requirements that the host we are using for our spoof");
puts("has no traffic, has not random IP id and we have all
firewalls down. Anyway, being this scanner stealth, it");
puts("is far from being 100% reliable. Enjoy it.\n");
puts("DISCLAIMER!!! IP SPOOFING, AS ANY KIND OF FORGEMENT IS
AN ILLEGAL PRACTICE. USE");
puts("THIS SCANNER ONLY FOR TESTING PURPOSES AND ON YOUR
LOCAL AREA NETWORK. IN NO EVENT");
puts("I CONSIDER MYSELF LIABLE FOR ANY ABUSE OF THIS PROGRAM.\n");
if (argc != 13)
usage(argv[0]);
while ( (ch = getopt(argc, argv, "a:s:l:h:n:t:")) != -1)
switch(ch) {
case 'a':
target_host = argv[optind - 1];
break;
case 's':
silent_host = argv[optind - 1];
break;
case 'l':
low_port = argv[optind - 1];
break;
case 'h':
high_port = argv[optind - 1];
break;
case 'n':
num_packets = argv[optind - 1];
if (atoi(num_packets) > 100) {
puts("You cannot send
more than 100 packets.\n");
exit(1);
}
break;
case 't':
timeout = argv[optind - 1];
break;
case '?':
default:
usage(argv[0]);
}
*p = 0;
if ( (s = socket(PF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("socket");
exit(1);
}
if ( (s2 = socket(PF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("socket");
exit(1);
}
if ( (s3 = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
perror("socket");
exit(1);
}
setsockopt(s, IPPROTO_IP, IP_HDRINCL, optval, sizeof(on));
setsockopt(s2, IPPROTO_IP, IP_HDRINCL, optval, sizeof(on));
memset(&sin, 0, sizeof(sin));
memset(&sin2, 0, sizeof(sin));
memset(&sin3, 0, sizeof(sin));
memset(ip, 0, sizeof(struct ip));
memset(ip2, 0, sizeof(struct ip));
memset(icmp, 0, sizeof(struct icmp));
memset(iprecv, 0, sizeof(struct ip));
sin.sin_family = sin2.sin_family = sin3.sin_family = AF_INET;
/* target host's ip address */
if ( (hostent = gethostbyname(target_host)))
memcpy (&sin.sin_addr, hostent->h_addr,
hostent->h_length);
else if ( (inet_pton(AF_INET, target_host, &sin.sin_addr)) !=
INADDR_NONE) {
herror("gethostbyname");
exit(1);
}
/* silent host's ip address */
if ( (hostent2 = gethostbyname(silent_host)))
memcpy (&sin2.sin_addr, hostent2->h_addr,
hostent2->h_length);
else if ( (inet_pton(AF_INET, silent_host, &sin2.sin_addr)) !=
INADDR_NONE) {
herror("gethostbyname");
exit(1);
}
sin3.sin_addr.s_addr = htonl(INADDR_ANY); /*my own ip
address */
if (check_traffic(s2, s3, sin3, sin2, atoi(num_packets),
silent_host))
exit(1);
/* sends icmp packets to the dumb host and tcp packets with
SYN flag set to the target host */
for (i = atoi(low_port); i <= atoi(high_port); i++) {
usleep(atoi(timeout));
printf("Id sequence relative to port %d of host
%s via %s:\t\t", i, target_host, silent_host);
tcp->th_dport = sin.sin_port = sin2.sin_port =
(uint16_t) i;
for (j = 0; j < atoi(num_packets); j++) {
icmp->icmp_seq = htons((uint16_t) j);
id[j] = send_icmp(s2, s3 , ip2, sin3,
sin2);
send_tcp(s, ip, sin2, sin, i);
printf("%d\t", id[j]);
}
k = 1;
for (j = 0; j < atoi(num_packets) - 1; j++)
a[j] = id[j + 1] - id[j];
for (j = 0; j < atoi(num_packets) - 2; j++) {
b[j] = (a[j + 1] == a[j]);
k = (k && b[j]);
}
/* if id field increases constantly and the silent host has
still no traffic the port must be closed, otherwise it must be open */
for (j = 0; j < atoi(num_packets) - 1; j++ )
if (!id[j]) {
puts("\nId field must not be 0.
Please try another host.\n");
return 1;
}
if (!k) {
usleep(atoi(timeout));
for (h = 0; h < atoi(num_packets);
h++)
id[h] = send_icmp(s2, s3, ip2, sin3,
sin2);
k = 1;
for (j = 0; j < atoi(num_packets) -
1; j++)
a[j] = id[j + 1] - id[j];
for (j = 0; j < atoi(num_packets) -
2; j++) {
b[j] = (a[j + 1] == a[j]);
k = (k && b[j]);
}
if (k) {
printf("\aHmmm...looks
like %d is OPEN.\n", i);
open_ports[t++] = i;
}
else {
printf("\nHost %s now has
too much traffic. Please change it or retry later.Stop at port %d.\n",
silent_host, i);
printf("\nPorts of %s
that look like open:\t", target_host);
while (*p)
print_service((uint16_t)
*p++);
puts("\b\b.");
exit(1);
}
}
else
printf("Hmmm...looks like %d is
closed.\n", i);
}
printf("\nPorts of %s that look like open:\t", target_host);
while (*p)
print_service((uint16_t) *p++);
puts("\b\b.");
close(s);
close(s2);
close(s3);
exit(0);
}
void
usage(char *how)
{
printf("Usage: %s -a target_host -s silent_host -l low_port -h
high_port -n num_packets -t timeout(in microseconds).\n", how);
exit(1);
}
void
print_service(uint16_t port)
{
struct servent *servent;
if ( (servent = getservbyport(htons(port), "tcp")))
printf("%d(%s), ", port, servent->s_name);
else
printf("%d, ", port);
}
/* usual checksum */
uint16_t
checksum(uint16_t *addr, int len)
{
register int sum = 0;
uint16_t answer = 0;
register uint16_t *w = addr;
register int nleft = len;
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
if (nleft == 1) {
*(uint16_t *) (&answer) = *(uint16_t *) w;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return (answer);
}
/* sends icmp packets to silent host */
uint16_t
send_icmp(int sendsock, int recvsock, struct ip *ip, struct sockaddr_in
mysin, struct sockaddr_in dumbsin)
{
int size = sizeof(struct sockaddr_in);
register int i;
uint16_t id;
ip->ip_hl = 5;
ip->ip_v = 4;
ip->ip_tos = 0;
ip->ip_len = sizeof(struct ip) + sizeof(struct icmp) + 48;
ip->ip_id = htons((uint16_t) random());
ip->ip_off = 0;
ip->ip_ttl = 255;
ip->ip_p = IPPROTO_ICMP;
ip->ip_sum = 0;
ip->ip_src = mysin.sin_addr;
ip->ip_dst = dumbsin.sin_addr;
icmp->icmp_type = 8; /* echo request */
icmp->icmp_code = 0;
icmp->icmp_cksum = 0;
icmp->icmp_id = htons((uint16_t) random()); /* thx awgn for
having told me how to fill this field */
/* thx again, man for this too */
for (i = 0; i < 48; i++)
data2[i] = i + 8;
icmp->icmp_cksum = checksum((uint16_t *) icmp, (sizeof(struct
icmp) + 48) & ~1);
sendto(sendsock, packet2, ip->ip_len, 0, (struct sockaddr *)
&dumbsin, size);
recvfrom(recvsock, buf, sizeof(struct ip) + sizeof(struct icmp)
+ sizeof(data), 0, (struct sockaddr *) &dumbsin, &size);
id = ntohs(iprecv->ip_id);
return (id);
}
/* sends tcp spoofed packets to target host with silent's host source ip
*/
void
send_tcp(int sock, struct ip *ip, struct sockaddr_in dumbsin, struct
sockaddr_in targetsin, int i)
{
memset(pseudo, 0, sizeof(struct pseudo));
ip->ip_hl = 5;
ip->ip_v = 4;
ip->ip_tos = 0;
ip->ip_len = sizeof(struct ip) + sizeof(struct tcphdr);
ip->ip_id = htons((uint16_t) random());
ip->ip_off = 0;
ip->ip_ttl = 255;
ip->ip_p = IPPROTO_TCP;
ip->ip_sum = 0;
ip->ip_src = dumbsin.sin_addr;
ip->ip_dst = targetsin.sin_addr;
pseudo->saddr = ip->ip_src.s_addr;
pseudo->daddr = ip->ip_dst.s_addr;
pseudo->unused = 0;
pseudo->proto = IPPROTO_TCP;
pseudo->length = htons(sizeof(struct tcphdr));
tcp->th_sport = htons(rand());
tcp->th_dport = htons((uint16_t)i);
tcp->th_seq = htonl(random());
tcp->th_ack = 0;
tcp->th_off = 5;
tcp->th_flags = TH_SYN;
tcp->th_win = htons(65535);
tcp->th_sum = 0;
tcp->th_urp =0;
memcpy(packet3, pseudo, sizeof(struct pseudo));
memcpy(packet3 + sizeof(struct pseudo), tcp, sizeof(struct
tcphdr));
memset(packet3 + sizeof(struct pseudo) + sizeof(struct tcphdr),
0, 12);
tcp->th_sum = checksum((uint16_t *) packet3, (sizeof(struct
pseudo) + sizeof(struct tcphdr) + 12) & ~1);
sendto(sock, packet, ip->ip_len, 0, (struct sockaddr *)
&targetsin, sizeof(struct sockaddr_in));
}
/* verifies if the silent host is really silent:) */
int
check_traffic(int sendsock, int recvsock, struct sockaddr_in mysin,
struct sockaddr_in dumbsin, int npack, char* host)
{
int k;
register int i;
uint16_t id[100], a[100], b[100];
printf("Id sequence relative to %s:\t\t", host);
k = 1;
for (i = 0; i < npack; i++) {
icmp->icmp_seq = htons((uint16_t)i);
id[i] = send_icmp(sendsock, recvsock, ip2, mysin,
dumbsin);
printf("%d\t", id[i]);
}
for (i = 0; i < npack - 1; i++)
a[i] = id[i + 1] - id[i];
for (i = 0; i < npack - 2; i++) {
b[i] = (a[i + 1] == a[i]);
k = (k && b[i]);
}
if (!id[i]) {
puts("\nId field must not be 0. Please try another
host.\n");
return (1);
}
if (k) {
printf("\nIt seems that host %s has no traffic:
excellent!!!\n\n", host);
return (0);
}
else {
printf("\nHost %s has too much traffic: please try
another one.\n\n", host);
return (1);
}
} |