CScanner
A quick programming tutorial
Table of Content
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 |