Whole new user level detector. Ported old bash script to python to more easily work with lists. Finnishes user level keylogger-detector.
This commit is contained in:
parent
10d7460409
commit
bb8f81ee12
254
src/userspace-keylogger-detector.py
Executable file
254
src/userspace-keylogger-detector.py
Executable file
@ -0,0 +1,254 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os # for going directories
|
||||||
|
import subprocess # for running commands, in particular fuser
|
||||||
|
import sys # for exiting
|
||||||
|
import signal # for killing processes
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
white_listed_programs_file = 'white_listed_programs.txt'
|
||||||
|
auto_kill_programs_file = 'auto_kill_programs.txt'
|
||||||
|
kbd_names_file = 'kbd_names.txt'
|
||||||
|
auto_kill_option = False
|
||||||
|
verbose_option = False
|
||||||
|
safe_option = False
|
||||||
|
kbd_names = ['kbd']
|
||||||
|
fuser_option = "-s" # -s for silent, -v for verbose
|
||||||
|
|
||||||
|
# Check if the user is in sudo mode
|
||||||
|
def check_sudo():
|
||||||
|
if os.geteuid() != 0:
|
||||||
|
print("[-] Please rerun as root")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Check if the user has the required packages installed
|
||||||
|
def check_packages():
|
||||||
|
packages = ['fuser']
|
||||||
|
missing_packages = []
|
||||||
|
for package in packages:
|
||||||
|
try:
|
||||||
|
subprocess.check_call(['which', package])
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
missing_packages.append(package)
|
||||||
|
if len(missing_packages) > 0:
|
||||||
|
print("[-] Please install the following packages:", str(missing_packages))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Follow symlinks to find real path
|
||||||
|
def get_real_path(path):
|
||||||
|
if os.path.islink(path):
|
||||||
|
return os.path.realpath(path)
|
||||||
|
else:
|
||||||
|
return path
|
||||||
|
|
||||||
|
# get keyboard device files
|
||||||
|
def get_keyboard_device_files():
|
||||||
|
keyboard_device_files = []
|
||||||
|
for root, dirs, files in os.walk('/dev/input/by-path'):
|
||||||
|
for file in files:
|
||||||
|
if any(kbd_name in file for kbd_name in kbd_names):
|
||||||
|
keyboard_device_files.append(get_real_path(os.path.join(root, file)))
|
||||||
|
return keyboard_device_files
|
||||||
|
|
||||||
|
# print a list to a file separated by newlines
|
||||||
|
def print_list_to_file(list, file):
|
||||||
|
with open(file, 'w') as f:
|
||||||
|
for item in list:
|
||||||
|
f.write("%s\n" % item)
|
||||||
|
|
||||||
|
# find pids using file using fuser
|
||||||
|
def get_pids(file):
|
||||||
|
try:
|
||||||
|
pids = subprocess.check_output(['fuser',fuser_option, file]).decode('utf-8').split()
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
if verbose_option:
|
||||||
|
print("[-] Error: fuser failed to run on", file)
|
||||||
|
return []
|
||||||
|
pids = [int(pid) for pid in pids]
|
||||||
|
return pids
|
||||||
|
|
||||||
|
# clear a file
|
||||||
|
def clear_file(file):
|
||||||
|
open(file, 'w').close()
|
||||||
|
|
||||||
|
|
||||||
|
# find programm name using pid
|
||||||
|
def get_program_name(pid):
|
||||||
|
status_file = '/proc/' + str(pid) + '/status'
|
||||||
|
with open(status_file, 'r') as f:
|
||||||
|
# See cat /proc/[pid]/status | grep Name
|
||||||
|
for line in f:
|
||||||
|
if line.startswith('Name:'):
|
||||||
|
program_name = line.split(":")[1].strip()
|
||||||
|
return program_name
|
||||||
|
|
||||||
|
# proces input arguments and set options
|
||||||
|
def set_input_arguments():
|
||||||
|
global auto_kill_option
|
||||||
|
global verbose_option
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
if '-a' in sys.argv:
|
||||||
|
auto_kill_option = True
|
||||||
|
if '-v' in sys.argv:
|
||||||
|
verbose_option = True
|
||||||
|
if '-s' in sys.argv:
|
||||||
|
safe_option = True
|
||||||
|
|
||||||
|
# initialize kbd_names based on input file
|
||||||
|
def initialize_kbd_names():
|
||||||
|
global kbd_names
|
||||||
|
try:
|
||||||
|
with open(kbd_names_file, 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
kbd_names.append(line.strip())
|
||||||
|
except:
|
||||||
|
pass # default is kbd_names=['kbd'] as set at the top
|
||||||
|
|
||||||
|
# ask user to confirm a list of programs to kill
|
||||||
|
def confirm_kill_programs(programs, times=0):
|
||||||
|
print("Confirm to kill the following programs:")
|
||||||
|
for program in programs:
|
||||||
|
print(program)
|
||||||
|
print("y/n?")
|
||||||
|
answer = input()
|
||||||
|
if answer == 'y':
|
||||||
|
return True
|
||||||
|
elif answer == 'n':
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if times > 5:
|
||||||
|
print("[-] Too many tries. Exiting")
|
||||||
|
sys.exit(1)
|
||||||
|
print("[-] Please answer y or n")
|
||||||
|
return confirm_kill_programs(programs, times+1)
|
||||||
|
|
||||||
|
# kill list of processes
|
||||||
|
def kill_processes(pids):
|
||||||
|
for pid in pids:
|
||||||
|
os.kill(pid, signal.SIGKILL)
|
||||||
|
if verbose_option:
|
||||||
|
print("[-] Killed process with pid", pid)
|
||||||
|
|
||||||
|
# the main program starts here
|
||||||
|
def detect_keyloggers():
|
||||||
|
###############################
|
||||||
|
# Step 0: Check minimal requirements/ Set up
|
||||||
|
###############################
|
||||||
|
check_sudo()
|
||||||
|
check_packages()
|
||||||
|
set_input_arguments()
|
||||||
|
###############################
|
||||||
|
# Step 1: Get keyboard device files
|
||||||
|
###############################
|
||||||
|
keyboard_device_files = get_keyboard_device_files()
|
||||||
|
clear_file('keyboard_device_files.txt')
|
||||||
|
print_list_to_file(keyboard_device_files, 'keyboard_device_files.txt')
|
||||||
|
|
||||||
|
###############################
|
||||||
|
# Step 2: Get pids using keyboard device files
|
||||||
|
###############################
|
||||||
|
pids = []
|
||||||
|
for file in keyboard_device_files:
|
||||||
|
pids += get_pids(file)
|
||||||
|
pids = sorted(list(set(pids)))
|
||||||
|
clear_file('pids.txt')
|
||||||
|
print_list_to_file(pids, 'pids.txt')
|
||||||
|
|
||||||
|
###############################
|
||||||
|
# Step 3: Get program names using pids
|
||||||
|
###############################
|
||||||
|
program_names = []
|
||||||
|
program_pid_dict = {}
|
||||||
|
auto_kill_programs = []
|
||||||
|
white_listed_programs = []
|
||||||
|
|
||||||
|
# Get white listed programs
|
||||||
|
try:
|
||||||
|
with open(white_listed_programs_file, 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
white_listed_programs.append(line.strip())
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Get auto kill programs
|
||||||
|
try:
|
||||||
|
with open(auto_kill_programs_file, 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
auto_kill_programs.append(line.strip())
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Get program names
|
||||||
|
for pid in pids:
|
||||||
|
program_name = get_program_name(pid)
|
||||||
|
program_pid_dict[program_name] = pid
|
||||||
|
if auto_kill_option and program_name in auto_kill_programs:
|
||||||
|
os.kill(pid, signal.SIGKILL)
|
||||||
|
if verbose_option:
|
||||||
|
print("[-] Auto-Killed process", program_name, "with pid", pid)
|
||||||
|
else:
|
||||||
|
program_names.append(program_name)
|
||||||
|
program_names = sorted(list(set(program_names)))
|
||||||
|
|
||||||
|
# Identify suspicious programs
|
||||||
|
suspicious_programs = []
|
||||||
|
for program_name in program_names:
|
||||||
|
if program_name not in white_listed_programs:
|
||||||
|
suspicious_programs.append(program_name)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if verbose_option:
|
||||||
|
###############################=
|
||||||
|
# Intermezzo: Print results
|
||||||
|
###############################
|
||||||
|
print("Keyboard device files:")
|
||||||
|
for file in keyboard_device_files:
|
||||||
|
print(file)
|
||||||
|
print("")
|
||||||
|
print("Pids:")
|
||||||
|
for pid in pids:
|
||||||
|
print(pid)
|
||||||
|
print("")
|
||||||
|
print("Program names:")
|
||||||
|
for program_name in program_names:
|
||||||
|
print(program_name)
|
||||||
|
print("")
|
||||||
|
|
||||||
|
if len(suspicious_programs) == 0:
|
||||||
|
print("[+] No suspicious programs found")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
###############################
|
||||||
|
# Step 4: Ask user to kill any suspicious programs
|
||||||
|
###############################
|
||||||
|
print("Suspicious programs:")
|
||||||
|
for program_name in suspicious_programs:
|
||||||
|
print(program_name)
|
||||||
|
user_input = input("Please enter any program/ that should be kept from running. Use the whitespace(spacebar) to separate values.")
|
||||||
|
if user_input == '':
|
||||||
|
print("[-] No programs to kill")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
programs_to_kill = user_input.split()
|
||||||
|
programs_to_kill = [program_name for program_name in programs_to_kill if program_name in suspicious_programs] # Filter out programs that are not suspicious
|
||||||
|
pids_to_kill = []
|
||||||
|
for program_name in programs_to_kill:
|
||||||
|
pids_to_kill.append(program_pid_dict[program_name])
|
||||||
|
|
||||||
|
if safe_option:
|
||||||
|
if confirm_kill_programs(programs_to_kill):
|
||||||
|
kill_processes(pids_to_kill)
|
||||||
|
else:
|
||||||
|
kill_processes(pids_to_kill)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
detect_keyloggers()
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user