Статья «Горшочек меда» для коллеги. Создаем «ловушку» на Python

Не знаю, как вы, но мне иногда на работе хотелось узнать, копается ли кто-нибудь в моем рабочем компьютере, когда меня нет на рабочем месте. И не там, где лежат общедоступные или рабочие файлы, а проверяет комп на наличие в нем личных фото или документов, которые не особо предназначены для чужих глаз.

Впрочем, это праздное любопытство просто хотя бы потому, что я не хранил на рабочем компьютере личных файлов. Но все равно, не особо приятно знать, что за тобой кто-то пытается следить, не так ли. И уже по прошествии времени я решил, что было бы полезно попрактиковаться и реализовать то, что хотел когда-то, а именно, сделать своими руками скрипт, который будет отслеживать изменения в файловой системе и сообщать мне об этом в чат-бота.

000.jpg

Те инструменты, что мы будем использовать для создания "ловушки для коллеги", изначально для этого не предназначались. Они созданы как раз таки для отслеживания изменений файловой системы и запуска тех или иных событий в зависимости от события. Например, у вас есть программа, которая создает важные файлы, которые могут быть перезаписаны. А потому, желательно отследить их создание и сразу же сделать бэкап. Но, мы воспользуемся данными инструментами в «корыстных» целях удовлетворения собственного любопытства и создадим бота, который будет все это дело проворачивать.


Что потребуется?

Для начала нужно установить библиотеку pyTelegramBotAPI, именно она будет служить связующим скелетом для нашего скрипта и отвечать за доставку сообщений в чат. Устанавливается она с помощью команды в терминале:

pip install pyTelegramBotAPI

Затем, если вы используете скрипт в ОС Windows, вам нужно установить библиотеку watchdog с помощью команды:

pip install watchdog

Ну, а если ваша ОС Linux, то устанавливаем библиотеку pyinotify, выполнив в терминале команду:

pip install pyinotify

Затем в блоке импорта импортируем часть библиотек. Библиотеки, которые нужны для Windows и Linux, в частности, мы будем импортировать непосредственно в функциях, которые запускаются на конкретной операционной системе.

Python:
from platform import system
import time

import telebot
from config import token, user_id

Как видите, в блоке импорта присутствует еще и модуль config. В нем я сохранил токен бота и user_id для последующего использования в боте при отправке сообщений. Вам также нужно будет создать бота, получить его токен и узнать ваш user_id. При желании вы можете использовать данные значения в скрипте в открытом виде, но я предпочел создать файл, в котором они будут благополучно храниться.

Давайте приступим к созданию скрипта. А начнем мы с создания бота, которому передадим полученный токен.

bot = telebot.TeleBot(token)

Затем создадим функцию, которая и будет отвечать за отправку сообщений в чат command(message). На входе данная функция будет получать сообщение в текстовом виде. За то, какой тип сообщений пересылает в данном случае бот отвечает его message_handler, в котором и указан тип пересылаемого сообщения:

Python:
@bot.message_handler(content_types=['text'])
def command(message):
    bot.send_message(user_id, message)

Теперь создадим функцию получения событий файловой системы в отслеживаемой директории для Windows. Я назвал ее dog_file_win(). На вход она ничего не получает, а просто выполняет свои непосредственные функции. Импортируем Observer из библиотеки watchdog, а также обработчик событий файловой системы, а точнее заголовки.

Python:
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

Создадим класс, в котором и опишем события, а также действия, которые будут выполнятся при наступлении данных событий. В принципе, все достаточно понятно.

Python:
class Handler(FileSystemEventHandler):
        def on_created(self, event):
            if event.is_directory:
                command(f'Создана папка: {event.src_path}')
            else:
                command(f'Создан файл: {event.src_path}')

        def on_deleted(self, event):
            if event.is_directory:
                command(f'Удалена папка: {event.src_path}')
            else:
                command(f'Удален файл: {event.src_path}')

        def on_moved(self, event):
            if event.is_directory:
                command(f'Переименована папка: {event.src_path}')
            else:
                command(f'Переименован файл: {event.src_path}')

        def on_modified(self, event):
            if event.is_directory:
                command(f'Изменена папка: {event.src_path}')
            else:
                command(f'Изменен файл: {event.src_path}')

Здесь возможно определить, была создана директория или файл. И в соответствии с этим отправлять нужное сообщение. Когда файл или папка перемещаются, срабатывает событие on_deleted, а когда файл или папка будут переименованы, сработает сразу несколько событий: on_moved и on_modifid. Ну, а все остальное срабатывает по классике. При создании on_created, при удалении on_deleted. Ну и в соответствии с наступающим событием отправляем сообщение с полным путем к модифицируемому файлу.

Тут все хорошо, но вот только нет события на открытие файла. И если никто, и ничего не будет создавать, удалять или перемещать, то и событий происходить не будет. Тут можно слегка схитрить, чтобы не создавать свой обработчик событий. Поместить в контролируемую директорию файлы Word или Excel. При открытии в папке создается временный файл. А соответственно, вы получите об этом сообщение. Что и будет сигнализировать о том, что ваши файлы открывали.

Теперь создаем объект Observer, помещаем в обработчик событий созданный класс, путь к контролируемой директории и указание на то, что все папки будут контролировать рекурсивно. То есть, если у вас есть папка с файлами, то события в ней так же будут подлежать контролю.

Python:
    observer = Observer()
    observer.schedule(Handler(), path=r'D:\Temp', recursive=True)
    observer.start()

    bot.polling()
    try:
        while True:
            time.sleep(0.1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()

Дальше запускаем Observer, стартуем бота и для того, чтобы процесс не останавливался при наступлении события, а продолжал отслеживать директорию дальше, создадим бесконечный цикл, из которого можно будет выйти с помощью комбинации Ctlr+C.

На этом функция для Windows завершена. Можно сказать, что ловушка для одной оси уже сделана. Даже запустить и попробовать, как это работает, если у вас Windows, конечно.

Python:
def dog_file_win():
    from watchdog.observers import Observer
    from watchdog.events import FileSystemEventHandler

    class Handler(FileSystemEventHandler):
        def on_created(self, event):
            if event.is_directory:
                command(f'Создана папка: {event.src_path}')
            else:
                command(f'Создан файл: {event.src_path}')

        def on_deleted(self, event):
            if event.is_directory:
                command(f'Удалена папка: {event.src_path}')
            else:
                command(f'Удален файл: {event.src_path}')

        def on_moved(self, event):
            if event.is_directory:
                command(f'Переименована папка: {event.src_path}')
            else:
                command(f'Переименован файл: {event.src_path}')

        def on_modified(self, event):
            if event.is_directory:
                command(f'Изменена папка: {event.src_path}')
            else:
                command(f'Изменен файл: {event.src_path}')

    observer = Observer()
    observer.schedule(Handler(), path= r'D:\Temp', recursive=True)
    observer.start()

    bot.polling()
    try:
        while True:
            time.sleep(0.1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()

Теперь давайте провернем то же самое, но только для Linux. Здесь уже будем использовать другую библиотеку, у которой гораздо больше возможностей, чем у ее виндового аналога. Тут можно отслеживать открытие файлов, удаление, модификацию… да много еще чего. Обработчик реагирует почти на каждый чих в контролируемой директории.

Создадим функцию dog_file_lin(). На входе, как и ее виндовая коллега она не принимает ничего. Импортируем необходимую библиотеку:

import pyinotify

А дальше создаем переменную, в которой описываем мониторинг сразу же нескольких событий. И создаем объект WatchManager.

Python:
multi_event = pyinotify.IN_OPEN | pyinotify.IN_CREATE | pyinotify.IN_MOVED_FROM
wm = pyinotify.WatchManager()

Как видите, здесь я указал, что будут обрабатываться события на открытие, на создание и на перемещение файла. Так как прямого обработчика событий на удаление тут нет, перемещение файла будет в данном случае восприниматься как удаление. То есть, по большему счету мы и делаем перемещение в корзину. Создадим класс обработки событий. В нем создадим функции с обработкой тех событий, которые были перечислены в переменной. Здесь event – это объект события, а event.pathname указывает путь к файлу, который вызывал событие.

Python:
    class MyEventHandler(pyinotify.ProcessEvent): 
        def process_IN_OPEN(self, event):
            command(f'OPEN: {event.pathname}')
        def process_IN_MOVED_FROM(self, event): 
            command(f'MOVED_FROM: {event.pathname}')
        def process_IN_CREATE(self, event): 
            command(f'CREATE: {event.pathname}')

И в обработчике будем отправлять сообщения в чат бота, с указанием события и полным путем к файлу.

Теперь создадим экземпляр класса обработки событий. Создадим переменную, в которой будем выполнять обработку события, согласно переменным, переданным в него. Ну а дальше добавляем каталог для отслеживания и событие, которое у нас представлено, в данном случае, тремя событиями. И запускаем Notifier.

Python:
handler = MyEventHandler()
notifier = pyinotify.Notifier(wm, handler) 
wm.add_watch(' /home/kali/tmp', multi_event)
notifier.loop()

На этом создание функции можно считать законченным.

Python:
def dog_file_lin():
    import pyinotify

    multi_event = pyinotify.IN_OPEN | pyinotify.IN_CREATE | pyinotify.IN_MOVED_FROM  # Мониторинг нескольких событий
    wm = pyinotify.WatchManager()

    class MyEventHandler(pyinotify.ProcessEvent):

        def process_IN_OPEN(self, event):
            command(f'OPEN: {event.pathname}')

        def process_IN_MOVED_FROM(self, event):
            command(f'MOVED_FROM: {event.pathname}')

        def process_IN_CREATE(self, event):
            command(f'CREATE: {event.pathname}')

    handler = MyEventHandler()
    notifier = pyinotify.Notifier(wm, handler)

    wm.add_watch('/home/kali/tmp', multi_event)  # Добавить отслеживаемый каталог и событие
    notifier.loop()

И последняя функция main(), в которой определяем версию операционной системы и в соответствии с этим вызываем нужную функцию.

Python:
def main():
    if system() == "Windows":
        dog_file_win()
    elif system() == "Linux":
        dog_file_lin()

Ниже, на скриншоте представлен результат обработки событий в контролируемых папках на Windows и Linux. Сразу видно, что Linux больше "нервничает". А значит и безопасность у него будет повыше )))

screenshot1.png

Ну и на этом все. Таким нехитрым кодом можно проверить, проверяют ли ваши коллеги файлы на вашем компьютере. Ну, или домашние… тут уж смотря, где и для чего применять…

Python:
# pip install pyTelegramBotAPI
# для Windows
# pip install watchdog
# для Linux
# pip install pyinotify

from platform import system
import time

import telebot
from config import token, user_id

bot = telebot.TeleBot(token)


# функция для отправки сообщений
# указываем тип сообщений
# отправляем сообщение
@bot.message_handler(content_types=['text'])
def command(message):
    bot.send_message(user_id, message)


# функция отслеживания событий файловой системы Linux
def dog_file_lin():
    import pyinotify

    multi_event = pyinotify.IN_OPEN | pyinotify.IN_CREATE | pyinotify.IN_MOVED_FROM  # Мониторинг нескольких событий
    wm = pyinotify.WatchManager()

    class MyEventHandler(pyinotify.ProcessEvent):

        def process_IN_OPEN(self, event):
            command(f'OPEN: {event.pathname}')

        def process_IN_MOVED_FROM(self, event):
            command(f'MOVED_FROM: {event.pathname}')

        def process_IN_CREATE(self, event):
            command(f'CREATE: {event.pathname}')

    handler = MyEventHandler()
    notifier = pyinotify.Notifier(wm, handler)

    wm.add_watch('/home/kali/tmp', multi_event)  # Добавить отслеживаемый каталог и событие
    notifier.loop()


# функция отслеживания событий файловой системы Windows
def dog_file_win():
    from watchdog.observers import Observer
    from watchdog.events import FileSystemEventHandler

    class Handler(FileSystemEventHandler):
        def on_created(self, event):
            if event.is_directory:
                command(f'Создана папка: {event.src_path}')
            else:
                command(f'Создан файл: {event.src_path}')

        def on_deleted(self, event):
            if event.is_directory:
                command(f'Удалена папка: {event.src_path}')
            else:
                command(f'Удален файл: {event.src_path}')

        def on_moved(self, event):
            if event.is_directory:
                command(f'Переименована папка: {event.src_path}')
            else:
                command(f'Переименован файл: {event.src_path}')

        def on_modified(self, event):
            if event.is_directory:
                command(f'Изменена папка: {event.src_path}')
            else:
                command(f'Изменен файл: {event.src_path}')

    observer = Observer()
    observer.schedule(Handler(), path=r'D:\Temp', recursive=True)
    observer.start()

    bot.polling()
    try:
        while True:
            time.sleep(0.1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()


# определение версии ОС
def main():
    if system() == "Windows":
        dog_file_win()
    elif system() == "Linux":
        dog_file_lin()


if __name__ == '__main__':
    main()

Спасибо за внимание. Надеюсь, что данная информация будет кому-нибудь полезна
 

Dart Moore

Green Team
16.04.2022
12
2
Мне вот интересно будет ли она верно отрабатывать на доменных ПК, в том плане что в домене можно зайти на чужой комп через c$ с правами администратора, можно ли при такой структуре отследить копирование файлов?
 

Johan Van

Green Team
13.06.2020
153
280
Мне вот интересно будет ли она верно отрабатывать на доменных ПК, в том плане что в домене можно зайти на чужой комп через c$ с правами администратора, можно ли при такой структуре отследить копирование файлов?

Теоретически должна. Ведь событие файловой системы происходит независимо от того, откуда заходит пользователь. Конечно, надо было бы потестировать. Но, для этого мне придется сколхозить небольшой домен. А у меня места на диске пока не хватает для сервака ))
 

Dart Moore

Green Team
16.04.2022
12
2
Теоретически должна. Ведь событие файловой системы происходит независимо от того, откуда заходит пользователь. Конечно, надо было бы потестировать. Но, для этого мне придется сколхозить небольшой домен. А у меня места на диске пока не хватает для сервака ))

Ну в том плане что при копировании файла, создаётся временный файл в папке темп,но на какой тачке вряд-ли на то с которой копируешь, завтра протестирую на домменом ПК
 
  • Нравится
Реакции: Johan Van

Johan Van

Green Team
13.06.2020
153
280
Ну в том плане что при копировании файла, создаётся временный файл в папке темп,но на какой тачке вряд-ли на то с которой копируешь, завтра протестирую на домменом ПК

Ну да, скорее всего на той машине, на которую копируешь. Да, потестировать было бы хорошо
 

Dart Moore

Green Team
16.04.2022
12
2
В доменное сети можно поставить будет работать но нужна скорее фильтрация, так как при запуске бота валятся сообщения в которых отображены работы разных систем таких как sccm, force point и т.п
 
  • Нравится
Реакции: Johan Van

Johan Van

Green Team
13.06.2020
153
280
В доменное сети можно поставить будет работать но нужна скорее фильтрация, так как при запуске бота валятся сообщения в которых отображены работы разных систем таких как sccm, force point и т.п

Это же здорово! А фильтрация да, бота иначе разорвет от сообщений )) Спасибо за тесты!
 

Dart Moore

Green Team
16.04.2022
12
2
Это же здорово! А фильтрация да, бота иначе разорвет от сообщений )) Спасибо за тесты!
уже разрывает, плюс если открывать через сетевую папку ПК ± создаётся папка с имени учётной записи администратора иногда создаётся иногда нет скорее всего зависит от событий, в целом если отследить все повидения и настроить фильтрацию можно отслеживать, но вот только было бы круто каким то образом зацепиться к учетным данные которые производят манипуляции в системы, вот хз откуда их выдергивать, можно по идеи из журнала, но есть ли там такая инфа

А ещё вопрос
Если прописываю что то типо
If message.text=="Q":
exit(0)
Else:
Bot.message.send.........
Выдает ошибку
По идеи можно добавить завершения запущенного скрипта
 

Johan Van

Green Team
13.06.2020
153
280
А ещё вопрос
Если прописываю что то типо
If message.text=="Q":
exit(0)
Else:
Bot.message.send.........
Выдает ошибку
По идеи можно добавить завершения запущенного скрипта

У вас и будет вылетать ошибка. Так как вы пытаетесь выйти полностью из скрипта. А значит бот будет вылетать. Попробуйте просто завершать функцию передачей пустого return
 

Johan Van

Green Team
13.06.2020
153
280
уже разрывает, плюс если открывать через сетевую папку ПК ± создаётся папка с имени учётной записи администратора иногда создаётся иногда нет скорее всего зависит от событий, в целом если отследить все повидения и настроить фильтрацию можно отслеживать, но вот только было бы круто каким то образом зацепиться к учетным данные которые производят манипуляции в системы, вот хз откуда их выдергивать, можно по идеи из журнала, но есть ли там такая инфа

Честно говоря, не знаю. В теории, в журнале данная инфа должна быть.
 

Dart Moore

Green Team
16.04.2022
12
2
У вас и будет вылетать ошибка. Так как вы пытаетесь выйти полностью из скрипта. А значит бот будет вылетать. Попробуйте просто завершать функцию передачей пустого return
в этом и прикол что он не вылетает, а продолжает работу скорее всего там try в декораторе
 

Johan Van

Green Team
13.06.2020
153
280
в этом и прикол что он не вылетает, а продолжает работу скорее всего там try в декораторе

А что за ошибка вылетает? Может быть потому, что у message нет свойства text? Ведь по идее, то что отправляется ботом уже является текстом
 
Мы в соцсетях: