- Регистрация
- 31.12.2019
- Сообщения
- 7,534
- Реакции
- 36
В 2021 году никого не удивишь всевозможными бэкдорами и прочими "полезными нагрузками" в различном ПО. Каналами распространения обычно служат всевозможные файлообменики и варезники, фишинговые ресурсы, а иногда и официальный репозиторий на Github или веб-сайт, когда кому-то удается получить несанкционированный доступ к нему. Время жизни подобных модификаций в известном ПО обычно прямо пропорционально их изощренности. Давайте рассмотрим один из возможных вариантов модификации на примере Bitcoin-клиента Electrum (https://electrum.org/).
Клиент Electrum написан на Python и обладает бинарными сборками под популярные ОС. Также в данном клиенте существует поддержка плагинов, позволяющих сторонним разработчикам реализовывать дополнительный функционал в рамках доступного API. Если бы мы захотели реализовать некоторую полезную нагрузку в рамках клиента, то написание плагина кажется одним из первоочередных вариантов, но мне этот вариант в данном случае кажется немного скучным и я поясню почему. Вернемся немного назад и подумаем, какие обычно полезные нагрузки встраивают в софт? Обычно это что-то из следующего списка:
Перечисленные модификации - это явно не то, что мы хотели бы сделать, если бы получили возможность как-то модифицировать официальные сборки или иным образом распространять свою версию клиента, то подобная модификация жила бы максимум неделю. Рассмотрим другой вариант.
С точки зрения криптовалют самый ценный актив - это приватный ключ. Генерация приватных ключей в клиенте происходит таким образом, чтобы нельзя было предугадать чей-то чужой ключ, а точнее, чтобы вероятность такого события была крайне мала. Например, в Electrum это происходит в следующем месте:
https://github.com/spesmilo/electru...12667857ee039f1b1f30c7e3/electrum/mnemonic.py
Как вы наверное догадались, я предлагаю модифицировать данный код, чтобы получать предсказуемые значения приватных ключей, которые мы затем смогли бы подобрать, если бы знали, что нашим модифицированным клиентом кто-то пользуется. Но сначала немного о форме представления приватных ключей. В рамках предложения BIP39 (BIP - Bitcoin Improvement Proposal) был предложен формат представлений приватного ключа в виде набора запоминаемых слов, подробнее можно прочитать тут: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki. Практическую полезную суть данной информации и приведенного выше фрагмента кода можно свести к следующим шагам:
И затем, благодаря BIP32 (https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) или иерархической генерации ключей, мы получаем условно бесконечный набор дочерних ключей для работы с криптовалютой. Подробнее на русском здесь: https://habr.com/ru/company/distributedlab/blog/413627/.
Как мы можем модифицировать данный код? Фактически нам необходимо сделать предсказуемым значение переменной 'entropy'. Например, добавим следующую строку после цикла генерации энтропии:
С помощью этого кода мы в итоге получаем предсказуемый seed, который зависит от текущего времени в формате unixtime возведенного в 4 степень. Таким образом с одной стороны мы получаем новое значение каждую секунду, с другой стороны диапазон значений абсолютно предсказуем и крайне мал. Единственная проблема - это вероятность одновременной генерации одинакового ключа в один и тот же момент времени на разных системах, но для подстраховки мы можем подмешать еще какие-нибудь предсказуемые данные, например, 4 псевдослучайных байта, что достаточно понизит вероятность подобной коллизии.
В принципе мы можем запросто протестировать данное изменение и посмотреть примеры генерируемых ключей. Для этого просто скачаем master-бранч с Github (https://github.com/spesmilo/electrum/tree/master), произведем модификацию, не забыв добавить import time в начале файла mnemonic.py, и выполним ./run_electrum. Далее примеры нескольких сгенерированных master seed с небольшим временным интервалом:
Как мы видим, последние несколько слов могут повторятся, но этот нюанс легко исправить, как описано выше.
В итоге мы получаем абсолютно предсказуемые ключи на модифицированных клиентах.
Далее предположим, что вы захотите провести подобную модификацию на рантайме на клиентской системе. И если на Linux - это еще относительно легко реализовать, так как собранный клиент поставляется в формате Appimage, который содержит все те же Python-скрипты, то как быть с Windows, где в директории с исполняемым файлом они отсутвуют?
В этом случае все довольно просто:
1. Исполняемый файл Electrum под Windows также содержит в себе Python-скрипты. Проверить это можно распаковав содержимое с использованием PyInstaller Extractor (https://github.com/extremecoders-re/pyinstxtractor)
2. Часть исполняемых файлов в клиенте Electrum подвержена известному классу уязвимостей под названием DLL Hijacking (https://www.upguard.com/blog/dll-hijacking#:~:text=DLL hijacking is a method,are susceptible to DLL hijacks.)
Данное поведение возможно подтвердить дополнительно с использованием утилиты Siofra (https://github.com/Cybereason/siofra )
3. Используя официальный гайд по сборке для Windows (https://github.com/spesmilo/electrum/tree/master/contrib/build-wine), либо только с использованием Python, мы можем сгенерировать скомпилированный байт-код (pyc-файлы) для нашего модифицированного скрипта mnemonic.py, который затем использовать, например, в совокупности с proxy dll (утилита для упрощенной генерации подобного https://www.codeproject.com/Articles/1179147/ProxiFy-Automatic-Proxy-DLL-Generation) на основе системной VERSION.dll, что позволит подменить фактически исполняемый Python-код в памяти процесса.
Естественно, сам подход предполагает, что клиент будет создавать новый кошелек на модифицированном клиенте (либо в системе, где память легитимного клиента модифицируется на рантайме) и это никак не повлияет на ранее сгенерированные приватные ключи. Подобный тип модификаций является существенно менее заезженым, хотя и широко применяется в более изощренных видах некоторыми "структурами", особенно в области прикладной криптографии, но это уже другая история.
Автор: Kaimi
Клиент Electrum написан на Python и обладает бинарными сборками под популярные ОС. Также в данном клиенте существует поддержка плагинов, позволяющих сторонним разработчикам реализовывать дополнительный функционал в рамках доступного API. Если бы мы захотели реализовать некоторую полезную нагрузку в рамках клиента, то написание плагина кажется одним из первоочередных вариантов, но мне этот вариант в данном случае кажется немного скучным и я поясню почему. Вернемся немного назад и подумаем, какие обычно полезные нагрузки встраивают в софт? Обычно это что-то из следующего списка:
- Типичный элемент ботнета (VNC, работа с файлами, выполнение команд и т.п.)
- Отправка каких-либо данных с системы на сторонний ресурс
- Выполнение статичной полезной нагрузки без возможности обновления (например, встраивание майнера в релизы с играми)
- Криптолокеры
- ...
Перечисленные модификации - это явно не то, что мы хотели бы сделать, если бы получили возможность как-то модифицировать официальные сборки или иным образом распространять свою версию клиента, то подобная модификация жила бы максимум неделю. Рассмотрим другой вариант.
С точки зрения криптовалют самый ценный актив - это приватный ключ. Генерация приватных ключей в клиенте происходит таким образом, чтобы нельзя было предугадать чей-то чужой ключ, а точнее, чтобы вероятность такого события была крайне мала. Например, в Electrum это происходит в следующем месте:
https://github.com/spesmilo/electru...12667857ee039f1b1f30c7e3/electrum/mnemonic.py
Код:
def make_seed(self, *, seed_type=None, num_bits=None) -> str:
from .keystore import bip39_is_checksum_valid
if seed_type is None:
seed_type = 'segwit'
if num_bits is None:
num_bits = 132
prefix = version.seed_prefix(seed_type)
# increase num_bits in order to obtain a uniform distribution for the last word
bpw = math.log(len(self.wordlist), 2)
num_bits = int(math.ceil(num_bits/bpw) * bpw)
self.logger.info(f"make_seed. prefix: '{prefix}', entropy: {num_bits} bits")
entropy = 1
while entropy < pow(2, num_bits - bpw):
# try again if seed would not contain enough words
entropy = randrange(pow(2, num_bits))
nonce = 0
Как вы наверное догадались, я предлагаю модифицировать данный код, чтобы получать предсказуемые значения приватных ключей, которые мы затем смогли бы подобрать, если бы знали, что нашим модифицированным клиентом кто-то пользуется. Но сначала немного о форме представления приватных ключей. В рамках предложения BIP39 (BIP - Bitcoin Improvement Proposal) был предложен формат представлений приватного ключа в виде набора запоминаемых слов, подробнее можно прочитать тут: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki. Практическую полезную суть данной информации и приведенного выше фрагмента кода можно свести к следующим шагам:
- По заданным параметрам генерируется некое случайное число (master seed)
- Число кодируется в набор из слов, который затем выдается пользователю
И затем, благодаря BIP32 (https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) или иерархической генерации ключей, мы получаем условно бесконечный набор дочерних ключей для работы с криптовалютой. Подробнее на русском здесь: https://habr.com/ru/company/distributedlab/blog/413627/.
Как мы можем модифицировать данный код? Фактически нам необходимо сделать предсказуемым значение переменной 'entropy'. Например, добавим следующую строку после цикла генерации энтропии:
Код:
entropy = pow(int(time.time()), 4)
В принципе мы можем запросто протестировать данное изменение и посмотреть примеры генерируемых ключей. Для этого просто скачаем master-бранч с Github (https://github.com/spesmilo/electrum/tree/master), произведем модификацию, не забыв добавить import time в начале файла mnemonic.py, и выполним ./run_electrum. Далее примеры нескольких сгенерированных master seed с небольшим временным интервалом:
Код:
recycle life oil meat tide exchange flame truth peanut trash occur able
tired fade sample motor sure water foam beach doctor travel occur able
Как мы видим, последние несколько слов могут повторятся, но этот нюанс легко исправить, как описано выше.
В итоге мы получаем абсолютно предсказуемые ключи на модифицированных клиентах.
Далее предположим, что вы захотите провести подобную модификацию на рантайме на клиентской системе. И если на Linux - это еще относительно легко реализовать, так как собранный клиент поставляется в формате Appimage, который содержит все те же Python-скрипты, то как быть с Windows, где в директории с исполняемым файлом они отсутвуют?
В этом случае все довольно просто:
1. Исполняемый файл Electrum под Windows также содержит в себе Python-скрипты. Проверить это можно распаковав содержимое с использованием PyInstaller Extractor (https://github.com/extremecoders-re/pyinstxtractor)
2. Часть исполняемых файлов в клиенте Electrum подвержена известному классу уязвимостей под названием DLL Hijacking (https://www.upguard.com/blog/dll-hijacking#:~:text=DLL hijacking is a method,are susceptible to DLL hijacks.)
Данное поведение возможно подтвердить дополнительно с использованием утилиты Siofra (https://github.com/Cybereason/siofra )
Код:
Siofra32.exe --mode file-scan --dll-hijack --enum-dependency -f "C:\Program Files (x86)\Electrum\python38.dll"
3. Используя официальный гайд по сборке для Windows (https://github.com/spesmilo/electrum/tree/master/contrib/build-wine), либо только с использованием Python, мы можем сгенерировать скомпилированный байт-код (pyc-файлы) для нашего модифицированного скрипта mnemonic.py, который затем использовать, например, в совокупности с proxy dll (утилита для упрощенной генерации подобного https://www.codeproject.com/Articles/1179147/ProxiFy-Automatic-Proxy-DLL-Generation) на основе системной VERSION.dll, что позволит подменить фактически исполняемый Python-код в памяти процесса.
Естественно, сам подход предполагает, что клиент будет создавать новый кошелек на модифицированном клиенте (либо в системе, где память легитимного клиента модифицируется на рантайме) и это никак не повлияет на ранее сгенерированные приватные ключи. Подобный тип модификаций является существенно менее заезженым, хотя и широко применяется в более изощренных видах некоторыми "структурами", особенно в области прикладной криптографии, но это уже другая история.
Автор: Kaimi