SkillAgentSearch skills...

ESNetworkMonitor

A native macOS network monitoring tool that captures socket bind and network connection events using Apple's Endpoint Security framework. This tool leverages **undocumented ES events** (RESERVED_3 through RESERVED_6) introduced in macOS 26.4 to provide real-time visibility into network activity.

Install / Use

/learn @nietzschelab/ESNetworkMonitor
About this skill

Quality Score

0/100

Category

Operations

Supported Platforms

Universal

README

ESNetworkMonitor

A native macOS network monitoring tool that captures socket bind and network connection events using Apple's Endpoint Security framework. This tool leverages undocumented ES events (RESERVED_3 through RESERVED_6) introduced in macOS 26.4 to provide real-time visibility into network activity.

Features

  • Socket Bind Monitoring: Capture when processes bind to network addresses/ports
  • Network Connection Monitoring: Track outbound connections with full endpoint details
  • Rich Process Metadata: Full process information including code signing, audit tokens, executable paths
  • JSON Output: eslogger-compatible JSON format for easy integration with SIEM/logging tools
  • Human-Readable Output: Colored terminal output for interactive monitoring
  • Reverse Engineering Mode: Raw hex dumps for further protocol analysis

Requirements

  • macOS 26.4+ (events don't exist in earlier versions)
  • System Integrity Protection (SIP) Disabled - Required because:
    • The ES client entitlement (com.apple.developer.endpoint-security.client) normally requires Apple's approval
    • With SIP disabled, ad-hoc signed binaries with this entitlement can run
  • Root privileges (sudo)

Why SIP Must Be Disabled

Apple restricts the Endpoint Security entitlement to approved developers. On a SIP-enabled system, only Apple-notarized apps with the proper provisioning profile can use ES. Disabling SIP allows:

  • Ad-hoc code signing (codesign -s "-")
  • Self-assigned ES entitlements
  • Running unsigned/locally-signed ES clients

Building

make release

This will:

  1. Compile with optimizations (-O2)
  2. Sign with ad-hoc signature and ES entitlements
  3. Output binary to build/ESNetworkMonitor

Build Requirements

  • Xcode Command Line Tools
  • macOS 14.0+ SDK (for ES framework headers)

Usage

Basic Monitoring (Human-Readable)

sudo ./build/ESNetworkMonitor

Output:

[SOCKET BIND AUTH]
  Process: /usr/sbin/mDNSResponder (PID: 197)
  UID: 65 | Platform Binary: Yes
  Socket Type: DGRAM (UDP)
  Protocol: UDP (17)
  Address Family: IPv6 (30)
  Bind Address: ::
  Bind Port: 5353 (0x14e9)

[NETWORK CONNECTION NOTIFY]
  Process: /usr/bin/curl (PID: 1234)
  UID: 501 | Platform Binary: Yes
  Local: port 0 (IPv4)
  Remote: 93.184.216.34:80 (IPv4)
  Direction: Outbound
  Protocol: TCP (6)
  Hostname: example.com

JSON Output (eslogger-compatible)

sudo ./build/ESNetworkMonitor -j

Output (one JSON object per line):

{"schema_version":1,"version":10,"event_type":"network_connect","mach_time":147441608386,"seq_num":4,"global_seq_num":12,"time":"2026-04-01T14:18:45.636230Z","action_type":"auth","thread":{"thread_id":44438},"process":{"audit_token":[501,501,20,501,20,2273,100106,6120],"ppid":1795,"signing_id":"com.apple.curl","executable":{"path":"/usr/bin/curl","stat":{...}},...},"event":{"network_connect":{"remote":{"address":"104.18.27.120","port":80},"hostname":"example.com",...}}}

Pipe to jq for pretty printing:

sudo ./build/ESNetworkMonitor -j | jq .

Verbose/Debug Modes

# Field analysis (shows struct offsets and values)
sudo ./build/ESNetworkMonitor -v

# Hex dumps of event structures
sudo ./build/ESNetworkMonitor -d

# Raw dump mode for reverse engineering (no parsing)
sudo ./build/ESNetworkMonitor -r -s 2048

All Options

Usage: sudo ./ESNetworkMonitor [options]

Options:
  -j, --json         Output eslogger-compatible JSON (one event per line)
  -d, --dump         Enable hex dump of raw event data
  -v, --verbose      Enable verbose field analysis
  -r, --raw          Raw dump only (no parsing, for RE)
  -s, --size <bytes> Set dump size in bytes (default: 512, max: 4096)
  -h, --help         Show this help

Event Types

This tool subscribes to four undocumented Endpoint Security events:

| Event ID | Name | Type | Description | |----------|------|------|-------------| | 151 | ES_EVENT_TYPE_RESERVED_3 | AUTH | Socket bind authorization request | | 152 | ES_EVENT_TYPE_RESERVED_4 | NOTIFY | Socket bind notification | | 153 | ES_EVENT_TYPE_RESERVED_5 | AUTH | Network connection authorization request | | 154 | ES_EVENT_TYPE_RESERVED_6 | NOTIFY | Network connection notification |

AUTH events require a response (allow/deny) - this tool always allows. NOTIFY events are informational only.

JSON Schema

The JSON output follows eslogger conventions:

{
  "schema_version": 1,
  "version": 10,
  "event_type": "network_connect",
  "mach_time": 147441608386,
  "seq_num": 4,
  "global_seq_num": 12,
  "time": "2026-04-01T14:18:45.636230Z",
  "action_type": "auth",
  "thread": {
    "thread_id": 44438
  },
  "process": {
    "audit_token": [501, 501, 20, 501, 20, 2273, 100106, 6120],
    "ppid": 1795,
    "original_ppid": 1795,
    "group_id": 2273,
    "session_id": 1795,
    "codesigning_flags": "0x26010801",
    "is_platform_binary": true,
    "is_es_client": false,
    "cdhash": "ad8b678c04af7b1407ff718998e403342e75c1d4",
    "signing_id": "com.apple.curl",
    "team_id": "",
    "executable": {
      "path": "/usr/bin/curl",
      "path_truncated": false,
      "stat": { "st_dev": 16777231, "st_ino": 1152921500312571174, "..." }
    },
    "tty": { "path": "/dev/ttys003", "..." },
    "start_time": "2026-04-01T14:18:45.587689Z",
    "responsible_audit_token": [501, 0, 0, 0, 0, 1790, 100106, 4798],
    "parent_audit_token": [501, 501, 20, 501, 20, 1795, 100106, 4804]
  },
  "action": {
    "result": {
      "result_type": "auth",
      "result": { "auth": "pending" }
    }
  },
  "event": {
    "network_connect": {
      "local": { "address_family": 2, "port": 0 },
      "remote": { "address_family": 2, "address": "104.18.27.120", "port": 80 },
      "direction": 0,
      "protocol": 6,
      "socket_type": 1,
      "hostname": "example.com"
    }
  }
}

Reverse Engineering Notes

The event structures were reverse-engineered from:

Socket Bind Event Structure (RESERVED_3/4)

es_event_socket_bind_t (+0x00)
└── inner_ptr (+0x00) -> es_socket_bind_inner_t
    ├── addr_ptr (+0x00) -> es_socket_bind_addr_t
    │   ├── family (+0x00): uint32 (AF_INET=2, AF_INET6=30)
    │   ├── addr (+0x04): 16 bytes (IPv4 or IPv6)
    │   └── port (+0x14): uint32
    ├── socket_type (+0x0c): uint32 (0=STREAM, 1=DGRAM)
    └── protocol (+0x10): uint32 (6=TCP, 17=UDP)

Network Connection Event Structure (RESERVED_5/6)

es_event_network_connect_t (+0x00)
├── local_family (+0x00): uint32
├── local_port (+0x14): uint32
├── remote_family (+0x18): uint32
├── remote_addr (+0x1c): 16 bytes
├── remote_port (+0x2c): uint32
├── direction (+0x30): uint32 (0=outbound)
├── protocol (+0x34): uint32
├── socket_type (+0x38): uint32
├── hostname_len (+0x40): uint32
├── hostname_ptr (+0x48): pointer
└── hostname (+0x50): char[256]

Security Considerations

  • This tool requires SIP disabled and root access - use only on test/research systems
  • AUTH events are auto-allowed - this tool is for monitoring, not firewalling
  • JSON output may contain sensitive information (hostnames, IPs, process paths)

License

MIT License - See LICENSE file.

Acknowledgments

Related Skills

View on GitHub
GitHub Stars6
CategoryOperations
Updated14h ago
Forks1

Languages

Objective-C

Security Score

85/100

Audited on Apr 2, 2026

No findings