Skip to content

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
  • 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

ItemPathNotes
Static hosts/etc/hostsConsulted before DNS with the usual hosts: files ... order
NSS config/etc/nsswitch.confSome 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.confOften 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 DNSconnection profiles, /etc/NetworkManager/conf.d/, /run/NetworkManager/resolv.confSee NetworkManager
Local resolvers/etc/dnsmasq.conf, /etc/dnsmasq.d/, /etc/unbound/address=/domain/IP lines redirect whole domains
Other/etc/host.conf, /etc/gai.confRarely changed legitimately

What it proves

  • Which names resolved to which addresses locally, regardless of DNS: /etc/hosts entries 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.0 or 127.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
ItemMeaning
/etc/hosts lineIP canonical-name [aliases...]; the first matching line wins
nsswitch.conf database linedatabase: source [ACTION] source ...; each source maps to libnss_<source>.so.2
[NOTFOUND=return], [!UNAVAIL=return] style actionsChange fallthrough; can make a malicious source authoritative
resolv.conf nameserver, search, optionsDNS 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/hosts entry 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.2 that no package owns, or a source name in nsswitch.conf that does not match any installed module, is as serious as an ld.so.preload hijack: every ls -l, id and ssh login loads it.
  • resolv.conf as a regular file on a system that normally uses a symlink, or DNS= and Domains=~. in a new resolved.conf.d drop-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-old and .dpkg-dist copies next to each file; they are free before-and-after snapshots.

See also