NetworkPersistenceAnti-forensics
/etc/hosts, nsswitch.conf and resolv.conf on Linux
Linux name resolution files as evidence: /etc/hosts redirects, resolv.conf and systemd-resolved DNS changes, and NSS module backdoors in nsswitch.conf.
- Location
- /etc/hosts, /etc/resolv.conf, /etc/nsswitch.conf, /etc/systemd/resolved.conf(.d), NSS modules in the library directory
- Proves
- Where the host sent name lookups, whether names were redirected or blocked locally, and whether an extra NSS module was inserted into user or host lookups
- Timestamps
- File system times only; systemd-resolved and NetworkManager log DNS server changes to the journal
- Access
- World-readable; root to modify
- Retention
- Persistent until edited; generated resolv.conf files are rewritten by the network stack
- Collection
- UAC, Velociraptor, cp -a, tar
Tools
Compare all tools- getentCLI · built into Linux
- resolvectlCLI · built into Linux
- grep / zgrepCLI · built into Linux
- rpmCLI · built into Linux
- dpkgCLI · built into Linux
- journalctlCLI · built into Linux
What it is
Every name lookup on Linux goes through the C library's Name Service Switch (NSS). /etc/nsswitch.conf decides which sources are consulted and in what order: files (/etc/hosts, /etc/passwd), dns (servers from /etc/resolv.conf), resolve (systemd-resolved), myhostname, sss, ldap and others. Each source is a shared library (libnss_<name>.so.2).
Attackers touch these files for three reasons: redirect names (point a bank, update server or C2 fallback at their IP via /etc/hosts), block security vendors (resolve EDR and update domains to 127.0.0.1), and persist or steal credentials by adding a malicious NSS module that every process loads for user and host lookups. Changed DNS servers also let them observe or spoof resolution for the whole host.
Where it lives
| Item | Path | Notes |
|---|---|---|
| Static hosts | /etc/hosts | Consulted before DNS with the usual hosts: files ... order |
| NSS config | /etc/nsswitch.conf | Some distros ship a vendor copy in /usr/etc/nsswitch.conf (openSUSE) or /usr/share/factory/etc/ |
| NSS modules | /usr/lib/x86_64-linux-gnu/libnss_*.so.2 (Debian), /usr/lib64/libnss_*.so.2 (RHEL, SUSE), /usr/lib/libnss_*.so.2 (Arch) | Loaded into every process that resolves names or users |
| Resolver config | /etc/resolv.conf | Often a symlink: /run/systemd/resolve/stub-resolv.conf (Ubuntu, Fedora, Arch with resolved), or a file written by NetworkManager |
| systemd-resolved | /etc/systemd/resolved.conf, /etc/systemd/resolved.conf.d/*.conf; live state /run/systemd/resolve/ | Global DNS, DNS-over-TLS, fallback servers |
| NetworkManager DNS | connection profiles, /etc/NetworkManager/conf.d/, /run/NetworkManager/resolv.conf | See NetworkManager |
| Local resolvers | /etc/dnsmasq.conf, /etc/dnsmasq.d/, /etc/unbound/ | address=/domain/IP lines redirect whole domains |
| Other | /etc/host.conf, /etc/gai.conf | Rarely changed legitimately |
What it proves
- Which names resolved to which addresses locally, regardless of DNS:
/etc/hostsentries override public records for every program that uses NSS. - That security tooling was deliberately blinded: vendor telemetry, package mirrors or threat intel domains mapped to
0.0.0.0or127.0.0.1. - Which DNS servers the host used, and whether they changed from the organization's resolvers to an attacker-controlled or public resolver.
- That an unexpected NSS source (
hosts: files evil dns,passwd: files systemd backdoor) was configured, and that its library exists. - It does not log individual lookups. Query logs only exist if a local resolver (dnsmasq, unbound, systemd-resolved with debug logging) or network sensor recorded them.
Key fields
# /etc/hosts
127.0.0.1 localhost
203.0.113.50 updates.example-vendor.com
0.0.0.0 telemetry.edr-vendor.example ingest.edr-vendor.example
# /etc/nsswitch.conf
passwd: files systemd
hosts: files myhostname resolve [!UNAVAIL=return] dns
| Item | Meaning |
|---|---|
/etc/hosts line | IP canonical-name [aliases...]; the first matching line wins |
nsswitch.conf database line | database: source [ACTION] source ...; each source maps to libnss_<source>.so.2 |
[NOTFOUND=return], [!UNAVAIL=return] style actions | Change fallthrough; can make a malicious source authoritative |
resolv.conf nameserver, search, options | DNS servers (max three), search domains, resolver options |
resolved.conf DNS=, FallbackDNS=, DNSOverTLS=, Domains=~. | Global servers and routing of all domains |
Timestamps
These are plain configuration files with only file system times. /etc/hosts on a server rarely changes after installation, so a recent mtime or ctime stands out; on cloud VMs, cloud-init may rewrite it at every boot if manage_etc_hosts is enabled, which resets the times. systemd-resolved and NetworkManager log server changes and link configuration to the journal with UTC timestamps.
Retention
Edits persist until changed. Generated resolv.conf content under /run is recreated at boot from configuration, so a live resolv.conf that differs from what the configuration would produce was changed at runtime. Package upgrades may replace a modified nsswitch.conf or leave it with a .rpmnew or .dpkg-dist beside it, which conveniently preserves both versions.
Collection
# Dead box
tar -C /mnt/evidence -cpf /cases/2026-017/nameres.tar etc/hosts etc/hosts.* etc/resolv.conf etc/nsswitch.conf* \
usr/etc/nsswitch.conf etc/host.conf etc/gai.conf etc/systemd/resolved.conf etc/systemd/resolved.conf.d \
etc/NetworkManager etc/dnsmasq.conf etc/dnsmasq.d etc/unbound 2>/dev/null
ls -la /mnt/evidence/etc/resolv.conf # record the symlink target
# Live: effective state
getent hosts updates.example-vendor.com
getent ahosts example.org
resolvectl status > /media/ir/resolvectl.txt 2>/dev/null
cp -a /run/systemd/resolve /run/NetworkManager/resolv.conf /media/ir/ 2>/dev/null
UAC collects /etc in full and runs network live-response commands. With Velociraptor, collect the files with Linux.Search.FileFinder.
Parsing
R=/mnt/evidence
grep -vE '^\s*(#|$)' "$R"/etc/hosts | grep -vE '^(127\.0\.[01]\.1|::1|fe00::|ff0[02]::)'
grep -vE '^\s*(#|$)' "$R"/etc/nsswitch.conf
# NSS sources configured versus libraries present, and ownership
grep -hoE '^\w+:.*' "$R"/etc/nsswitch.conf | tr ' ' '\n' | grep -vE ':|\[|^$' | sort -u
ls -la --time-style=full-iso "$R"/usr/lib64/libnss_* "$R"/usr/lib/x86_64-linux-gnu/libnss_* 2>/dev/null
rpm --root "$R" -V glibc 2>/dev/null; dpkg --root="$R" -V libc6 2>/dev/null
journalctl -D "$R"/var/log/journal -u systemd-resolved -u NetworkManager -g 'DNS|nameserver' -o short-iso-precise
Investigator tips
- Any
/etc/hostsentry for a public domain needs a business reason. Entries for EDR, antivirus, package mirror or OS update domains pointing to loopback are a defense-evasion indicator in their own right. - A
libnss_*.so.2that no package owns, or a source name innsswitch.confthat does not match any installed module, is as serious as an ld.so.preload hijack: everyls -l,idandsshlogin loads it. resolv.confas a regular file on a system that normally uses a symlink, orDNS=andDomains=~.in a newresolved.conf.ddrop-in, points to deliberate DNS redirection.- Compare the DNS servers here with outbound UDP/TCP 53 and 853 flows in firewall logs or network telemetry to see whether the host actually used them.
- Check
.rpmnew,.rpmsave,.dpkg-oldand.dpkg-distcopies next to each file; they are free before-and-after snapshots.
See also
Related artifacts
- NetworkManager Profiles and State: Linux Network History
- Linux Firewall Logs: iptables, nftables, ufw, firewalld
- /etc/ld.so.preload and LD_PRELOAD: Linux Linker Hijacking
- PAM Configuration and Modules: Linux Auth Backdoors
- systemd Journal: Linux Binary System Log
- cloud-init Logs and Instance Data: Linux Cloud VM Forensics