Tags: crypto reverse 


Well, this challenge was a mix of reverse & crypto.
I (nobodyisnobody) did the 1st part of reversing,
and my teammate kikko (aka the crypto killer) did the crypto part.

After first analysis, the OSDev.img given file, is a 2 sector floppy img,
that can be launch with: qemu-system-x86_64 -fda OSDev.img

with the help of IDA , I reverse the 8086 assembly bootblock.

It read the second sector (512 bytes) to address 0x7e00
then read input from keyboard, until a carriage return is send.
then a serie of transformations are applied to the input,
that is finally dumped as a 16bytes hexadecimal output.

the challenge's authors, give only these numbers:
> 96 69 85 4b 6d 4d 4d 4c ed 52 ab ab c8 89 90 ca

which are the number to obtain as the hexadecimal output,
given a 16 bytes(max) ascii flag..

I have used ghidra after, to convert the 8086 opcodes, to an intermediate C program,
that gives the same output from a given input, than the original code.

It appears that the C code, looks furiously as AES encryption,
so I give the task, to my teammate kikko, who is good at crypto.

Script by kikko:

The cipher is basically an AES128 in which the substitute bytes step is replaced with a weird function. The whole process can be reversed to get a decipher function.

# AES subkeys
TXOR = [
0x51, 0xae, 0x3b, 0x46, 0x33, 0x80, 0xa6, 0xb6, 0x48, 0xb7, 0x69, 0x30,
0xeb, 0x7a, 0xe2, 0x51, 0x8a, 0x36, 0xea, 0xaf, 0xb9, 0xb6, 0x4c, 0x19,
0xf1, 0x01, 0x25, 0x29, 0x1a, 0x7b, 0xc7, 0x78, 0xa9, 0xf0, 0x56, 0x0d,
0x10, 0x46, 0x1a, 0x14, 0xe1, 0x47, 0x3f, 0x3d, 0xfb, 0x3c, 0xf8, 0x45,
0x46, 0xb1, 0x38, 0x02, 0x56, 0xf7, 0x22, 0x16, 0xb7, 0xb0, 0x1d, 0x2b,
0x4c, 0x8c, 0xe5, 0x6e, 0x2a, 0x68, 0xa7, 0x2b, 0x7c, 0x9f, 0x85, 0x3d,
0xcb, 0x2f, 0x98, 0x16, 0x87, 0xa3, 0x7d, 0x78, 0x30, 0x97, 0x1b, 0x3c,
0x4c, 0x08, 0x9e, 0x01, 0x87, 0x27, 0x06, 0x17, 0x00, 0x84, 0x7b, 0x6f,
0x4f, 0xb6, 0xb3, 0x5f, 0x03, 0xbe, 0x2d, 0x5e, 0x84, 0x99, 0x2b, 0x49,
0x84, 0x1d, 0x50, 0x26, 0xab, 0xe5, 0x44, 0x00, 0xa8, 0x5b, 0x69, 0x5e,
0x2c, 0xc2, 0x42, 0x17, 0xa8, 0xdf, 0x12, 0x31, 0xb5, 0x2c, 0x83, 0xc2,
0x1d, 0x77, 0xea, 0x9c, 0x31, 0xb5, 0xa8, 0x8b, 0x99, 0x6a, 0xba, 0xba,
0xac, 0xd8, 0x77, 0x2c, 0xb1, 0xaf, 0x9d, 0xb0, 0x80, 0x1a, 0x35, 0x3b,
0x19, 0x70, 0x8f, 0x81, 0xcb, 0xab, 0x7b, 0xf8, 0x7a, 0x04, 0xe6, 0x48,
0xfa, 0x1e, 0xd3, 0x73, 0xe3, 0x6e, 0x5c, 0xf2, 0x6a, 0x2d, 0x81, 0xf3,
0xa7, 0x3f, 0x72, 0xdc, 0x69, 0x37, 0x12, 0x5d, 0x87, 0xe4, 0x0f, 0xe8,
0xcd, 0x79, 0xb5, 0x26, 0xd6, 0x6f, 0x6f, 0x91, 0xb7, 0xfd, 0xe2, 0x98,
0xac, 0x57, 0x28, 0x16, 0x85, 0xaa, 0x09, 0x2c, 0xe9, 0x7b, 0x08, 0x53,
0xb3, 0x1b, 0xb0, 0x3a, 0xff, 0xbf, 0x23, 0xcc, 0x38, 0xd8, 0xf3, 0x0f,
0x47, 0x62, 0xa0, 0xfe, 0x5f, 0x83, 0x96, 0x0b, 0xda, 0xbf, 0x21, 0x5f,
0x69, 0x2b, 0x8c, 0x52, 0xa6, 0x94, 0xa5, 0x59, 0xaf, 0x55, 0x94, 0xae,
0x14, 0xb7, 0x7b, 0x4d, 0x8f, 0x6e, 0x5c, 0xd6, 0xd0, 0xfc, 0xd4, 0x2f,
0x7f, 0x6a, 0x3b, 0x5a, 0x29, 0x5c, 0xb9, 0x92, 0x87, 0x45, 0xe5, 0x2e,
0xda, 0x8a, 0x87, 0x89, 0xe0, 0x1b, 0x38, 0xf4, 0xd2, 0xb3, 0x41, 0x61,
0x21, 0x9d, 0x37, 0xf1, 0x9a, 0x0b, 0x20, 0x19, 0x76, 0x5b, 0x73, 0x9f,
0xb8, 0x2d, 0x32, 0x3f, 0x72, 0x17, 0x6d, 0x4c, 0xa1, 0xf5, 0xd6, 0x81,
0x10, 0x0e, 0x76, 0xe3, 0xc1, 0xb7, 0x44, 0xe2, 0x55, 0x7c, 0xd3, 0xef,
0x87, 0xf3, 0x08, 0xfd, 0x4f, 0x7c, 0x9d, 0x07, 0xa9, 0xcf, 0x46, 0x1b,
0xe6, 0xb4, 0x68, 0x87, 0xa9, 0x3e, 0x09, 0xb9, 0x4c, 0x7f, 0x9c, 0x0d,
0x36, 0xe1, 0xef, 0x8b, 0x5d, 0xc2, 0x7a, 0xe4, 0xb5, 0x83, 0xe2, 0x04,
0xff, 0x7f, 0x0b, 0xa8, 0x4e, 0x52, 0xc3, 0x34, 0x06, 0x2b, 0xbb, 0xaf,
0x69, 0xc4, 0x68, 0xb5, 0x43, 0x05, 0xc2, 0x7a, 0xe6, 0xb1, 0x05, 0x43,
0x73, 0x80, 0x27, 0x29, 0x03, 0x09, 0x2d, 0x02, 0x88, 0x39, 0xaa, 0xd6,
0x8b, 0x6d, 0x0a, 0x91, 0x99, 0xc6, 0x40, 0x02, 0x8a, 0xa8, 0xb8, 0xce,
0xad, 0x7a, 0x48, 0x93, 0x2c, 0x4d, 0xd6, 0x9f, 0xcd, 0xfe, 0xc8, 0xd0,
0x07, 0xf6, 0xd2, 0x90, 0x2f, 0x7c, 0x66, 0xba, 0xea, 0x71, 0x4b, 0x83,
0x37, 0x8b, 0x85, 0xc1, 0x33, 0x3d, 0x8f, 0xe1, 0xb8, 0xd7, 0x74, 0xe4,
0x25, 0x4b, 0x83, 0xf2, 0x49, 0x4c, 0xc3, 0x50, 0x42, 0x95, 0xe0, 0x71,
0x12, 0x47, 0x2b, 0xfc, 0xb8, 0x76, 0x7f, 0xef, 0x01, 0x04, 0xb0, 0x34,
0x42, 0x40, 0x15, 0xfa, 0x17, 0x8a, 0xde, 0x3c, 0xd5, 0x61, 0x2f, 0x1e,
0xad, 0xf2, 0x6e, 0xef, 0x87, 0x4f, 0x60, 0x99, 0x96, 0x8b, 0x95, 0x4e,
0x01, 0x14, 0x3d, 0x02, 0x19, 0xed, 0x37, 0x5b, 0x2d, 0x4c, 0x55, 0x45,
0xd6, 0x33, 0x81, 0xab, 0x94, 0xb0, 0xc9, 0x42
u = 0x11b

def mult(a,b):
x = 0
while a > 0:
if a & 1:
x ^= b
b *= 2
a = a >> 1
if (b >> 8) & 1:
b = b ^ u
return x

def inv(x):
if x:
for i in range(0x100):
y = mult(i,x)
if y == 1:
return i
return 0

# reverse osdev functions
def iwtf(x):
global u
u = 0x101
a = mult(inv(0x1f)&0xff,x^0x63) & 0xff
u = 0x11b
return inv(a)

def ifuckBytes(input):
for i in range(16):
input[i] = iwtf( input[i] )
return input

def imixColumns(input):
for i in range(4):
j = 4*i
a,b,c,d = input[j],input[j+1],input[j+2],input[j+3]
input[j] = mult(14,a) ^ mult(11,b) ^ mult(13,c) ^ mult(9,d)
input[j+1] = mult(9,a) ^ mult(14,b) ^ mult(11,c) ^ mult(13,d)
input[j+2] = mult(13,a) ^ mult(9,b) ^ mult(14,c) ^ mult(11,d)
input[j+3] = mult(11,a) ^ mult(13,b) ^ mult(9,c) ^ mult(14,d)
return input

def ishiftRows(input):
iSR = [0,13,10,7,4,1,14,11,8,5,2,15,12,9,6,3]
return [ input[iSR[i]] for i in range(16) ]

# print functions
def dmp(title,x):
print(title," ".join(["%02x" % _ for _ in x]))

# target cyphertext
c = [0x96, 0x69, 0x85, 0x4b, 0x6d, 0x4d, 0x4d, 0x4c, 0xed, 0x52, 0xab, 0xab, 0xc8, 0x89, 0x90, 0xca]

# reverse cipher
p = [c[i] ^ TXOR[160+i] for i in range(16)]
for rnd in reversed(range(10)):
if rnd != 9:
p = imixColumns(p)
p = ishiftRows(p)
p = ifuckBytes(p)
for i in range(16):
p[i] ^= TXOR[16*rnd+i]
dmp("plaintext ",p)
print("KAF{"+"".join([chr(x) for x in p])+"}")
ciphertext 96 69 85 4b 6d 4d 4d 4c ed 52 ab ab c8 89 90 ca
plaintext 54 48 34 4e 4b 53 5f 45 56 34 52 31 53 54 33 21