Skip to content

Latest commit

 

History

History
1017 lines (887 loc) · 38.8 KB

lab7.md

File metadata and controls

1017 lines (887 loc) · 38.8 KB

7. Lab: Logging under the Linux operating system

Instructions

  1. Find the files that log events under the Linux operating system.
  2. Send logs in real time over the network between two virtual computers.
  3. Implement a program that reads keystrokes and sends them to the system log.

More information

Detailed instructions

1. Logging under the Linux operating system

Logging of events locally and over the network takes place via the syslog protocol. The syslog protocol and network message format are specified in RFC5424.

The message for an individual event contains:

  1. priority,
  2. location,
  3. perpetrator of the event,
  4. time,
  5. description.

The PRI value describes the level or event severity with values between 0 and 23, where 0 describes the highest level or highest severity. Several programs implement RFC5424, as it does not define how we store data locally:

Since the programs implement the same standard, they can exchange messages in syslog format with each other (rsyslogd --(syslog_message)--> syslog-ng).

The program init is the first program launched by the Linux operating system and takes care of user processes and terminates when the operating system is shut down. One of the most popular init programs is systemd, which also has its own way of logging events with journalctl. Logging with journalctl takes up less space compared to syslog as it saves in binary rather than text format. It starts logging events earlier during the boot process of the operating system, so it can catch more events. Also, it can convert its logs into the correct format and then send them over the network using the syslog protocol.

Some programs do not use syslog logs, but have their own log format and location, for example apache2.

Notepad Locations:

  • /var/log/ - system logs, for example /var/log/syslog.
  • /var/lib/ - temporary files that persist across reboots, for example /var/lib/dpkg.
  • /var/spool/ - temporary files currently in use, for example /var/spool/cups.
  • .bash_history - command history in the terminal.
  • .cache - temporary files.

Now we clone our Linux virtual computer, set the network on both to Bridged Adapter or NAT network so that they are on the same network, and run them. The original virtual computer will serve us as a server, while the clone will be a client.

With the command apt we check whether we have any implementation of the syslog protocol installed, if we do not install it with the package manager of our operating system. Now we print the system logs with the commands cat, less, tail and the like.

apt install rsyslog

apt list --installed | grep syslog

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

rsyslog/stable,stable-security,now 8.2102.0-2+deb11u1 amd64 [installed]

cat /var/log/syslog

less /var/log/syslog

tail -f /var/log/syslog

The systemd system logs are printed out with the journalctl command.

journalctl

Now install the apache2 program and check its operation with the command service.

apt update
apt install apache2

service apache2 status

● apache2.service - The Apache HTTP Server
    Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor prese>
    Active: active (running) since Tue 2023-04-04 14:13:52 CEST; 17s ago
    Docs: https://httpd.apache.org/docs/2.4/
Main PID: 3881 (apache2)
    Tasks: 55 (limit: 4657)
    Memory: 21.3M
        CPU: 21ms
    CGroup: /system.slice/apache2.service
            ├─3881 /usr/sbin/apache2 -k start
            ├─3883 /usr/sbin/apache2 -k start
            └─3884 /usr/sbin/apache2 -k start

Apr 04 14:13:52 debian systemd[1]: Starting The Apache HTTP Server...
Apr 04 14:13:52 debian apachectl[3880]: AH00558: apache2: Could not reliably de>
Apr 04 14:13:52 debian systemd[1]: Started The Apache HTTP Server.

With the command dpkg-query we find all the files that were installed when the apache2 package was installed.

dpkg-query -L apache2

/.
/etc
/etc/apache2
/etc/apache2/apache2.conf
/etc/apache2/conf-available
/etc/apache2/conf-available/charset.conf
/etc/apache2/conf-available/localized-error-pages.conf
/etc/apache2/conf-available/other-vhosts-access-log.conf
/etc/apache2/conf-available/security.conf
/etc/apache2/conf-available/serve-cgi-bin.conf
/etc/apache2/conf-enabled
/etc/apache2/envvars
/etc/apache2/magic
/etc/apache2/mods-available
/etc/apache2/mods-available/access_compat.load
/etc/apache2/mods-available/actions.conf
/etc/apache2/mods-available/actions.load
/etc/apache2/mods-available/alias.conf
/etc/apache2/mods-available/alias.load
/etc/apache2/mods-available/allowmethods.load
/etc/apache2/mods-available/asis.load
/etc/apache2/mods-available/auth_basic.load
/etc/apache2/mods-available/auth_digest.load
/etc/apache2/mods-available/auth_form.load
/etc/apache2/mods-available/authn_anon.load
/etc/apache2/mods-available/authn_core.load
/etc/apache2/mods-available/authn_dbd.load
/etc/apache2/mods-available/authn_dbm.load
/etc/apache2/mods-available/authn_file.load
/etc/apache2/mods-available/authn_socache.load
/etc/apache2/mods-available/authnz_fcgi.load
/etc/apache2/mods-available/authnz_ldap.load
/etc/apache2/mods-available/authz_core.load
/etc/apache2/mods-available/authz_dbd.load
/etc/apache2/mods-available/authz_dbm.load
/etc/apache2/mods-available/authz_groupfile.load
/etc/apache2/mods-available/authz_host.load
/etc/apache2/mods-available/authz_owner.load
/etc/apache2/mods-available/authz_user.load
/etc/apache2/mods-available/autoindex.conf
/etc/apache2/mods-available/autoindex.load
/etc/apache2/mods-available/brotli.load
/etc/apache2/mods-available/buffer.load
/etc/apache2/mods-available/cache.load
/etc/apache2/mods-available/cache_disk.conf
/etc/apache2/mods-available/cache_disk.load
/etc/apache2/mods-available/cache_socache.load
/etc/apache2/mods-available/cern_meta.load
/etc/apache2/mods-available/cgi.load
/etc/apache2/mods-available/cgid.conf
/etc/apache2/mods-available/cgid.load
/etc/apache2/mods-available/charset_lite.load
/etc/apache2/mods-available/data.load
/etc/apache2/mods-available/dav.load
/etc/apache2/mods-available/dav_fs.conf
/etc/apache2/mods-available/dav_fs.load
/etc/apache2/mods-available/dav_lock.load
/etc/apache2/mods-available/dbd.load
/etc/apache2/mods-available/deflate.conf
/etc/apache2/mods-available/deflate.load
/etc/apache2/mods-available/dialup.load
/etc/apache2/mods-available/dir.conf
/etc/apache2/mods-available/dir.load
/etc/apache2/mods-available/dump_io.load
/etc/apache2/mods-available/echo.load
/etc/apache2/mods-available/env.load
/etc/apache2/mods-available/expires.load
/etc/apache2/mods-available/ext_filter.load
/etc/apache2/mods-available/file_cache.load
/etc/apache2/mods-available/filter.load
/etc/apache2/mods-available/headers.load
/etc/apache2/mods-available/heartbeat.load
/etc/apache2/mods-available/heartmonitor.load
/etc/apache2/mods-available/http2.conf
/etc/apache2/mods-available/http2.load
/etc/apache2/mods-available/ident.load
/etc/apache2/mods-available/imagemap.load
/etc/apache2/mods-available/include.load
/etc/apache2/mods-available/info.conf
/etc/apache2/mods-available/info.load
/etc/apache2/mods-available/lbmethod_bybusyness.load
/etc/apache2/mods-available/lbmethod_byrequests.load
/etc/apache2/mods-available/lbmethod_bytraffic.load
/etc/apache2/mods-available/lbmethod_heartbeat.load
/etc/apache2/mods-available/ldap.conf
/etc/apache2/mods-available/ldap.load
/etc/apache2/mods-available/log_debug.load
/etc/apache2/mods-available/log_forensic.load
/etc/apache2/mods-available/lua.load
/etc/apache2/mods-available/macro.load
/etc/apache2/mods-available/md.load
/etc/apache2/mods-available/mime.conf
/etc/apache2/mods-available/mime.load
/etc/apache2/mods-available/mime_magic.conf
/etc/apache2/mods-available/mime_magic.load
/etc/apache2/mods-available/mpm_event.conf
/etc/apache2/mods-available/mpm_event.load
/etc/apache2/mods-available/mpm_prefork.conf
/etc/apache2/mods-available/mpm_prefork.load
/etc/apache2/mods-available/mpm_worker.conf
/etc/apache2/mods-available/mpm_worker.load
/etc/apache2/mods-available/negotiation.conf
/etc/apache2/mods-available/negotiation.load
/etc/apache2/mods-available/proxy.conf
/etc/apache2/mods-available/proxy.load
/etc/apache2/mods-available/proxy_ajp.load
/etc/apache2/mods-available/proxy_balancer.conf
/etc/apache2/mods-available/proxy_balancer.load
/etc/apache2/mods-available/proxy_connect.load
/etc/apache2/mods-available/proxy_express.load
/etc/apache2/mods-available/proxy_fcgi.load
/etc/apache2/mods-available/proxy_fdpass.load
/etc/apache2/mods-available/proxy_ftp.conf
/etc/apache2/mods-available/proxy_ftp.load
/etc/apache2/mods-available/proxy_hcheck.load
/etc/apache2/mods-available/proxy_html.conf
/etc/apache2/mods-available/proxy_html.load
/etc/apache2/mods-available/proxy_http.load
/etc/apache2/mods-available/proxy_http2.load
/etc/apache2/mods-available/proxy_scgi.load
/etc/apache2/mods-available/proxy_uwsgi.load
/etc/apache2/mods-available/proxy_wstunnel.load
/etc/apache2/mods-available/ratelimit.load
/etc/apache2/mods-available/reflector.load
/etc/apache2/mods-available/remoteip.load
/etc/apache2/mods-available/reqtimeout.conf
/etc/apache2/mods-available/reqtimeout.load
/etc/apache2/mods-available/request.load
/etc/apache2/mods-available/rewrite.load
/etc/apache2/mods-available/sed.load
/etc/apache2/mods-available/session.load
/etc/apache2/mods-available/session_cookie.load
/etc/apache2/mods-available/session_crypto.load
/etc/apache2/mods-available/session_dbd.load
/etc/apache2/mods-available/setenvif.conf
/etc/apache2/mods-available/setenvif.load
/etc/apache2/mods-available/slotmem_plain.load
/etc/apache2/mods-available/slotmem_shm.load
/etc/apache2/mods-available/socache_dbm.load
/etc/apache2/mods-available/socache_memcache.load
/etc/apache2/mods-available/socache_redis.load
/etc/apache2/mods-available/socache_shmcb.load
/etc/apache2/mods-available/speling.load
/etc/apache2/mods-available/ssl.conf
/etc/apache2/mods-available/ssl.load
/etc/apache2/mods-available/status.conf
/etc/apache2/mods-available/status.load
/etc/apache2/mods-available/substitute.load
/etc/apache2/mods-available/suexec.load
/etc/apache2/mods-available/unique_id.load
/etc/apache2/mods-available/userdir.conf
/etc/apache2/mods-available/userdir.load
/etc/apache2/mods-available/usertrack.load
/etc/apache2/mods-available/vhost_alias.load
/etc/apache2/mods-available/xml2enc.load
/etc/apache2/mods-enabled
/etc/apache2/ports.conf
/etc/apache2/sites-available
/etc/apache2/sites-available/000-default.conf
/etc/apache2/sites-available/default-ssl.conf
/etc/apache2/sites-enabled
/etc/cron.daily
/etc/cron.daily/apache2
/etc/default
/etc/default/apache-htcacheclean
/etc/init.d
/etc/init.d/apache-htcacheclean
/etc/init.d/apache2
/etc/logrotate.d
/etc/logrotate.d/apache2
/lib
/lib/systemd
/lib/systemd/system
/lib/systemd/system/apache-htcacheclean.service
/lib/systemd/system/apache-htcacheclean@.service
/lib/systemd/system/apache2.service
/lib/systemd/system/apache2@.service
/usr
/usr/lib
/usr/lib/cgi-bin
/usr/sbin
/usr/sbin/a2enmod
/usr/sbin/a2query
/usr/sbin/apache2ctl
/usr/share
/usr/share/apache2
/usr/share/apache2/apache2-maintscript-helper
/usr/share/apache2/ask-for-passphrase
/usr/share/bash-completion
/usr/share/bash-completion/completions
/usr/share/bash-completion/completions/a2enmod
/usr/share/bug
/usr/share/bug/apache2
/usr/share/doc
/usr/share/doc/apache2
/usr/share/doc/apache2/NEWS.Debian.gz
/usr/share/doc/apache2/PACKAGING.gz
/usr/share/doc/apache2/README.Debian.gz
/usr/share/doc/apache2/README.backtrace
/usr/share/doc/apache2/README.multiple-instances
/usr/share/doc/apache2/changelog.Debian.gz
/usr/share/doc/apache2/changelog.gz
/usr/share/doc/apache2/copyright
/usr/share/doc/apache2/examples
/usr/share/doc/apache2/examples/apache2.monit
/usr/share/doc/apache2/examples/secondary-init-script
/usr/share/doc/apache2/examples/setup-instance
/usr/share/lintian
/usr/share/lintian/overrides
/usr/share/lintian/overrides/apache2
/usr/share/man
/usr/share/man/man1
/usr/share/man/man1/a2query.1.gz
/usr/share/man/man8
/usr/share/man/man8/a2enconf.8.gz
/usr/share/man/man8/a2enmod.8.gz
/usr/share/man/man8/a2ensite.8.gz
/usr/share/man/man8/apache2ctl.8.gz
/var
/var/cache
/var/cache/apache2
/var/cache/apache2/mod_cache_disk
/var/lib
/var/lib/apache2
/var/log
/var/log/apache2
/var/www
/var/www/html
/usr/sbin/a2disconf
/usr/sbin/a2dismod
/usr/sbin/a2dissite
/usr/sbin/a2enconf
/usr/sbin/a2ensite
/usr/sbin/apachectl
/usr/share/bash-completion/completions/a2disconf
/usr/share/bash-completion/completions/a2dismod
/usr/share/bash-completion/completions/a2dissite
/usr/share/bash-completion/completions/a2enconf
/usr/share/bash-completion/completions/a2ensite
/usr/share/bug/apache2/control
/usr/share/bug/apache2/script
/usr/share/man/man8/a2disconf.8.gz
/usr/share/man/man8/a2dismod.8.gz
/usr/share/man/man8/a2dissite.8.gz
/usr/share/man/man8/apachectl.8.gz

We find that the apache2 program records logs in the /var/log/apache2 folder and stores the currently open files in the /var/lib/apache2 folder. We print out, for example, the web page access log /var/log/apache2/access.log, then open the web page with the command curl and a web browser and look again at the access log.

ls /var/log/apache2

access.log  error.log  other_vhosts_access.log

ls /var/lib/apache2

conf  module  site

cat /var/log/apache2/access.log

apt update
apt install curl

cat /var/log/apache2/access.log 

curl http://localhost

cat /var/log/apache2/access.log

::1 - - [04/Apr/2023:14:31:39 +0200] "GET / HTTP/1.1" 200 10956 "-" "curl/7.74.0"
127.0.0.1 - - [04/Apr/2023:14:32:48 +0200] "GET / HTTP/1.1" 200 3380 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0"
127.0.0.1 - - [04/Apr/2023:14:32:48 +0200] "GET /icons/openlogo-75.png HTTP/1.1" 200 6040 "http://localhost/" "Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0"
127.0.0.1 - - [04/Apr/2023:14:32:48 +0200] "GET /favicon.ico HTTP/1.1" 404 487 "http://localhost/" "Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0"

Now let's print the rest of the notes in the /var/log, /var/lib and .cache folders as well as the .bash_history file.

ls /var/log

alternatives.log    btmp	  fontconfig.log  speech-dispatcher
alternatives.log.1  btmp.1	  gdm3		  syslog
apache2		    cups	  installer	  syslog.1
apt		    daemon.log	  journal	  unattended-upgrades
auth.log	    daemon.log.1  kern.log	  user.log
auth.log.1	    debug	  kern.log.1	  user.log.1
boot.log	    debug.1	  lastlog	  vboxadd-install.log
boot.log.1	    dpkg.log	  messages	  vboxadd-setup.log
boot.log.2	    dpkg.log.1	  messages.1	  wtmp
boot.log.3	    faillog	  private

ls /var/lib

AccountsService      emacsen-common  PackageKit  ucf
alsa		     fwupd	     pam	 udisks2
apache2		     gdm3	     plymouth	 unattended-upgrades
app-info	     geoclue	     polkit-1	 upower
apt		     ghostscript     private	 usb_modeswitch
aspell		     grub	     python	 usbutils
boltd		     ispell	     realmd	 VBoxGuestAdditions
colord		     libreoffice     sgml-base	 vim
dbus		     logrotate	     snmp	 xfonts
dhcp		     man-db	     sudo	 xkb
dictionaries-common  misc	     synaptic	 xml-core
dkms		     NetworkManager  systemd
dpkg		     os-prober	     tpm

ls .cache

appstream

cat .bash_history

2. Sending logs over the network

We need two virtual computers, the first one will receive and print log events, the second one will send them over the network. On the first virtual machine, check its network IP address with the command ip, then open the configuration file of the rsyslog program /etc/rsyslog.conf and uncomment the lines in it that enable receiving events via UDP network protocol. Now we start the rsyslog program again with the service command and start printing system events in real time.

ip a

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
    valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:ab:74:50 brd ff:ff:ff:ff:ff:ff
    inet 192.168.34.109/24 brd 192.168.34.255 scope global dynamic noprefixroute enp0s3
    valid_lft 283294sec preferred_lft 283294sec
    inet6 2001:1470:fffd:101c:a40a:34d4:35c:9a83/64 scope global temporary dynamic 
    valid_lft 600100sec preferred_lft 81102sec
    inet6 2001:1470:fffd:101c:a00:27ff:feab:7450/64 scope global dynamic mngtmpaddr noprefixroute 
    valid_lft 2591982sec preferred_lft 604782sec
    inet6 fe80::a00:27ff:feab:7450/64 scope link noprefixroute 
    valid_lft forever preferred_lft forever

nano /etc/rsyslog.conf

# /etc/rsyslog.conf configuration file for rsyslog
#
# For more information install rsyslog-doc and see
# /usr/share/doc/rsyslog-doc/html/configuration/index.html


#################
#### MODULES ####
#################

module(load="imuxsock") # provides support for local system logging
module(load="imklog")   # provides kernel logging support
#module(load="immark")  # provides --MARK-- message capability

# provides UDP syslog reception
module(load="imudp")
input(type="imudp" port="514")

# provides TCP syslog reception
#module(load="imtcp")
#input(type="imtcp" port="514")


###########################
#### GLOBAL DIRECTIVES ####
###########################

#
# Use traditional timestamp format.
# To enable high precision timestamps, comment out the following line.
#
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat

#
# Set the default permissions for all log files.
#
$FileOwner root
$FileGroup adm
$FileCreateMode 0640
$DirCreateMode 0755
$Umask 0022

#
# Where to place spool and state files
#
$WorkDirectory /var/spool/rsyslog

#
# Include all config files in /etc/rsyslog.d/
#
$IncludeConfig /etc/rsyslog.d/*.conf


###############
#### RULES ####
###############

#
# First some standard log files.  Log by facility.
#
auth,authpriv.*			/var/log/auth.log
*.*;auth,authpriv.none		-/var/log/syslog
#cron.*				/var/log/cron.log
daemon.*			-/var/log/daemon.log
kern.*				-/var/log/kern.log
lpr.*				-/var/log/lpr.log
mail.*				-/var/log/mail.log
user.*				-/var/log/user.log

#
# Logging for the mail system.  Split it up so that
# it is easy to write scripts to parse these files.
#
mail.info			-/var/log/mail.info
mail.warn			-/var/log/mail.warn
mail.err			/var/log/mail.err

#
# Some "catch-all" log files.
#
*.=debug;\
    auth,authpriv.none;\
    mail.none		-/var/log/debug
*.=info;*.=notice;*.=warn;\
    auth,authpriv.none;\
    cron,daemon.none;\
    mail.none		-/var/log/messages

#
# Emergencies are sent to everybody logged in.
#
*.emerg				:omusrmsg:*

service rsyslog restart

tail -f /var/log/syslog

On the second virtual machine, we add to the configuration file /etc/rsyslog.conf a setting that forwards all system events over the network to our first virtual machine. Now we restart the rsyslog program with the service command and create arbitrary text events with the logger command.

nano /etc/rsyslog.conf

# /etc/rsyslog.conf configuration file for rsyslog
#
# For more information install rsyslog-doc and see
# /usr/share/doc/rsyslog-doc/html/configuration/index.html


#################
#### MODULES ####
#################

module(load="imuxsock") # provides support for local system logging
module(load="imklog")   # provides kernel logging support
#module(load="immark")  # provides --MARK-- message capability

# provides UDP syslog reception
#module(load="imudp")
#input(type="imudp" port="514")

# provides TCP syslog reception
#module(load="imtcp")
#input(type="imtcp" port="514")


###########################
#### GLOBAL DIRECTIVES ####
###########################

#
# Use traditional timestamp format.
# To enable high precision timestamps, comment out the following line.
#
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat

#
# Set the default permissions for all log files.
#
$FileOwner root
$FileGroup adm
$FileCreateMode 0640
$DirCreateMode 0755
$Umask 0022

#
# Where to place spool and state files
#
$WorkDirectory /var/spool/rsyslog

#
# Include all config files in /etc/rsyslog.d/
#
$IncludeConfig /etc/rsyslog.d/*.conf


###############
#### RULES ####
###############

#
# First some standard log files.  Log by facility.
#
auth,authpriv.*			/var/log/auth.log
*.*;auth,authpriv.none		-/var/log/syslog
#cron.*				/var/log/cron.log
daemon.*			-/var/log/daemon.log
kern.*				-/var/log/kern.log
lpr.*				-/var/log/lpr.log
mail.*				-/var/log/mail.log
user.*				-/var/log/user.log

#
# Logging for the mail system.  Split it up so that
# it is easy to write scripts to parse these files.
#
mail.info			-/var/log/mail.info
mail.warn			-/var/log/mail.warn
mail.err			/var/log/mail.err

#
# Some "catch-all" log files.
#
*.=debug;\
    auth,authpriv.none;\
    mail.none		-/var/log/debug
*.=info;*.=notice;*.=warn;\
    auth,authpriv.none;\
    cron,daemon.none;\
    mail.none		-/var/log/messages

#
# Emergencies are sent to everybody logged in.
#
*.emerg				:omusrmsg:*
*.* @192.168.34.109

service rsyslog restart

logger "This is a test event!"

On the first virtual computer, a new event now appears in the /var/log/syslog file.

tail -f /var/log/syslog
Apr  4 14:57:06 debian systemd[1]: Started System Logging Service.
Apr  4 14:59:58 debian systemd[1]: Stopping System Logging Service...
Apr  4 14:59:58 debian systemd[1]: rsyslog.service: Succeeded.
Apr  4 14:59:58 debian rsyslogd: [origin software="rsyslogd" swVersion="8.2102.0" x-pid="509" x-info="https://www.rsyslog.com"] exiting on signal 15.
Apr  4 14:59:58 debian systemd[1]: Stopped System Logging Service.
Apr  4 14:59:58 debian systemd[1]: Starting System Logging Service...
Apr  4 14:59:58 debian rsyslogd: imuxsock: Acquired UNIX socket '/run/systemd/journal/syslog' (fd 3) from systemd.  [v8.2102.0]
Apr  4 14:59:58 debian rsyslogd: [origin software="rsyslogd" swVersion="8.2102.0" x-pid="3603" x-info="https://www.rsyslog.com"] start
Apr  4 14:59:58 debian systemd[1]: Started System Logging Service.
Apr  4 15:10:28 debian aleks: This is a test event!

3. Program for recording keystrokes

First, we need to figure out how to get to the keyboard-triggered events in the first place. On Linux operating system we have /dev folder which contains all devices while /dev/input folder contains all input devices. All devices that trigger events are listed in the /proc/bus/input/devices file.

ls /dev

autofs		 input	       sg0	 tty20	tty41  tty62	  vcsa2
block		 kmsg	       sg1	 tty21	tty42  tty63	  vcsa3
bsg		 log	       shm	 tty22	tty43  tty7	  vcsa4
btrfs-control	 loop-control  snapshot  tty23	tty44  tty8	  vcsa5
bus		 mapper        snd	 tty24	tty45  tty9	  vcsa6
cdrom		 mem	       sr0	 tty25	tty46  ttyS0	  vcsu
char		 mqueue        stderr	 tty26	tty47  ttyS1	  vcsu1
console		 net	       stdin	 tty27	tty48  ttyS2	  vcsu2
core		 null	       stdout	 tty28	tty49  ttyS3	  vcsu3
cpu		 nvram	       tty	 tty29	tty5   uhid	  vcsu4
cpu_dma_latency  port	       tty0	 tty3	tty50  uinput	  vcsu5
cuse		 ppp	       tty1	 tty30	tty51  urandom	  vcsu6
disk		 psaux	       tty10	 tty31	tty52  vboxguest  vfio
dri		 ptmx	       tty11	 tty32	tty53  vboxuser   vga_arbiter
dvd		 pts	       tty12	 tty33	tty54  vcs	  vhci
fb0		 random        tty13	 tty34	tty55  vcs1	  vhost-net
fd		 rfkill        tty14	 tty35	tty56  vcs2	  vhost-vsock
full		 rtc	       tty15	 tty36	tty57  vcs3	  zero
fuse		 rtc0	       tty16	 tty37	tty58  vcs4
hidraw0		 sda	       tty17	 tty38	tty59  vcs5
hpet		 sda1	       tty18	 tty39	tty6   vcs6
hugepages	 sda2	       tty19	 tty4	tty60  vcsa
initctl		 sda5	       tty2	 tty40	tty61  vcsa1

ls /dev/input

by-id	 event0  event2  event4  event6  js0  mice    mouse1
by-path  event1  event3  event5  event7  js1  mouse0

cat /proc/bus/input/devices

I: Bus=0011 Vendor=0001 Product=0001 Version=ab41
N: Name="AT Translated Set 2 keyboard"
P: Phys=isa0060/serio0/input0
S: Sysfs=/devices/platform/i8042/serio0/input/input0
U: Uniq=
H: Handlers=sysrq kbd leds event0 
B: PROP=0
B: EV=120013
B: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe
B: MSC=10
B: LED=7

I: Bus=0019 Vendor=0000 Product=0001 Version=0000
N: Name="Power Button"
P: Phys=LNXPWRBN/button/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXPWRBN:00/input/input2
U: Uniq=
H: Handlers=kbd event1 
B: PROP=0
B: EV=3
B: KEY=10000000000000 0

I: Bus=0019 Vendor=0000 Product=0006 Version=0000
N: Name="Video Bus"
P: Phys=LNXVIDEO/video/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A03:00/LNXVIDEO:00/input/input3
U: Uniq=
H: Handlers=kbd event2 
B: PROP=0
B: EV=3
B: KEY=3e000b00000000 0 0 0

I: Bus=0019 Vendor=0000 Product=0003 Version=0000
N: Name="Sleep Button"
P: Phys=LNXSLPBN/button/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXSLPBN:00/input/input4
U: Uniq=
H: Handlers=kbd event3 
B: PROP=0
B: EV=3
B: KEY=4000 0 0

I: Bus=0011 Vendor=0002 Product=0006 Version=0000
N: Name="ImExPS/2 Generic Explorer Mouse"
P: Phys=isa0060/serio1/input0
S: Sysfs=/devices/platform/i8042/serio1/input/input5
U: Uniq=
H: Handlers=mouse0 event4 
B: PROP=1
B: EV=7
B: KEY=1f0000 0 0 0 0
B: REL=143

I: Bus=0003 Vendor=80ee Product=0021 Version=0110
N: Name="VirtualBox USB Tablet"
P: Phys=usb-0000:00:06.0-1/input0
S: Sysfs=/devices/pci0000:00/0000:00:06.0/usb1/1-1/1-1:1.0/0003:80EE:0021.0001/input/input6
U: Uniq=
H: Handlers=mouse1 event5 js0 
B: PROP=0
B: EV=1f
B: KEY=1f0000 0 0 0 0
B: REL=1940
B: ABS=3
B: MSC=10

I: Bus=0001 Vendor=80ee Product=cafe Version=0601
N: Name="VirtualBox mouse integration"
P: Phys=
S: Sysfs=/devices/pci0000:00/0000:00:04.0/input/input7
U: Uniq=
H: Handlers=event6 js1 
B: PROP=0
B: EV=b
B: KEY=10000 0 0 0 0
B: ABS=3

I: Bus=0010 Vendor=001f Product=0001 Version=0100
N: Name="PC Speaker"
P: Phys=isa0061/input0
S: Sysfs=/devices/platform/pcspkr/input/input8
U: Uniq=
H: Handlers=kbd event7 
B: PROP=0
B: EV=40001
B: SND=6

In our example, the keyboard sends events to the event0 input. To find out what events are triggered by the keyboard, install the program evtest with the package manager of our operating system.

apt update
apt install evtest

evtest

No device specified, trying to scan all of /dev/input/event*
Available devices:
/dev/input/event0:	AT Translated Set 2 keyboard
/dev/input/event1:	Power Button
/dev/input/event2:	Video Bus
/dev/input/event3:	Sleep Button
/dev/input/event4:	ImExPS/2 Generic Explorer Mouse
/dev/input/event5:	VirtualBox USB Tablet
/dev/input/event6:	VirtualBox mouse integration
/dev/input/event7:	PC Speaker
Select the device event number [0-7]: 0
Input driver version is 1.0.1
Input device ID: bus 0x11 vendor 0x1 product 0x1 version 0xab41
Input device name: "AT Translated Set 2 keyboard"
Supported events:
Event type 0 (EV_SYN)
Event type 1 (EV_KEY)
    Event code 1 (KEY_ESC)
    Event code 2 (KEY_1)
    Event code 3 (KEY_2)
    Event code 4 (KEY_3)
    Event code 5 (KEY_4)
    Event code 6 (KEY_5)
    Event code 7 (KEY_6)
    Event code 8 (KEY_7)
    Event code 9 (KEY_8)
    Event code 10 (KEY_9)
    Event code 11 (KEY_0)
    Event code 12 (KEY_MINUS)
    Event code 13 (KEY_EQUAL)
    Event code 14 (KEY_BACKSPACE)
    Event code 15 (KEY_TAB)
    Event code 16 (KEY_Q)
    Event code 17 (KEY_W)
    Event code 18 (KEY_E)
    Event code 19 (KEY_R)
    Event code 20 (KEY_T)
    Event code 21 (KEY_Y)
    Event code 22 (KEY_U)
    Event code 23 (KEY_I)
    Event code 24 (KEY_O)
    Event code 25 (KEY_P)
    Event code 26 (KEY_LEFTBRACE)
    Event code 27 (KEY_RIGHTBRACE)
    Event code 28 (KEY_ENTER)
    Event code 29 (KEY_LEFTCTRL)
    Event code 30 (KEY_A)
    Event code 31 (KEY_S)
    Event code 32 (KEY_D)
    Event code 33 (KEY_F)
    Event code 34 (KEY_G)
    Event code 35 (KEY_H)
    Event code 36 (KEY_J)
    Event code 37 (KEY_K)
    Event code 38 (KEY_L)
    Event code 39 (KEY_SEMICOLON)
    Event code 40 (KEY_APOSTROPHE)
    Event code 41 (KEY_GRAVE)
    Event code 42 (KEY_LEFTSHIFT)
    Event code 43 (KEY_BACKSLASH)
    Event code 44 (KEY_Z)
    Event code 45 (KEY_X)
    Event code 46 (KEY_C)
    Event code 47 (KEY_V)
    Event code 48 (KEY_B)
    Event code 49 (KEY_N)
    Event code 50 (KEY_M)
    Event code 51 (KEY_COMMA)
    Event code 52 (KEY_DOT)
    Event code 53 (KEY_SLASH)
    Event code 54 (KEY_RIGHTSHIFT)
    Event code 55 (KEY_KPASTERISK)
    Event code 56 (KEY_LEFTALT)
    Event code 57 (KEY_SPACE)
    Event code 58 (KEY_CAPSLOCK)
    Event code 59 (KEY_F1)
    Event code 60 (KEY_F2)
    Event code 61 (KEY_F3)
    Event code 62 (KEY_F4)
    Event code 63 (KEY_F5)
    Event code 64 (KEY_F6)
    Event code 65 (KEY_F7)
    Event code 66 (KEY_F8)
    Event code 67 (KEY_F9)
    Event code 68 (KEY_F10)
    Event code 69 (KEY_NUMLOCK)
    Event code 70 (KEY_SCROLLLOCK)
    Event code 71 (KEY_KP7)
    Event code 72 (KEY_KP8)
    Event code 73 (KEY_KP9)
    Event code 74 (KEY_KPMINUS)
    Event code 75 (KEY_KP4)
    Event code 76 (KEY_KP5)
    Event code 77 (KEY_KP6)
    Event code 78 (KEY_KPPLUS)
    Event code 79 (KEY_KP1)
    Event code 80 (KEY_KP2)
    Event code 81 (KEY_KP3)
    Event code 82 (KEY_KP0)
    Event code 83 (KEY_KPDOT)
    Event code 85 (KEY_ZENKAKUHANKAKU)
    Event code 86 (KEY_102ND)
    Event code 87 (KEY_F11)
    Event code 88 (KEY_F12)
    Event code 89 (KEY_RO)
    Event code 90 (KEY_KATAKANA)
    Event code 91 (KEY_HIRAGANA)
    Event code 92 (KEY_HENKAN)
    Event code 93 (KEY_KATAKANAHIRAGANA)
    Event code 94 (KEY_MUHENKAN)
    Event code 95 (KEY_KPJPCOMMA)
    Event code 96 (KEY_KPENTER)
    Event code 97 (KEY_RIGHTCTRL)
    Event code 98 (KEY_KPSLASH)
    Event code 99 (KEY_SYSRQ)
    Event code 100 (KEY_RIGHTALT)
    Event code 102 (KEY_HOME)
    Event code 103 (KEY_UP)
    Event code 104 (KEY_PAGEUP)
    Event code 105 (KEY_LEFT)
    Event code 106 (KEY_RIGHT)
    Event code 107 (KEY_END)
    Event code 108 (KEY_DOWN)
    Event code 109 (KEY_PAGEDOWN)
    Event code 110 (KEY_INSERT)
    Event code 111 (KEY_DELETE)
    Event code 112 (KEY_MACRO)
    Event code 113 (KEY_MUTE)
    Event code 114 (KEY_VOLUMEDOWN)
    Event code 115 (KEY_VOLUMEUP)
    Event code 116 (KEY_POWER)
    Event code 117 (KEY_KPEQUAL)
    Event code 118 (KEY_KPPLUSMINUS)
    Event code 119 (KEY_PAUSE)
    Event code 121 (KEY_KPCOMMA)
    Event code 122 (KEY_HANGUEL)
    Event code 123 (KEY_HANJA)
    Event code 124 (KEY_YEN)
    Event code 125 (KEY_LEFTMETA)
    Event code 126 (KEY_RIGHTMETA)
    Event code 127 (KEY_COMPOSE)
    Event code 128 (KEY_STOP)
    Event code 140 (KEY_CALC)
    Event code 142 (KEY_SLEEP)
    Event code 143 (KEY_WAKEUP)
    Event code 155 (KEY_MAIL)
    Event code 156 (KEY_BOOKMARKS)
    Event code 157 (KEY_COMPUTER)
    Event code 158 (KEY_BACK)
    Event code 159 (KEY_FORWARD)
    Event code 163 (KEY_NEXTSONG)
    Event code 164 (KEY_PLAYPAUSE)
    Event code 165 (KEY_PREVIOUSSONG)
    Event code 166 (KEY_STOPCD)
    Event code 172 (KEY_HOMEPAGE)
    Event code 173 (KEY_REFRESH)
    Event code 183 (KEY_F13)
    Event code 184 (KEY_F14)
    Event code 185 (KEY_F15)
    Event code 217 (KEY_SEARCH)
    Event code 226 (KEY_MEDIA)
Event type 4 (EV_MSC)
    Event code 4 (MSC_SCAN)
Event type 17 (EV_LED)
    Event code 0 (LED_NUML) state 0
    Event code 1 (LED_CAPSL) state 0
    Event code 2 (LED_SCROLLL) state 0
Key repeat handling:
Repeat type 20 (EV_REP)
    Repeat code 0 (REP_DELAY)
    Value    250
    Repeat code 1 (REP_PERIOD)
    Value     33
Properties:
Testing ... (interrupt to exit)
Event: time 1680637986.976124, type 4 (EV_MSC), code 4 (MSC_SCAN), value 1c
Event: time 1680637986.976124, type 1 (EV_KEY), code 28 (KEY_ENTER), value 0
Event: time 1680637986.976124, -------------- SYN_REPORT ------------
Event: time 1680637990.155637, type 4 (EV_MSC), code 4 (MSC_SCAN), value 20
Event: time 1680637990.155637, type 1 (EV_KEY), code 32 (KEY_D), value 1
Event: time 1680637990.155637, -------------- SYN_REPORT ------------
dEvent: time 1680637990.303721, type 4 (EV_MSC), code 4 (MSC_SCAN), value 20
Event: time 1680637990.303721, type 1 (EV_KEY), code 32 (KEY_D), value 0
Event: time 1680637990.303721, -------------- SYN_REPORT ------------
Event: time 1680637991.193166, type 4 (EV_MSC), code 4 (MSC_SCAN), value 21
Event: time 1680637991.193166, type 1 (EV_KEY), code 33 (KEY_F), value 1
Event: time 1680637991.193166, -------------- SYN_REPORT ------------
fEvent: time 1680637991.324400, type 4 (EV_MSC), code 4 (MSC_SCAN), value 21
Event: time 1680637991.324400, type 1 (EV_KEY), code 33 (KEY_F), value 0
Event: time 1680637991.324400, -------------- SYN_REPORT ------------
Event: time 1680637992.015830, type 4 (EV_MSC), code 4 (MSC_SCAN), value 24
Event: time 1680637992.015830, type 1 (EV_KEY), code 36 (KEY_J), value 1
Event: time 1680637992.015830, -------------- SYN_REPORT ------------
jEvent: time 1680637992.175462, type 4 (EV_MSC), code 4 (MSC_SCAN), value 24
Event: time 1680637992.175462, type 1 (EV_KEY), code 36 (KEY_J), value 0
Event: time 1680637992.175462, -------------- SYN_REPORT ------------

We read from eventX 16 B at a time:

  • Unsigned integer (4 B) - Time in seconds.
  • Unsigned integer (4 B) - Time in microseconds.
  • Short (2 B) - Event type.
  • Short (2 B) - Event code.
  • Integer (4 B) - A value that describes the event.

Now let's write our Python program that reads events from the input device /dev/input/event0. It reads 16 B at a time representing seconds, microseconds, type, code and value. Since we want to print only one event when the keyboard is pressed, we create an event only in the case when the type has the value 1 and the value and also the value 1. Now we convert the key code into a text description, for which we need the evdev library and write the event to the standard output. Then we enable the execution of the program with the command chmod.

apt update
apt install python3-evdev

nano keylogger.py

#!/usr/bin/env python3

from evdev import ecodes
import struct
import sys

with open("/dev/input/event0", "rb") as f:
        while True:
                d = f.read(16)
                sec, usec, type, code, value = struct.unpack("IIhhi", d)
                if type == 1 and value == 1:
                        print(ecodes.KEY[code])
                        sys.stdout.flush()    

chmod +x keylogger.py

Now let's test the operation by running our program in one command line window and redirecting its output to the logger program. In the second window of the command line, we start printing system logs /var/log/syslog in real time and start pressing any keys on the keyboard.

./keylogger.py | logger

tail -f /var/log/syslog

Apr  4 22:22:26 debian aleks: KEY_T
Apr  4 22:22:27 debian aleks: KEY_H
Apr  4 22:22:27 debian aleks: KEY_I
Apr  4 22:22:28 debian aleks: KEY_S
Apr  4 22:22:28 debian aleks: KEY_SPACE
Apr  4 22:22:29 debian aleks: KEY_I
Apr  4 22:22:29 debian aleks: KEY_S
Apr  4 22:22:30 debian aleks: KEY_SPACE
Apr  4 22:22:30 debian aleks: KEY_A
Apr  4 22:22:30 debian aleks: KEY_SPACE
Apr  4 22:22:31 debian aleks: KEY_T
Apr  4 22:22:31 debian aleks: KEY_E
Apr  4 22:22:32 debian aleks: KEY_S
Apr  4 22:22:32 debian aleks: KEY_T