23 Commits

Author SHA1 Message Date
Sebastian Lenzlinger
39a56a53f0 Update README.md 2023-06-14 12:23:29 +02:00
Sebastian Lenzlinger
000d485da0 Update README.md 2023-06-14 12:21:32 +02:00
Sebastian Lenzlinger
65733380d4 Update README.md 2023-06-14 12:14:35 +02:00
Sebastian Lenzlinger
b934ffded1 Rename keylogger_detector.py to kldetect.py 2023-06-13 16:44:22 +02:00
Sebastian Lenzlinger
efc5b26e60 Merge pull request #10 from sebaschi/fiex
Fiex
2023-06-13 14:36:30 +02:00
Sebastian Lenzlinger
e3c076b1df Update README.md 2023-06-13 14:35:53 +02:00
Sebastian Lenzlinger
dfac235733 Update README.md
Add warning about updating whitelist.txt with current kernel modules
2023-06-13 14:34:12 +02:00
Sebastian Lenzlinger
ba4bc26b2c Merge pull request #9 from sebaschi/fiex
Fiex
2023-06-13 14:20:49 +02:00
Sebastian Lenzlinger
5680143977 Merge branch 'main' into fiex 2023-06-13 14:20:31 +02:00
Sebastian Lenzlinger
7d4bc93243 Update README.md 2023-06-13 13:10:24 +02:00
Sebastian Lenzlinger
326f5011e0 Update README.md 2023-06-13 13:07:14 +02:00
Sebastian Lenzlinger
79bad57439 Update README.md 2023-06-13 13:05:49 +02:00
Sebastian Lenzlinger
33eb3c6fb4 Update README.md 2023-06-13 13:05:00 +02:00
Sebastian Lenzlinger
b59c659553 Update README.md 2023-06-13 12:57:39 +02:00
Sebastian Lenzlinger
ec19a08e63 Upate Readme 2023-06-13 12:56:15 +02:00
SoulKindred
689508282c Add files via upload
Made print-statements preaty and added doc
2023-06-13 12:55:11 +02:00
Sebastian Lenzlinger
6fac965976 Update README.md 2023-06-13 12:49:40 +02:00
Sebastian Lenzlinger
c8fc7dc2b7 Update README.md 2023-06-13 12:49:20 +02:00
Sebastian Lenzlinger
05f86101dd Update README.md 2023-06-13 12:49:02 +02:00
Sebastian Lenzlinger
c30de44832 Merge branch 'main' of github.com:sebaschi/keylogger-detector 2023-06-13 12:48:02 +02:00
Sebastian Lenzlinger
496ee97d3f Update Readme 2023-06-13 12:47:45 +02:00
Sebastian Lenzlinger
1d40184e5f Merge pull request #8 from sebaschi/sebaschi-patch-2
Update dev_journal.md
2023-06-13 12:44:48 +02:00
SoulKindred
efbc9bc88f Add files via upload
Just took the essential code from my script and I put it into keylogger_detector.py
No clue why it works now
2023-06-12 17:55:12 +02:00
2 changed files with 284 additions and 4 deletions

View File

@@ -1,2 +1,65 @@
# keylogger-detector # KLDetect
University project for an Operating Systems lecture. The goal is to develope a keystroke-logger-detector for a Linux environment. Developement Environment: Fedora 37 VM under Gnome on VirtualBox. A project journal can be found [here](https://github.com/sebaschi/keylogger-detector/blob/main/doc/dev_journal.md) KLDetect is a keylogger detector for the Linux Desktop.
It can detect processes reading from ```/dev/input/event*``` devices and kernel modules registered to listen to keyboard events.
# Dependencies
* [Python](https://www.python.org/downloads/)
* [SystemTap](https://sourceware.org/systemtap/wiki)
* [```fuser```](https://www.man7.org/linux/man-pages/man1/fuser.1.html)
* Utilities that come with [Fedora](https://fedoraproject.org/) like ```which```.
# Setup
Download or clone this repository:
```
git clone https://github.com/sebaschi/keylogger-detector.git
```
Navigate into the src directory:
```
cd keylogger-detector/src
```
Run a keylogger. KLDetect has been tested and shown to work on the following keylogger.
User progams:
* [simple-key-logger](https://github.com/gsingh93/simple-key-logger/tree/master)
* [logkeys](https://github.com/kernc/logkeys)
* [keylog](https://github.com/SCOTPAUL/keylog)
Kernel Module:
* [spy](https://github.com/jarun/spy)
# Usage
KLDetect **must** be run as root (sudo).
If KLDetect is not run as root the user is reminded to try again with root permissions.
Running without options just runs userspace detection:
```
./kldetect.py
```
To get a list of command line options:
```
./kldetect.py -h
```
To run with kernel module detection:
```
./kldetect.py -k
```
To run just kernel module detection
```
./kernel_detector.py
```
# Warning
Running any part if this program in a lightheaded manner may break your system.
Killing processes and unloading modules should be done with caution. We suggest testing it an a VM.
If one runs the KLDetect with the kernel module keylogger detection option set, make sure to update the [whitelist.txt](https://github.com/sebaschi/keylogger-detector/blob/main/src/whitelist.txt) with the safe kernel modules that you know you have on your system. In particular we highly suggest running ```lsmod > <path-to-kldetect>/whitelist.txt```, before inserting a kernel keylogger. This writes the modules currently inserted in the kernel to the whitelist. This way 'normal' modules that you already have installed on the 'clean' kernel will not accidentally be unloaded. Altough KLDetect should not unload any kernel modules currently used, better safe than sorry.
# Developers
Copyright © 2023[Michel Romancuk](https://github.com/SoulKindred), [Sebastian Lenzlinger](https://github.com/sebaschi)
This project is Part of a Univeristy project at the [Operating Systems](https://dmi.unibas.ch/de/studium/computer-science-informatik/lehrangebot-fs23/vorlesung-operating-systems-1/) lecture at the University of Basel, Switzerland.
A project journal can be found [here](https://github.com/sebaschi/keylogger-detector/blob/main/doc/dev_journal.md).

View File

@@ -1,5 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import subprocess
import time
import os
import sys import sys
from config import CONFIG_FILE, load_config, save_config from config import CONFIG_FILE, load_config, save_config
from utils import ( from utils import (
@@ -106,6 +108,176 @@ def confirm_kill_procces(process_name, times=0):
else: else:
return confirm_kill_procces(process_name, times+1) return confirm_kill_procces(process_name, times+1)
def detect_kernel(module):
"""
Start the systemtap-script.
load and unload modules twice.
load module when finished.
Args:
module(str): Path + name of the module being tested
Returns:
String: Path + name of the module that is logging keystrokes
"""
if verbose_option:
print('[Verbose] Started kernel keylogger detection')
process = subprocess.Popen(['stap','funcall_trace.stp', '-T', '10'], stdout=subprocess.PIPE, text=True)
for i in range(2):
subprocess.Popen(['sudo','insmod', module])
time.sleep(1)
print(".", end="")
subprocess.Popen(['sudo','rmmod', module])
time.sleep(1)
subprocess.Popen(['sudo','insmod', module])
print(".")
out = process.communicate()[0]
if verbose_option:
print('[Verbose] Started kernel keylogger detection')
print(out)
if out == "[-]":
return module
print("FAILED")
return 0
def getpath(sus_modules):
"""
Gets the path of a list of modules being tested
calls "find_file()" function
Args:
List[module(str)] List of all modules being tested
Returns:
List[modules(str)]List of the Path of all modules being tested
"""
for i in range(len(sus_modules)):
sus_modules[i] = find_file(sus_modules[i] + ".ko")
return sus_modules
def find_file(filename):
"""
Searches for a file begining at root
Args:
filename(str) The filename one is looking for
Returns:
result_out(str) 'The Path_to_Module/Module_name'
"""
result = []
for root, dirs, files in os.walk("/"):
if filename in files:
file_path = os.path.join(root, filename)
result.append(file_path)
result_out = result
result_out = ''.join(result_out)
return result_out
def unload_mod(modules):
"""
Unloads modules.
Args:
module(str) the module that needs to be unloaded. Has to be Path_to_Module/Module_name
"""
tmp = []
for module in modules:
result = subprocess.run(['sudo','rmmod', module],capture_output = True, text = True)
if result.returncode == 0:
if verbose_option:
print(f"[Verbose] Unloaded module: {module}")
else:
if verbose_option:
print(f"[Verbose] Failed to unloaded module: {module}")
print("[Verbose] " + result.stderr)
tmp.append(module)
result_out = compare_mods(tmp, modules)
if verbose_option:
print("[Verbose] ", end="")
print(result_out)
return result_out
def tidy_up(entries):
"""
Takes a txt file and removes everything except the first word of a line
Args:
File(.txt) in this usecase a whitelist.txt
Returns:
clean_entries(List[str]) List of only the first wrod from each line
"""
cleaned_entries = []
for entry in entries:
modules = entry.split()
if modules:
first_mod = modules[0]
cleaned_entries.append(first_mod)
return cleaned_entries
def compare_mods(A, B):
"""
Does set-suptraction to.
Args:
A(list[str]) List of elements one wants to ignore
B(list[str]) List of elements that one wants without all elements in A
Returns:
result(list[str] List of elements that are in B but not in A
"""
setA = set(A)
setB = set(B)
result = setB - setA
return list(result)
def get_whitelist(file_path):
"""
reads a text-file
Args:
file_path(str) Path to file one wants to read
Returns:
lines(list[str]) List of each line from a file
"""
try:
with open(file_path, 'r') as file:
lines = file.read().splitlines()
return lines
except IOError:
print(f'Error: Failed to load whitelist{file_path}')
def list_modules(command):
"""
Calls a command in terminal
Args:
command(str) the command one wants to execute
Returns:
result(list[std]) List of each line the command has as an output.
"""
result = subprocess.run(command, shell = True, capture_output=True, text=True)
if result.returncode == 0:
return result.stdout.strip().split('\n')
else:
print(f"Failed with error:{result.stderr}")
return[]
def detect_keyloggers(): def detect_keyloggers():
""" """
Detect (userland) keylogger processes based on which processes have a keyboard file open (/dev/input/event*) Detect (userland) keylogger processes based on which processes have a keyboard file open (/dev/input/event*)
@@ -288,11 +460,56 @@ def detect_keyloggers():
if verbose_option: if verbose_option:
print('[Verbose] Config file saved') print('[Verbose] Config file saved')
print('[+] Program completed. Exiting.')
debug(debug_option, 'Kernel detection option: ' + str(kernel_detection_option)) debug(debug_option, 'Kernel detection option: ' + str(kernel_detection_option))
###########################
# 10. If kernel_detection_option is set, run kernel detection
###########################
if kernel_detection_option:
whitelist = get_whitelist("whitelist.txt")
lsmod_output = list_modules("lsmod")
sus_modules = compare_mods(whitelist, lsmod_output)
sus_modules = tidy_up(sus_modules)
sus_modules = unload_mod(sus_modules)
time.sleep(1)
sus_modules = getpath(sus_modules)
suspects = []
if verbose_option:
print("[Verbose] ", end="")
print(sus_modules)
if len(sus_modules) == 0 and verbose_option:
print("[Verbose] Nothing to do")
for module in sus_modules:
if module == '': #if modules have an empty path, they are in root
break
suspects.append(detect_kernel(module))
time.sleep(1)
print("Following modules are logging your keystrokes: ")
for i in range(len(suspects)):
print( f"[{i}] {suspects[i]}")
print("Enter the number of the module you want to remove: ")
user_input = input().split()
to_remove = []
for j in user_input:
to_remove = suspects[int(j)]
subprocess.Popen(['sudo','rmmod', to_remove])
if len(to_remove) < 1:
print(f"Removed {to_remove}")
print('[+] Program completed. Exiting.')
if __name__ == '__main__': if __name__ == '__main__':
detect_keyloggers() detect_keyloggers()