Skip to content

NetworkExecution

netusage.sqlite: macOS Per-Process Network Usage

netusage.sqlite records which processes used the network on a Mac, with first and last seen times and bytes over Wi-Fi, wired and cellular links.

Location
/private/var/networkd/db/netusage.sqlite
Proves
That a process used the network, when it was first and last seen, how much data it moved per interface type, and which networks the Mac attached to
Timestamps
Mac absolute time (seconds since 2001-01-01 UTC)
Access
root; the networkd folder is protected, collect with Full Disk Access or from an image
Retention
Rows persist for long periods; counters are cumulative and records are pruned by networkd on its own schedule
Collection
mac_apt, ditto, Disk image

What it is

networkd keeps a Core Data SQLite database of network usage per process and per network attachment. It is the closest macOS counterpart to the Windows SRUM network usage table: a record, independent of the Unified Logs, that a named process exchanged data, with running totals of bytes in and out.

For intrusions, it answers questions that are hard to answer otherwise: did this unsigned binary ever talk to the network, and roughly how much did it send?

Where it lives

VersionPath
10.15 Catalina and earlier/private/var/networkd/netusage.sqlite
11 Big Sur and later/private/var/networkd/db/netusage.sqlite

Collect the -wal and -shm files with the database: recent rows are often still in the write-ahead log. On a dead-box image look under /System/Volumes/Data/private/var/networkd/.

What it proves

  • A process (by name, sometimes with bundle identifier) used the network at least once, with the first and last time networkd saw it.
  • Cumulative bytes in and out, split by Wi-Fi, wired and cellular (WWAN).
  • The networks the Mac attached to (ZNETWORKATTACHMENT), with first and last seen times, which complements Wi-Fi networks.

It does not record destinations: no IP addresses, domains or ports. Pair it with the Unified Logs, proxy or firewall logs for that.

Key fields

TableColumnsMeaning
ZPROCESSZPROCNAME, ZBUNDLENAMEProcess name, bundle ID when known
ZPROCESSZFIRSTTIMESTAMP, ZTIMESTAMPFirst seen, last seen
ZLIVEUSAGEZHASPROCESSForeign key to ZPROCESS.Z_PK
ZLIVEUSAGEZWIFIIN, ZWIFIOUT, ZWIREDIN, ZWIREDOUT, ZWWANIN, ZWWANOUTBytes per interface type
ZLIVEUSAGEZTIMESTAMPTime of the usage record
ZNETWORKATTACHMENTZIDENTIFIER, ZFIRSTTIMESTAMP, ZTIMESTAMPNetwork identity and seen times
ZLIVEROUTEPERFZBYTESIN, ZBYTESOUT, ZTIMESTAMPPer-network route statistics
Z_PRIMARYKEYZ_NAMEEntity name for each Z_ENT

Column sets change between releases. Check PRAGMA table_info(ZPROCESS); before trusting a saved query.

Timestamps

All timestamps are Mac absolute time. Add 978307200 to get Unix time. Byte counters are cumulative over the life of the row, not per session: two snapshots of the database taken at different times (for example live and from an APFS snapshot) are needed to measure activity in between.

Retention

networkd keeps rows for a long time, often months, but prunes on its own logic and version-dependent limits, which are not documented. A process that used the network once and was then deleted from disk can still be listed, which is the main value of this source.

Collection

sudo ditto /private/var/networkd/db ./case/networkd_db

The Terminal or collector needs Full Disk Access on current releases. mac_apt NETUSAGE copies and parses the database; APOLLO ships netusage_zprocess, netusage_zliveusage and netusage_zliverouteperf modules.

Parsing

-- Processes with traffic, newest first
SELECT p.ZPROCNAME,
       datetime(p.ZFIRSTTIMESTAMP + 978307200, 'unixepoch') AS first_seen_utc,
       datetime(p.ZTIMESTAMP      + 978307200, 'unixepoch') AS last_seen_utc,
       lu.ZWIFIIN, lu.ZWIFIOUT, lu.ZWIREDIN, lu.ZWIREDOUT
FROM ZPROCESS p
LEFT JOIN ZLIVEUSAGE lu ON lu.ZHASPROCESS = p.Z_PK
ORDER BY p.ZTIMESTAMP DESC;
python3 mac_apt.py -o out E01 image.E01 NETUSAGE
python3 apollo.py extract -o sql -p apple -v 10.15 -k modules ./case

APOLLO module queries are version-scoped, and its version list stops at older releases (10.15 / 10.16 for macOS). On newer images the queries usually still run, but check the schema first or use the SQL above.

Investigator tips

  • Sort by ZFIRSTTIMESTAMP around the suspected intrusion time: new process names appearing for the first time are strong leads.
  • Unusual names (random strings, names imitating Apple daemons, interpreters such as python3, osascript or curl) with large outbound totals deserve a look in launch agents and daemons and the Unified Logs.
  • A high OUT versus IN ratio for a non-backup process suggests upload or exfiltration; confirm with other sources before asserting it.
  • Browsers, cloud sync clients and update agents dominate totals; filter them before reviewing.

See also