Использование screen для логирования действий (аудита) пользователей в Linux

    Задача:


    Собирать информацию о действиях пользователя (аудита) в консоли Linux, а именно вводимых им командах и выводимой на экран информации.

    Предлагаемое решение:


    screen по умолчанию для всех пользователей в Linux с логированием

    Необходимые условия:


    1. Полное логирование всех пользователей в консоли, включая вывод информации процессами, чтобы можно было оценить почему пользователь принял то или иное решение
    2. Без возможности отключения логирования
    3. Раз уж выбрали screen — максимально используем его возможности (открытие новых окон, отключение по ^a + d, оставляя рабочие процессы запущенными и другие удобства)
    4. Максимальное удобство — не должно быть каких-либо несовместимостей с приложениями
    5. В случае использования пользователями, не знакомыми с screen — сделать работу максимально знакомой и близкой к обычной командной оболочке (shell)



    Возможные варианты:


    1) Предложенный на Хабре вариант. Рабочий, но есть несколько моментов:
    • По-хорошему надо было бы указать shell пользователя в /etc/shells
    • screen как таковой не работает. Иначе говоря дополнительные окна не открываются
    • Логирование отключается банальным ^a + H (заглавная)

    2) Тут тоже предложены варианты, но это больше сырые заготовки

    Итак, приступим:


    Имеется 2 возможных варианта использования screen для нашей задачи:
    • Использование родной командной оболочки (shell), а затем вызывать screen автоматически скриптом
    • Использование screen как командную оболочку пользователя

    Судя по цитатам по ссылке, второй вариант нехорош по
    определённым причинам
    ...this may break programs which run the login shell defined in /etc/passwd for various commands…
    ...It then becomes hard to do anything with your account other than log in. Also, your sysadmin probably doesn't have screen in /etc/shells...


    Создаём скрипт для запуска screen, чтобы при запуске командной оболочки bash (ведь у вас bash, правда?) все пользователи использовали этот файл и загружались в screen по умолчанию с включённым логированием. При выходе из screen – сессия закрывается:
    vi /usr/local/bin/get_in.sh
    #!/bin/sh
    
    SCREEN=/usr/bin/screen
    KILL=/bin/kill
    
    ## Check if we are already in screen ($STY is set)
            if [ -z "$STY" ]; then
                    $SCREEN -LARR -S Shared -c /etc/screenrc
    
    ## Force SHELL close on exit - we don't want to allow users to escape logging outside screen
                    $KILL -SIGHUP $PPID
            fi
    
    

    Что мы имеем:
    -L — направить весь лог в файл (куда именно — см. директиву logfile в файле /etc/screenrc ниже)
    -A — Адаптировать размеры окон к размеру текущего терминала. Взято отсюда.
    -RR — Переподключить сессию и, если необходимо, отсоединить (detach) её или создать заново. Используется первая сессия, если больше чем одна доступна. В случае отключения по ^a + d, при повторном входе откроется эта же сессия этого же пользователя.
    -c — мы чётко указываем, какой конфигурационный файл использовать, чтобы избежать возможности отключения логирования и переназначения опций пользователями, к примеру созданием файла в ~/.screenrc.
    -S — Назначаем сессии понятное имя. У каждого пользователя может быть одно и то же имя.

    Делаем скрипт исполняемым:
    chmod 0755 /usr/local/bin/get_in.sh

    Делаем так, чтобы все использовали этот скрипт. Для этого в конец файла /etc/bash.bashrc добавляем строку:
    /usr/local/bin/get_in.sh

    Корректируем файл /etc/screenrc:

    ## Выбираем, хотим ли мы видеть заметку о правообладателях во время запуска.  По умолчанию включено (on), как вы заметили.
    startup_message off                     # default: on
    
    ## Отключаем визуальный сигнал - включается обычное "пикание" как в shell
    vbell off
    
    ## Размер буфера прокрутки увеличиваем до 4096. Значение по умолчанию - 100.
    defscrollback 4096                      # default: 100
    
    ## Устанавливаем командную оболочку (shell), которая будет использоваться при создании новых окон. Переназначает значение переменной окружения $SHELL. Если команда начинается с символа '-' , то командная оболочка будет запущена как login-shell.
    defshell -/bin/bash
    
    ## Влияет на копирование текста комадной ^a+[ . 
    crlf off                                # default: off
    
    ## Добавляет симпатичную строку состояния внизу экрана.
    caption always "%{= kg} %H | %{kc}%?%-w%?%{kY}%n*%f %t%?(%u)%?%{= kc}%?%+w%? %=|%{kW} %l %{kw}| %{kc}%{-b}%D, %m/%d/%Y | %{kW}%{+b}%c %{wk}"
    
    ## Set terminal cap info
    termcapinfo xterm* 'hs:ts=\E]0;:fs=\007:ds=\E]0;\007'
    
    hardstatus off
    
    ## Отключаем возможность отключения логирования из самой сессии screen (^a + H)
    bind H
    
    ## Устанавливаем расположение и именование лог-файлов
    logfile /var/log/screen/$USER@%H-%Y%m%d-%c:%s.log
    
    ## By default, screen uses an 8-color terminal emulator. Use the following line to enable more colors, which is useful if you are using a more-capable terminal emulator:
    term screen-256color
    
    ## Устанавливает функцию записи отметок времени в лог-файл
    logtstamp on
    
    


    Не забываем создать директорию для логов:
    mkdir /var/log/screen

    chmod 0777 /var/log/screen

    Этим мы добиваемся, что все команды будут логироваться в лог-файлы вида:
    /var/log/screen/user@server-20130716-19:52:34.log


    В Debian, чтобы в screen работало автозавершение команд (bash_completion), необходимо раскомментировать в /etc/bash.bashrc:
    # enable bash completion in interactive shells
    if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
        . /etc/bash_completion
    fi


    Уважаемый 1ex подсказал решение, как с помощью wrapper-а для ssh логировать команды, выполняемые без входа в интерактивный режим bash вида: ssh user@host «ls -l». Для этого необходимо:
    в /etc/ssh/sshd_config указать ссылку на обработку wrapper-ом:
    ForceCommand /etc/ssh/hook.sh
    

    Затем создать сам wrapper /etc/ssh/hook.sh:
    #!/bin/sh
    
    if [ ! -z "${SSH_ORIGINAL_COMMAND}" ]; then
            echo "User "${USER}" remotely runs a command: ${SSH_ORIGINAL_COMMAND}" >> /var/log/screen/$USER@`hostname`-`date +%Y%m%d-%H:%M:%S`-command.log
            bash -c "$SSH_ORIGINAL_COMMAND"
    else
        cat /etc/motd
            ${SHELL}
    fi
    

    Не забыть сделать его исполняемым:
    chmod +x /etc/ssh/hook.sh
    

    Этим мы добиваемся, чтобы все такие команды (и только команды — без информации, что выводится на экране) логировались в ту же директорию и будут дополнены суффиксом "-command":
    /var/log/screen/user@server-20130717-12:47:53-command.log


    Ну вот и всё. Теперь при подключении все пользователи (включая root — будьте осторожны, если потеряете возможность входа!) будут работать в screen, который запускается из bash. При выходе из screen, родительский bash закрывается и соединение прерывается. Если необходимо оставить работать процессы в фоне, то для выхода используем ^a+d. При следующем подключении эта сессия подключится автоматически.

    Для дальнейшего изучения:


    • Так как в логи пишется вывод команд — они могут занимать большое количество места. Необходимо предусмотреть методы сжатия для уменьшения объёма/трафика
    • Лучшее место для логов — удалённая машина и далее обработку производить там, так как логи на локальной машине создаются с uid/guid пользователя и могут быть им удалены/изменены. Предполагается использование syslog.
    • Возможно, есть методы обойти screen и, соответственно, логирования при этой конфигурации. Хотелось бы услышать их и внести изменения


    Используемые источники:




    Update:


    1) По замечанию joneleth пути изменены на жёсткие:
    Абзац:
    SCREEN=`which screen`
    KILL=`which kill`
    
    Заменён на:
    SCREEN=/usr/bin/screen
    KILL=/bin/kill
    


    На данный момент существуют 2 метода обхода логирования команд:


    1) Подсказана kiltum: команды типа ssh user@host «ls -l» не логируются. В этом случае команды выполняются как /bin/bash -c <команда>, при этом нужный /etc/bash.bashrc не читается.
    Уважаемый 1ex подсказал решение с помощью wrapper-а для ssh. Теперь все команды такого типа логируются. Изменения в текст внесены.
    2) Подсказана ForeverYoung: команда screen -X log отключает логирование.
    Возможности отключить эту особенность пока что нету, поэтому необходимо применять административные меры к пользователям, кто запускает эту команду (сама эта команда всё равно будет записана в лог).
    Лучшие решения приветствуются.

    ИТОГИ:


    Как выяснилось screen не совсем предназначен для решения такого рода задач, а именно принудительного логирования команд и их вывода без возможности отключения логирования. Это приводит к тому, что приходится дополнительно править другие файлы.
    Как порекомендовал уважаемый amarao для решения такого рода задач лучше посмотреть на другие решения:
    а) сниффинга всего трафика, проходящего через псевдотерминалы (более серьёзно). kiltumподсказал conspy. Slipeer предложил Snoopy Logger.
    б) систем аудита (SELinux/Apparmor/etc), которые будут записывать реально всё выполняемое.
    Но эти решения выходят за рамки данной статьи.

    Считаю, что несмотря на недостатки, использование screen для логирования действий пользователей и выводимой на экран информации в Linux оправдано, ввиду несложности реализации, а главное — простоты чтения логов (в отличие от auditd, напимер).
    Поделиться публикацией

    Похожие публикации

    Комментарии 58

      +2
      Как это защитит от ssh user@server /bin/bash -l?
        0
        Опередили. Правда, я хотел предложить ssh user@host /bin/sh
          0
          Проверил. Логируется.
            0
            Это потому что

            # ls -l /bin/sh
            lrwxrwxrwx 1 root root 4 Mar 7 08:33 /bin/sh -> bash

            В центоси есть к примеру /bin/dash, ну и всякие tcsh и прочие обычно в комплекте у некоторых
              0
              У меня на тестовой машине Debian Squeeze:

              root@server:~# ls -l /bin/sh
              lrwxrwxrwx 1 root root 4 Jan 10  2013 /bin/sh -> dash
                0
                Вот не поверю, что ssh user@host «ls -l» тоже залогируется :)
                  0
                  Не логируется! Идей пока нет как решить, но чую, что если будут, то это будут большие костыли…
                  Есть идеи?
                    0
                    Как вариант есть возможность в ~/.ssh/authorized_keys сделать:
                    command="/bin/bash". Вижу сразу 2 нюанса:
                    1) Необходимо добавлять этот файл каждому пользователю
                    2) Авторизацию придётся запрещать по логину — только по ключу.
                      0
                      На уровне «положить файлик бла-бла-бла» — нет. Если серьёзно — смотреть в сторону:

                      а) сниффинга всего трафика, проходящего через псевдотерминалы
                      (более серьёзно)
                      б) систем аудита (SELinux/Apparmor/etc), которые будут записывать реально всё выполняемое.

                      Нужно понимать, что все эти screen, bash, history, etc — всего лишь условности интерфейсы, и никто не может принудить (то есть может — но это и есть SEL/AA) к их использованию.

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

                      Вся описанная конструкция всего лишь паллиатив а-ля «запретить программу в window 9x». Решений много и все они обходятся из спортивного интереса.
                        +2
                        Легко логируется враппером для sshd

                        ForceCommand /etc/ssh/rsh-hook.sh

                        а в хуке чтото вроде

                        if [[ ! -z ${SSH_ORIGINAL_COMMAND} ]]; then
                                . /etc/bash.bashrc
                                logger -p local6.debug -t "rem ${USER}" "${USER}: ${SSH_ORIGINAL_COMMAND}"
                                ${SSH_ORIGINAL_COMMAND}
                        else
                            cat /etc/motd
                                ${SHELL}
                        fi
                        


                          0
                          Спасибо за информацию.
                          Скрипт чуть модифицирован (не работали команды типа ssh user@server «ls -al /; sleep 5; echo Works», а также изменён метод записи в лог-файл — теперь это простое echo >>) и внесён в статью.
                            0
                            А может быть у вас и рецепт для логирования scp есть ?)
                0
                Если я правильно понимаю после аутентификации пользователь просто набирает /bin/bash -l. Проверил — логируется и это.
                  0
                  Нет, неправильно понимаете. ssh root@localhost -t /bin/bash -l и посмотрите логи.

                  Алсо, можно вообще /bin/bash -i, и тогда даже хистори не запишется.
                    0
                    И тот, и другой вариант логируется нормально.
                    Полагаю потому что bash при загрузке всё равно читает /etc/bash.bashrc.
                    А вот если эту возможность как-нибудь обойти… Надо подумать.
                      0
                      Ну в лоб — написать малюсенькую библиотеку, которая перехватывает fopen и подсовывает нужные. А потом через LD_PRELOAD ее грузить…

                      Но думаю, это точно выходит за возможности потенциального нарушителя :)
                        –1
                        Полагаю это всё должно делаться из под рута и пока будет делаться, всё это будет логироваться:).
                        0
                        Предполагается, что команду печают не на севрере. Я localhost сказал, чтобы на самой машине проверить можно будет.
                          0
                          Я проверил и удалённо, и локально — логируется. С другой машины ввёл:
                          ssh root@server -t /bin/bash -l
                          root@server's password: 
                          root@server:~# this is a test message
                          bash: this: command not found
                          

                          Выхожу, смотрю логи:
                          root@server:~# cat /var/log/screen/root@server-20130716-\ 9\:32\:04.log 
                          root@server:~# 
                          root@server:~# this is a test message
                          bash: this: command not found
                          root@server:~# ogout
                          

                          0
                          --norc Do not read and execute the system wide initialization file /etc/bash.bashrc and the personal initialization file ~/.bashrc if the shell is interactive. This option is on by default if the shell is invoked as
                          sh.


                          Можно вот с этим ключиком и тогда ничего читать не будет, или можно указать при подключении явно, какой файл читать:
                          ssh root@localhost -t /bin/bash -i --rcfile <rc.file>
                            0
                            При такой команде всё равно попадает в screen и лог работает.
                    0
                    Да, вопрос наверное запоздалый. А почему бы просто не логгировать все происходящее с помощью conspy (http://ace-host.stuart.id.au/russell/files/conspy/) или аналогичного, который тупо грабит pts/*?
                      0
                        0
                          0
                          Насколько мне известно auditd не логирует вывод информации на экран.
                            0
                            Не логирует. Но зато это штатный функционал ядра и можно настроить аудит только нужного, важных типов событий.
                            Везде нужен баланс, в этой задаче — тоже. Иначе можно запросто задосить лог-сервер просто сделав cat /dev/urandom и уйдя спать.
                    • НЛО прилетело и опубликовало эту надпись здесь
                        0
                        Согласен. Пожалуй security ради надо жёстко указать путь.
                        • НЛО прилетело и опубликовало эту надпись здесь
                            0
                            А где ещё быть утилитам screen и kill и, главное, зачем?
                            Для меня это имеет смысл, когда приходится одни и те же скрипты запускать на Linux и OpenWRT. У них пути разные и which очень помогает.
                            P.S. Кстати изменения в текст статьи внёс — путь указал точно.
                              +1
                              which kill и просто kill ничем отличаться не будет, т.к. PATH одинаковый.
                                0
                                Не будет, просто исключатся возможные махинации с PATH и, соответственно, запуск собственного screen-а или kill-а.
                        0
                        На логи можно попробовать натравить logrotate.
                          0
                          На удалённом сервере. Всё верно.
                          +1
                          curl something | sh
                          

                          Олсоу, логгирует ли оно всё происходящее в консольных редакторах вроде nano?
                            0
                            А еще можно так:
                            read -s a; eval $a
                            

                            Вобщем, совершенно негодный способ
                              0
                              Логирует всё, что выводит текст. Есть даже побочные эффекты этого — если запустить top и забыть выключить, то будет очень много логов.
                              0
                              screen -X log — отключает логгирование, и биндинг не нужен…
                                0
                                Спасибо за информацию. Отключает логирование! Думаю как заблокировать эту команду.
                                  0
                                  Решение не найдено, кроме применения административных мер к пользователю («С какой целью запускал отключение логов?»).
                                    0
                                    Кастомная сборка screen…
                                0
                                ## Force SHELL close on exit - we don't want to allow users to escape logging outside screen
                                $KILL -SIGHUP $PPID
                                

                                Здесь бы и просто 'exit' хватило.
                                  0
                                  Нет, не хватает. Тогда при выходе из screen (^d или просто exit) попадаем в bash без логирования. Поэтому и надо убить родительский процесс.
                                    0
                                    read answer
                                    if [ "$answer" != "n" ]; then
                                        screen -D -RR screen_name
                                        exit
                                    fi
                                    

                                    (это на сервера прописываю, при заходе если не ответить «n», открывает прошлую сессию)

                                    Работает как надо. Вопрос на linuxquestions
                                      0
                                      Спасибо за информацию. Считаю это не совсем нужным действием — отвечать нужно ли подключать, ведь для того, чтобы отключиться от screen и оставить работать процессы в фоне — надо проделать «телодвижения», соответственно зачем их проделывать, если потом отвечать «не подключать screen». А если просто выйти (^d или exit), то и screen убивается.
                                        0
                                        Про ответ — это у меня так, не помню уже зачем, скорее всего когда-то была трудность с неправильной настройкой screen, из-за чего не мог подключиться.
                                  0
                                  скроллинг назад в скрине не совпадает с «обычным» поведением.
                                  Так же не совсем понятна изначальная постановка задачи. Иными словами — логгировать — ладно. Но зачем?
                                  Если просто ради тайп-каста, то по-моему script более для этого приспособлен чем screen.
                                  А если что-то типа шпиона — то наверное лучше вообще подключиться где-нибудь на уровне системы и наблюдать, что происходит во всевозможных ttyX.
                                    0
                                    Скроллинг назад под screen у меня абсолютно нормальный (Shift+PgUp), не считая возврата к предыдущему состоянию, когда минуты в caption внизу страницы меняют своё значение. А вот обычный скроллинг страниц, к примеру man bash — притормаживает. Другие претензии к screen в плане удобства, которые у меня были вначале — отсутствие «пикания» и автозавершения команд — исправлены и рецепт приведёт в статье.
                                    Я старался не проводить в статье обзор методов аудита в Linux. Это статья для тех, кто как я, решит остановиться на этом методе из обзорной статьи про script, screen, sudo, auditd.
                                    Вариант с подключением на уровне системы к ttyX думаю лучше, но я с ним не знаком и их не было в статье, на основании которой был выбран метод (см.выше).
                                    0
                                    del
                                      0
                                      Ну так закачиваем скрипт на сервер через sftp и выполняем там.
                                        0
                                        Думаю для таких вариантов нужно более серьёзные решения (auditd, к примеру), но там непросто читать лог-информацию.
                                        К примеру на команду
                                        “hostname audit-test.home.private”

                                        В логе окажется:
                                        type=SYSCALL msg=audit(1358306046.744:260): arch=c000003e syscall=170 success=yes exit=0 a0=2025010 a1=17 a2=7 a3=18 items=0 ppid=23922 pid=26742 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts4 ses=16 comm="hostname" exe="/usr/bin/hostname" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key="system-locale"
                                          0
                                          aureport, ausearch
                                        0
                                        А что должен выводить кусок "%{kc}%{-b}%D" в caption always?
                                        У меня на этом месте выводится какой-то юникодный мусор.
                                          0
                                          У меня строка выглядит вот так (ну и разноцветно):
                                          hostname | открытые окна        | load average   | date            | time
                                          server   | 0*$(L) bash  1 bash  | 0.00 0.00 0.00 | Wed, 07/17/2013 | 13:14
                                          

                                            0
                                            Ага. Значит день недели у меня пытается вывестись по-русски, и не может.
                                          0
                                          А вот, кстати, интересный способ вести лог команд в баше: askubuntu.com/questions/93566/how-to-log-all-bash-commands-by-all-users-on-a-server
                                            0
                                            А кто-нибудь может прокомментировать этот способ? Он работает, но при переходе в другой шелл перестаёт. Если все остальные шеллы сделать симлинками на bash, то будет ли такой вариант надёжным?

                                            Мне этот способ гораздо интересней чем screen, ибо в последнем довольно кривая консоль.
                                            0
                                            Возможно, есть методы обойти screen и, соответственно, логирования при этой конфигурации. Хотелось бы услышать их и внести изменения

                                            Ещё один метод обхода, не оставляющий следов:


                                            Ctrl-A : log


                                            Блокировка:


                                            .screenrc


                                            bind :


                                            Пользователь теряет возможность выполнять команды screen и перенастраивать его.

                                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                            Самое читаемое