Показать сообщение отдельно
Старый 17.05.2017, 00:57   #3
Beched
 
Регистрация: 06.07.2010
Сообщений: 403
Репутация: 118
По умолчанию

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))))
Beched вне форума   Ответить с цитированием