Flash CTF – Clock Out

Challenge Overview

In the “Clock Out” challenge, participants are tasked with exploiting a timing-based side channel vulnerability in a product key validation program. The goal is to deduce a valid product key by observing the time it takes for the program to validate each character of the input.

Understanding the Vulnerability

The vulnerability lies in the verify function of the program, where the validation time varies depending on the correctness of each character in the product key. This discrepancy in execution time can be exploited to infer the correct characters of the product key one by one.

Key Validation Mechanism

The program uses a series of predefined hash values stored in an array called validation. Each character of the input product key is hashed and compared against this array. If a character is correct, the program performs a longer sleep operation, thus taking more time to process:

int verify(char* data, int len)
{
    int i;
    int f = len * 16;
    for (i=0; i < len; i++)
    {
        if (validation[i] == hashit(data[i]))
        {
            f -= 16;
            usleep(10000);
        }
        else
        {
            f -= 8;
            usleep(100);
        }
    }
    return f == 0;
}

Timing Side Channel

The essence of the attack is to measure how long it takes for the program to validate each character. A longer response time for a particular character suggests that the character is correct, as the program executes a longer sleep operation.

Exploitation Strategy

The provided Python script demonstrates how to automate the attack by measuring the execution time for each possible character and selecting the one that results in the longest validation time:

import time
import subprocess

def run_proc(cmd, flag):
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
    out, _ = p.communicate(bytes(flag, encoding='ascii'))
    return out


flag = "MetaCTF{"

for _ in range(22 - len(flag)):
    timings = list()
    for i in range(32, 127):
        temp_flag = flag + chr(i) + '~'*(32-(len(flag) + 1))

        now = time.time()
        out = run_proc(["./clock_out"], temp_flag)
        run_time = time.time() - now

        timings.append((i, run_time))

    timings = sorted(timings, key=lambda x:x[1], reverse=True)

    flag += chr(timings[0][0])
    print(flag)

This script iteratively constructs the product key by appending the character that maximizes the response time until the entire key is correctly guessed.

Flag: MetaCTF{time->tm_hour}

Conclusion

This challenge highlights the importance of constant-time operations in security-sensitive code to prevent side-channel attacks. By carefully analyzing the timing of the program’s responses, an attacker can effectively reconstruct sensitive data, underscoring the need for developers to mitigate such vulnerabilities in their applications.