Hello and welcome to Programming Thursdays! Today, we’ll be diving into the world of C++ programming language. As a red teamer and pen tester, having a solid grasp of programming concepts and syntax is crucial. In this article, we’ll cover the basics of C++ as well as how it can be used for pen testing and red teaming. So grab your favorite caffeinated beverage and let’s get started!

C++ Basics

C++ is an object-oriented programming language that was first released in 1985. It was designed to improve on the C programming language by adding features such as classes, templates, and inheritance. C++ is widely used in a variety of applications, including operating systems, video games, and financial systems.

C++ Syntax

C++ is a powerful programming language that is widely used in software development, including pen testing and red teaming. In this section, we will cover some of the basic concepts of C++.

Variables and Constants

  • Declare a variable: int x = 5;
  • Declare a constant: const int y = 10;
  • Change the value of a variable: x = 7;
  • Constants cannot be changed: // y = 20; // This line would cause a compile-time error because y is a constant

Data Types

  • int: int x = 5;
  • double: double y = 3.14;
  • char: char c = 'a';
  • bool: bool b = true;
  • string: std::string s = "hello";

Arrays and Dictionaries

  • Declare an array:

    int arr[5] = {1, 2, 3, 4, 5};
    
  • Declare a dictionary:

    std::unordered_map<std::string, int> dict = {
        {"apple", 1}, {"banana", 2}, {"orange", 3}
    };
    
  • Access an array element:

    arr[2]
    
  • Access a dictionary element:

    dict["banana"]
    

Functions

  • Declare a function:

    int add(int a, int b);
    
  • Define a function:

    int add(int a, int b) {
        return a + b;
    }
    
  • Call a function:

    int result = add(2, 3);
    
  • Return a value from a function:

    return a + b;
    

Control Flow

  • if statement:

    if (x > 0) {
        std::cout << "x is positive" << std::endl;
    }
    
  • for loop:

    for (int i = 0; i < 5; i++) {
        std::cout << i << std::endl;
    }
    
  • while loop:

    while (x < 10) { x++; }
    
  • switch statement:

    switch (x) {
        case 0:
            std::cout << "x is zero" << std::endl;
            break;
        case 1:
            std::cout << "x is one" << std::endl;
            break;
        default:
            std::cout << "x is not zero or one" << std::endl;
            break;
        }
    

The basic syntax of C++ is similar to that of C. C++ code is compiled into machine code, which can be run directly on a computer. Here’s an example of a “Hello, World!” program in C++:

#include <iostream>

int main() {
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

Let’s break down this code:

  • #include <iostream>: This line includes the input/output library, which contains the std::cout function we’ll be using to print our message to the console.
  • int main(): This line declares the main function, which is the entry point for the program.
  • {}: These curly braces define the scope of the main function.
  • std::cout << "Hello, World!" << std::endl;: This line prints the message “Hello, World!” to the console using the std::cout function. The << operator is used to concatenate multiple strings together, and std::endl is used to add a newline character to the end of the message.
  • return 0;: This line returns a value of 0 to indicate that the program executed successfully. Now that we’ve covered the basics of C++ syntax, let’s dive into how it can be used for pen testing and red teaming.

Pen Testing and Red Teaming with C++

C++ is a powerful programming language that can be used to develop tools for pen testing and red teaming. In this section, we’ll cover three examples: a port scanner, a password cracker, and a web crawler.

Port Scanner

A port scanner is a tool used to scan a network for open ports. This is useful for identifying potential vulnerabilities in a network. Here’s an example of a port scanner written in C++:

#include <iostream>
#include <cstdlib>
#include <string>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>

int main(int argc, char *argv[]) {
    if (argc < 2) {
        std::cout << "Usage: " << argv[0] << " <hostname>" << std::endl;
        return 1;
    }

    const char* hostname = argv[1];
    struct hostent* host = gethostbyname(hostname);

    if (host == nullptr) {
        std::cout << "Could not resolve hostname: " << hostname << std::endl;
        return 1;
    }

    for (int port = 1; port <= 65535; port++) {
        int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (socket_fd < 0) {
            std::cout << "Error creating socket" << std::endl;
            return 1;
        }

        struct sockaddr_in server_addr;
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(port);
        memcpy(&server_addr.sin_addr.s_addr, &host->h_addr_list[0], host->h_length);

        int result = connect(socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
        if (result == 0) {
            std::cout << "Port " << port << " is open" << std::endl;
        }

        close(socket_fd);
    }

    return 0;
}

This port scanner now loops over all ports from 1 to 65535 and attempts to connect to each one using the TCP protocol. If a connection is successful, it prints a message indicating that the port is open. Note that this approach can be slow, as it will try to connect to every port, even if most of them are closed. A more efficient approach would be to use multithreading to scan multiple ports simultaneously.

Password Cracker

A password cracker is a tool used to guess passwords by trying different combinations of characters. This can be useful for testing the strength of passwords on a system. Here’s an example of a password cracker written in C++:

#include <iostream>
#include <cstring>
#include <algorithm>

bool check_password(const char* password) {
    // TODO: Implement password checking logic
    return false;
}

void brute_force_password(const char* charset, size_t length) {
    char* password = new char[length + 1];
    memset(password, 0, length + 1);

    while (true) {
        if (check_password(password)) {
            std::cout << "Password found: " << password << std::endl;
            break;
        }

        size_t i = 0;
        while (true) {
            if (i == length) {
                break;
            }

            if (password[i] == charset[strlen(charset) - 1]) {
                password[i] = charset[0];
                i++;
            } else {
                password[i] = charset[strchr(charset, password[i]) - charset + 1];
                break;
            }
        }
    }

    delete[] password;
}

int main() {
    const char* charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    size_t length = 8;

    brute_force_password(charset, length);

    return 0;
}

This password cracker uses a brute force method to try every possible combination of characters in a given character set up to a specified length. Let’s break down the code:

  • bool check_password(const char* password): This function checks if the provided password is correct. In a real-world password cracker, this function would be replaced with code that actually attempts to log in with the guessed password.
  • void brute_force_password(const char* charset, size_t length): This function generates all possible passwords up to the specified length and checks them using the check_password function.
  • char* password = new char[length + 1];: This line creates a new character array to hold the password.
  • while (true): This line starts an infinite loop that generates passwords until a correct password is found.
  • if (check_password(password)): This line checks if the current password is correct using the check_password function.
  • size_t i = 0;: This line initializes a counter for the password length.
  • while (true): This line starts an infinite loop that generates the next password.
  • if (i == length): This line checks if the password has reached the maximum length. If so, the loop exits and the next password is checked.
  • if (password[i] == charset[strlen(charset) - 1]): This line checks if the current character is the last character in the character set. If so, it resets the character to the first character and increments the counter.
  • password[i] = charset[strchr(charset, password[i]) - charset + 1];: This line increments the current character to the next character in the character set.
  • const char* charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";: This line defines the character set to be used for the password cracker.
  • size_t length = 8;: This line defines the maximum length of the generated passwords.

Web Crawler

A web crawler is a tool used to automatically navigate and collect data from websites. This can be useful for finding vulnerabilities in web applications. Here’s an example of a web crawler written in C++:

#include <iostream>
#include <cstring>
#include <curl/curl.h>

size_t write_callback(char* ptr, size_t size, size_t nmemb, void* userdata) {
    std::string* data = reinterpret_cast<std::string*>(userdata);
    data->append(ptr, size * nmemb);
    return size * nmemb;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        std::cout << "Usage: " << argv[0] << " <url>" << std::endl;
        return 1;
    }

    CURL* curl = curl_easy_init();
    if (curl == nullptr) {
        std::cout << "Error initializing curl" << std::endl;
        return 1;
    }

    curl_easy_setopt(curl, CURLOPT_URL, argv[1]);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);

    std::string response_data;
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data);

    CURLcode result = curl_easy_perform(curl);
    if (result != CURLE_OK) {
        std::cout << "Error performing curl request: " << curl_easy_strerror(result) << std::endl;
        return 1;
    }

    std::cout << "Response data: " << std::endl << response_data << std::endl;

    curl_easy_cleanup(curl);
    return 0;
}

This web crawler takes a URL as a command line argument and retrieves the contents of that URL using the libcurl library. Let’s break down the code:

  • size_t write_callback(char* ptr, size_t size, size_t nmemb, void* userdata): This callback function is called by libcurl to process the data received from the HTTP request.
  • std::string* data = reinterpret_cast<std::string*>(userdata);: This line casts the userdata pointer to a std:: string* so that the received data can be appended to it.
  • curl_easy_setopt(curl, CURLOPT_URL, argv[1]);: This line sets the URL to retrieve.
  • curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);: This line enables following HTTP redirects.
  • curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);: This line sets the callback function to be called with the received data.
  • curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data);: This line sets the userdata pointer to be passed to the callback function.
  • CURLcode result = curl_easy_perform(curl);: This line performs the HTTP request.
  • std::cout << "Response data: " << std::endl << response_data << std::endl;: This line displays the received data.

Pros and Cons of C++ for Pen Testers and Red Team Members

C++ has several advantages and disadvantages for pen testers and red team members.

Pros

  1. Performance: C++ is a compiled language, which means it can be optimized for performance. This can be important when developing tools that need to be run quickly.
  2. Portability: C++ can be compiled for a variety of platforms, which makes it a good choice for developing cross-platform tools.
  3. Low-level control: C++ provides direct access to low-level system resources, which can be useful for developing tools that interact with the operating system or hardware.

Cons

  1. Steep learning curve: C++ has a complex syntax and can be difficult to learn for beginners.
  2. Memory management: C++ requires manual memory management, which can be error-prone and lead to memory leaks or buffer overflows.
  3. Lack of built-in networking and threading support: C++ does not have built-in support for networking or threading, which can make it more difficult to develop tools that require these features.

Conclusion

C++ is a powerful programming language that can be used for pen testing and red teaming. It provides low-level control and high performance, but can be difficult to learn and requires manual memory management. With the examples provided in this article, you should have a good starting point for developing your own tools in C++. So go forth and hack with confidence!