Регистрация: 06.07.2010
Сообщений: 402
|
13. https://rosnadzorcom.ru/FortBoyard.exe
Windows-приложение с рик-роллом, запускаем под strace в wine и видим, что оно дропает w.exe в темпе. Распаковываем w.exe в UPX и тщательно реверсим. Переписываем весь код на Python.
Пробуем решить крякми в angr и z3, осознаём, что это тщетно. Осознаём, что это ни что иное, как самодельная 128-раундовая функция шифрования с двумя s-боксами (второй используется только в 128-м раунде.
Открываем write-up'ы hellman'а по линейному криптоанализу, берём оттуда его скрипты для поиска линейных зависимостей и обнаруживаем 100%-ую зависимость 7-го бита выхода от 7-го бита входа в первом s-боксе.
Осознаём, что эта линейная зависимость выживает в остальных преобразованиях за счёт циклического сдвига ключа при XOR'е. Поскольку ключ 8-байтовый, воздействие ключа нивелируется.
В бинаре есть 32 пары ciphertext-plaintext для проверки ключа. Пишем побайтовый брут ключа с обращением 128-го раунда и дальнейшей проверкой совпадения 7-го бита входа и 7-го бита выхода для каждой из 32 пар.
Эксплойт:
Код:
str_buffer = '''75gbEMLB
E3c98QMl
rhQ5v7qp
5SsP2lbg
kCeZs3gi
Ny29PYdF
GKloIUOp
ejCVdiKV
T8UeM7UU
G37g8IA0
Kccsjo09
BnuEj5Sr
nr2jyP4m
sN2ltUD0
oWnUp5jj
cJJQg2dQ
qaGfxXR5
GSeLODez
zYihllB9
eOglfap7
QIVxWOgF
rWvInEmA
LRIm7Bds
AvGsBGZL
K1W5COqg
WJYNZcWR
c5FHpaUI
okURCwt3
KtmCmarD
sLmlJ1Ac
Sz9RAuuo
TQpqz3yP'''.split('\n')[::-1]
unperm_table = [69, 14, 172, 187, 16, 156, 85, 226, 236, 253, 33, 240, 86, 163, 79, 208, 23, 229, 152, 1, 228, 92, 40, 96, 249, 95, 2, 18, 176, 175, 150, 195, 82, 202, 124, 87, 39, 173, 108, 247, 252, 255, 238, 0, 219, 64, 13, 225, 146, 153, 180, 121, 32, 223, 151, 98, 136, 214, 12, 200, 81, 231, 43, 161, 10, 169, 185, 130, 147, 184, 245, 111, 91, 45, 19, 52, 102, 28, 83, 112, 241, 88, 126, 77, 70, 244, 190, 237, 7, 144, 123, 145, 80, 251, 248, 174, 234, 191, 160, 55, 125, 221, 11, 89, 204, 42, 188, 62, 215, 217, 246, 49, 220, 100, 192, 51, 181, 171, 38, 68, 149, 101, 84, 104, 25, 194, 59, 239, 76, 242, 17, 164, 41, 35, 132, 74, 61, 26, 201, 218, 139, 58, 186, 37, 177, 162, 197, 113, 128, 179, 8, 109, 183, 232, 3, 137, 103, 189, 155, 22, 211, 36, 135, 57, 116, 66, 199, 120, 9, 34, 29, 138, 54, 67, 233, 5, 158, 182, 119, 254, 56, 71, 203, 168, 30, 141, 31, 93, 193, 154, 196, 20, 230, 117, 15, 75, 243, 129, 107, 60, 159, 133, 78, 140, 47, 27, 167, 118, 63, 90, 142, 72, 105, 4, 6, 106, 222, 110, 114, 210, 53, 207, 224, 73, 250, 115, 157, 148, 48, 212, 165, 94, 50, 216, 65, 227, 122, 46, 24, 205, 213, 166, 178, 235, 131, 206, 170, 198, 127, 134, 21, 209, 143, 99, 44, 97]
unperm_table_1 = [140, 17, 163, 115, 61, 161, 122, 187, 144, 77, 18, 34, 224, 108, 15, 55, 9, 92, 247, 194, 101, 229, 226, 159, 89, 165, 223, 75, 145, 109, 170, 215, 112, 65, 190, 230, 193, 216, 143, 94, 129, 84, 167, 47, 53, 220, 123, 127, 56, 41, 119, 238, 205, 4, 35, 135, 72, 233, 14, 39, 213, 36, 251, 23, 125, 208, 126, 178, 120, 88, 182, 90, 197, 136, 158, 46, 116, 81, 186, 254, 32, 49, 31, 86, 221, 68, 139, 59, 85, 173, 130, 6, 132, 60, 250, 231, 192, 253, 95, 155, 5, 248, 27, 162, 137, 196, 154, 222, 64, 184, 43, 191, 124, 249, 38, 211, 45, 204, 175, 70, 80, 201, 22, 142, 105, 121, 210, 227, 217, 156, 203, 110, 25, 252, 103, 102, 153, 57, 166, 243, 164, 13, 67, 207, 37, 133, 71, 235, 48, 21, 218, 87, 176, 225, 74, 214, 149, 236, 198, 3, 244, 20, 199, 79, 16, 93, 50, 134, 8, 100, 63, 11, 152, 168, 91, 107, 128, 245, 54, 219, 189, 69, 111, 255, 104, 209, 246, 151, 76, 169, 30, 234, 52, 113, 118, 242, 180, 73, 239, 66, 0, 240, 195, 26, 181, 24, 147, 146, 212, 44, 150, 10, 96, 148, 174, 2, 185, 28, 78, 206, 160, 33, 106, 42, 1, 141, 131, 62, 241, 177, 171, 51, 40, 12, 179, 114, 97, 188, 19, 99, 232, 117, 98, 7, 172, 237, 83, 202, 157, 200, 82, 183, 228, 29, 58, 138]
base = 0x401e00
t = open('w_unpacked.exe', 'rb').read()
def getbuf(o, n):
return map(ord, t[o - base:o - base + n])
byte_4030A0 = getbuf(0x4030a0, 256)
perm_table_1 = getbuf(0x4031a0, 256)
perm_table = getbuf(0x4032a0, 256)
byte_4033A0 = getbuf(0x4033a0, 64)
buf_one_to_8 = getbuf(0x4033e0, 8)
buf_one_to_8_1 = getbuf(0x4033e8, 8)
byte_4033F0 = getbuf(0x4033f0, 64)
byte_403430 = getbuf(0x403430, 256)
byte_403530 = getbuf(0x403530, 256)
def encrypt_func(plaintext, serial):
result = list(plaintext)
v5 = 0
v6 = False
while v5 <= 128:
v7 = perm_table_1
if v5 == 128:
v7 = perm_table
result[0] = v7[result[0]]
result[1] = v7[result[1]]
result[2] = v7[result[2]]
result[3] = v7[result[3]]
result[4] = v7[result[4]]
result[5] = v7[result[5]]
result[6] = v7[result[6]]
result[7] = v7[result[7]]
result[0] ^= serial[v5 % 8] ^ buf_one_to_8_1[v5 % 8]
result[1] ^= serial[(v5 + 1) % 8] ^ buf_one_to_8[(v5 + 1) % 8]
result[2] ^= serial[(v5 + 2) % 8] ^ buf_one_to_8[(v5 + 2) % 8]
result[3] ^= serial[(v5 + 3) % 8] ^ buf_one_to_8[(v5 + 3) % 8]
result[4] ^= serial[(v5 + 4) % 8] ^ buf_one_to_8[(v5 + 4) % 8]
result[5] ^= serial[(v5 + 5) % 8] ^ buf_one_to_8[(v5 + 5) % 8]
result[6] ^= serial[(v5 + 6) % 8] ^ buf_one_to_8[(v5 + 6) % 8]
result[7] ^= serial[(v5 + 7) % 8] ^ buf_one_to_8[(v5 + 7) % 8]
if v5 < 128:
v9 = result[1]
v10 = result[0]
result[0] = v9 ^ (v9 ^ result[0]) & 0xF
v11 = v9 ^ result[2]
v12 = result[2]
result[1] = v12 ^ v11 & 0xF
v13 = v12 ^ result[3]
v14 = result[3]
result[2] = v14 ^ v13 & 0xF
v15 = v14 ^ result[4]
v16 = result[4]
result[3] = v16 ^ v15 & 0xF
v17 = v16 ^ result[5]
v18 = result[5]
result[4] = v18 ^ v17 & 0xF
v19 = v18 ^ result[6]
v20 = result[6]
result[5] = v20 ^ v19 & 0xF
result[6] = result[7] ^ (v20 ^ result[7]) & 0xF
result[7] = v10 & 0xF0 | result[7] & 0xF
v5 += 1
return result
def flag_func(serial):
idx = 0
while idx < 64:
v2 = byte_4033A0[idx + 1]
byte_4033F0[idx] = byte_4033A0[idx]
v3 = byte_4033A0[idx + 2]
byte_4033F0[idx + 1] = v2
v4 = byte_4033A0[idx + 3]
byte_4033F0[idx + 2] = v3
v5 = byte_4033A0[idx + 4]
byte_4033F0[idx + 3] = v4
v6 = byte_4033A0[idx + 5]
byte_4033F0[idx + 4] = v5
v7 = byte_4033A0[idx + 6]
byte_4033F0[idx + 5] = v6
v8 = byte_4033A0[idx + 7]
byte_4033F0[idx + 6] = v7
byte_4033F0[idx + 7] = v8
v9 = 128
while v9 >= 0:
if v9 < 128:
v10 = byte_4033F0[idx + 6]
v11 = byte_4033F0[idx + 7]
byte_4033F0[idx + 7] = v10 ^ (v10 ^ byte_4033F0[idx + 7]) & 0xF
v12 = v10 ^ byte_4033F0[idx + 5]
v13 = byte_4033F0[idx + 5]
byte_4033F0[idx + 6] = v13 ^ v12 & 0xF
v14 = v13 ^ byte_4033F0[idx + 4]
v15 = byte_4033F0[idx + 4]
byte_4033F0[idx + 5] = v15 ^ v14 & 0xF
v16 = v15 ^ byte_4033F0[idx + 3]
v17 = byte_4033F0[idx + 3]
byte_4033F0[idx + 4] = v17 ^ v16 & 0xF
v18 = v17 ^ byte_4033F0[idx + 2]
v19 = byte_4033F0[idx + 2]
byte_4033F0[idx + 3] = v19 ^ v18 & 0xF
v20 = v19 ^ byte_4033F0[idx + 1]
v21 = byte_4033F0[idx + 1]
byte_4033F0[idx + 2] = v21 ^ v20 & 0xF
byte_4033F0[idx + 1] = byte_4033F0[idx] ^ (v21 ^ byte_4033F0[idx]) & 0xF
byte_4033F0[idx] = v11 & 0xF0 | byte_4033F0[idx] & 0xF
byte_4033F0[idx] ^= buf_one_to_8_1[v9 % 8] ^ serial[v9 % 8]
byte_4033F0[idx + 1] ^= buf_one_to_8_1[(v9 + 1) % 8] ^ serial[(v9 + 1) % 8]
byte_4033F0[idx + 2] ^= buf_one_to_8_1[(v9 + 2) % 8] ^ serial[(v9 + 2) % 8]
byte_4033F0[idx + 3] ^= buf_one_to_8_1[(v9 + 3) % 8] ^ serial[(v9 + 3) % 8]
byte_4033F0[idx + 4] ^= buf_one_to_8_1[(v9 + 4) % 8] ^ serial[(v9 + 4) % 8]
byte_4033F0[idx + 5] ^= buf_one_to_8_1[(v9 + 5) % 8] ^ serial[(v9 + 5) % 8]
byte_4033F0[idx + 6] ^= buf_one_to_8_1[(v9 + 6) % 8] ^ serial[(v9 + 6) % 8]
byte_4033F0[idx + 7] ^= buf_one_to_8_1[(v9 + 7) % 8] ^ serial[(v9 + 7) % 8]
v22 = byte_4033F0[idx]
if v9 == 128:
v23 = unperm_table[v22]
v24 = byte_4033F0[idx +1]
byte_4033F0[idx] = v23
v25 = unperm_table[v24]
v26 = byte_4033F0[idx + 2]
byte_4033F0[idx + 1] = v25
v27 = unperm_table[v26]
v28 = byte_4033F0[idx + 3]
byte_4033F0[idx + 2] = v27
v29 = unperm_table[v28]
v30 = byte_4033F0[idx + 4]
byte_4033F0[idx + 3] = v29
v31 = unperm_table[v30]
v32 = byte_4033F0[idx + 5]
byte_4033F0[idx + 4] = v31
v33 = unperm_table[v32]
v34 = byte_4033F0[idx + 6]
byte_4033F0[idx + 5] = v33
v35 = unperm_table[v34]
v36 = byte_4033F0[idx + 7]
byte_4033F0[idx + 6] = v35
v37 = unperm_table[v36]
else:
v38 = unperm_table_1[v22]
v39 = byte_4033F0[idx + 1]
byte_4033F0[idx] = v38
v40 = unperm_table_1[v39]
v41 = byte_4033F0[idx + 2]
byte_4033F0[idx + 1] = v40
v42 = unperm_table_1[v41]
v43 = byte_4033F0[idx + 3]
byte_4033F0[idx + 2] = v42
v44 = unperm_table_1[v43]
v45 = byte_4033F0[idx + 4]
byte_4033F0[idx + 3] = v44
v46 = unperm_table_1[v45]
v47 = byte_4033F0[idx + 5]
byte_4033F0[idx + 4] = v46
v48 = unperm_table_1[v47]
v49 = byte_4033F0[idx + 6]
byte_4033F0[idx + 5] = v48
v50 = unperm_table_1[v49]
v51 = byte_4033F0[idx + 7]
byte_4033F0[idx + 6] = v50
v37 = unperm_table_1[v51]
v9 -= 1
byte_4033F0[idx + 7] = v37
idx += 8
return byte_4033F0
def decrypt_func(ciphertext, serial):
result = list(ciphertext)
v9 = 128
while v9 >= 0:
if v9 < 128:
v10 = result[6]
v11 = result[7]
result[7] = v10 ^ (v10 ^ result[7]) & 0xF
v12 = v10 ^ result[5]
v13 = result[5]
result[6] = v13 ^ v12 & 0xF
v14 = v13 ^ result[4]
v15 = result[4]
result[5] = v15 ^ v14 & 0xF
v16 = v15 ^ result[3]
v17 = result[3]
result[4] = v17 ^ v16 & 0xF
v18 = v17 ^ result[2]
v19 = result[2]
result[3] = v19 ^ v18 & 0xF
v20 = v19 ^ result[1]
v21 = result[1]
result[2] = v21 ^ v20 & 0xF
result[1] = result[0] ^ (v21 ^ result[0]) & 0xF
result[0] = v11 & 0xF0 | result[0] & 0xF
result[0] ^= buf_one_to_8_1[v9 % 8] ^ serial[v9 % 8]
result[1] ^= buf_one_to_8_1[(v9 + 1) % 8] ^ serial[(v9 + 1) % 8]
result[2] ^= buf_one_to_8_1[(v9 + 2) % 8] ^ serial[(v9 + 2) % 8]
result[3] ^= buf_one_to_8_1[(v9 + 3) % 8] ^ serial[(v9 + 3) % 8]
result[4] ^= buf_one_to_8_1[(v9 + 4) % 8] ^ serial[(v9 + 4) % 8]
result[5] ^= buf_one_to_8_1[(v9 + 5) % 8] ^ serial[(v9 + 5) % 8]
result[6] ^= buf_one_to_8_1[(v9 + 6) % 8] ^ serial[(v9 + 6) % 8]
result[7] ^= buf_one_to_8_1[(v9 + 7) % 8] ^ serial[(v9 + 7) % 8]
v22 = result[0]
if v9 == 128:
v23 = unperm_table[v22]
v24 = result[1]
result[0] = v23
v25 = unperm_table[v24]
v26 = result[2]
result[1] = v25
v27 = unperm_table[v26]
v28 = result[3]
result[2] = v27
v29 = unperm_table[v28]
v30 = result[4]
result[3] = v29
v31 = unperm_table[v30]
v32 = result[5]
result[4] = v31
v33 = unperm_table[v32]
v34 = result[6]
result[5] = v33
v35 = unperm_table[v34]
v36 = result[7]
result[6] = v35
v37 = unperm_table[v36]
else:
v38 = unperm_table_1[v22]
v39 = result[1]
result[0] = v38
v40 = unperm_table_1[v39]
v41 = result[2]
result[1] = v40
v42 = unperm_table_1[v41]
v43 = result[3]
result[2] = v42
v44 = unperm_table_1[v43]
v45 = result[4]
result[3] = v44
v46 = unperm_table_1[v45]
v47 = result[5]
result[4] = v46
v48 = unperm_table_1[v47]
v49 = result[6]
result[5] = v48
v50 = unperm_table_1[v49]
v51 = result[7]
result[6] = v50
v37 = unperm_table_1[v51]
v9 -= 1
result[7] = v37
return result
def encrypt_127_func(plaintext, serial):
result = list(plaintext)
v5 = 0
v6 = False
while v5 < 128:
v7 = perm_table_1
result[0] = v7[result[0]]
result[1] = v7[result[1]]
result[2] = v7[result[2]]
result[3] = v7[result[3]]
result[4] = v7[result[4]]
result[5] = v7[result[5]]
result[6] = v7[result[6]]
result[7] = v7[result[7]]
result[0] ^= serial[v5 % 8] ^ buf_one_to_8_1[v5 % 8]
result[1] ^= serial[(v5 + 1) % 8] ^ buf_one_to_8[(v5 + 1) % 8]
result[2] ^= serial[(v5 + 2) % 8] ^ buf_one_to_8[(v5 + 2) % 8]
result[3] ^= serial[(v5 + 3) % 8] ^ buf_one_to_8[(v5 + 3) % 8]
result[4] ^= serial[(v5 + 4) % 8] ^ buf_one_to_8[(v5 + 4) % 8]
result[5] ^= serial[(v5 + 5) % 8] ^ buf_one_to_8[(v5 + 5) % 8]
result[6] ^= serial[(v5 + 6) % 8] ^ buf_one_to_8[(v5 + 6) % 8]
result[7] ^= serial[(v5 + 7) % 8] ^ buf_one_to_8[(v5 + 7) % 8]
if v5 < 128:
v9 = result[1]
v10 = result[0]
result[0] = v9 ^ (v9 ^ result[0]) & 0xF
v11 = v9 ^ result[2]
v12 = result[2]
result[1] = v12 ^ v11 & 0xF
v13 = v12 ^ result[3]
v14 = result[3]
result[2] = v14 ^ v13 & 0xF
v15 = v14 ^ result[4]
v16 = result[4]
result[3] = v16 ^ v15 & 0xF
v17 = v16 ^ result[5]
v18 = result[5]
result[4] = v18 ^ v17 & 0xF
v19 = v18 ^ result[6]
v20 = result[6]
result[5] = v20 ^ v19 & 0xF
result[6] = result[7] ^ (v20 ^ result[7]) & 0xF
result[7] = v10 & 0xF0 | result[7] & 0xF
v5 += 1
return result
def check_serial(serial, a1):
unperm_table = [0] * 256
unperm_table_1 = [0] * 256
#copy_serial = map(ord,serial)
copy_serial = serial
for v3 in xrange(256):
unperm_table_1[perm_table_1[v3]] = v3
for v4 in xrange(256):
unperm_table[perm_table[v4]] = v4
good_buffer = [[byte_4030A0[j] for j in xrange(i, i+8)]for i in xrange(0, 256, 8)]
for i in xrange(len(good_buffer)):
result_buffer = encrypt_func(map(ord,str_buffer[i]), copy_serial)
for v7 in xrange(8):
if result_buffer[v7] != good_buffer[i][v7]:
return False
flag_func(copy_serial)
return True
'''for v3 in xrange(256):
unperm_table_1[perm_table_1[v3]] = v3
for v4 in xrange(256):
unperm_table[perm_table[v4]] = v4
#'''
good_buffer = [[byte_4030A0[j] for j in xrange(i, i+8)]for i in xrange(0, 256, 8)]
### CRYPTANALYSIS ###
for i in xrange(32):
str_buffer[i] = map(ord, str_buffer[i])
key = ''
for i in xrange(8): # key byte index
for v in xrange(256): # key byte value
flag = True
for k in xrange(32): # each pair
result = good_buffer[k][i] ^ (i + 1) ^ v
result = unperm_table[result] & 0b0000010
if result != str_buffer[k][i] & 0b0000010:
flag = False
break
if flag:
key += chr(v)
print 'FOUND byte %s: %s' % (i, chr(v))
print 'KEY', key
print ''.join(map(chr, flag_func(map(ord, key))))
|