Skip to content

Instantly share code, notes, and snippets.

@marcan
Created January 9, 2024 10:23
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcan/727947e7dd4ac283f2522a0ed63957c6 to your computer and use it in GitHub Desktop.
Save marcan/727947e7dd4ac283f2522a0ed63957c6 to your computer and use it in GitHub Desktop.
import struct, time
## This experiment demonstrates that the claimed "hash" (that is not a hash) used
## by the L2 cache ECC debug feature used by Operation Triangulation is not secure,
## and can be trivially reverse engineered by anyone who owns one of the machines
## with the hardware (such as any M1 Mac), in seconds to days. Therefore, this proves
## that no "insider" access or leak is necessary to obtain this table, and that the
## attackers most likely did exactly the same thing.
## This is the "black box", i.e. the hardware: The table is not exposed to the caller.
class BlackBox:
__table = [
0x007, 0x00B, 0x00D, 0x013, 0x00E, 0x015, 0x01F, 0x016,
0x019, 0x023, 0x02F, 0x037, 0x04F, 0x01A, 0x025, 0x043,
0x03B, 0x057, 0x08F, 0x01C, 0x026, 0x029, 0x03D, 0x045,
0x05B, 0x083, 0x097, 0x03E, 0x05D, 0x09B, 0x067, 0x117,
0x02A, 0x031, 0x046, 0x049, 0x085, 0x103, 0x05E, 0x09D,
0x06B, 0x0A7, 0x11B, 0x217, 0x09E, 0x06D, 0x0AB, 0x0C7,
0x127, 0x02C, 0x032, 0x04A, 0x051, 0x086, 0x089, 0x105,
0x203, 0x06E, 0x0AD, 0x12B, 0x147, 0x227, 0x034, 0x04C,
0x052, 0x076, 0x08A, 0x091, 0x0AE, 0x106, 0x109, 0x0D3,
0x12D, 0x205, 0x22B, 0x247, 0x07A, 0x0D5, 0x153, 0x22D,
0x038, 0x054, 0x08C, 0x092, 0x061, 0x10A, 0x111, 0x206,
0x209, 0x07C, 0x0BA, 0x0D6, 0x155, 0x193, 0x253, 0x28B,
0x307, 0x0BC, 0x0DA, 0x156, 0x255, 0x293, 0x30B, 0x058,
0x094, 0x062, 0x10C, 0x112, 0x0A1, 0x20A, 0x211, 0x0DC,
0x196, 0x199, 0x256, 0x165, 0x259, 0x263, 0x30D, 0x313,
0x098, 0x064, 0x114, 0x0A2, 0x15C, 0x0EA, 0x20C, 0x0C1,
0x121, 0x212, 0x166, 0x19A, 0x299, 0x265, 0x2A3, 0x315,
0x0EC, 0x1A6, 0x29A, 0x266, 0x1A9, 0x269, 0x319, 0x2C3,
0x323, 0x068, 0x0A4, 0x118, 0x0C2, 0x122, 0x214, 0x141,
0x221, 0x0F4, 0x16C, 0x1AA, 0x2A9, 0x325, 0x343, 0x0F8,
0x174, 0x1AC, 0x2AA, 0x326, 0x329, 0x345, 0x383, 0x070,
0x0A8, 0x0C4, 0x124, 0x218, 0x142, 0x222, 0x181, 0x241,
0x178, 0x2AC, 0x32A, 0x2D1, 0x0B0, 0x0C8, 0x128, 0x144,
0x1B8, 0x224, 0x1D4, 0x182, 0x242, 0x2D2, 0x32C, 0x281,
0x351, 0x389, 0x1D8, 0x2D4, 0x352, 0x38A, 0x391, 0x0D0,
0x130, 0x148, 0x228, 0x184, 0x244, 0x282, 0x301, 0x1E4,
0x2D8, 0x354, 0x38C, 0x392, 0x1E8, 0x2E4, 0x358, 0x394,
0x362, 0x3A1, 0x150, 0x230, 0x188, 0x248, 0x284, 0x302,
0x1F0, 0x2E8, 0x364, 0x398, 0x3A2, 0x0E0, 0x190, 0x250,
0x2F0, 0x288, 0x368, 0x304, 0x3A4, 0x370, 0x3A8, 0x3C4,
0x160, 0x290, 0x308, 0x3B0, 0x3C8, 0x3D0, 0x1A0, 0x260,
0x310, 0x1C0, 0x2A0, 0x3E0, 0x2C0, 0x320, 0x340, 0x380
]
def __calculate_hash(self, buffer):
acc = 0
for i in range(8):
pos = i * 4
value = struct.unpack("<I", buffer[pos:pos+4])[0]
for j in range(32):
if (((value >> j) & 1) != 0):
acc ^= self.__table[32 * i + j]
return acc
def is_hash_valid(self, buffer, hash):
return hash == self.__calculate_hash(buffer)
# Now we reverse engineer the table "black box", just by trying data and hash values and seeing if they work
tries = 0
reverse_engineered_table = []
b = BlackBox()
start = time.time()
for databit in range(256):
buffer = (1 << databit).to_bytes(length=32, byteorder="little")
for hash in range(0x400):
tries += 1
if b.is_hash_valid(buffer, hash):
reverse_engineered_table.append(hash)
break
else:
assert False
t = time.time() - start
print(f"Extracted {len(reverse_engineered_table)} table entries in {tries} tries ({t:.02f} seconds).")
# Assume 100 microseconds per trial (this is very, very generous)
t1 = tries * 100e-6
print(f"Time to do this on real hardware, without reboots: {t1:.02f} seconds (conservatively)")
# Approximately 7 seconds to reboot an M1 Mac Mini into m1n1 and run an experiment
t2 = tries * 7 / 86400
print(f"Time to do this on real hardware, with reboots: {t2:.02f} days")
print()
print("Table:")
for i, v in enumerate(reverse_engineered_table):
print(f"{v:03x} ", end="")
if i % 16 == 15:
print()
@SuperKenVery
Copy link

Man you're a genius at reverse engineering. How I wish I had your knowledge!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment