This page looks best with JavaScript enabled

0xL4ugh24 Hardware Challenges Official Writeups

 ·  ☕ 8 min read

Lately, I have been doing some hardware security research, specifically focusing on side channel stuff, this inspired me to write these challenges for the 0xL4ugh CTF.

You will find all the challenge files on this repo, at the end of the blog I will list some notable writeups by players who have completed this challenge.

Tempus

Summary: Timing side channel attack allows us to bruteforce the pin digit by digit reducing the keyspace significantly (from 10^9 to 10*9).
Tempus is the latin word for time

After spinning up the instance and connecting, we test the challenge logic.

The flag seems to be 9 digits long by elimination, so we know the length of the password. The next step was to check the timing of the responses for different digits. I used the time command to measure this, and it turns out that the digit ‘5’ takes significantly longer to process than the rest, hinting at a possible timing attack.

Non-constant time operations can pose a significant security risk, especially in cryptographic systems. This was demonstrated as early as 1996 by Kocher in his famous paper.

To find the letters of the correct password, we can use the following one-liner:

1
for i in {0..9}; do cat <(echo "$i") - | time nc localhost 11111 ; done

We don’t use echo directly but instead use it along with stdin as parameters for cat. This keeps the connection alive after the echo, and time will give us the correct timing once the netcat connection closes.

Using this one-liner we can start bruteforcing the flag digit by digit:

and the correct pin is 562951413.

562951413 is the reverse of the first 8 digits of pi: 3.14159265

Here’s the python solver as well:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import time
from pwn import *
import string
import numpy as np
from tqdm import tqdm


def try_letter(letter):
    # io = process("./chal")
    # host = "f3c7d0159c523472a737fce4144226a6.chal.ctf.ae"
    # io = remote(host, 443, ssl=True, sni=host)
    io = remote('localhost', 11111)
    io.recvuntil("Please enter the pin:\r\n")
    start = time.perf_counter()
    io.sendline(letter)
    io.recvuntil("Analyzing...")
    diff = time.perf_counter() - start
    io.close()
    return diff

def get_timing(attempt, samples=5):
    times = [try_letter(attempt) for _ in range(samples)]
    return np.mean(times)

timings = {}
flag = ""
charset = string.digits

for i in range(9):
    timings.clear()

    for ch in tqdm(charset, position=0):
        timings[ch] = get_timing(flag + ch, samples=1)

    max_val = max(timings, key=timings.get)
    flag += max_val

    print(bytes(flag, encoding="utf-8"))

io = remote('localhost', 11111)
io.clean(1)
io.sendline(flag)
print(io.clean(1).decode())

Squinty

Summary: We receive a power consumption trace as a NumPy array. By visualizing this array as a line plot, we can identify distinct patterns associated with certain operations. The square and multiply operations each have unique patterns, which help us recover the flag due to their data dependency. This approach is an example of a Simple Power Analysis (SPA) attack.

We are given some power traces in .npy format, which we can load in Python using np.load('traces.npy'). I used Plotly to generate the following plot: