• Профессиональным авторам. Срочный заказ!

    Необходимо сделать развернутое описание каждой из наших услуг. Ограничений на объем текста нет. ЦА - руководство компаний (сухой технический текст). При отсутствии исполнителей среди участников форума, работа будет передана фрилансерам 10 февраля.

    Подробнее о заказе ...

Статья Простейший криптоанализ простейшего шифра

PingVinich

PingVinich

Технарь
19.03.2017
138
461
Привет, форум. Давненько я не писал статьи, но на это были свои причины. В этой статье я решил рассказать о том, как с помощью простейших дедуктивных умозаключений мне удалось взломать шифр, возможно Вам будет, что подчерпнуть для себя. Я не являюсь экспертом в области криптографии, поэтому у меня могут быть какие-либо ошибки и неточности в статье. Пишите в комментарии - поправлю, если что-то серьёзное.

Введение

Одним солнечным днём, я решил поиграть в одну многопользовательскую игру, назовём её N. Играть в неё было неинтересно, и я чисто из любопытства решил создать свой чит-лаунчер для этой игры с различными шифками. Благо, в интернете есть много читов для данной игры, поэтому создавать их не пришлось. Нужно было только внедрить их, а лаунчер этой игры не позволял внедряться в процесс и проверял папку (да, можно конечно было сделать это простой установкой прав дебаг режима, но как вы узнаете дальше, мне не особо хотелось заглядывать в логику игры, искать значения, т.д. и т.п.) с клиентом в отдельном потоке. Достаточно было заменить только 1 файл и он бы удалился. Все файлы клиента проверялись с помощью методов криптографии на целостность (хэщ-суммы), поэтому заменить на свои их тоже не удастся. В данном случае есть несколько следующий вариантов, которые я мог бы предпринять:

  • нахождение уязвимости, которая бы помогла обойти эту проверку
  • простой патчинг байт в лаунчере
  • написание своего лаунчера, т.е. его обход
  • ...

Я не хотел выбирать первый и второй варианты, так как день был жаркий, я устал и особо не хотелось париться и копаться в листинге дизассемблера. Да и хотелось уже подтренировать навыки криптоанализа.

Процесс анализа

При авторизации, лаунчер отправлял серверу зашифрованный логин, пароль и айди компьютера, который своеобразным способом высчитывался изходя их железа ПК. Я поймал этот запрос в WireShark и увидел следующее:

123.png


(Я затёрь некоторые чувствительные данные.)

В данном случае, я отправил логин testtest и пароль testtest. Первое, что можно заметить, что логин и пароль шифруются одной функцией. Велика вероятность шифрования и Hardware ID этой же функцией.
Я отправил данные разных размеров, и заметил, что длина шифротекста равна длине исходного сообщения помноженного на 2, а также то, что каждый байт кодируется другим байтом, который здесь представлен в шестнадцатеричном представлении. Так же, потому что шифротексты не дополнялись байтами, можно сделать вывод, что данный шифр не является блочным, а является поточным. У нас, как мы видим, есть возможность отправлять любые данные и получать результат шифрования, единственное, что нам необходимо сделать, это найти способ шифрования/дешифрования не зная ключа и метода шифрования досконально. Шифр не является моноалфавитным, так как один и тот же символ кодируется по разному. Также, он не является перестановочным. Давайте отправим символ 64 символа A, чтобы выявить возможную цикличность.
Вот, что чему равен результат шифрования строки A*64:

7A 39 18 D9 9A A0 18 AB 60 B1 B1 AB 60 39 9B 9B C0 24 9E 9A C0 AB C0 7A 9E A0 39 60 A0 01 39 2A 7A 39 18 D9 9A A0 18 AB 60 B1 B1 AB 60 39 9B 9B C0 24 9E 9A C0 AB C0 7A 9E A0 39 60 A0 01 39 2A

Ничего не замечаете? После 32 символа, шифротекст повторяется... Это даёт нам отличный шанс для атаки. Можно составить шифрокарту для каждого символа и исходя из его положения в тексте подставлять нужный байт для шифрования и проделовать обратную операцию для дешифрования.
Ниже представлен формат шифрокарты для некоторых символов.

Открытый текст: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Шифротекст: 7A 39 18 D9 9A A0 18 AB 60 B1 B1 AB 60 39 9B 9B C0 24 9E 9A C0 AB C0 7A 9E A0 39 60 A0 01 39 2A

Открытый текст: BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
Шифротекст: C0 B7 B1 A0 2A D9 B1 9E 3D 18 18 9E 3D B7 24 24 7A 9B AB 2A 7A 9E 7A C0 AB D9 B7 3D D9 E0 B7 9A

Открытый текст: CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
Шифротекст: 2A 9E 9B 60 C0 3D 9B B7 D9 24 24 B7 D9 9E 18 18 9A B1 39 C0 9A B7 9A 2A 39 3D 9E D9 3D 93 9E 7A

Также, видим некоторые повторения, что является хорошим знаком для нас. Проанализировав совпадения в шифротексте возможна атака на алгоритм. Для её осуществления нужно составить 32 символный массив байтов для каждого символа и исходя из их положения в тексте шифровать и дешифровать его простой заменой. Приступим к реализации атаки!

Атака

Писать этот код долго и рутинно, поэтому я написал скрипт, который написал скрипт за меня. Нужно подать на вход только шифрокарту:

Python:
# -*- coding: utf-8 -*-
# codepage=UTF8

import base64
from itertools import izip, cycle

def main():
    cipherCard = open("cipherCard.txt", "r")

    f = open("newcryptor_test.py", "w")
    f.write("def encrypt(data):\n")
    f.write("    result = ''\n")
    f.write("    n = 1\n")
    f.write("    for symbol in data:\n")
    f.write("        if n > 32:\n")
    f.write("            n = n % 32\n")
    nSymbols = [i + 1 for i in range(95)]
    isFirstSymbol = True
    for n in nSymbols:
        isFirstCode = True
        symbol = cipherCard.readline().strip()
        if symbol == "'":
            symbol = "\\'"
        elif symbol == "\\":
            symbol = "\\\\"
        i = 1
        codes = cipherCard.readline()
        for (code1, code2) in zip(codes[0::2], codes[1::2]):
            if isFirstSymbol == True:
                f.write("        if (symbol == '"+symbol+"') and (n == " + str(i) + "):\n")
                isFirstSymbol = False
            else:
                f.write("        elif (symbol == '"+symbol+"') and (n == " + str(i) + "):\n")
            f.write("            result += '" + code1 + code2 + "'\n")
            i+=1
    f.write("        else:\n")
    f.write("            result += '00'\n")
    f.write("        n += 1\n")
    f.write("    return result\n")
    f.write("\n")

    cipherCard.close()

    cipherCard = open("cipherCard.txt", "r")

    f.write("def decrypt(data):\n")
    f.write("    result = ''\n")
    f.write("    n = 1\n")
    f.write("    for (code1, code2) in zip(data[0::2], data[1::2]):\n")
    f.write("        code = code1 + code2\n")
    f.write("        if n > 32:\n")
    f.write("            n = n % 32\n")
    nSymbols = [i + 1 for i in range(95)]
    isFirstCode = True
    for n in nSymbols:
        symbol = cipherCard.readline().strip()
        if symbol == "'":
            symbol = "\\'"
        elif symbol == "\\":
            symbol = "\\\\"
        i = 1
        codes = cipherCard.readline()
        for (code1, code2) in zip(codes[0::2], codes[1::2]):
            if isFirstCode:
                f.write("        if (n == " + str(i) + ") and (code == \""+code1+code2+"\") ")
                isFirstCode = False
            else:
                f.write("or (n == " + str(i) + ") and (code == \""+code1+code2+"\"):\n")
            f.write("            result += '" + symbol + "'\n")
            i+=1
    f.write("        else:\n")
    f.write("            result +=\"*\"\n")
    f.write("        n += 1\n")
    f.write("    return result\n")

    f.write("\n")

    f.write("def main():\n")
    f.write("    data = raw_input(\"[*] Data: \")\n")
    f.write("    print(\"Encrypted: \" + encrypt(data))\n")
    f.write("    print(\"Decrypted: \" + decrypt(encrypt(data)))\n")

    f.write("\n")

    f.write("if __name__==\"__main__\":\n")
    f.write("    main()\n")

    cipherCard.close()

    f.close()

if __name__=="__main__":
    main()
Кусок шифрокарты для примера:

A
3B6FD6D28F46D62061DBDB20616FD1D1FEC81A8FFE20FE3B1A466F6146276F41
B
FEF4DB4641D2DB1A0DD6D61A0DF4C8C83BD120413B1A3BFE20D2F40DD232F48F
C
411AD161FE0DD1F4D2C8C8F4D21AD6D68FDB6FFE8FF48F416F0D1AD20D051A3B
D
D6D23B6FC8F43B0D1AFEFE0D1AD24141DB8F61C8DB0DDBD661F4D21AF499D2D1
E
C80D8F20D61A8FD2F44141D2F40DFEFED13B46D6D1D2D1C8461A0DF41A4E0DDB
F
D161411ADB2041466F8F8F466F613B3BC8FED2DBC846C8D1D220616F205561D6
G
DB46FEF4D16FFE61203B3B6120468F8FD6410DD1D661D6DB0D6F46206FA146C8
H
99FF27284E5D27696A3232696AFF0505A1FAB24EA169A199B25DFF6A5DD6FF55
I
4E69FA4C996AFAFF5D0505FF5D6932325527539955FF554E536A695D6AC869A1
J
55B2056AA14C055328FAFA5328B227274E32FFA14E534E55FF4CB2284CD1B299
K
A153325D552832B24C2727B24C53FAFA9905695599B299A16928534C28DB534E
...

И так для каждого печатаемого ASCII символа.

Составлял я эту шифрокарту не вручную, а с помощью записи символов в процесс и последующим дампом пакета. Скрипт затерялся в просторах жёсткого диска :). Ну вот и всё, такой простой шифр мы с вами сегодня проанализировали и взломали. Всем удачной охоты!
 
Последнее редактирование:
Мы в соцсетях: