CServiceAttack
A quick programming tutorial

Table of Content

  1. Introduction
  2. Compiling
  3. Getting Started
    1. Initialising
    2. Reading User Input
    3. Choosing Input/Output Methods
    4. Setting Options
    5. Cleaning Up
  4. Beyond The Basics
    1. Putting It All Together
    2. Performance Tips
  5. Feedback

Introduction

This is a easy tutorial for programmers wanting to use the CServiceAttack 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. You should also have some basic understanding of IPv4 network addressing. Expierence in writting multi threaded aplication will also come in handy. If you want to know more about the functions this class offers you should familiarise yourself with my Chimera project. This is not a complete list of functions that CServiceAttack offers. I will go over most of them, but please refer to the documentation for futher details. Please note that

typedef unsigned int uint;

is used throughout the code.

Compiling

Please #define LINUX or WINDOWS when building CServiceAttack. Also remember about a #define OPENSSL if you want SSL support.

Getting Started

This is the easy part. Just untar the CServiceAttack class's files into a directory in your project's source tree. Add the files to your project. You must have the pthread headers and libraries installed. You will also have to link your project against the pthread library. You will notice that CServiceAttack actually uses a small class called CBrutePasswd for internal brute forcing, but this tutorial will focus on using the CServiceAttack class, because CBrutePasswd is never used directly.

In order to use CServiceAttack you must include the "CServiceAttack.h" header, and include the -lpthread option during linking. If you wish to use SSL you will have to have openssl libraries and headers installed on your system. Just link your project to -lssl and put #define OPENSSL before #include "CServiceAttack.h".

CServiceAttack.h will include all the other necessary headers. You should have the following:

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <string>
#include <list>
#include <iostream>
#include <fstream>
#include <pthread.h>

If you are to use SSL you will also need these:

#ifdef OPENSSL
  #include <openssl/ssl.h>
  #include <openssl/des.h>
  #include <openssl/err.h>
#endif

Initialising

Lets jump right in and start with some code

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

int main()
{
    CServiceAttack *crack = new CServiceAttack(); // creating the object

    //
    // some actions
    //

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

Reading User Input

You must use the CServiceAttack::target_input_data class to pass targets to CServiceAttack and later call CServiceAttack::run_atack().

class CServiceAttack::target_input_data {
public:
    target_input_data();
    ~target_input_data();

    CServiceAttack::service_type type;
    const char *user;
    CServiceAttack::PasswdOptions passwd_options;
    sockaddr_in addr;
    bool ssl;
    const char *charset;
    uint min_chars;
    uint max_chars;
};

typedef enum {
    SERVICE_NONE = 0,
    SERVICE_POP3,
    SERVICE_FTP,
    SERVICE_MYSQL
} CServiceAttack::service_type;

typedef enum {
    PASSWD_OPTIONS_NONE = 0,
  // default
    PASSWD_OPTIONS_NULL = 1,
  // check for NULL passwords
    PASSWD_OPTIONS_LOGIN = 2,
  // check for passwords same as login
    PASSWD_OPTIONS_LOGIN_REV = 4
  // check for passwords same as reversed login
} CServiceAttack::PasswdOptions;

To aid you in filling the target_input_data structure the CServiceAttack namespace provides a couple of functions to help you with user input.

sockaddr_in *CServiceAttack::get_host_data(const char *host, uint);

The first argument should be a pointer to a hostname or ip address in the form a.b.c.d, the second is the port number in host byte order. Upon success the sockaddr_in *CServiceAttack::get_host_data(const char *host, uint) fills a static sockaddr_in structure that needs to be set in target_input_data (addr field) and returns a pointer to it. NULL is returned on error. Because it is a pointer to a static variable inside a function, you must use memcpy() to copy the data to your structure. Let this example clear things out:

target_input_data target_host;           // our data structure
const char *host = "www.example.com";    // host name
uint port = 110;                         // port number

void *host_data = CServiceAttack::get_host_data(host, port);
if (!host_data) {
    printf("unable to resolve hostname\n"); // something went wrong
    return ( false );
}

memcpy(&target_host.addr, host_data, sizeof(target_host.addr));
// remember to copy the data

The second function that CServiceAttack provides is const char *CServiceAttack::get_next_line(FILE * hFile). The name says it all. Use this function to get the next from an open file descriptor. NULL is returned if hFile is not a valid file descriptor or EOF is reached.

const char *p = CServiceAttack::get_next_line(hFile);
if (!p)
    rewind(hFile);

There is one more useful function CServiceAttack provides called char *alloc_copy(const char *str). Please note that it's not part of the CServiceAttack namespace, but is declared in misc.h. It is important when using target_input_data to use this function to set the user name and charset, because the deconstructor will delete these strings when going out of scope.

example:

void foo_bar() {
    target_host.user = alloc_copy("tomicki"); // good
    // target_host.user = "tomicki"
  // bad - will segfault at the end of foo_bar()
   }

In order to use CServiceAttack you must create the object, create a CServiceAttack::target_input_data object, populate the object, pass it to the CServiceAttack object using void CServiceAttack::add_target(...);, and wait for results.

void CServiceAttack::
  add_target(target_input_data &start_options, bool = false);

CServiceAttack::target_input_data target_host; // creating the object

target_host.type = CServiceAttack::SERVICE_POP3;
target_host.user = alloc_copy(argv[1]);

void *host_data = CServiceAttack::get_host_data(argv[2], atoi(argv[3]));
if (!host_data) {
    printf("unable to resolve hostname\n"); // something went wrong
    return ( false );
}

memcpy(&target_host.addr, host_data, sizeof(target_host.addr));

target_host.ssl = true;                            // default false
target_host.passwd_options =
    CServiceAttack::PasswdOptions(CServiceAttack::PASSWD_OPTIONS_NULL |
    CServiceAttack::PASSWD_OPTIONS_LOGIN);         // optional
target_host.charset = alloc_copy(argv[4]);         // optional
target_host.min_chars = 6;                         // optional
target_host.max_chars = 12;                        // optional
void
CServiceAttack::add_target(target_input_data &start_options, bool = false);

The second argument of add_target is optional. If true the cracking will begin immediately (in the same thread) thus blocking futher execution till cracking is finished.

example:
    crack->add_target(target_host);     // adding the target
                  // do something - perhaps add more targets

    crack->run_atack();                 // running the attack

Choosing Input/Output Methods

In order for CServiceAttack to work you as an external programmer must provide it with a couple of pointers to external functions it will use. The functions

void
CServiceAttack::set_output(void (*p)(const char*));
void
CServiceAttack::set_passwd_func(const char* (*p)(bool));
void
CServiceAttack::set_notice(void (*p)(target_output_data*));

are used to set the external functions CServiceAttack will use. They are all mandatory, CServiceAttack will work fine if you don't supply them, won't really be of much use!

First we have the

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

function. This is used by CServiceAttack to output messages about it's progress and errors. The very basic function should look something like this:

void print_data(const char *p)
{
    printf("%s", p); // please note that using printf(p)
                     // is a *very* bad idea
                     // due to formating string vulnerabilities
                     // please the form show above
                     // your program will probably segfault
                     // if you use printf(p)
}

example:
    crack->set_output(print_data);

Setting the verbostity level is described, under Setting Options.

Second there is

void CServiceAttack::set_passwd_func(const char* (*p)(bool));

it is called by CServiceAttack whenever it need's a password to check. Please note that brute forcing is done internally but providing successive passwords from password lists, stdin or memory is your responsibility. The first (and only) argument of this function is a bool value. If it is true CServiceAttack wants you to rewind the password list and return NULL. This will happen when an account is cracked, or cracking the next target begins. Your functions must return NULL if no more passwords are available. I have created two basic external implementation of this function

const char* get_single_passwd(bool r)
{
    static bool t(true);

    if (r) {
        t = true;
        return 0;
    }

    if (t) {
        t = false;
        return ( passwd );
    } else
        return 0;
}

const char* get_passwd(bool r)
{
    if (r) {
        rewind(hFile);
        return 0;
    }

    const char *p = CServiceAttack::get_next_line(hFile);

    if (!p)
        rewind(hFile);

    return ( p );
}

    crack->set_passwd_func(get_single_passwd);
or
    crack->set_passwd_func(get_passwd);

Finally we have the most important of function of the three

void
CServiceAttack::set_notice(void (*p)(CServiceAttack::target_output_data*));

This is the function that CServiceAttack will call when it cracks and account. When it does a pointer to a newly created

class CServiceAttack::target_output_data;
GOTO the documentation

will be passed to your function. It is a pointer to an object created using the operator new. It's your job to delete it when u finish using it.

void deal_with_results(CServiceAttack::target_output_data *p)
{
    printf("service: ");
    switch (p->type) {
        case CServiceAttack::SERVICE_POP3:
            printf("pop3");
        break;

        case CServiceAttack::SERVICE_FTP:
            printf("ftp");
        break;

        case CServiceAttack::SERVICE_MYSQL:
            printf("mysql");
        break;
    }
    printf(" host: %s port: %d user: %s password: %s\n",
        inet_ntoa(p->addr.sin_addr), ntohs(p->addr.sin_port), p->user,
        p->passwd ? p->passwd : "null");
    fflush(stdout);

    delete p;
}

example:
    crack->set_notice(deal_with_results);

Setting Options

CServiceAttack should work fine for most configurations, but it has a couple of useful options which can be fine tuned to increase performance and cracking success rate. These options include setting the verbosity level, the number of threads, delay between creating new threads, socket timeout, etc.

CServiceAttack will output messages using it's internal output() function. The amount of verbosity can be set and checked by using

void set_output_level(CServiceAttack::MessageLevel level);
CServiceAttack::MessageLevel get_output_level();

CServiceAttack::MessageLevel being one of the below

typedef enum {
    MSG_NONE = 0,
    MSG_BASIC,    // default
    MSG_VERBOSE,
    MSG_WARNING,
    MSG_ERROR,
    MSG_DEBUG,
    MSG_ALL
} CServiceAttack::MessageLevel;

example:
    crack->set_output_level(CServiceAttack::MSG_DEBUG);

By default CServiceAttack will use 256 threads to run the attack. You can adjust this value by using these functions.

void CServiceAttack::set_threads(uint n);
uint CServiceAttack::get_threads();

By default every connection, read and write attempt will timeout after 60 seconds. If you need to retrieve or change that value use these functions

long CServiceAttack::get_conn_timeout();
void CServiceAttack::set_conn_timeout(long);

Certain servers don't like too many connection attempts at once, others will don't like too many connections above some delta average. That is why when cracking we sleep for a certain amount of time between creating new threads. These functions set and get the time between creating new threads in microseconds.

uint CServiceAttack::get_thread_creation_speed();
void CServiceAttack::set_thread_creation_speed(uint);

If a connection is reset by the remote host or an connection error occurs, CServiceAttack will reduce the number of threads that are being used. If don't want to reduce threads when errors occur use these functions.

bool CServiceAttack::get_thread_reduction();
void CServiceAttack::set_thread_reduction(bool);

Cleaning Up

CServiceAttack offers one clean up function

void CServiceAttack::flush();

this is called by the deconstructor, but you can also call it manually to free up memory. It will stop all cracking threads, and flush all target's that have been set.

Beyond The Basics

CServiceAttack is a flexible class that can be used in any enviroment that implements the use of pthreads and has an IPv4 network connection. It efficiently uses system resources to crack vulnereable user accounts. It is your choice how to implement it's capabilities.

Putting It All Together

Let's take all the above code and create simple remote password cracking program.

GOTO chimera.cc

No dealing with protocol details, no thread managment, no memory managment! Just read the input, create the targets and run the attack!

Performance Tips

The biggest hit that performance takes is adding more threads to the cracking process. 512 pthreads are handled nicely without any problem on a P4/AthlonXP class system. Reducing the thread number will bring down the memory consumption and CPU utilization. It is important to note that using more that 256 threads only makes sens on systems having a lot of available bandwith. Please note that services like mysql have a connection error limit. After such limit is reached the mysqld server will drop all new connections making futher attack attemps futile. Many FTP servers also have a connection limit from a single IP as low as 10, so using more then 10 threads to attack such server is also a waste of resources.

Feedback

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


"The greatest thing you can do is surprise yourself."

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