Linux Anti-Forensics: Timestomping

2025-03-05 DFIR linux anti-forensics

What is Timestomping?

Timestomping is an anti-forensics technique used to modify the timestamps of files on the file system, allowing attackers to conceal when files were written or modifled. By changing timestamps an attacker can blend their malicious activity into the system, thus reducing the chances of detection during an investigation or casual observation.

Timestomping is mapped in the MITRE ATT&CK framework as T1070.006 and affects all modern operating systems.

An example scenario where timestomping may be employed:

  • An attacker modifies a pre-existing PHP file belonging to a web app. After their backdoor is placed, all of the PHP /var/www/htdocs/webapp/ have the same timestamp except for the one they have altered. To cover their tracks, the attacker changes the timestamp on the modified file to match the other files, making their webshell harder to detect

This post will cover the basics of timestomping on Linux systems, highlighting methods used to alter timestamps and detect these modifications.

Timestomping in Practice

The methods used to timestomp files can vary depending on the file system. Generally, it is done with the touch command or C language APIs.

Using the touch Command

The touch command is the most straightforward way to timestomp files on Linux. However, due to it being around for so long and being written about extensively, this method is commonly detected by security tools. Nonetheless, attackers still use this technique. This is largely because of its ease of use and high probability that touch will exist on their victim systems, which makes it an easy and reliable choice for timestomping.

A basic example of touch is as follows:

touch -m -a -t YYYYMMDDHHMMSS FILENAME_TO_TIMESTOMP

The -m and -a flags instruct touch to modify the modification and access times of the specified file.

Example output:

daniel@rattlesnake /tmp/timestomp % ls -l
-rwxr-xr-x 1 daniel daniel 151344 Mar  5 09:23 ls*
-rwxr-xr-x 1 daniel daniel 125640 Mar  5 09:23 sh*

daniel@rattlesnake /tmp/timestomp % touch -m -a -t 202402151952 sh

daniel@rattlesnake /tmp/timestomp % ls -l
-rwxr-xr-x 1 daniel daniel 151344 Mar  5 09:23 ls*
-rwxr-xr-x 1 daniel daniel 125640 Feb 15  2024 sh*

As you can see, the sh file has been modified to have a timestamp of February 15th, 2024.

Alternatively, touch can use a reference file for timestamps:

touch -r /path/to/referencefile FILENAME_TO_TIMESTOMP

This is especially useful in scenarios as highlighted above where all of the files in a directory except for the ones manipulated by an attacker have the same timestamps. The attacker can easily use one of the unaltered files as a reference to blend in.

Example output:

daniel@rattlesnake /tmp/timestomp % ls -l
-rwxr-xr-x 1 daniel daniel 151344 Mar  5 09:23 ls*
-rwxr-xr-x 1 daniel daniel 125640 Feb 15  2024 sh*

daniel@rattlesnake /tmp/timestomp % touch -r ls sh

daniel@rattlesnake /tmp/timestomp % ls -l
-rwxr-xr-x 1 daniel daniel 151344 Mar  5 09:23 ls*
-rwxr-xr-x 1 daniel daniel 125640 Mar  5 09:23 sh*

As you can see, sh has had its timestamp restored to match the timestamp of ls.

Changing the System Time

The most glaring and obvious problem with using touch is that it does not modify a file’s birth date or change time. It is also noteworthy that most detections for timestomping rely on discrepancies between birthdates, change dates, modification dates, and access times.

To work around this, more sophisticated attackers may temporarily change the system’s clock to their desired time prior to before their malicious files. Afterward, they can revert the system time back to its normal setting, effectively timestomping their files.

This technique is more potent than using touch, but may lead to unusual log entries if the system logs any activity while the time is in an altered state. For example:

2025-03-05 09:41:33 -- attacker logs in
2025-03-05 09:41:49 -- attacker sets the system date to January 1st
2025-01-01 09:41:55 -- legitimate service creates a log entry using the bogus system time <---- log entry in the past!!!
2025-01-01 09:42:03 -- attacker places their malware
2025-01-01 09:42:09 -- attacker sets the date back to March 5th
2025-03-05 09:42:10 -- ...
2025-03-05 09:42:10 -- normal logs
2025-03-05 09:42:11 -- normal logs

In this scenario, logs generated during the window in which the time was manipulated by the attacker will contain timestamps from January 1st, which may raise suspicion during an investigation.

To mitigate this, the attacker may disable logging and NTP services before changing the system’s time. However, even this approach has its drawbacks; many logging services genearate entries when they start up, and if the time discrepancies aren’t reconciled, the startup logs become another detection point. This is especially true if system logging services or NTP startup times don’t correlate with the system booting or a package manager applying updates to these services.

To set the system’s date, attackers can use either the date command or timedatectl on systemd-based systems.

Using utime(), futimens(), and utimensat()

Under the hood, touch uses standard C library calls to utimensat(), or on older systems utime(). For portability’s sake, utime() will almost certainly be available on POSIX-compliant hosts.

The difference between utime() and utimensat() is that the former has second precision and the latter has nanosecond precision. futimens() is similar to utimensat() as it is also capable of nanosecond precision, however it works against file descriptors rather than file paths.

Attackers can trivially bake touch-like timestomping into their applications using these functions, avoiding the use of touch altogether and defeating command line-based detections.

utime()

utime() is the simplest and oldest of these APIs, but lacks nanosecond permissions:

#include <utime.h>
#include <stdio.h>
#include <time.h>

int main() {
    struct utimbuf new_times;

    new_times.actime  = 1672531200; // Jan 1, 2023
    new_times.modtime = 1672534800;

    if (utime("example_file", &new_times) == -1) {
        perror("utime");
        return 1;
    }

    return 0;
}

utimensat()

utimensat() is similar to utime(), but offers nanosecond precision.

#define _POSIX_C_SOURCE 200809L
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <stdio.h>
#include <time.h>

int main() {
    struct timespec times[2];

    times[0].tv_sec = 1672531200; // access time: Jan 1, 2023
    times[0].tv_nsec = 0;

    times[1].tv_sec = 1672534800; // modification time: Jan 1, 2023
    times[1].tv_nsec = 0;

    if (utimensat(AT_FDCWD, "example_file, times, 0) == -1) {
       perror("utimensat");
       return 1;
    }

    return 0;
}

futimens()

futimens() is similar to utimensat(), except it works on a file descriptor rather than against a file path.

#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <time.h>

int main() {
    int fd = open("example_file", O_WRONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    struct timespec times[2];
    times[0].tv_sec = 1672531200; // access time Jan 1, 2023
    times[0].tv_nsec = 0;
    times[1].tv_sec = 1672534800; // modification time
    times[1].tv_nsec = 0;

    if (futimens(fd, times) == -1) {
        perror("futimens");
        return 1;
    }

    close(fd);
    return 0;
}

Python Using utime()

Other languages such as Python can call these functions as well. Here is a basic example using the os module and utime()

import os
import time

new_time = 1672531200  # UNIX timestamp (Jan 1, 2023)
os.utime("/path/to/file", (new_time, new_time))

Detection

Using the stat Command

The most straightforward (and error-prone) method to find timestomped files on Linux is with the stat command

Comparing the output of stat with other files in the same directory, timestomped files may have different birth dates than every other file, or birthdays in the future compared to change time.

This is error prone for files copied from other systems, installed with package managers, restored from backups, and so on, but it may offer a quick win.

Reviewing logs

Depending on how a system is configured and the heterogeneous nature of the Linux ecosystem, reviewing logs can vary wildly. Nonetheless, here are some common things to check for

  • Check for suspicious starts and stops of syslogd and ntpd.

auditd

auditd can be configured to log calls to execve, utimes, and utimesat. This may be used to search for execution of touch or direct calls to utimes and utimesat.

File Integrity Monitoring

File integrity monitoring tools such as Tripwire or AIDE may be useful. Although they do not detect timestomping specifically, they may alert if the timestamps of a file change or the hash of the file changes.

The problem with file integrity monitoring is that it needs to be in place before the attack occurs; they cannot be used for retrospective detection.

Package Manager Verification

If a file was introduced to a system by a package manager, the verification feature can be used to detect timestamp and hash alterations.

Package managers may also be used to determine which files in a given directory were not installed via a package, which may reveal the presence of malware.

This is explored deeper in Finding Bad with Linux Package Managers

debugfs

Depending on the file system, extra metadata may be stored that can be useful for detecting timestomping. On ext4 systems, debugfs may be used to get stat-like information related to the inode structure of a file:

sudo debugfs -R 'stat /bin/malware' /dev/sda1

Conclusion

Detecting timestomped files on Linux can be challenging. Using tools like stat, auditd, file integrity monitoring, package manager verification, and debugfs may help in incident response scenarios.

It is imperative to have enhanced logging and file integrity monitoring in place in order to properly detect and hunt for timestomping; retrospective detection is far more complex and prone to error.

Hopefully, these techniques will provide you with a good starting point to identify timestomped files.


No notes link to this note