Created
October 5, 2025 07:39
-
-
Save 0xNDI/d82f491ac4e6fa205dfb3475ca5d4fbb to your computer and use it in GitHub Desktop.
Fix rusthound zip so it imports to latest BH CE
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 | |
| import json | |
| import sys | |
| import zipfile | |
| import tempfile | |
| import os | |
| import shutil | |
| def main(): | |
| if len(sys.argv) != 2: | |
| print("Usage: python fix-rusthound.py <zip_file>") | |
| sys.exit(1) | |
| zip_file = sys.argv[1] | |
| if not os.path.exists(zip_file): | |
| print(f"Error: File '{zip_file}' not found") | |
| sys.exit(1) | |
| if not zipfile.is_zipfile(zip_file): | |
| print(f"Error: '{zip_file}' is not a valid zip file") | |
| sys.exit(1) | |
| domains_file = None | |
| with zipfile.ZipFile(zip_file, 'r') as zf: | |
| for filename in zf.namelist(): | |
| if filename.endswith('domains.json'): | |
| domains_file = filename | |
| break | |
| if not domains_file: | |
| print("Error: No file ending with 'domains.json' found in the zip") | |
| sys.exit(1) | |
| print(f"Found domains file: {domains_file}") | |
| try: | |
| with zipfile.ZipFile(zip_file, 'r') as zf: | |
| with zf.open(domains_file) as f: | |
| data = json.load(f) | |
| except json.JSONDecodeError as e: | |
| print(f"Error: Invalid JSON in {domains_file} - {e}") | |
| sys.exit(1) | |
| if not isinstance(data, dict) or 'data' not in data: | |
| print("Error: JSON must have a top-level 'data' key containing an array") | |
| sys.exit(1) | |
| if not isinstance(data['data'], list): | |
| print("Error: The 'data' key must contain an array") | |
| sys.exit(1) | |
| original_count = len(data['data']) | |
| data['data'] = [ | |
| item for item in data['data'] | |
| if isinstance(item, dict) and | |
| item.get('ObjectIdentifier', '').strip() != '' | |
| ] | |
| new_count = len(data['data']) | |
| try: | |
| zip_dir = os.path.dirname(os.path.abspath(zip_file)) | |
| with tempfile.NamedTemporaryFile(delete=False, dir=zip_dir, suffix='.tmp') as temp_zip: | |
| temp_zip_path = temp_zip.name | |
| with zipfile.ZipFile(zip_file, 'r') as original_zip, \ | |
| zipfile.ZipFile(temp_zip_path, 'w', zipfile.ZIP_DEFLATED) as new_zip: | |
| for item in original_zip.infolist(): | |
| if item.filename != domains_file: | |
| new_zip.writestr(item, original_zip.read(item.filename)) | |
| cleaned_json = json.dumps(data, indent=2, ensure_ascii=False) + '\n' | |
| new_zip.writestr(domains_file, cleaned_json.encode('utf-8')) | |
| shutil.move(temp_zip_path, zip_file) | |
| except PermissionError: | |
| print(f"Error: Permission denied writing to '{zip_file}'") | |
| if 'temp_zip_path' in locals() and os.path.exists(temp_zip_path): | |
| os.unlink(temp_zip_path) | |
| sys.exit(1) | |
| except Exception as e: | |
| print(f"Error: Failed to update zip file - {e}") | |
| if 'temp_zip_path' in locals() and os.path.exists(temp_zip_path): | |
| os.unlink(temp_zip_path) | |
| sys.exit(1) | |
| print(f"Cleaned {domains_file} in {zip_file}: {original_count} -> {new_count} entries") | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment