Description from ATT&CK

Adversaries may log user keystrokes to intercept credentials as the user types them. Keylogging is likely to be used to acquire credentials for new access opportunities when OS Credential Dumping efforts are not effective, and may require an adversary to intercept keystrokes on a system for a substantial period of time before credentials can be successfully captured.

Keylogging is the most prevalent type of input capture, with many different ways of intercepting keystrokes.[1] Some methods include:

  • Hooking API callbacks used for processing keystrokes. Unlike Credential API Hooking, this focuses solely on API functions intended for processing keystroke data.
  • Reading raw keystroke data from the hardware buffer.
  • Windows Registry modifications.
  • Custom drivers.

Modify System Image may provide adversaries with hooks into the operating system of network devices to read raw keystrokes for login sessions.[2]


Configuration

To build a set of controls to detect the activities described in MITRE ATT&CK’s T1056.001 - Input Capture: Keylogging we will use the Linux Audit daemon auditd to detect and record any configuration changes.

auditd rules

auditctl -w /usr/bin/logger -p xa -k CMD_LOGGER
auditctl -w /usr/bin/tee -p xa -k CMD_TEE


Controls and Tests

1. Logging bash history to syslog

There are several variables that can be set to control the appearance of the bash command prompt: PS1, PS2, PS3, PS4 and PROMPT_COMMAND. The contents of these variables are executed as if they had been typed on the command line. The PROMPT_COMMAND variable “if set” will be executed before the PS1 variable and can be configured to write the latest “bash history” entries to the syslog.

To gain persistence the command could be added to the users .bashrc or .bash_aliases or the systems default .bashrc in /etc/skel/

Command:

PROMPT_COMMAND='history -a >(tee -a ~/.bash_history |logger -t "$USER[$$] $SSH_CONNECTION ")'

Test:

date +"%b %d %T"
echo "Hello World!" 
if [ "$(grep 'Hello World!' /var/log/syslog)" ]; \
then echo "FOUND"; \
else echo NOT FOUND; \
fi 

Log: syslog

Jul 10 10:53:41 killingtime ubuntu[2837]  : echo "Hello World!"

Log: ausearch -i –start 10/07/21 10:50:00

----
type=PROCTITLE ... proctitle=tee -a /home/ubuntu/.bash_history 
type=PATH ... name=/usr/bin/tee ... 
type=CWD ... cwd=/home/ubuntu 
type=EXECVE ... a0=tee a1=-a a2=/home/ubuntu/.bash_history 
type=SYSCALL ... comm=tee exe=/usr/bin/tee ... key=CMD_TEE 
----
type=PROCTITLE ... proctitle=logger -t ubuntu[2837]   
type=PATH ... name=/usr/bin/logger ...
type=CWD ... cwd=/home/ubuntu 
type=EXECVE ... a0=logger a1=-t a2=ubuntu[2837]   
type=SYSCALL ... comm=logger exe=/usr/bin/logger ... key=CMD_LOGGER 

Cleanup:

unset PROMPT_COMMAND


2. Bash session based keylogger

When a command is executed in bash, the BASH_COMMAND variable contains that command. For example :~$ echo $BASH_COMMAND = “echo $BASH_COMMAND”. The trap command is not external, but a built-in function of bash and can be used in a script to run a bash function when some event occurs. trap will detect when the BASH_COMMAND variable value changes and then pipe that value into a file, creating a bash session based keylogger.

To gain persistence the command could be added to the users .bashrc or .bash_aliases or the systems default .bashrc in /etc/skel/

Command:

trap 'echo "$(date +"%d/%m/%y %H:%M:%S.%s") $USER $BASH_COMMAND" >> /tmp/.keyboard.log' DEBUG

Test:

echo "Hello World!"

if [ "$(grep 'Hello World!' /tmp/.keyboard.log)" ]; \
then echo "FOUND!"; \
else echo NOT FOUND!; \
fi 

Log: tail -f /tmp/.keyboard.log

10/07/21 11:06:18.1625911578 ubuntu echo "Hello World!"

Cleanup:

rm /tmp/.keyboard.log


3. SSHD PAM keylogger

Linux PAM (Pluggable Authentication Modules) is used in sshd authentication. The linux audit tool auditd can use the pam_tty_audit module to enable auditing of TTY input and capture all keystrokes in an ssh session and place them in the /var/log/audit/audit.log file after the session closes.

Command:

cp -v /etc/pam.d/sshd /tmp/

echo "session required pam_tty_audit.so disable=* enable=* open_only log_passwd" >> /etc/pam.d/sshd

systemctl restart sshd
systemctl restart auditd

Test:

ssh ubuntu@localhost 
echo "ubuntu@localhost"
sudo su
echo "root@localhost"
exit
exit

Log: aureport –tty

57. 07/12/21 16:37:52 681 1000 ? 26 sudo "ubuntu"
58. 07/12/21 16:38:08 691 1000 ? 26 bash "echo \"root@localhost\"",<ret>,"exit",<ret>
59. 07/12/21 16:38:08 696 1000 ? 26 sudo <nl>
60. 07/12/21 16:38:09 697 1000 ? 26 bash "echo \"ubuntu@localhost\"",<ret>,"sudo su",<ret>,"exit",<ret>

Log: ausearch -i

type=TTY msg=audit(07/12/21 16:37:52.111:681) : tty pid=130120 uid=ubuntu auid=ubuntu ses=26 major=136 minor=0 comm=sudo data="ubuntu"
type=TTY msg=audit(07/12/21 16:38:08.199:691) : tty pid=130123 uid=root auid=ubuntu ses=26 major=136 minor=0 comm=bash data="echo \"root@localhost\"",<ret>,"exit",<ret>
type=TTY msg=audit(07/12/21 16:38:08.203:696) : tty pid=130120 uid=root auid=ubuntu ses=26 major=136 minor=0 comm=sudo data=<nl>
type=TTY msg=audit(07/12/21 16:38:09.487:697) : tty pid=130111 uid=ubuntu auid=ubuntu ses=26 major=136 minor=0 comm=bash data="echo \"ubuntu@localhost\"",<ret>,"sudo su",<ret>,"exit",<ret>

Cleanup:

cp -fv /tmp/sshd /etc/pam.d/


4. Auditd keylogger

The linux audit tool auditd can be used to capture 32 and 64bit command execution and place the command in the /var/log/audit/audit.log audit log.

Command:

auditctl -a always,exit -F arch=b64 -S execve -k CMDS 
auditctl -a always,exit -F arch=b32 -S execve -k CMDS

We can control these duplicates using HISTCONTROL variable. HISTCONTROL can have the following values:

  • ignorespace - lines beginning with a space will not be saved in history.
  • ignoredups - lines matching the previous history entry will not be saved. In other words, duplicates are ignored.
  • ignoreboth - It is shorthand for “ignorespace” and “ignoredups” values. If you set these two values to HISTCONTROL variable, the lines beginning with a space and the duplicates will not be saved.
  • erasedups - eliminate duplicates across the whole history.

    echo $HISTCONTROL -> ignoredups:ignorespace OLD_HISTCONTROL=$HISTCONTROL; echo $OLD_HISTCONTROL HISTCONTROL=””; echo $HISTCONTROL

Test:

T=$(date +"%d/%m/%y %H:%M:%S"); whoami

Log: ausearch -i –start $T –end $T

----
type=PROCTITLE ... proctitle=date +%d/%m/%y %H:%M:%S 
type=PATH ... name=/usr/bin/date ... 
type=CWD ... cwd=/root 
type=EXECVE ... a0=date a1=+%d/%m/%y %H:%M:%S 
type=SYSCALL ... comm=date exe=/usr/bin/date ... key=CMDS 
----
type=PROCTITLE ... proctitle=whoami 
type=PATH ... name=/usr/bin/whoami ... 
type=CWD ... cwd=/root 
type=EXECVE ... a0=whoami 
type=SYSCALL ... comm=whoami exe=/usr/bin/whoami ... key=CMDS 
----
type=PROCTITLE ... proctitle=ausearch -i --start 09/07/21 18:13:19 ...
type=PATH ... name=/usr/sbin/ausearch ... 
type=CWD ... cwd=/root 
type=EXECVE ... a0=ausearch a1=-i a2=--start a3=09/07/21 a4=18:13:19 ...
type=SYSCALL ... comm=ausearch exe=/usr/sbin/ausearch ... key=CMDS 


Conclusion

auditd can detect changes to configuration files and the use of executables, but cannot detect bash session loggers.


References: