Shell profile modified

Severity mediumLinuxSingle eventstablelinux.persistence.shell_profile_modified · v1.0.0

A shell startup file was created or replaced — a user's .bashrc, .bash_profile, .profile, .zshrc, .zshenv or .bash_logout, a system-wide…

What it detects

A shell startup file was created or replaced — a user's .bashrc, .bash_profile, .profile, .zshrc, .zshenv or .bash_logout, a system-wide /etc/profile, /etc/bash.bashrc or /etc/zsh/*, or a drop-in under /etc/profile.d.

Everything in those files runs on the next shell, as whoever opened it. That makes them persistence that needs no scheduler, no service and no root: one appended line re-launches an implant every time the user logs in. /etc/profile.d/*.sh is the same trick at host scope, executed for every interactive login on the machine, and .bash_logout is the quieter variant that runs on the way out instead.

The same files are also used to hide activity — an alias or a shadowing function that makes ls, ps or history lie to whoever is looking.

Matches CREATE and DELETE, which is what an append or an in-place edit looks like in auditd once an editor has written a temp file and renamed over the original. A read is NORMAL and does not fire, which matters: every shell that starts reads these files.

MITRE ATT&CK mapping

  • T1546.004Event Triggered Execution: Unix Shell Configuration Modification· Persistence

False positives and triage

This fires on legitimate work regularly, and the rate depends entirely on the host: a developer workstation edits .bashrc constantly, a production server should not. Judge it on that first.

Routine causes worth ruling out: package installs that drop a /etc/profile.d snippet (nvm, conda, rvm, cloud CLIs all do), a new account being provisioned with skeleton files copied from /etc/skel, dotfile-management tooling, and config management applying a standard shell profile.

What raises it: an edit to another user's profile by an account that is not root and not that user; an edit to /etc/profile.d on a host with no package activity around it; and any of these on a service account that has no interactive login history at all — nothing should be setting up a shell for an identity that never opens one.

Read the resulting file. Persistence here looks like a line that executes something — a curl/wget piped to a shell, a path in /tmp or /dev/shm, a base64 blob, or an alias shadowing a command an investigator would use.

The rule

Declarative YAML read by the detection engine — data, never executed. Confidence 50%. Source: rules/linux/shell_profile_modified.yaml, licensed under the Apache License 2.0.

id: linux.persistence.shell_profile_modified
version: 1.0.0
status: stable
severity: medium
confidence: 0.5
platforms: [linux]
mitre_techniques: [T1546.004]
description: |
  A shell startup file was created or replaced — a user's `.bashrc`, `.bash_profile`,
  `.profile`, `.zshrc`, `.zshenv` or `.bash_logout`, a system-wide `/etc/profile`,
  `/etc/bash.bashrc` or `/etc/zsh/*`, or a drop-in under `/etc/profile.d`.

  Everything in those files runs on the next shell, as whoever opened it. That makes
  them persistence that needs no scheduler, no service and no root: one appended
  line re-launches an implant every time the user logs in. `/etc/profile.d/*.sh` is
  the same trick at host scope, executed for every interactive login on the machine,
  and `.bash_logout` is the quieter variant that runs on the way out instead.

  The same files are also used to hide activity — an alias or a shadowing function
  that makes `ls`, `ps` or `history` lie to whoever is looking.

  Matches CREATE and DELETE, which is what an append or an in-place edit looks like
  in auditd once an editor has written a temp file and renamed over the original. A
  read is `NORMAL` and does not fire, which matters: every shell that starts reads
  these files.
match:
  file_path_regex: '^(/etc/(profile(\.d/[^/]+)?|bash\.bashrc|zsh/[^/]+)|/(home|root|Users)/[^/]+/\.(bashrc|bash_profile|bash_login|bash_logout|profile|zshrc|zshenv|zprofile))~?$'
  event_action_any:
    - file_created
    - file_deleted
false_positive_guidance: |
  This fires on legitimate work regularly, and the rate depends entirely on the host:
  a developer workstation edits `.bashrc` constantly, a production server should not.
  Judge it on that first.

  Routine causes worth ruling out: package installs that drop a `/etc/profile.d`
  snippet (nvm, conda, rvm, cloud CLIs all do), a new account being provisioned with
  skeleton files copied from `/etc/skel`, dotfile-management tooling, and config
  management applying a standard shell profile.

  What raises it: an edit to another user's profile by an account that is not root
  and not that user; an edit to `/etc/profile.d` on a host with no package activity
  around it; and any of these on a service account that has no interactive login
  history at all — nothing should be setting up a shell for an identity that never
  opens one.

  Read the resulting file. Persistence here looks like a line that executes
  something — a `curl`/`wget` piped to a shell, a path in /tmp or /dev/shm, a
  base64 blob, or an alias shadowing a command an investigator would use.

Related detections

Run this rule on your own logs — offline

KIROSEC runs this rule and the rest of the library over Windows, Linux, macOS and cloud audit logs on the analyst's own machine. Every alert links to the events that raised it, and nothing leaves the device.

Browse all detections