CScanner
A quick programming tutorial

Table of Content

  1. Introduction
  2. Getting Started
    1. Initialising
    2. Reading User Input
    3. Dealing With Output
    4. Setting Options
    5. Putting It All Together
  3. Feedback

Introduction

This is a easy tutorial for programmers wanting to use the CScanner class. It explains everything there is to know about using objects of this class. It's written in C++ thus solid knowledge of the language is required. Knowlegde about how TCP/IP works is required. You must understand how the three-way handshake works. This tutorial will not cover all the features CScanner offers to you, please refer to the documentation for futher details. Please note that

typedef unsigned int u32;
typedef unsigned short int u16;
typedef unsigned char u8;

is used throughout the code.

Getting Started

This is the easy part. Just untar the CScanners class's files into a directory in your project's source tree. Add the files to your project. In order for CScanner to work your program must be able to create raw sockets, because CScanner needs to be able to craft packets for it's scanning purposes. On most systems this means running with an effective user id of 0. This little piece of code can be used to check whether the proper privilages are set.

int euid = geteuid();
if (euid) {
  printf("euid 0 is required (currently %d)\n", euid);
  return 0;
}

In order to use CScanner you must include the file "colitas.h" header which holds the definition of the class and will include all other necessary headers. These include:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <vector>

In order to use CScanner you must: create the object, set the member scan_data input_data to reflect your desired scan range (refer to the documentation for more details about scan_data), set the ports you want to scan by using the push_back() method of the public member std::vector<u16> ports, set the external function to deal with the results, set extra options if you need them and run the attack.

Initialising

Lets jump right in and start with some code

#include "colitas.h" // including the proper header

int main()
{
    CScanner *basic_scan = new CScanner(); // creating the object

    //
    // some actions
    //

    delete basic_scan; // remember to delete the object once you finish using it
    return 0;
}

Reading User Input

There are three functions that can aid you in reading the user's input. These are:

void CScanner::populate_port_list(const char*);
void CScanner::populate_ip_addr(const char*);
void CScanner::get_options(int, char**);

example:
if (argc > 1)
    basic_scan->populate_ip_addr(argv[1]);
if (argc > 2)
    basic_scan->populate_port_list(argv[2]);

They are all described in detail in the documentation, please refer there for futher information.

Dealing With Output

This is the part where knowledge about how TCP/IP works will come in handy. The first thing you need to do as a programer before running the scan is setting an external output function. This is done by calling

void CScanner::set_output(void (*p)(char const*));

with a valid pointer to a function like

void syn_print_func(char const *buffer);

When a packet reply is received (positive or negative) a pointer to a buffer containing the packets header will be passed to your function. What you do with it is your choice.

The very basic thing most programmers should do is check whether the packet is a positive or negative reply. This can be done by:

iphdr *ip = (iphdr *)buffer;
tcphdr *tcp = (tcphdr *)(buffer + sizeof(struct iphdr));
u16 port = ntohs(tcp->source);

if (tcp->ack && tcp->syn)
    // positive reply
else if (tcp->rst && tcp->ack)
    // negative reply
else
    // other ?? (someone/something is crafting misconstructed reply packets)

For example:

void syn_print_func(char const *buffer)
{
	iphdr *ip = (iphdr *)buffer;
	tcphdr *tcp = (tcphdr *)(buffer + sizeof(struct iphdr));
	u16 port = ntohs(tcp->source);
			
	if (tcp->ack && tcp->syn) {
		if (show_positive) {
			if (!simple) {
				printf("[open]");
				printf(" %-15s %5d ", inet_ntoa((in_addr&)ip->saddr), port);
							
				if (resolve_hostnames) {
					hostent *h = gethostbyaddr((const char*) &ip->saddr, 4, AF_INET );
					if (h)
						printf("[%s]", h->h_name);
				}
			} else {
				printf(" %-15s %5d ", inet_ntoa((in_addr&)ip->saddr), port);
				
			}
			printf("\n");
		}
	}
	if (tcp->rst && tcp->ack) {
		if (show_negative) {
			if (!simple) {
				printf("[closed]");
				printf(" %-15s %d ", inet_ntoa((in_addr&)ip->saddr), port);
							
				if (resolve_hostnames) {
					hostent *h = gethostbyaddr((const char*) &ip->saddr, 4, AF_INET );
					if (h)
						printf("[%s]", h->h_name);
				}
			} else {
				printf(" %-15s %5d ", inet_ntoa((in_addr&)ip->saddr), port);
			}
			printf("\n");
		}
	}
	fflush(stdout);
	return;
}

This basic code will print out the IP address and port the reply came from

printf(" %s %d ", inet_ntoa((in_addr&)ip->saddr), port);

This is just one example of what you can do with the packet's header. It's really up to you.

Setting Options

Finally there a couple of options that can help you fine tune the scanning process. These include: the delay between scanning packets (in microseconds default:15), the time to wait after sending the last scan packet (in seconds default:3) and the whether to scan all the IP addresses in range or all the ports first (this sounds strange, but will be explained in a moment).

This can be done by using the

void get_options(int, char**);

which is described further in the documentation or set them manually by modifing the proper members of the class. These are:

bool ports_first;   // whether to scan IP addresses
                    // in range or all the ports first
                    // default: false

u32 scan_speed;     // the delay between scanning packets
                    // default: 25

u32 wait_seconds;   // the time to wait after sending
                    // the last scan packet
                    // default: 3

Putting It All Together

    int euid = geteuid();
    if (euid) {
        printf("euid 0 is required (currently %d)\n", euid);
        return 0;
    }

    CScanner *scanner = new CScanner;

    if (argc > 1)
        scanner->populate_ip_addr(argv[1]);
    if (argc > 2)
        scanner->populate_port_list(argv[2]);

    opterr = 0;
	bool ping_scan(false); // check program arguments if you need to set this
  scanner->get_options(argc, argv);
  optind = 0;

   if (ping_scan) {
    	scanner->set_output(ping_print_func);
		if (!scanner->start_ping_scan()) {
			puts("scanning error");
			delete scanner;
			return 0;
		}
	} else {
    	scanner->set_output(syn_print_func);
		if (!scanner->start_syn_scan()) {
			puts("scanning error");
			delete scanner;
			return 0;
		}
	}

    return 0;
  }

    delete scanner;

Pretty simple! And extremely flexible! Enjoy!

Feedback

If you have any questions or something in this tutorial is unclear please email me.


"People want to learn about the world without sacrificing their worldview."

Last update: Wednesday, 11th October, 2023
Copyright © 2001-2024 by Lukasz Tomicki