Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ phone-home. If you want a smarter model and have the RAM, swap it in `.env`.
- **Collects telemetry** from Windows and Linux agents over a single TCP
channel. SIEM events, alerts, FIM, packages, network connections,
open ports, Docker activity, screen frames.
- **Detects with Sigma rules, on the endpoint.** 37 rules covering 38 MITRE
- **Detects with Sigma rules, on the endpoint.** 43 rules covering 47 MITRE
ATT&CK techniques ship in `conf/sigma/builtin/`; drop community rulesets in
beside them. Sigma matches *named fields* rather than text, so
`Image|endswith: '\vssadmin.exe'` cannot be defeated by the word "vssadmin"
Expand All @@ -47,7 +47,7 @@ phone-home. If you want a smarter model and have the RAM, swap it in `.env`.
that is the more competent attack, since spraying wide and shallow stays
under both per-account lockout and per-host thresholds.

Total coverage with Sigma: 42 techniques. Every window fires once rather than
Total coverage with Sigma: 51 techniques. Every window fires once rather than
once per event, and every counter is bounded — a counter keyed on an
attacker-supplied username is a memory exhaustion primitive, not a detection.
- **Maps detections to MITRE ATT&CK, from the rules themselves.** Rules carry
Expand Down
2 changes: 1 addition & 1 deletion Sentora/conf/sigma/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ addresses.

## What ships in `builtin/`

A baseline of 37 rules covering 38 ATT&CK techniques. It exists because the
A baseline of 43 rules covering 47 ATT&CK techniques. It exists because the
alternative was worse: this directory was empty by design, on the argument
that a detection nobody reviewed is not an improvement — which is true, and
which produced zero ATT&CK coverage on every install and a coverage page with
Expand Down
61 changes: 61 additions & 0 deletions Sentora/conf/sigma/builtin/linux_data_staged_in_archive.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
title: Local Data Collected Into An Archive In A World-Writable Directory
id: 6d91b28c-3a47-4e5f-9c02-8b7ae1d43c05
status: stable
description: >
The Linux half of the same step. Data is gathered into one object before
it moves, and on a server that object lands somewhere the account can
write without being noticed - /tmp, /dev/shm, /var/tmp.

/dev/shm is worth its own mention. It is memory, not disk, so an archive
staged there leaves nothing for a later forensic image to recover and
disappears on reboot. A backup script has no reason to use it; somebody
who does not want the file found does.

The rule is on the pairing. tar and zip are how this machine is
administered, and /tmp is where ordinary work happens. An archive being
*created* in one of those directories out of a home directory, /etc or a
database path is the shape that matters.
references:
- https://attack.mitre.org/techniques/T1560/001/
- https://attack.mitre.org/techniques/T1074/001/
author: Sentora
date: 2026/09/07
logsource:
product: linux
category: process_creation
detection:
archive_create:
CommandLine|contains:
- 'tar -c'
- 'tar c'
- 'tar --create'
- 'zip -r'
- '7z a'
- 'gzip -c'
staging_location:
CommandLine|contains:
- '/tmp/'
- '/dev/shm/'
- '/var/tmp/'
sensitive_source:
CommandLine|contains:
- '/home/'
- '/root/'
- '/etc/'
- '/var/lib/mysql'
- '/var/lib/postgresql'
- '/opt/'
- '/srv/'
memory_backed:
CommandLine|contains: '/dev/shm/'
condition: archive_create and (staging_location or sensitive_source) and
(sensitive_source or memory_backed)
falsepositives:
- Backup jobs staging in /var/tmp. They recur on a schedule from cron,
which is what separates them from a single collection.
- Package builds archiving out of /opt or /srv.
level: high
tags:
- attack.collection
- attack.t1560.001
- attack.t1074.001
83 changes: 83 additions & 0 deletions Sentora/conf/sigma/builtin/linux_file_pushed_offhost.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
title: File Pushed Off The Host Over A Non-Interactive Channel
id: a2f37e50-8c94-4d16-b7e3-5f108ca6db29
status: stable
description: >
A server has fewer excuses than a workstation. Nobody is sitting at it
browsing, so an outbound transfer carrying a local file is either a job
somebody configured or somebody taking something.

Two shapes, and each is a different level of deliberate. `curl -T` and
`curl --upload-file` say a file is the payload rather than the response.
And a file redirected into `nc`, `openssl s_client` or `/dev/tcp` is a raw
socket carrying bytes with no protocol to inspect - which is chosen
precisely because there is nothing for a proxy to read.

`scp` and `rsync` were a third branch and are deliberately gone. They are
how a server is administered: the sample `rsync -az --delete /srv/data/
backup-01:/srv/data/` is a scheduled backup, and a rule that pages on
every backup gets muted - which is worse than not having it, because the
console still counts it as coverage. Catching that would need to know
which destinations belong to the estate, and this rule cannot.

`/dev/tcp` deserves the attention. It is a bash builtin, so it needs
nothing installed, leaves no binary to find, and works on a host stripped
of every network tool. On a system where somebody has removed curl to
harden it, this is what is left.

The paste and tunnel services are matched on their own. A managed Linux
host has no routine business with them, and naming them catches the
transfers that use an ordinary POST rather than a recognisable switch.
references:
- https://attack.mitre.org/techniques/T1048/
- https://attack.mitre.org/techniques/T1567/002/
author: Sentora
date: 2026/09/07
logsource:
product: linux
category: process_creation
detection:
curl_upload:
CommandLine|contains|all:
- 'curl'
CommandLine|contains:
- ' -T '
- ' -F '
- '--upload-file'
- '--data-binary @'
raw_socket:
CommandLine|contains:
- '/dev/tcp/'
- 'nc -'
- 'ncat '
- 'openssl s_client'
reads_a_file:
CommandLine|contains:
- ' < '
# `cat /` and not `cat `, because `cat ` is a substring of `ncat `
# and matched every netcat command line - including the reverse
# shell that has its own rule. An absolute path after it is what
# actually says a file is being read.
- 'cat /'
- '@/'
known_drop_service:
CommandLine|contains:
- 'pastebin.com'
- 'transfer.sh'
- 'file.io'
- 'anonfiles'
- 'gofile.io'
- 'ngrok.io'
- 'webhook.site'
- 'api.telegram.org'
- 'discord.com/api/webhooks'
condition: known_drop_service or curl_upload or
(raw_socket and reads_a_file)
falsepositives:
- A deployment script posting an artefact to an internal service with
`curl -T`. The hostname is what separates it from exfiltration.
- Health-check tooling using netcat with a here-string rather than a file.
level: high
tags:
- attack.exfiltration
- attack.t1048
- attack.t1567.002
64 changes: 64 additions & 0 deletions Sentora/conf/sigma/builtin/win_clipboard_and_screen_captured.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
title: Clipboard Or Screen Captured From A Script Host
id: 8b2c7f19-64ad-4f83-a5e1-0d3b96c7e4f8
status: stable
description: >
Two things on a workstation carry credentials that never touch a file: the
clipboard, which is where a password manager puts a password for the
fifteen seconds before it is pasted, and the screen, which is where it is
displayed.

Both are reachable from PowerShell in one line, with no dropped binary and
nothing to allow-list against. `Get-Clipboard` is a supported cmdlet.
`CopyFromScreen` is one call on a Graphics object. Neither needs
privileges beyond the user's own, which is the point - this is what an
attacker does *after* landing as an ordinary user and before finding
anything worth escalating to.

Scoped to script hosts rather than to the calls alone. A person copying
text is not this; a script reading what they copied is.

Repetition is what separates a helper script from surveillance, and this
rule cannot see it - `core.correlation` counts recurrence across events,
and one hit here is worth looking at rather than acting on.
references:
- https://attack.mitre.org/techniques/T1115/
- https://attack.mitre.org/techniques/T1113/
author: Sentora
date: 2026/09/07
logsource:
product: windows
category: process_creation
detection:
script_host:
CommandLine|contains:
- 'powershell'
- 'pwsh'
- 'cscript'
- 'wscript'
clipboard_read:
CommandLine|contains:
- 'Get-Clipboard'
- 'Windows.Forms.Clipboard'
- 'GetText()'
screen_capture:
CommandLine|contains:
- 'CopyFromScreen'
- 'Drawing.Bitmap'
- 'PrimaryScreen'
keystroke_hooks:
CommandLine|contains:
- 'GetAsyncKeyState'
- 'SetWindowsHookEx'
condition: keystroke_hooks or (script_host and (clipboard_read or screen_capture))
falsepositives:
- A remote-support or screenshot utility driven from PowerShell. Those are
usually the same script on a schedule; a one-off from an unexpected
parent is not.
- Clipboard helpers in developer tooling.
level: high
tags:
- attack.collection
- attack.credential_access
- attack.t1115
- attack.t1113
- attack.t1056.001
80 changes: 80 additions & 0 deletions Sentora/conf/sigma/builtin/win_data_staged_in_archive.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
title: Local Data Collected Into An Archive In A Staging Directory
id: 3f8a1d64-7c52-4e09-b3d7-9a1e6f0c58b2
status: stable
description: >
Data almost never leaves a host as loose files. It is gathered, compressed
into one object, and then moved - because one upload is quicker, quieter
and far less likely to be interrupted halfway than three thousand.

The rule is on the pairing, not on the tools. rar, 7-Zip, tar and
Compress-Archive are ordinary; so is writing to %TEMP%. What is not
ordinary is an archive being *created* in a directory nobody keeps
documents in - Temp, ProgramData, the Public profile, a Recycle Bin - and
that combination is what an operator needs to see.

Password-protected archives get their own branch and no location
requirement. `rar a -hp` exists to make an archive whose contents cannot
be inspected in transit, which is a reason a backup script does not have.

This is the step before exfiltration, and it is the last one that still
happens on a host you control. After this the data is a single file and
the next event is it leaving.
references:
- https://attack.mitre.org/techniques/T1560/001/
- https://attack.mitre.org/techniques/T1074/001/
author: Sentora
date: 2026/09/07
logsource:
product: windows
category: process_creation
detection:
rar_create:
CommandLine|contains|all:
- 'rar'
- ' a '
sevenzip_create:
CommandLine|contains|all:
- '7z'
- ' a '
tar_create:
# `tar -c` as one string, not `tar` and `-c` separately. `Start-Sleep`
# contains "tar", and any PowerShell line with `-c` in it then matched
# - a clipboard-stealing loop fired this rule for no reason. Same
# class as `cat ` matching inside `ncat `.
CommandLine|contains:
- 'tar -c'
- 'tar.exe -c'
- 'tar cf'
- 'tar czf'
powershell_archive:
CommandLine|contains: 'Compress-Archive'
makecab:
CommandLine|contains: 'makecab'
staging_location:
CommandLine|contains:
- '\Temp\'
- '\Windows\Temp'
- '\ProgramData\'
- '\Users\Public'
- '\$Recycle.Bin'
- '\PerfLogs'
- 'C:\Windows\Tasks'
password_protected:
CommandLine|contains:
- ' -hp'
- ' -p'
condition: >
((rar_create or sevenzip_create) and password_protected) or
((rar_create or sevenzip_create or tar_create or powershell_archive or
makecab) and staging_location)
falsepositives:
- A backup or packaging job that legitimately stages in %TEMP%. Those
repeat on a schedule from the same parent, which is what tells them
apart from a one-off collection.
- Installers unpacking into ProgramData. Those extract rather than create,
and this rule keys on the create switch.
level: high
tags:
- attack.collection
- attack.t1560.001
- attack.t1074.001
11 changes: 10 additions & 1 deletion Sentora/conf/sigma/builtin/win_local_account_created.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,17 @@ detection:
EventID: 4720
net_user_add:
CommandLine|contains|all:
- 'net user'
- 'user'
- '/add'
# `net user` and `net.exe user` are the same command, and matching the
# first spelling alone missed every command line that carries the
# extension - which is most of them. Split so either works: `net`
# here, `user` and `/add` above.
CommandLine|contains:
- 'net user'
- 'net.exe user'
- 'net1 user'
- 'net1.exe user'
localgroup_add:
CommandLine|contains|all:
- 'localgroup'
Expand Down
Loading
Loading