Your hosts, on the same stream.
BetaThe TillTell agent reports what happens on your Linux, macOS and Windows hosts: processes started, sign-ins, privilege use, new accounts and admins, persistence, SSH keys, kernel modules, listening ports, cleared logs and defences turned off. Those events join the security stream every Till product writes, so TillTell rules, TillHunt, incidents and the coverage map read them like any other source. It runs in user mode on each OS’s own event sources, with no kernel driver. From TillShield you can end a process on a host or cut the host off the network. Manage hosts under Shield → Endpoints.
One command per host
Make an enrolment token under Shield → Endpoints, then on each host run, as root:
curl -fsSL https://tilldev.dev/downloads/tell-agent/install.sh | sudo shOn Windows, in PowerShell run as Administrator:
irm https://tilldev.dev/downloads/tell-agent/install.ps1 | iexThe installer:
- Picks this host’s build: Linux, macOS or Windows, on x86-64 or ARM64.
- Checks the release’s signed checksum list against the release key built into the installer, then the binary against that list. If either check fails it installs nothing.
- Installs the agent to
/usr/local/binorProgram Files\TillTell, asks for the token without echoing it, enrols the host and starts the service. - Prints the host key’s fingerprint, which you compare when you approve the host.
Running it again upgrades the agent and keeps the enrolment. Linux and macOS need curl and ssh-keygen. Windows needs ssh-keygen too, from the OpenSSH Client optional feature. TELL_AGENT_VERSION pins a version and, on Linux and macOS, TELL_AGENT_DIR installs somewhere else.
Without a prompt
For images and configuration management, give the token in a file instead:
# Linux and macOS: the token in a file only root can read
curl -fsSL https://tilldev.dev/downloads/tell-agent/install.sh -o install.sh
sudo TELL_ENROLL_TOKEN_FILE=/root/tell-token sh install.sh
# Windows, elevated PowerShell
$env:TELL_ENROLL_TOKEN_FILE = 'C:\secure\tell-token'
irm https://tilldev.dev/downloads/tell-agent/install.ps1 | iexTELL_ENROLL_TOKEN works too, but a variable can leak into process listings and logs where a file does not.
Checking a release by hand
The same checks the installer makes, for a host where you place the binary yourself. Each release lists its six builds in SHA256SUMS, signed with the release key:
v=$(curl -fsSL https://tilldev.dev/downloads/tell-agent/LATEST)
f=tell-agent_${v}_linux_amd64
curl -fsSLO https://tilldev.dev/downloads/tell-agent/allowed_signers
curl -fsSLO https://tilldev.dev/downloads/tell-agent/$v/SHA256SUMS
curl -fsSLO https://tilldev.dev/downloads/tell-agent/$v/SHA256SUMS.sig
curl -fsSLO https://tilldev.dev/downloads/tell-agent/$v/$f
ssh-keygen -Y verify -f allowed_signers -I releases@tilldev.dev -n tell-agent-release -s SHA256SUMS.sig < SHA256SUMS
grep " $f\$" SHA256SUMS | sha256sum -c -On macOS, use shasum -a 256 -c - for the last line.
Tokens and approval
A host enrols with a single-purpose enrolment token. On first enrolment it makes its own Ed25519 key, which never leaves the host, and every later request is signed with it. The server takes the workspace and host from that key, never from what an event claims.
| Token setting | Means |
|---|---|
| Shown once | Only a short hint of it is kept. Lose it and make another. |
| Expiry | 1 to 365 days; 30 by default. |
| Hosts it can enrol | Unlimited, or 1 to 100,000. |
| Approval | By a person by default. A token made to approve on its own adds hosts that report straight away. |
| Live tokens | Up to 50 per workspace. |
A host enrolled with a token that needs approval waits under Shield → Endpoints. It keeps collecting into its local spool and sends nothing until an owner or admin types the fingerprint the host printed. A fingerprint that doesn’t match is refused, so get it from the host itself:
sudo tell-agent enroll --token - # paste the token; it is read from stdin
sudo tell-agent install # register and start the service
sudo tell-agent fingerprint # compare this before approving the host
sudo tell-agent check # permissions, enrolment, a signed session, clock, service, collectors
sudo tell-agent status # what the running agent last reportedAutomatic approval suits machines you build yourself. Anyone holding such a token can add a host, so give it a host limit and a short expiry. Revoking a token stops it enrolling more hosts. Hosts it already enrolled keep reporting. The same steps run from the CLI: tilldev shield endpoints tokens create, tilldev shield endpoints approve.
What each OS reports
| Event | Linux | macOS | Windows |
|---|---|---|---|
host.process_started | Every process, from the kernel’s process connector | Endpoint Security when entitled; otherwise a 2-second poll, shown degraded | Sysmon event 1 when Sysmon is installed; otherwise Security 4688 |
host.login, host.login_failed | SSH and console, from journald or the auth log | SSH, console and Screen Sharing; failed local password checks with Endpoint Security | Security 4624 and 4625, with logon type and source address |
host.privilege_used | sudo and su | sudo and su | — |
host.user_created, host.user_deleted | Accounts file poll | Directory Services poll, or Endpoint Security | Security 4720 and 4726 |
host.group_member_added | Group file poll; admin-equivalent groups flagged | Directory Services; admin and wheel flagged | Security 4728, 4732 and 4756; administrator-equivalent groups flagged |
host.group_member_removed | Group file poll | Directory Services poll | — |
host.persistence_added, host.persistence_changed | systemd units, cron and at, rc.local, init scripts, ld.so.preload, shell profiles, autostart | Launch daemons and agents, background items, startup items, cron, at and periodic jobs, shell profiles | Startup folders, scheduled tasks, Run and RunOnce keys, services installed |
host.ssh_key_added | Every authorized_keys file sshd reads | Every authorized_keys file sshd reads | Each user’s authorized_keys and administrators_authorized_keys |
host.kernel_module_loaded | Loaded modules, with taint flags | Kernel extensions | — |
host.listener_opened | TCP and UDP, with the owning process | TCP and UDP, with the owning process | TCP and UDP, with the owning process |
host.log_cleared | Auth, system, login-record and audit logs emptied, deleted or swapped | — | Security log cleared (1102), any log cleared (104) |
host.defense_changed | SELinux, AppArmor, the firewall | Firewall, Gatekeeper, System Integrity Protection, FileVault | Firewall per profile, Defender real-time and tamper protection, audit policy |
host.malware_detected | — | XProtect, with Endpoint Security | Defender detections (1116, 1117) |
host.credential_access | — | — | A process opening LSASS, with Sysmon |
File, account, module and listener changes are found by comparing against a baseline every 30 seconds, so the first pass reports nothing and a restart doesn’t report again. A change the logs and a poller both see is reported once. Process starts are capped at 1,500 a minute per host; past that they are counted, not sent. Very short-lived processes can exit before a polling collector reads them, and those are counted too.
macOS and Endpoint Security
Apple’s Endpoint Security framework is the full-fidelity source on macOS. Using it needs Apple’s entitlement, root and Full Disk Access, and only a release signed with the entitlement includes it. Every other build polls the process table, reads the unified log for sign-ins, sudo and su, and shows the process collector as degraded with the reason.
Windows and Sysmon
The agent runs as a service under LocalSystem and reads the event logs, registry and socket tables through Windows’ own interfaces, so it works the same in any system language. Sysmon, if installed when the agent starts, adds binary hashes, LSASS reads and the process behind Run key writes.
Degraded collectors and how to fix them
Every collector is live, degraded or off on each host, with the reason. Open a host under Shield → Endpoints, or run tell-agent check on it. A degraded collector names the command that fixes it:
| Reason | Fix |
|---|---|
| Windows: an audit subcategory is off, such as Process Creation or Logon | The auditpol /set command the host shows, or the same setting in Group Policy under Advanced Audit Policy Configuration. |
| Windows: process command lines are off | Set ProcessCreationIncludeCmdLine_Enabled to 1, or enable “Include command line in process creation events” in Group Policy. |
| Windows: a log is disabled | The wevtutil sl … /e:true command the host shows. Task Scheduler’s operational log is off by default. |
| Linux: process connector unavailable | Run the agent as root outside a container. Without CAP_NET_ADMIN it polls and misses short-lived processes. |
| macOS: no Endpoint Security client | Shown on every build without the entitlement; a Mac also refuses one without root or Full Disk Access. |
Each host also shows its counters: events spooled, sent and rejected, and every drop by cause. A host that misses 30 minutes of check-ins shows as silent. The server records that as its own event, and again when the host comes back, so a rule can act on an agent going quiet.
Ending a process and isolating a host
From a host under Shield → Endpoints, the CLI or a playbook, an owner or admin can end a process on the host or isolate it. Each is a command TillShield signs for that one host. The agent checks the signature, that the command names this host and that it hasn’t lapsed before it acts, runs each command once, and reports what happened. An online agent picks a command up within about a minute.
| Command | What the agent does | Lapses if not taken |
|---|---|---|
| End a process | Ends the process only if the PID still runs the binary you name, so a PID the system has reused is left alone. | 15 minutes |
| Isolate | Blocks all traffic, connections already open included, except loopback, DHCP, the agent’s link to TillShield and any networks you leave open. | 1 day |
| Release | Removes the block. | 7 days |
tilldev shield endpoints isolate <endpoint-id> --reach 10.0.8.0/24 --for 4h
tilldev shield endpoints release <endpoint-id>
tilldev shield endpoints kill <endpoint-id> 4312 /tmp/.x/miner
tilldev shield endpoints commands <endpoint-id>
tilldev shield endpoints --status isolated- An isolated host keeps reporting, so you can watch it and release it from TillShield. Up to 16 more addresses or networks can stay open, none wider than a /8, or a /16 for IPv6.
- An isolation can lift by itself after 5 minutes to 30 days. The agent lifts it on time even if the host can’t reach TillShield. Without a time, it holds until released.
- The block is kept in place. The agent checks it every 30 seconds and puts back rules that were removed. It uses nftables, or iptables where nftables is missing, on Linux; a pf anchor on macOS; and Windows Filtering Platform filters on Windows. On Windows the block holds through a restart; on Linux and macOS the agent puts it back when it starts.
- Lifted on the host, it is reported. Someone with administrator rights on the host can lift it with the command below. If the agent reports the host open again with no release sent, TillShield records it as a server-observed event, which the library rule “Host isolation lifted on the host” reads.
- Revoking an isolated host lifts its isolation once the agent learns it is revoked, and commands the host hasn’t taken are called back. A command still waiting can be called back by hand.
sudo tell-agent isolation # whether this host is isolated, and until when
sudo tell-agent isolation release # lift it on the host, without TillShieldRevoking and removing a host
Revoking a host refuses its events at once, or within 10 minutes at most, and refuses its next check-in. The agent then stops for good and doesn’t start again with the same key. To bring the host back, enrol it with a new key and a token:
sudo tell-agent enroll --new-key --token -Removing deletes a pending or revoked host’s record. Its events stay in the stream for the workspace’s retention. A pending host that is removed stops too. tell-agent uninstall removes the service and leaves the key, enrolment and spool in the data directory.
What leaves the host
- Secrets are scrubbed on the host before anything is spooled: passwords and tokens after their flag or name, bearer and basic credentials, credentials in URLs, known token formats and private key blocks. Run
tell-agent previewto see each event exactly as it would be sent, without enrolling or sending anything. - Everything the agent reports is client-reported. An agent on a host an attacker owns can be made to lie, so most rules that read host events suggest notifying people. The few that suggest ending a process or isolating the host wait for a person unless the rule has earned unattended runs. What the server sees for itself, such as enrolment, approval, revocation, silence and an isolation lifted on the host, is server-observed.
- Values are clipped: command lines to 4,096 characters, at most 64 arguments of 1,024 characters each.
- Events are kept for the workspace’s TillTell retention: 30, 90 or 400 days.
- The data directory holds the key, enrolment, spool and baselines, and is closed to everyone but root, or SYSTEM and Administrators on Windows.
Rules and hunts
The library ships 21 rules that read host events:
| Rule | Fires on | ATT&CK |
|---|---|---|
tell-host-account-created | Local account created on a host | T1136.001 |
tell-host-admin-group-add | Account added to an admin group on a host | T1098 |
tell-host-agent-silent | Endpoint agent went silent | T1685 |
tell-host-autostart-added | New autostart entry on a host | T1547.001, T1543.001, T1547.015, T1546.004, T1037.004 |
tell-host-defense-disabled | Host protection turned off | T1685, T1685.001, T1686 |
tell-host-download-and-run | Script downloaded and run in one command | T1105, T1059.004, T1059.001 |
tell-host-encoded-powershell | PowerShell given an encoded command | T1059.001, T1027.010 |
tell-host-isolation-lifted | Host isolation lifted on the host | T1685 |
tell-host-kernel-module | Kernel module loaded after boot | T1547.006 |
tell-host-log-cleared | Security log cleared on a host | T1685.005, T1685.006 |
tell-host-lsass-read | Process read the memory of lsass | T1003.001 |
tell-host-malware-detected | Malware detected on a host | T1204.002 |
tell-host-preload-hijack | Library preloaded into every process | T1574.006 |
tell-host-proxy-execution | Windows system binary used to run remote code | T1218.005, T1218.010, T1218.011 |
tell-host-remote-admin-login | Remote login as root or Administrator | T1078.003 |
tell-host-reverse-shell | Reverse shell started | T1059.004 |
tell-host-scheduled-job | New scheduled job on a host | T1053.003, T1053.005 |
tell-host-service-installed | New system service on a host | T1543.002, T1543.003, T1543.004 |
tell-host-ssh-brute-force | Password guessing against a host | T1110.001 |
tell-host-ssh-key-added | SSH key added to an account on a host | T1098.004 |
tell-host-web-shell | Web server started a shell | T1505.003 |
Every host event carries raw.host.id, raw.host.os and raw.collector, and process events carry raw.process.path, raw.process.sha256 and raw.process.user. “Hunt this host” on a host opens TillHunt on its events. Some searches:
raw.host.id:<endpoint-id> action:host.process_started
action:host.login_failed raw.host.os:linux actor.ip|cidr:203.0.113.0/24
raw.collector:run_keysLimits
| What | Limit |
|---|---|
| Events per host | 2,000 a minute; the agent spools the rest |
| A batch | 500 events and 512 KB |
| Spool on the host | 64 MB; the oldest events drop first, and every drop is counted |
| Check-ins | about every 8 minutes; 20 per host per 10 minutes |
| Enrolments | 60 per address per 10 minutes |
| Clock | within 5 minutes of server time; signed requests fail past that |
| Commands waiting per host | 20 |
Managing hosts and tokens and sending commands take an owner or admin, and every change and command is in the audit log. The API is under /api/v1/shield/endpoints in the API reference.