Skip to content

Commit

Permalink
Merge pull request #4 from OS2borgerPC/2-sikkerhedsscripts
Browse files Browse the repository at this point in the history
issue #2 - tilføj sikkerhedsscripts. Disse vises under fanen 'Sikkerh…
  • Loading branch information
NeutraChikara authored Dec 13, 2024
2 parents 205e0c0 + 56d5897 commit db31967
Show file tree
Hide file tree
Showing 6 changed files with 400 additions and 0 deletions.
45 changes: 45 additions & 0 deletions detect_keyboard_event.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
title: "Detekter nytilsluttet keyboard"
parent: "Sikkerhed"
source: scripts/detect_keyboard_event.py
compatibility:
- "22.04"
- "BorgerPC"
metadata:
security: true
---

## Beskrivelse
Sikkerhedsscriptet identificerer ny-tilsluttede keyboards helt tilbage fra sidste gang systemet blev tjekket. Findes det resulterer det i en sikkerhedshændelse.
At fjerne et keyboard giver IKKE en advarsel.

BEMÆRK: Dette sikkerhedsscript er afhængigt af, om USB-enheden identificerer sig selv som et keyboard. Af denne grund, vil vi - såfremt det er muligt i jeres anvendelse - anbefale i stedet at benytte scriptet, der låser maskinen ved indsættelse af ALLE USB-enheder ("Bloker for login ved USB-event"), sammen med sikkerhedscriptet der giver en advarsel, når Borger-kontoen er blevet låst ("Detekter låst Borgerkonto").

Dette sikkerhedsscript virker både på OS2borgerPC og OS2borgerPC Kiosk, men vi mener det er mest relevant på førstnævnte, ift. faren ved keyloggers på publikumsmaskiner.

VIGTIG BEMÆRKNING:
Sikkerhedsscriptet er kun aktivt, når maskinen er tændt!

Af ovenstående grund er det centralt, at besøgende ikke kan tilgå maskinerne mens de er slukket, uden at det opdages.

Derfor foreslår vi at kombinere det med følgende tre scripts:

1. Scriptet "Desktop - Fjern Luk Ned og Genstart fra sessionmenuen og blokér for nedlukning via systempolitik"

2. Scriptet "OS2borgerPC - Blokér for login ved hård nedlukning"

3. Sikkerhedsscriptet "Detekter låst Borgerkonto"

Sammen betyder de tre:
1. At brugeren ikke kan lukke maskinen ned fra menuen.
2. Trykker de på knappen for at lukke den ned, eller hiver de strømstikket ud, så låses der for login for Borger-kontoen. (Da de potentielt være have indsat en keylogger)
3. Hvis Borger-kontoen låses modtager man, pga. script tre, en sikkerhedshændelse

Ønsker man slet ikke at Borgere skal kunne rode med USB-enheder så kan man bruge scriptet
"OS2borgerPC - Blokér for login ved USB-event"
Med dette andet script vil både at tilføje eller fjerne en USB-enhed mens maskinen er tændt, betyde at Borgeren logges øjeblikkeligt ud, og at der derefter låses for login.

Når Borger-kontoen er låst kan man fra adminsitet køre scriptet "OS2borgerPC - Sæt bruger aktiv efter blokeret login (lås op)" for at åbne for login på Borger-kontoen igen.

## Parametre
Ingen
26 changes: 26 additions & 0 deletions detect_sudo_event.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: "Detekter sudo-kørsel"
parent: "Sikkerhed"
source: scripts/detect_sudo_event.py
compatibility:
- "22.04"
- "BorgerPC"
metadata:
security: true
---

## Beskrivelse
Dette Sikkerhedsscript giver en sikkerhedshændelse ved sudo-kørsel.

Dette script virker både på OS2borgerPC og OS2borgerPC Kiosk.

Der gives både en advarsel hvis sudo køres med succes, hvis det fejler pga. det køres fra Borger fremfor superuser, eller den indtastede kode er forkert.
Nærmere specifikt:
sudo-kommandoen giver én tre forsøg på at indtaste koden - taster man forkert tre gange vil det give en advarsel. Taster man korrekt vil det ligeledes give en advarsel.

Derfor: Hvis du har tilføjet en regel for en maskine, og du selv er inde på den fra superuser, vil der også komme en advarsel, hvis du kører sudo.

Når du modtager en advarsel vil der ofte stå USER=root i beskeden. Dette betyder ikke, at brugeren allerede har root-adgang (dvs. administrator-adgang), men alene at brugeren, personen forsøger at køre kommandoer som, er administrator-kontoen.

## Parametre
Ingen
22 changes: 22 additions & 0 deletions detect_user_expired_event.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: "Detekter låst Borgerkonto"
parent: "Sikkerhed"
source: scripts/detect_user_expired_event.py
compatibility:
- "22.04"
- "BorgerPC"
metadata:
security: true
---

## Beskrivelse
Dette Sikkerhedsscript giver en Sikkerhedshændelse hvis Borger bliver låst ude/sat til udløbet.

Dette script virker kun på OS2borgerPC, ikke OS2borgerPC Kiosk.

Bruges sammen med en eller begge af følgende:
- "Bloker for login ved USB-event" + "Sæt bruger aktiv efter blokeret login"
- "OS2borgerPC - Bloker for login ved hård nedlukning" + "Sæt bruger aktiv efter blokeret login"

## Parametre
Ingen
129 changes: 129 additions & 0 deletions scripts/detect_keyboard_event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#!/usr/bin/env python3

"""
Security Script for finding USB keyboard attachment events
"""

import sys
from datetime import datetime, timedelta
import re

__copyright__ = "Copyright 2017-2024 Magenta ApS"
__license__ = "GPL"


def log_read(last_security_check, log_name):
"""Search a (system) log for events that occurred
between "last_security_check" and now."""
log_event_tuples = []
now = datetime.now()

with open(log_name) as f:
for line in f.readlines():
line = str(line.replace("\0", ""))
log_event_timestamp = line[:15]
log_event = line.strip("\n")
# convert from log event timestamp to security event log timestamp.
log_event_datetime = datetime.strptime(
str(now.year) + " " + log_event_timestamp, "%Y %b %d %H:%M:%S"
)
security_event_log_timestamp = datetime.strftime(
log_event_datetime, "%Y%m%d%H%M%S"
)
# Detect lines from within the last x seconds to now.
if last_security_check <= log_event_datetime <= now:
log_event_tuples.append((security_event_log_timestamp, log_event))

return log_event_tuples


def csv_writer(security_events):
"""Write security events to security events file."""
with open("/etc/os2borgerpc/security/securityevent.csv", "at") as csvfile:
for timestamp, security_problem_uid, log_event in security_events:
event_line = log_event.replace("\n", " ").replace("\r", "").replace(",", "")
csvfile.write(f"{timestamp},{security_problem_uid},{event_line}\n")


def filter_duplicate_events(security_events):
"""This function filters duplicate events related to
the same keyboard"""

unique_tuples = []
unique_keyboards = []

for security_event in security_events:
# This identifier is based on the ID of the USB device.
# The ID is identical for identical USB devices so
# if two identical keyboards are inserted simultaneously,
# only one event will be generated.
regex = (
r"[0-9a-z]{4}:[0-9a-z]{4}:[0-9a-z]{4}"
r"(?!.*/[0-9a-z]{4}:[0-9a-z]{4}:[0-9a-z]{4})"
)
match = re.search(regex, security_event[2], flags=re.IGNORECASE)
# Keyboard event lines should always contain a match, but in order
# to prevent possibly overlooking a relevant event, we always include
# events with no match
if match:
keyboard_identifier = match.group(0)
if keyboard_identifier not in unique_keyboards:
unique_tuples.append(security_event)
unique_keyboards.append(keyboard_identifier)
else: # This part should never be relevant, but it is here just in case
unique_tuples.append(security_event)

return unique_tuples


# The file to inspect for events
log_name = "/var/log/syslog"

now = datetime.now()
# The default value in case lastcheck.txt is nonexisting or empty:
last_security_check = now - timedelta(hours=24)
try:
with open("/etc/os2borgerpc/security/lastcheck.txt", "r") as fp:
timestamp = fp.read()
if timestamp:
last_security_check = datetime.strptime(timestamp, "%Y%m%d%H%M%S")
except IOError:
pass

log_event_tuples = log_read(last_security_check, log_name)

security_problem_uid_template_var = "%SECURITY_PROBLEM_UID%"

# Match keyboard events that are after 9.9999 seconds of boot up
# (so we don't match upstart keyboard events),
# Also remove system control and consumer control entries:
# The reason is that some keyboards add three keyboard entries when connected.
# Example from inserting a keyboard once:
# Jun 28 14:24:43 kbh-nuc-venstre kernel: [ 1948.130701] input: Logitech HID compliant keyboard as /devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0/0003:046D:C30E.000A/input/input25
# Jun 28 14:24:43 kbh-nuc-venstre kernel: [ 1948.264053] input: Logitech HID compliant keyboard System Control as /devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.1/0003:046D:C30E.000B/input/input27
# Jun 28 14:24:43 kbh-nuc-venstre kernel: [ 1948.204460] input: Logitech HID compliant keyboard Consumer Control as /devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.1/0003:046D:C30E.000B/input/input26
# Fortunately it seems Consumer Control and System Control aren't Logitech specific, as we've seen the exact same with Lenovo keyboards.
# The second regex matches certain keyboards that do not generate a log line with "input:" and "Keyboard"
# Most regular keyboards also generate a log line that matches the second regex, but
# the duplicate events are removed by the filtering
regexes = [
r".*\[[ ]{0,3}[0-9]{2,}\..*\] input: .*Keyboard "
r"(?!((mouse )?system control))(?!((mouse )?consumer control)).*",
r".*\[[ ]{0,3}[0-9]{2,}\..*\].*input,hidraw.*keyboard (?!mouse)",
]

# Filter log_event_tuples based on regex matches and put them
# on the form the admin site expects:
# (timestamp, security_problem_uid, summary)
log_event_tuples = [
(log_timestamp, security_problem_uid_template_var, log_event)
for (log_timestamp, log_event) in log_event_tuples
if any([re.search(regex, log_event, flags=re.IGNORECASE) for regex in regexes])
]

log_event_tuples = filter_duplicate_events(log_event_tuples)

if not log_event_tuples:
sys.exit()

csv_writer(log_event_tuples)
80 changes: 80 additions & 0 deletions scripts/detect_sudo_event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#!/usr/bin/env python3

"""
Security Script for finding sudo events
"""

import sys
from datetime import datetime, timedelta
import re

__copyright__ = "Copyright 2017-2024 Magenta ApS"
__license__ = "GPL"


def log_read(last_security_check, log_name):
"""Search a (system) log for events that occurred
between "last_security_check" and now."""
log_event_tuples = []
now = datetime.now()

with open(log_name) as f:
for line in f.readlines():
line = str(line.replace("\0", ""))
log_event_timestamp = line[:15]
log_event = line.strip("\n")
# convert from log event timestamp to security event log timestamp.
log_event_datetime = datetime.strptime(
str(now.year) + " " + log_event_timestamp, "%Y %b %d %H:%M:%S"
)
security_event_log_timestamp = datetime.strftime(
log_event_datetime, "%Y%m%d%H%M%S"
)
# Detect lines from within the last x seconds to now.
if last_security_check <= log_event_datetime <= now:
log_event_tuples.append((security_event_log_timestamp, log_event))

return log_event_tuples


def csv_writer(security_events):
"""Write security events to security events file."""
with open("/etc/os2borgerpc/security/securityevent.csv", "at") as csvfile:
for timestamp, security_problem_uid, log_event in security_events:
event_line = log_event.replace("\n", " ").replace("\r", "").replace(",", "")
csvfile.write(f"{timestamp},{security_problem_uid},{event_line}\n")


# The file to inspect for events
log_name = "/var/log/auth.log"

now = datetime.now()
# The default value in case lastcheck.txt is nonexisting or empty:
last_security_check = now - timedelta(hours=24)
try:
with open("/etc/os2borgerpc/security/lastcheck.txt", "r") as fp:
timestamp = fp.read()
if timestamp:
last_security_check = datetime.strptime(timestamp, "%Y%m%d%H%M%S")
except IOError:
pass

log_event_tuples = log_read(last_security_check, log_name)

security_problem_uid_template_var = "%SECURITY_PROBLEM_UID%"
# Ignore if not a sudo event or if a sudo event from root
regexes = [r"sudo:(?!\s*root).*COMMAND"]

# Filter log_event_tuples based on regex matches and put them
# on the form the admin site expects:
# (timestamp, security_problem_uid, summary)
log_event_tuples = [
(log_timestamp, security_problem_uid_template_var, log_event)
for (log_timestamp, log_event) in log_event_tuples
if any([re.search(regex, log_event, flags=re.IGNORECASE) for regex in regexes])
]

if not log_event_tuples:
sys.exit()

csv_writer(log_event_tuples)
Loading

0 comments on commit db31967

Please sign in to comment.