|
| 1 | +from pathlib import Path |
| 2 | + |
| 3 | +from bbot.modules.base import BaseModule |
| 4 | + |
| 5 | + |
| 6 | +class filedownload(BaseModule): |
| 7 | + """ |
| 8 | + Watch for common filetypes and download them |
| 9 | + """ |
| 10 | + |
| 11 | + watched_events = ["URL_UNVERIFIED"] |
| 12 | + produced_events = [] |
| 13 | + flags = ["active", "safe"] |
| 14 | + meta = {"description": "Download common filetypes such as PDF, DOCX, PPTX, etc."} |
| 15 | + options = { |
| 16 | + "extensions": [ |
| 17 | + "bak", # Backup File |
| 18 | + "bash", # Bash Script or Configuration |
| 19 | + "bashrc", # Bash Script or Configuration |
| 20 | + "conf", # Configuration File |
| 21 | + "cfg", # Configuration File |
| 22 | + "cr2", # Canon RAW Image |
| 23 | + "crt", # Certificate File |
| 24 | + "crw", # Canon RAW Image (Older Format) |
| 25 | + "csv", # Comma Separated Values File |
| 26 | + "db", # SQLite Database File |
| 27 | + "sqlite", # SQLite Database File |
| 28 | + "doc", # Microsoft Word Document (Old Format) |
| 29 | + "docx", # Microsoft Word Document |
| 30 | + "ica", # Citrix Independent Computing Architecture File |
| 31 | + "indd", # Adobe InDesign Document |
| 32 | + "ini", # Initialization File |
| 33 | + "jar", # Java Archive |
| 34 | + "jpg", # JPEG Image |
| 35 | + "jpeg", # JPEG Image |
| 36 | + "js", # JavaScript File |
| 37 | + "json", # JavaScript Object Notation File |
| 38 | + "key", # Private Key File |
| 39 | + "pub", # Public Key File |
| 40 | + "log", # Log File |
| 41 | + "md", # Markdown File |
| 42 | + "markdown", # Markdown File |
| 43 | + "odg", # OpenDocument Graphics (LibreOffice, OpenOffice) |
| 44 | + "odp", # OpenDocument Presentation (LibreOffice, OpenOffice) |
| 45 | + "ods", # OpenDocument Spreadsheet (LibreOffice, OpenOffice) |
| 46 | + "odt", # OpenDocument Text (LibreOffice, OpenOffice) |
| 47 | + "pdf", # Adobe Portable Document Format |
| 48 | + "pem", # Privacy Enhanced Mail (SSL certificate) |
| 49 | + "png", # Portable Network Graphics Image |
| 50 | + "pps", # Microsoft PowerPoint Slideshow (Old Format) |
| 51 | + "ppsx", # Microsoft PowerPoint Slideshow |
| 52 | + "ppt", # Microsoft PowerPoint Presentation (Old Format) |
| 53 | + "pptx", # Microsoft PowerPoint Presentation |
| 54 | + "ps1", # PowerShell Script |
| 55 | + "raw", # Raw Image File Format |
| 56 | + "rdp", # Remote Desktop Protocol File |
| 57 | + "sh", # Shell Script |
| 58 | + "sql", # SQL Database Dump |
| 59 | + "svg", # Scalable Vector Graphics |
| 60 | + "svgz", # Compressed SVG |
| 61 | + "swp", # Swap File (temporary file, often Vim) |
| 62 | + "sxw", # OpenOffice.org Writer document |
| 63 | + "tar", # Tar Archive |
| 64 | + "tar.gz", # Gzip-Compressed Tar Archive |
| 65 | + "zip", # Zip Archive |
| 66 | + "txt", # Plain Text Document |
| 67 | + "vbs", # Visual Basic Script |
| 68 | + "wpd", # WordPerfect Document |
| 69 | + "xls", # Microsoft Excel Spreadsheet (Old Format) |
| 70 | + "xlsx", # Microsoft Excel Spreadsheet |
| 71 | + "xml", # eXtensible Markup Language File |
| 72 | + "yml", # YAML Ain't Markup Language |
| 73 | + "yaml", # YAML Ain't Markup Language |
| 74 | + ], |
| 75 | + "max_filesize": "10MB", |
| 76 | + } |
| 77 | + options_desc = { |
| 78 | + "extensions": "File extensions to download", |
| 79 | + "max_filesize": "Cancel download if filesize is greater than this size", |
| 80 | + } |
| 81 | + |
| 82 | + scope_distance_modifier = 1 |
| 83 | + |
| 84 | + async def setup(self): |
| 85 | + self.extensions = list(set([e.lower().strip(".") for e in self.options.get("extensions", [])])) |
| 86 | + self.max_filesize = self.options.get("max_filesize", "10MB") |
| 87 | + self.download_dir = self.scan.home / "filedownload" |
| 88 | + self.helpers.mkdir(self.download_dir) |
| 89 | + self.files_downloaded = 0 |
| 90 | + return True |
| 91 | + |
| 92 | + async def handle_event(self, event): |
| 93 | + url_lower = event.data.lower() |
| 94 | + if any(url_lower.endswith(f".{e}") for e in self.extensions): |
| 95 | + timestamp = self.helpers.make_date(event.timestamp) |
| 96 | + filepath = Path(event.parsed.path) |
| 97 | + filename_stem = self.helpers.tagify(filepath.stem) |
| 98 | + filename = f"{timestamp}_{filename_stem}{filepath.suffix}" |
| 99 | + file_destination = self.download_dir / filename |
| 100 | + base_url = f"{event.parsed.scheme}://{event.parsed.netloc}" |
| 101 | + self.info(f'Found "{filepath.name}" at "{base_url}", downloading to {file_destination}') |
| 102 | + await self.helpers.download(event.data, filename=file_destination, max_size=self.max_filesize) |
| 103 | + self.files_downloaded += 1 |
| 104 | + |
| 105 | + async def report(self): |
| 106 | + if self.files_downloaded > 0: |
| 107 | + self.success(f"Downloaded {self.files_downloaded:,} file(s) to {self.download_dir}") |
0 commit comments