Linux File System Monitoring & Actions
There can be multiple reasons to keep an eye on a critical/suspicious file or directory. For example, you could track an attacker and wait for some access to the captured credentials in a phishing kit installed on a compromised server. You could deploy an EDR solution or an OSSEC agent that implements an FIM (‘File Integrity Monitoring”)[1]. Upon a file change, an action can be triggered. Nice, but what if you would like a quick solution but agentless? (In the scope of an incident, for example)
There is a well-known suite of API calls on Linux that track filesystem changes: inotify[2]. Around the API, a set of tools are available, like “inotifywatch” that generates an event when a file is “accessed”:
remnux@remnux:~$ inotifywatch /etc/hosts Establishing watches... Finished establishing watches, now collecting statistics. ^Ctotal access close_nowrite open filename 5 1 2 2 /etc/hosts
Another helpful command in scripts is “inotifywait”:
remnux@remnux:~$ inotifywait /etc/hosts Setting up watches. Watches established. /etc/hosts OPEN
This one waits for some activity, and when it happens, it exists. In a shell script, it helps to wait for an event and then continue the script. That’s interesting, but what if you can’t keep a shell running? What if the shell script exists? How to handle multiple events?
I recently discovered an interesting tool to implement better file system monitoring: incron[3]. The idea is to have an "inotify cron" system. It consists of a daemon and a table manipulator. Like the regular cron, you can schedule scripts that will be executed upon a filesystem change. Here is a quick example:
root@remnux:~# incrontab -l /var/www/wp/wp-plugins/compromized/phishing.log IN_CLOSE_WRITE /usr/local/bin/script.sh
You specify the file/directory to monitor, which access triggers the command. You can specify multiple access types. They are based on the ones defined in inotify.h:
#define IN_ACCESS 0x00000001 /* File was accessed */ #define IN_MODIFY 0x00000002 /* File was modified */ #define IN_ATTRIB 0x00000004 /* Metadata changed */ #define IN_CLOSE_WRITE 0x00000008 /* Writtable file was closed */ #define IN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */ #define IN_OPEN 0x00000020 /* File was opened */ #define IN_MOVED_FROM 0x00000040 /* File was moved from X */ #define IN_MOVED_TO 0x00000080 /* File was moved to Y */ #define IN_CREATE 0x00000100 /* Subfile was created */ #define IN_DELETE 0x00000200 /* Subfile was deleted */ #define IN_DELETE_SELF 0x00000400 /* Self was deleted */ #define IN_MOVE_SELF 0x00000800 /* Self was moved */
The following wildcards may be used inside the command specification:
$$ Prints a dollar sign $@ Add the watched filesystem path $# Add the event-related file name $% Add the event flags (textually) $& Add the event flags (numerically)
This is very efficient because you don't have to take care of loops or keep scripts running for a long time. Just be careful that your command(s) can be triggered many times if a lot of activity is detected on the monitored files/dirs!
Happy hunting!
[1] https://atomicorp.com/file-integrity-monitoring-fim/
[2] https://man7.org/linux/man-pages/man7/inotify.7.html
[3] https://inotify.aiken.cz/?section=incron&page=about&lang=en
Xavier Mertens (@xme)
Xameco
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key
Reverse-Engineering Malware: Malware Analysis Tools and Techniques | Amsterdam | Jan 20th - Jan 25th 2025 |
Comments