
Analyzing Linux System Artifacts
- 353 installs
- 27.3k repo stars
- Updated August 2, 2026
- mukul975/anthropic-cybersecurity-skills
Analyzing Linux System Artifacts is an agent skill that structures investigation of Linux logs, configs, and persistence indicators for security triage.
About
Analyzing Linux System Artifacts is an agent skill aimed at solo and indie builders who run their own Linux servers or ship backends on VPS and containers. When something looks wrong—a odd cron job, unfamiliar user, or suspicious binary path—you need a repeatable way to walk through system evidence without guessing. This skill packages cybersecurity-oriented procedural knowledge for Linux artifact analysis so your coding agent asks the right questions, cites the right locations, and keeps investigation steps consistent. It is most natural during security review before launch, after a dependency scare, or when operating production and chasing anomalies in monitoring alerts. It is not a replacement for professional incident response or automated EDR; it is a structured copilot for artifact-focused review. Pair it with your own backups, access controls, and the Security Audits panel on this Prism page before trusting any automated conclusions.
- Structured prompts for interpreting Linux system artifacts during security investigations
- Fits agent-assisted triage when you cannot afford a full SOC on a solo stack
- Complements broader cybersecurity skills in the same Anthropic-oriented collection
- Use when logs, cron, users, or persistence paths need methodical review on Linux hosts
- Apache 2.0 licensed skill package for reuse in Claude Code and similar agents
Analyzing Linux System Artifacts by the numbers
- 353 all-time installs (skills.sh)
- +28 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #578 of 2,203 Security skills by installs in the Skillselion catalog
- Security screen: HIGH risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/mukul975/anthropic-cybersecurity-skills --skill analyzing-linux-system-artifactsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 353 |
|---|---|
| repo stars | ★ 27.3k |
| Security audit | 2 / 3 scanners passed |
| Last updated | August 2, 2026 |
| Repository | mukul975/anthropic-cybersecurity-skills ↗ |
What it does
Guide an agent through structured review of Linux logs, configs, and process artifacts when investigating compromise or hardening a server.
Who is it for?
Best when you're self-hosting APIs or workers on Linux and want agent-guided forensic steps during a suspected compromise or pre-launch hardening pass.
Skip if: Skip if you already run managed EDR/SIEM with dedicated IR retainers, or developers and only develop on macOS/Windows without Linux production targets.
When should I use this skill?
When investigating Linux hosts for signs of compromise, unexpected persistence, or pre-release security hardening on artifact-heavy systems.
What you get
You get a guided, repeatable Linux artifact review path your agent can follow so findings are documented and you can decide whether to patch, rotate secrets, or restore from backup.
- Structured artifact review notes
- List of suspicious paths, users, or jobs to remediate
- Recommended next hardening or rotation steps
Files
Analyzing Linux System Artifacts
When to Use
- When investigating a compromised Linux server or workstation
- For identifying persistence mechanisms (cron, systemd, SSH keys)
- When tracing user activity through shell history and authentication logs
- During incident response to determine the scope of a Linux-based breach
- For detecting rootkits, backdoors, and unauthorized modifications
Prerequisites
- Forensic image or live access to the Linux system (read-only)
- Understanding of Linux file system hierarchy (FHS)
- Knowledge of common Linux logging locations (/var/log/)
- Tools: chkrootkit, rkhunter, AIDE, auditd logs
- Familiarity with systemd, cron, and PAM configurations
- Root access for complete artifact collection
Workflow
Step 1: Mount and Collect System Artifacts
# Mount forensic image read-only
mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/linux_evidence.dd /mnt/evidence
# Create collection directories
mkdir -p /cases/case-2024-001/linux/{logs,config,users,persistence,network}
# Collect authentication logs
cp /mnt/evidence/var/log/auth.log* /cases/case-2024-001/linux/logs/
cp /mnt/evidence/var/log/secure* /cases/case-2024-001/linux/logs/
cp /mnt/evidence/var/log/syslog* /cases/case-2024-001/linux/logs/
cp /mnt/evidence/var/log/kern.log* /cases/case-2024-001/linux/logs/
cp /mnt/evidence/var/log/audit/audit.log* /cases/case-2024-001/linux/logs/
cp /mnt/evidence/var/log/wtmp /cases/case-2024-001/linux/logs/
cp /mnt/evidence/var/log/btmp /cases/case-2024-001/linux/logs/
cp /mnt/evidence/var/log/lastlog /cases/case-2024-001/linux/logs/
cp /mnt/evidence/var/log/faillog /cases/case-2024-001/linux/logs/
# Collect user artifacts
for user_dir in /mnt/evidence/home/*/; do
username=$(basename "$user_dir")
mkdir -p /cases/case-2024-001/linux/users/$username
cp "$user_dir"/.bash_history /cases/case-2024-001/linux/users/$username/ 2>/dev/null
cp "$user_dir"/.zsh_history /cases/case-2024-001/linux/users/$username/ 2>/dev/null
cp -r "$user_dir"/.ssh/ /cases/case-2024-001/linux/users/$username/ 2>/dev/null
cp "$user_dir"/.bashrc /cases/case-2024-001/linux/users/$username/ 2>/dev/null
cp "$user_dir"/.profile /cases/case-2024-001/linux/users/$username/ 2>/dev/null
cp "$user_dir"/.viminfo /cases/case-2024-001/linux/users/$username/ 2>/dev/null
cp "$user_dir"/.wget-hsts /cases/case-2024-001/linux/users/$username/ 2>/dev/null
cp "$user_dir"/.python_history /cases/case-2024-001/linux/users/$username/ 2>/dev/null
done
# Collect root user artifacts
cp /mnt/evidence/root/.bash_history /cases/case-2024-001/linux/users/root/ 2>/dev/null
cp -r /mnt/evidence/root/.ssh/ /cases/case-2024-001/linux/users/root/ 2>/dev/null
# Collect system configuration
cp /mnt/evidence/etc/passwd /cases/case-2024-001/linux/config/
cp /mnt/evidence/etc/shadow /cases/case-2024-001/linux/config/
cp /mnt/evidence/etc/group /cases/case-2024-001/linux/config/
cp /mnt/evidence/etc/sudoers /cases/case-2024-001/linux/config/
cp -r /mnt/evidence/etc/sudoers.d/ /cases/case-2024-001/linux/config/
cp /mnt/evidence/etc/hosts /cases/case-2024-001/linux/config/
cp /mnt/evidence/etc/resolv.conf /cases/case-2024-001/linux/config/
cp -r /mnt/evidence/etc/ssh/ /cases/case-2024-001/linux/config/Step 2: Analyze User Accounts and Authentication
# Analyze user accounts for anomalies
python3 << 'PYEOF'
print("=== USER ACCOUNT ANALYSIS ===\n")
# Parse /etc/passwd
with open('/cases/case-2024-001/linux/config/passwd') as f:
for line in f:
parts = line.strip().split(':')
if len(parts) >= 7:
username, _, uid, gid, comment, home, shell = parts[0], parts[1], int(parts[2]), int(parts[3]), parts[4], parts[5], parts[6]
# Flag accounts with UID 0 (root equivalent)
if uid == 0 and username != 'root':
print(f" ALERT: UID 0 account: {username} (shell: {shell})")
# Flag accounts with login shells that shouldn't have them
if shell not in ('/bin/false', '/usr/sbin/nologin', '/bin/sync') and uid >= 1000:
print(f" User: {username} (UID:{uid}, Shell:{shell}, Home:{home})")
# Flag system accounts with login shells
if uid < 1000 and uid > 0 and shell in ('/bin/bash', '/bin/sh', '/bin/zsh'):
print(f" WARNING: System account with shell: {username} (UID:{uid}, Shell:{shell})")
# Parse /etc/shadow for account status
print("\n=== PASSWORD STATUS ===")
with open('/cases/case-2024-001/linux/config/shadow') as f:
for line in f:
parts = line.strip().split(':')
if len(parts) >= 3:
username = parts[0]
pwd_hash = parts[1]
last_change = parts[2]
if pwd_hash and pwd_hash not in ('*', '!', '!!', ''):
hash_type = 'Unknown'
if pwd_hash.startswith('$6$'): hash_type = 'SHA-512'
elif pwd_hash.startswith('$5$'): hash_type = 'SHA-256'
elif pwd_hash.startswith('$y$'): hash_type = 'yescrypt'
elif pwd_hash.startswith('$1$'): hash_type = 'MD5 (WEAK)'
print(f" {username}: {hash_type} hash, last changed: day {last_change}")
PYEOF
# Analyze login history
last -f /cases/case-2024-001/linux/logs/wtmp > /cases/case-2024-001/linux/analysis/login_history.txt
lastb -f /cases/case-2024-001/linux/logs/btmp > /cases/case-2024-001/linux/analysis/failed_logins.txt 2>/dev/nullStep 3: Examine Persistence Mechanisms
# Check cron jobs for all users
echo "=== CRON JOBS ===" > /cases/case-2024-001/linux/persistence/cron_analysis.txt
# System cron
for cronfile in /mnt/evidence/etc/crontab /mnt/evidence/etc/cron.d/*; do
echo "--- $cronfile ---" >> /cases/case-2024-001/linux/persistence/cron_analysis.txt
cat "$cronfile" 2>/dev/null >> /cases/case-2024-001/linux/persistence/cron_analysis.txt
echo "" >> /cases/case-2024-001/linux/persistence/cron_analysis.txt
done
# User cron tabs
for cronfile in /mnt/evidence/var/spool/cron/crontabs/*; do
echo "--- User crontab: $(basename $cronfile) ---" >> /cases/case-2024-001/linux/persistence/cron_analysis.txt
cat "$cronfile" 2>/dev/null >> /cases/case-2024-001/linux/persistence/cron_analysis.txt
echo "" >> /cases/case-2024-001/linux/persistence/cron_analysis.txt
done
# Check systemd services for persistence
echo "=== SYSTEMD SERVICES ===" > /cases/case-2024-001/linux/persistence/systemd_analysis.txt
find /mnt/evidence/etc/systemd/system/ -name "*.service" -newer /mnt/evidence/etc/os-release \
>> /cases/case-2024-001/linux/persistence/systemd_analysis.txt
for svc in /mnt/evidence/etc/systemd/system/*.service; do
echo "--- $(basename $svc) ---" >> /cases/case-2024-001/linux/persistence/systemd_analysis.txt
cat "$svc" >> /cases/case-2024-001/linux/persistence/systemd_analysis.txt
echo "" >> /cases/case-2024-001/linux/persistence/systemd_analysis.txt
done
# Check authorized SSH keys (backdoor detection)
echo "=== SSH AUTHORIZED KEYS ===" > /cases/case-2024-001/linux/persistence/ssh_keys.txt
find /mnt/evidence/home/ /mnt/evidence/root/ -name "authorized_keys" -exec sh -c \
'echo "--- {} ---"; cat {}; echo ""' \; >> /cases/case-2024-001/linux/persistence/ssh_keys.txt
# Check rc.local and init scripts
cat /mnt/evidence/etc/rc.local 2>/dev/null > /cases/case-2024-001/linux/persistence/rc_local.txt
# Check /etc/profile.d/ for login-triggered scripts
ls -la /mnt/evidence/etc/profile.d/ > /cases/case-2024-001/linux/persistence/profile_scripts.txt
# Check for LD_PRELOAD hijacking
grep -r "LD_PRELOAD" /mnt/evidence/etc/ 2>/dev/null > /cases/case-2024-001/linux/persistence/ld_preload.txt
cat /mnt/evidence/etc/ld.so.preload 2>/dev/null >> /cases/case-2024-001/linux/persistence/ld_preload.txtStep 4: Analyze Shell History and Command Execution
# Analyze bash history for each user
python3 << 'PYEOF'
import os, glob
print("=== SHELL HISTORY ANALYSIS ===\n")
suspicious_commands = [
'wget', 'curl', 'nc ', 'ncat', 'netcat', 'python -c', 'python3 -c',
'perl -e', 'base64', 'chmod 777', 'chmod +s', '/dev/tcp', '/dev/udp',
'nmap', 'masscan', 'hydra', 'john', 'hashcat', 'passwd', 'useradd',
'iptables -F', 'ufw disable', 'history -c', 'rm -rf /', 'dd if=',
'crontab', 'at ', 'systemctl enable', 'ssh-keygen', 'scp ', 'rsync',
'tar czf', 'zip -r', 'openssl enc', 'gpg --encrypt', 'shred',
'chattr', 'setfacl', 'awk', '/tmp/', '/dev/shm/'
]
for hist_file in glob.glob('/cases/case-2024-001/linux/users/*/.bash_history'):
username = hist_file.split('/')[-2]
print(f"User: {username}")
with open(hist_file, 'r', errors='ignore') as f:
lines = f.readlines()
print(f" Total commands: {len(lines)}")
flagged = []
for i, line in enumerate(lines):
line = line.strip()
for cmd in suspicious_commands:
if cmd in line.lower():
flagged.append((i+1, line))
break
if flagged:
print(f" Suspicious commands: {len(flagged)}")
for lineno, cmd in flagged:
print(f" Line {lineno}: {cmd[:120]}")
print()
PYEOFStep 5: Check for Rootkits and Modified Binaries
# Check for known rootkit indicators
# Compare system binary hashes against known-good
find /mnt/evidence/usr/bin/ /mnt/evidence/usr/sbin/ /mnt/evidence/bin/ /mnt/evidence/sbin/ \
-type f -executable -exec sha256sum {} \; > /cases/case-2024-001/linux/analysis/binary_hashes.txt
# Check for SUID/SGID binaries (potential privilege escalation)
find /mnt/evidence/ -perm -4000 -type f 2>/dev/null > /cases/case-2024-001/linux/analysis/suid_files.txt
find /mnt/evidence/ -perm -2000 -type f 2>/dev/null > /cases/case-2024-001/linux/analysis/sgid_files.txt
# Check for suspicious files in /tmp and /dev/shm
find /mnt/evidence/tmp/ /mnt/evidence/dev/shm/ -type f 2>/dev/null \
-exec file {} \; > /cases/case-2024-001/linux/analysis/tmp_files.txt
# Check for hidden files and directories
find /mnt/evidence/ -name ".*" -not -path "*/\." -type f 2>/dev/null | \
head -100 > /cases/case-2024-001/linux/analysis/hidden_files.txt
# Check kernel modules
ls -la /mnt/evidence/lib/modules/$(ls /mnt/evidence/lib/modules/ | head -1)/extra/ 2>/dev/null \
> /cases/case-2024-001/linux/analysis/extra_modules.txt
# Check for modified PAM configuration (authentication backdoors)
diff /mnt/evidence/etc/pam.d/ /cases/baseline/pam.d/ 2>/dev/null \
> /cases/case-2024-001/linux/analysis/pam_changes.txtKey Concepts
| Concept | Description |
|---|---|
| /var/log/auth.log | Primary authentication log on Debian/Ubuntu systems |
| /var/log/secure | Primary authentication log on RHEL/CentOS systems |
| wtmp/btmp | Binary logs recording successful and failed login sessions |
| .bash_history | User command history file (can be cleared by attackers) |
| crontab | Scheduled task system commonly used for persistence |
| authorized_keys | SSH public keys granting passwordless access to an account |
| SUID bit | File permission allowing execution as the file owner (privilege escalation vector) |
| LD_PRELOAD | Environment variable that loads a shared library before all others (hooking technique) |
Tools & Systems
| Tool | Purpose |
|---|---|
| chkrootkit | Rootkit detection scanner for Linux systems |
| rkhunter | Rootkit Hunter - checks for rootkits, backdoors, and local exploits |
| AIDE | Advanced Intrusion Detection Environment - file integrity monitor |
| auditd | Linux audit framework for system call and file access monitoring |
| last/lastb | Parse wtmp/btmp for login and failed login history |
| Plaso/log2timeline | Super-timeline creation including Linux artifacts |
| osquery | SQL-based system querying for live forensic investigation |
| Velociraptor | Endpoint agent with Linux artifact collection capabilities |
Common Scenarios
Scenario 1: SSH Brute Force Followed by Compromise Analyze auth.log for failed SSH attempts followed by success, identify the attacking IP, check .bash_history for post-compromise commands, examine authorized_keys for added backdoor keys, check crontab for persistence, review network connections.
Scenario 2: Web Server Compromise via Application Vulnerability Examine web server access and error logs for exploitation attempts, check /tmp and /dev/shm for webshells, analyze the web server user's activity (www-data), check for privilege escalation via SUID binaries or kernel exploits, review outbound connections.
Scenario 3: Insider Threat on Database Server Analyze the suspect user's bash_history for database dump commands, check for large tar/zip files in home directory or /tmp, examine scp/rsync commands for data transfer, review cron jobs for automated exfiltration, check USB device logs.
Scenario 4: Crypto-Miner on Cloud Instance Check for high-CPU processes in /proc (live) or systemd service files, examine crontab entries for miner restart scripts, check /tmp for mining binaries, analyze network connections for mining pool communications, review authorized_keys for attacker access.
Output Format
Linux Forensics Summary:
System: webserver01 (Ubuntu 22.04 LTS)
Hostname: webserver01.corp.local
Kernel: 5.15.0-91-generic
User Accounts:
Total: 25 (3 with UID 0 - 1 ANOMALOUS)
Interactive shells: 8 users
Recently created: admin2 (created 2024-01-15)
Authentication Events:
Successful SSH logins: 456
Failed SSH attempts: 12,345 (from 23 unique IPs)
Sudo executions: 89
Persistence Mechanisms Found:
Cron jobs: 3 suspicious (reverse shell, miner restart)
Systemd services: 1 unknown (update-checker.service)
SSH keys: 2 unauthorized keys in root authorized_keys
rc.local: Modified with download cradle
Suspicious Activity:
- bash_history contains wget to pastebin URL
- SUID binary /tmp/.hidden/escalate found
- /dev/shm/ contains compiled ELF binary
- LD_PRELOAD in /etc/ld.so.preload pointing to /lib/.hidden.so
Report: /cases/case-2024-001/linux/analysis/
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
API Reference: Linux Forensic Artifact Analysis Tools
Key Artifact Locations
| Artifact | Path | Description |
|---|---|---|
| Auth logs | /var/log/auth.log (Debian) /var/log/secure (RHEL) | Authentication events |
| Login history | /var/log/wtmp | Successful logins (binary, use last) |
| Failed logins | /var/log/btmp | Failed logins (binary, use lastb) |
| Bash history | ~/.bash_history | Command history per user |
| SSH keys | ~/.ssh/authorized_keys | Authorized public keys |
| Crontab | /etc/crontab, /var/spool/cron/crontabs/ | Scheduled tasks |
| Systemd services | /etc/systemd/system/ | Service definitions |
| LD_PRELOAD | /etc/ld.so.preload | Shared library preloading |
| SUID binaries | find / -perm -4000 | Setuid executables |
last / lastb - Login History
Syntax
last -f /var/log/wtmp # Successful logins
lastb -f /var/log/btmp # Failed logins
last -i -f /var/log/wtmp # Show IP addresses
last -s 2024-01-15 -t 2024-01-20 # Date range filterOutput Format
user pts/0 192.168.1.50 Mon Jan 15 09:00 still logged inchkrootkit - Rootkit Scanner
Syntax
chkrootkit # Full scan
chkrootkit -r /mnt/evidence # Scan mounted evidence
chkrootkit -q # Quiet (infected only)rkhunter - Rootkit Hunter
Syntax
rkhunter --check # Full system check
rkhunter --check --rootdir /mnt/ev # Check evidence root
rkhunter --list tests # List available tests
rkhunter --propupd # Update file properties DBCheck Categories
| Check | Description |
|---|---|
rootkits | Known rootkit signatures |
trojans | Trojanized system binaries |
properties | File permission anomalies |
filesystem | Hidden files and directories |
auditd Log Parsing
ausearch Syntax
ausearch -m execve -ts recent # Recent command execution
ausearch -m USER_AUTH -ts today # Authentication events
ausearch -k suspicious_activity # Custom audit rule key
ausearch -ua 0 -ts today # Root user actionsaureport Syntax
aureport --auth # Authentication summary
aureport --login # Login summary
aureport --file # File access summary
aureport --summary # Overall summaryosquery - SQL-based System Queries
Syntax
osqueryi "SELECT * FROM users WHERE uid = 0"
osqueryi "SELECT * FROM crontab"
osqueryi "SELECT * FROM authorized_keys"
osqueryi "SELECT * FROM suid_bin"
osqueryi "SELECT * FROM process_open_sockets"Key Tables
| Table | Content |
|---|---|
users | User account information |
crontab | Cron job entries |
authorized_keys | SSH authorized keys |
suid_bin | SUID binaries |
process_open_sockets | Network connections by process |
shell_history | Command history entries |
Plaso / log2timeline - Super Timeline
Syntax
log2timeline.py /cases/timeline.plaso /mnt/evidence
psort.py -o l2tcsv /cases/timeline.plaso > timeline.csv
psort.py -o l2tcsv /cases/timeline.plaso "date > '2024-01-15'"AIDE - File Integrity
Syntax
aide --init # Initialize database
aide --check # Check for changes
aide --compare # Compare databases#!/usr/bin/env python3
"""Linux system artifact forensics agent for investigating compromised systems."""
import os
import sys
import glob
import shlex
import subprocess
def run_cmd(cmd):
"""Execute a command and return output."""
if isinstance(cmd, str):
cmd = shlex.split(cmd)
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
return result.stdout.strip(), result.stderr.strip(), result.returncode
def analyze_passwd(passwd_path):
"""Analyze /etc/passwd for suspicious accounts."""
findings = []
with open(passwd_path, "r") as f:
for line in f:
parts = line.strip().split(":")
if len(parts) < 7:
continue
username, _, uid, gid = parts[0], parts[1], int(parts[2]), int(parts[3])
home, shell = parts[5], parts[6]
if uid == 0 and username != "root":
findings.append({
"severity": "CRITICAL",
"finding": f"UID 0 account: {username} (shell: {shell})",
})
login_shells = ["/bin/bash", "/bin/sh", "/bin/zsh", "/usr/bin/zsh"]
if uid < 1000 and uid > 0 and shell in login_shells:
findings.append({
"severity": "WARNING",
"finding": f"System account with login shell: {username} (UID:{uid})",
})
if uid >= 1000 and shell not in ["/bin/false", "/usr/sbin/nologin", "/bin/sync"]:
findings.append({
"severity": "INFO",
"finding": f"Interactive user: {username} (UID:{uid}, Home:{home})",
})
return findings
def analyze_shadow(shadow_path):
"""Analyze /etc/shadow for password hash types and status."""
findings = []
with open(shadow_path, "r") as f:
for line in f:
parts = line.strip().split(":")
if len(parts) < 3:
continue
username = parts[0]
pwd_hash = parts[1]
if pwd_hash and pwd_hash not in ("*", "!", "!!", ""):
hash_type = "Unknown"
if pwd_hash.startswith("$6$"):
hash_type = "SHA-512"
elif pwd_hash.startswith("$5$"):
hash_type = "SHA-256"
elif pwd_hash.startswith("$y$"):
hash_type = "yescrypt"
elif pwd_hash.startswith("$1$"):
hash_type = "MD5 (WEAK)"
findings.append({
"severity": "WARNING",
"finding": f"{username} uses weak MD5 password hash",
})
findings.append({
"severity": "INFO",
"finding": f"{username}: {hash_type} hash, last changed day {parts[2]}",
})
return findings
def analyze_bash_history(history_path, username="unknown"):
"""Analyze bash history for suspicious commands."""
suspicious_patterns = [
"wget", "curl", "nc ", "ncat", "netcat", "python -c", "python3 -c",
"perl -e", "base64", "chmod 777", "chmod +s", "/dev/tcp", "/dev/udp",
"nmap", "masscan", "hydra", "john", "hashcat", "passwd", "useradd",
"iptables -F", "ufw disable", "history -c", "rm -rf", "dd if=",
"crontab", "systemctl enable", "ssh-keygen", "scp ", "rsync",
"/tmp/", "/dev/shm/", "mkfifo", "socat",
]
findings = []
with open(history_path, "r", errors="ignore") as f:
lines = f.readlines()
for i, line in enumerate(lines):
line_stripped = line.strip()
for pattern in suspicious_patterns:
if pattern in line_stripped.lower():
findings.append({
"user": username,
"line_number": i + 1,
"command": line_stripped[:200],
"matched_pattern": pattern,
})
break
return findings
def check_cron_persistence(evidence_root):
"""Check cron jobs for persistence mechanisms."""
findings = []
cron_paths = [
os.path.join(evidence_root, "etc/crontab"),
*glob.glob(os.path.join(evidence_root, "etc/cron.d/*")),
*glob.glob(os.path.join(evidence_root, "var/spool/cron/crontabs/*")),
]
for cron_path in cron_paths:
if os.path.exists(cron_path) and os.path.isfile(cron_path):
with open(cron_path, "r", errors="ignore") as f:
for line in f:
line = line.strip()
if line and not line.startswith("#"):
suspicious = any(
p in line.lower()
for p in ["wget", "curl", "/tmp/", "/dev/shm/", "base64",
"python", "bash -i", "reverse", "nc ", "ncat"]
)
if suspicious:
findings.append({
"severity": "HIGH",
"source": cron_path,
"entry": line[:200],
})
return findings
def check_ssh_keys(evidence_root):
"""Check for unauthorized SSH authorized_keys."""
findings = []
key_files = glob.glob(
os.path.join(evidence_root, "home/*/.ssh/authorized_keys")
) + glob.glob(
os.path.join(evidence_root, "root/.ssh/authorized_keys")
)
for key_file in key_files:
if os.path.exists(key_file):
with open(key_file, "r") as f:
keys = [l.strip() for l in f if l.strip() and not l.startswith("#")]
if keys:
findings.append({
"file": key_file,
"key_count": len(keys),
"keys": [k[:80] + "..." for k in keys],
})
return findings
def check_systemd_persistence(evidence_root):
"""Check for suspicious systemd service files."""
findings = []
service_dirs = [
os.path.join(evidence_root, "etc/systemd/system"),
os.path.join(evidence_root, "usr/lib/systemd/system"),
]
for svc_dir in service_dirs:
if not os.path.exists(svc_dir):
continue
for svc_file in glob.glob(os.path.join(svc_dir, "*.service")):
with open(svc_file, "r", errors="ignore") as f:
content = f.read()
suspicious = any(
p in content.lower()
for p in ["/tmp/", "/dev/shm/", "wget", "curl", "reverse",
"bash -i", "nc ", "python", "base64"]
)
if suspicious:
findings.append({
"severity": "HIGH",
"file": svc_file,
"preview": content[:300],
})
return findings
def check_ld_preload(evidence_root):
"""Check for LD_PRELOAD rootkit indicators."""
findings = []
preload_path = os.path.join(evidence_root, "etc/ld.so.preload")
if os.path.exists(preload_path):
with open(preload_path, "r") as f:
content = f.read().strip()
if content:
findings.append({
"severity": "CRITICAL",
"finding": f"/etc/ld.so.preload contains: {content}",
})
return findings
def find_suid_binaries(evidence_root):
"""Find SUID/SGID binaries (potential privilege escalation)."""
result = subprocess.run(
["find", evidence_root, "-perm", "-4000", "-type", "f"],
capture_output=True, text=True, timeout=30
)
stdout = result.stdout.strip()
return stdout.splitlines() if result.returncode == 0 and stdout else []
def find_suspicious_tmp_files(evidence_root):
"""Find suspicious files in /tmp and /dev/shm."""
findings = []
for tmp_dir in ["tmp", "dev/shm"]:
full_path = os.path.join(evidence_root, tmp_dir)
if os.path.exists(full_path):
for root, dirs, files in os.walk(full_path):
for fname in files:
fpath = os.path.join(root, fname)
findings.append(fpath)
return findings
if __name__ == "__main__":
print("=" * 60)
print("Linux System Artifacts Forensics Agent")
print("User accounts, persistence, shell history, rootkit detection")
print("=" * 60)
evidence_root = sys.argv[1] if len(sys.argv) > 1 else "/mnt/evidence"
if os.path.exists(evidence_root):
print(f"\n[*] Examining evidence root: {evidence_root}")
passwd_path = os.path.join(evidence_root, "etc/passwd")
if os.path.exists(passwd_path):
print("\n--- User Account Analysis ---")
for f in analyze_passwd(passwd_path):
print(f" [{f['severity']}] {f['finding']}")
print("\n--- Cron Persistence ---")
cron = check_cron_persistence(evidence_root)
for c in cron:
print(f" [{c['severity']}] {c['source']}: {c['entry'][:80]}")
print("\n--- SSH Authorized Keys ---")
ssh = check_ssh_keys(evidence_root)
for s in ssh:
print(f" {s['file']}: {s['key_count']} keys")
print("\n--- Systemd Persistence ---")
systemd = check_systemd_persistence(evidence_root)
for s in systemd:
print(f" [{s['severity']}] {s['file']}")
print("\n--- LD_PRELOAD Rootkit Check ---")
ld = check_ld_preload(evidence_root)
for l in ld:
print(f" [{l['severity']}] {l['finding']}")
print("\n--- Suspicious Temp Files ---")
tmp = find_suspicious_tmp_files(evidence_root)
for t in tmp[:20]:
print(f" {t}")
else:
print(f"\n[DEMO] Usage: python agent.py <evidence_mount_point>")
print("[*] Mount a forensic image and provide the path for analysis.")
Related skills
How it compares
Use as a procedural security skill for Linux triage, not as a passive MCP connector that pulls telemetry automatically.
FAQ
Who is analyzing-linux-system-artifacts for?
Developers who deploy on Linux and want their coding agent to follow disciplined artifact review during security scares or audit prep, without hiring a full-time security engineer.
When should I use analyzing-linux-system-artifacts?
Use it during Ship security review before going live, in Operate when monitoring or support tickets hint at persistence or privilege abuse, and in Build when hardening a new VPS image—whenever Linux host evidence needs structured interpretation.
Is analyzing-linux-system-artifacts safe to install?
Treat it like any third-party agent skill: review the Security Audits panel on this Prism page, confirm the repo source, and avoid granting broader shell access than your investigation requires.