{"id":49182267,"url":"https://github.com/franckferman/hidemylogs","last_synced_at":"2026-04-23T02:01:12.951Z","repository":{"id":347688046,"uuid":"1194918649","full_name":"franckferman/hidemylogs","owner":"franckferman","description":"Surgical Linux log cleaner - selectively erase access records from lastlog, wtmp, btmp, and utmp while preserving file metadata.","archived":false,"fork":false,"pushed_at":"2026-03-29T02:40:55.000Z","size":24,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"stable","last_synced_at":"2026-03-29T04:29:53.133Z","etag":null,"topics":["advanced-threat-hunting","btmp","clean-logs","lastlog","linux","linux-cleaner","linux-logrotate","linux-logs","log-cleaner","opsec","opsec-safe","opsec-toolkit","opsectoolkit","redteam","redteaming","security","security-tools","utmp","wipe-files","wtmp"],"latest_commit_sha":null,"homepage":"https://github.com/franckferman/hidemylogs","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/franckferman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-29T01:29:24.000Z","updated_at":"2026-03-29T02:40:57.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/franckferman/hidemylogs","commit_stats":null,"previous_names":["franckferman/hidemylogs"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/franckferman/hidemylogs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franckferman%2Fhidemylogs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franckferman%2Fhidemylogs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franckferman%2Fhidemylogs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franckferman%2Fhidemylogs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/franckferman","download_url":"https://codeload.github.com/franckferman/hidemylogs/tar.gz/refs/heads/stable","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franckferman%2Fhidemylogs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32162611,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-22T17:06:48.269Z","status":"online","status_checked_at":"2026-04-23T02:00:06.710Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["advanced-threat-hunting","btmp","clean-logs","lastlog","linux","linux-cleaner","linux-logrotate","linux-logs","log-cleaner","opsec","opsec-safe","opsec-toolkit","opsectoolkit","redteam","redteaming","security","security-tools","utmp","wipe-files","wtmp"],"created_at":"2026-04-23T02:01:11.760Z","updated_at":"2026-04-23T02:01:12.943Z","avatar_url":"https://github.com/franckferman.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# hidemylogs\n\n**Surgical \\*nix log cleaner** - selectively erase access records from lastlog, wtmp, btmp, and utmp while preserving file metadata.\n\n[![Stars](https://img.shields.io/github/stars/franckferman/hidemylogs?style=flat-square\u0026color=c0392b)](https://github.com/franckferman/hidemylogs/stargazers)\n![](https://img.shields.io/badge/Rust-CE422B?style=flat-square\u0026logo=rust\u0026logoColor=white)\n![](https://img.shields.io/badge/License-AGPL--3.0-blue?style=flat-square)\n\n\u003c/div\u003e\n\n---\n\n## Overview\n\nhidemylogs is a modern Rust rewrite of [hidemyass](https://github.com/evilpan/hidemyass) (2016). It removes individual log records from Linux authentication databases without deleting the entire file, preserving file permissions, ownership, and timestamps.\n\nThree subcommands:\n- **`print`** - Read and display records from utmp, wtmp, btmp, and lastlog\n- **`wipe`** - Remove records matching a username, IP, or time range filter\n- **`forge`** - Overwrite a lastlog record with a fake timestamp, terminal, and host\n\nAll operations support `--dry-run` to preview changes without modifying files.\n\n---\n\n## How It Works\n\n### What gets modified\n\nLinux tracks authentication events across four binary databases:\n\n| File | Format | Content | Read by |\n|---|---|---|---|\n| `/var/run/utmp` | struct utmp (384 B) | Currently logged-in users | `who`, `w`, `finger` |\n| `/var/log/wtmp` | struct utmp (384 B) | Full login/logout history | `last` |\n| `/var/log/btmp` | struct utmp (384 B) | Failed login attempts | `lastb` |\n| `/var/log/lastlog` | struct lastlog (292 B) | Last login per UID | `lastlog` |\n\nhidemylogs operates directly on these binary files using `struct` layouts, reading and rewriting individual records without shell commands or external tools.\n\n**`wipe`** removes matching records from utmp/wtmp/btmp by reconstructing the file without them. For lastlog, it zeroes the record at the target UID offset.\n\n**`forge`** overwrites a specific lastlog record at `offset = UID * 292` with attacker-supplied timestamp, terminal, and hostname.\n\n### File metadata preservation\n\nAfter writing, hidemylogs restores the original `atime` and `mtime` using `utimensat`. This prevents file integrity monitors from flagging the modification based on timestamp change alone. The file size changes only if records are removed from utmp/wtmp/btmp (inevitable when deleting records from a sequential file).\n\n### Why Rust, not a shell script\n\nThis is a deliberate OPSEC choice:\n\n| Aspect | Shell script / Python | Compiled binary |\n|---|---|---|\n| **Command history** | Every `sed`, `dd`, `truncate` logged in `.bash_history` | Single `execve` in history |\n| **auditd trace** | Multiple syscalls per operation, each logged separately | One process, direct `read`/`write`/`lseek` syscalls |\n| **Process visibility** | `ps` shows `python3 cleaner.py --ip 1.2.3.4` in cleartext | `ps` shows `hidemylogs` only (args visible but no interpreter) |\n| **Disk artifacts** | Script file persists on disk (`.py`, `.sh`) | Binary can run from `/dev/shm` (tmpfs) and be deleted |\n| **Dependencies** | Requires Python/Bash interpreter on target | musl build: zero runtime deps, drop and run |\n\nA compiled binary reduces the forensic footprint to a single `execve` syscall. No interpreter spawning, no child processes, no shell built-in logging. The musl-linked static binary can be deployed to `/dev/shm`, executed, and removed - leaving no file on persistent storage.\n\n### MITRE ATT\u0026CK\n\n| Technique | ID | Relevance |\n|---|---|---|\n| Indicator Removal: Clear Linux or Mac System Logs | T1070.002 | Direct purpose of the tool |\n| Indicator Removal: Timestomp | T1070.006 | `forge` modifies lastlog timestamps |\n| Indicator Removal: Clear Command History | T1070.003 | Binary execution avoids shell history artifacts |\n\n---\n\n## Build\n\n```bash\ngit clone https://github.com/franckferman/hidemylogs.git\ncd hidemylogs\ncargo build --release\n```\n\nBinary: `target/release/hidemylogs` (~600 KB, optimized + stripped).\n\nPre-built binaries for x86_64 (glibc), x86_64 (musl/static), and aarch64 are available in [Releases](https://github.com/franckferman/hidemylogs/releases). The musl build has zero runtime dependencies - drop and run on any Linux.\n\n---\n\n## Test Samples\n\nSample log files are included for safe testing without touching system logs:\n\n```bash\n# Generate samples (or use the pre-built ones in samples/)\npython3 scripts/generate_samples.py\n\n# Print all sources from the compromised scenario\n./hidemylogs print \\\n  -u samples/compromised.utmp \\\n  -w samples/compromised.wtmp \\\n  -b samples/compromised.btmp \\\n  -l samples/compromised.lastlog\n\n# Dry-run wipe of attacker IP\n./hidemylogs wipe \\\n  -w samples/compromised.wtmp \\\n  -b samples/compromised.btmp \\\n  -a 185.220.101.34 \\\n  -s wb --dry-run\n```\n\nThe scenario simulates: brute force from Tor exit node, root compromise, backdoor account, lateral movement.\n\n---\n\n## Usage\n\n### `print` - Display log records\n\n```\nhidemylogs print [OPTIONS]\n\nOptions:\n  -u, --utmp \u003cPATH\u003e        utmp file     [default: /var/run/utmp]\n  -w, --wtmp \u003cPATH\u003e        wtmp file     [default: /var/log/wtmp]\n  -b, --btmp \u003cPATH\u003e        btmp file     [default: /var/log/btmp]\n  -l, --lastlog \u003cPATH\u003e     lastlog file  [default: /var/log/lastlog]\n  -s, --sources \u003cSOURCES\u003e  Sources to display: u/w/b/l or any combination [default: uwbl]\n```\n\n```bash\n# All sources\nsudo ./hidemylogs print\n\n# Only wtmp and lastlog\nsudo ./hidemylogs print -s wl\n\n# Only btmp (failed logins)\nsudo ./hidemylogs print -s b\n\n# Custom paths\n./hidemylogs print -w /path/to/wtmp -l /path/to/lastlog -s wl\n```\n\n### `wipe` - Remove matching records\n\n```\nhidemylogs wipe [OPTIONS]\n\nOptions:\n  -u, --utmp \u003cPATH\u003e        utmp file     [default: /var/run/utmp]\n  -w, --wtmp \u003cPATH\u003e        wtmp file     [default: /var/log/wtmp]\n  -b, --btmp \u003cPATH\u003e        btmp file     [default: /var/log/btmp]\n  -l, --lastlog \u003cPATH\u003e     lastlog file  [default: /var/log/lastlog]\n  -s, --sources \u003cSOURCES\u003e  Sources to wipe [default: uwbl]\n  -n, --name \u003cUSER\u003e        Filter by username\n  -a, --address \u003cIP\u003e       Filter by IP/hostname\n  -t, --time \u003cRANGE\u003e       Filter by time range (HH:MM-HH:MM)\n      --and                All filters must match (default: any matches)\n      --dry-run            Preview without modifying files\n```\n\n```bash\n# Always dry-run first\nsudo ./hidemylogs wipe -a 185.220.101.34 --dry-run\n\n# Wipe all records from an IP\nsudo ./hidemylogs wipe -a 185.220.101.34\n\n# Wipe by username\nsudo ./hidemylogs wipe -n root\n\n# Wipe only from wtmp and btmp\nsudo ./hidemylogs wipe -a 185.220.101.34 -s wb\n\n# Wipe by time range (all records between 03:00 and 04:00)\nsudo ./hidemylogs wipe -t 03:00-04:00\n\n# AND filter: IP + time range must both match\nsudo ./hidemylogs wipe -a 185.220.101.34 -t 03:00-04:00 --and\n\n# OR filter (default): matches name OR address\nsudo ./hidemylogs wipe -n root -a 185.220.101.34\n\n# AND filter: must be root AND from that IP\nsudo ./hidemylogs wipe -n root -a 185.220.101.34 --and\n```\n\nAfter wiping, file atime and mtime are restored to their original values.\n\n### `forge` - Fake a lastlog entry\n\n```\nhidemylogs forge [OPTIONS] --uid \u003cUID\u003e --time \u003cTIME\u003e\n\nOptions:\n  -l, --lastlog \u003cPATH\u003e     lastlog file  [default: /var/log/lastlog]\n      --uid \u003cUID\u003e          Target UID\n  -t, --time \u003cTIME\u003e        Fake timestamp (YYYY-MM-DD HH:MM:SS)\n      --line \u003cTTY\u003e         Fake terminal  [default: pts/0]\n      --host \u003cHOST\u003e        Fake hostname/IP [default: \"\"]\n      --dry-run            Preview without modifying\n```\n\n```bash\n# Fake root's last login to look like a normal admin session\nsudo ./hidemylogs forge --uid 0 -t \"2026-03-15 09:30:00\" --line pts/0 --host 10.0.1.50\n\n# Preview\nsudo ./hidemylogs forge --uid 0 -t \"2026-03-15 09:30:00\" --dry-run\n```\n\n### Global flags\n\n```bash\n# Suppress banner (scripting/pipelines)\nsudo ./hidemylogs -q wipe -a 185.220.101.34\n\n# Version\n./hidemylogs --version\n```\n\n---\n\n## Why hidemylogs\n\nModern rewrite of [hidemyass](https://github.com/evilpan/hidemyass) (2016, unmaintained).\n\n|  | hidemyass | hidemylogs |\n|---|---|---|\n| **Language** | C (manual memory) | Rust (memory safe) |\n| **Last update** | 2017 | Active |\n| **CLI** | Flags only (`-uwbl -p -c`) | Subcommands (`print`, `wipe`, `forge`) |\n| **Preview before action** | No | `--dry-run` on everything |\n| **Filter by time** | No | `-t 03:00-04:00` |\n| **Filter logic** | OR only | `--and` / OR |\n| **Lastlog forge** | Timestamp only | Timestamp + terminal + host |\n| **File timestamps** | atime/ctime preserved | atime + mtime preserved |\n| **Scripting** | No | `-q` suppresses banner |\n| **Test samples** | No | Included scenario with all log types |\n| **Cross-compile** | Manual | CI builds x86_64, aarch64, musl |\n\n---\n\n## Defensive context\n\nThis tool exists to demonstrate what attackers can do post-exploitation. For defenders:\n\n- **Remote log forwarding** (rsyslog, syslog-ng) is the only reliable defense\n- **File integrity monitoring** (AIDE, Tripwire) detects modifications to log files\n- **Cross-source correlation** reveals discrepancies when one source is tampered but not others\n- **[LastLog-Audit](https://github.com/franckferman/LastLog-Audit)** is the detection counterpart to this tool - it parses lastlog, wtmp, and auth.log, cross-references all three sources, and includes a [forensic training lab](https://franckferman.github.io/LastLog-Audit/learn.html) with 9 attack scenarios\n\n---\n\n## Legal Disclaimer\n\nThis tool is provided for **authorized security assessments, red team engagements, and educational purposes only**. Unauthorized modification of system logs is illegal. You are solely responsible for your use of this tool.\n\n---\n\n## License\n\nAGPL-3.0. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffranckferman%2Fhidemylogs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffranckferman%2Fhidemylogs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffranckferman%2Fhidemylogs/lists"}