Last active
February 23, 2023 04:10
-
-
Save shellcromancer/1192b537e690a1cceee7c057529b9d59 to your computer and use it in GitHub Desktop.
Run the XProtect.yara ruleset over the Objective-See malware collection.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# author: @shellcromancer | |
# Day 53 of #100DaysofYARA | |
import io | |
import os | |
import requests | |
import zipfile | |
import yara | |
import logging | |
import matplotlib.pyplot as plt | |
import numpy as np | |
rules = yara.compile('/Library/Apple/System/Library/CoreServices/XProtect.bundle/Contents/Resources/XProtect.yara') | |
base_path = 'tmp/' | |
try: | |
os.makedirs(base_path) | |
except FileExistsError: | |
pass | |
def pull_objc_malware() -> None: | |
response = requests.get(r"https://objective-see.com/malware.json") | |
data = response.json().get('malware', []) | |
for sample in data: | |
dl_url, name = sample.get('download'), sample.get('name') | |
if dl_url is None or dl_url == '#': | |
continue | |
dl_path = os.path.join(base_path, name) | |
if os.path.isdir(dl_path): | |
continue | |
try: | |
with requests.get(dl_url, stream=True) as r: | |
r.raise_for_status() | |
z = zipfile.ZipFile(io.BytesIO(r.content)) | |
z.setpassword(b"infect3d") | |
z.extractall(dl_path) | |
except (requests.RequestException, zipfile.BadZipFile) as e: | |
logging.error(f"failed to download {name}: {e}") | |
def scan_directory(dirname: str) -> bool: | |
for folder,_, files in os.walk(dirname): | |
for file in files: | |
path = os.path.join(folder, file) | |
try: | |
with open(path, 'rb') as f: | |
matches = rules.match(data=f.read()) | |
if len(matches) > 0: | |
return True | |
except Exception as e: | |
print(e) | |
pass | |
return False | |
def scan_objc_malware() -> dict[str, bool]: | |
dirs = next(os.walk(base_path))[1] | |
coverage = {} | |
for d in dirs: | |
result = scan_directory(os.path.join(base_path, d)) | |
coverage[d] = result | |
return coverage | |
def plot(coverage: dict[str, bool]): | |
detected = sum(coverage.values()) | |
labels = ['Detected', 'Not Detected'] | |
data = [detected, len(coverage) - detected] | |
def func(pct, allvals): | |
absolute = int(np.round(pct/100.*np.sum(allvals))) | |
return f"{pct:.1f}%\n({absolute:d})" | |
fig, ax = plt.subplots(figsize =(10, 7)) | |
ax.pie(data, labels=labels, autopct=lambda pct: func(pct, data)) | |
version = os.popen('/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" /Library/Apple/System/Library/CoreServices/XProtect.bundle/Contents/version.plist').read().strip() | |
ax.set_title(f"XProtect (Version: {version}) Objective-See Detections") | |
plt.savefig('xprotect-detections.png') | |
if __name__ == "__main__": | |
pull_objc_malware() | |
coverage = scan_objc_malware() | |
plot(coverage) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment