Cover Image

FCSC 2023 - Zéro Pointé

In this article, we will explore the step-by-step walkthrough of the ‘Zéro Pointé’ challenge presented at FCSC 2023.

In this challenge, we exploited a vulnerability related to an integer overflow in a C program to trigger a SIGFPE signal and execute the flag() function. The code reads two long values, performs a division, and handles a specific case of division by zero.

Challenge Overview

We have the source code zero-pointe.c available:

You can download the binary here: zero-pointe

Code Analysis

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

static void flag(int sig) {
    (void) sig;
    char flag[128];

    int fd = open("flag.txt", O_RDONLY);
    if (fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    int n = read(fd, flag, sizeof(flag));
    if (n == -1) {
        perror("read");
        exit(EXIT_FAILURE);
    }

    flag[n] = 0;
    flag[strstr(flag, "\n") - flag] = 0;

    if (close(fd) == -1) {
        perror("close");
        exit(EXIT_FAILURE);
    }

    printf("%s\n", flag);
    exit(EXIT_SUCCESS);
}

long read_long() {
    long val;
    scanf("%ld", &val);
    return val;
}

int main() {
    long a;
    long b;
    long c;

    if (signal(SIGFPE, flag) == SIG_ERR) {
        perror("signal");
        exit(EXIT_FAILURE);
    }

    a: read_long();
    b: read_long();
    c: b ? a / b : 0;

    printf("%ld\n", c);
    exit(EXIT_SUCCESS);
}

Code Overview

The source code provides an overview of the main parts of the program:

  • The flag() function reads and displays the contents of the "flag.txt" file.
  • The read_long() function reads a long value from standard input.
  • The main function reads two long values (a and b) and performs the division a / b.

The goal is to trigger a SIGFPE signal, which calls the flag() function and displays the contents of the "flag.txt" file. The SIGFPE signal is triggered when a calculation exception occurs, such as division by zero or integer overflow.

Exploitation Strategy

After examining the code, we determined that the best approach to trigger the SIGFPE signal was to cause an integer overflow during the division a / b.

To do this, we sent the following values:

a: -9223372036854775808
b: -1

These values were chosen for the following reasons:

  • a is equal to LONG_MIN, which is the smallest value that a long can store on a 64-bit system.
  • b is equal to -1, which ensures that division by zero does not occur, as the code already handles this specific case.

When the code performs the division a / b, it results in an integer overflow. Indeed, dividing LONG_MIN by -1 would give a result greater than LONG_MAX, which cannot be represented by a long. This division with integer overflow triggers a SIGFPE signal, which calls the flag() function and displays the contents of the "flag.txt" file.

Result

Here is what it looks like during the challenge:

$ nc challenges.france-cybersecurity-challenge.fr 2050
-9223372036854775808
-1
FCSC{0366ff5c59934da7301c0fc6cf7d617c99ad6f758831b1dc70378e59d1e060bf}

Flag

The flag is therefore FCSC{0366ff5c59934da7301c0fc6cf7d617c99ad6f758831b1dc70378e59d1e060bf}