Skip to content
Snippets Groups Projects
Jose Carlos Luna Duran's avatar
Jose Carlos Luna Duran authored
Update alert.go

See merge request ComputerSecurity/gocanary!3
72077fc6
History

Go Canary Collector

Gocanary is a simple collector of honeytokens that will generate alerts once a token has been interacted with.

Gocanary implements a DNS, HTTPS and HTTP honeytoken interaction traps.

The tokens are defined in a file, by default canary.yaml

The yaml is pretty simple and containts a sequence of canaries, example:

- key: 'mycanary1'
  tag: 'gitlab-canary'
  description: 'this canary is in gitlab project blah blah'
  type: 'all'
  alert: 'all'
  level: 'low'
- key: 'mycanary2'
  tag: 'gitlab-canary2'
  description: 'test2'
  level: 'low'
- key: 'mycanary3'
  tag: 'gitlab-canary3'
  description: 'test3 asdf lkasj kla sjlk j'
  type: 'http'
  alert: 'log'
  level: 'low'

key should be unique and will be token canary that needs to be exposed to the potential attackers.

tag and level are metadata that are included in all the alerts.

type limits the types of alerts generated for that token.

The alert can have different sinks. Gocanary implements three sinks:

  • slack: uses a webhook to send the alert using the slack/mattermost format
  • log: prints to stdout or logfile
  • syslog: send the alert to syslog

The alert content depends on the interaction trigger and contains both information of the token and the triggering source and system.

Eg: {"time":"2024-05-16T10:49:16.374474022+02:00","level":"INFO","msg":"token-alert","Key":"mycanary1","Tag":"gitlab-canary","Level":"low","FullUrl":"http://myhost/test%20this/mycanary1/","UserAgent":"curl/7.81.0","RemoteIP":"127.0.0.1","RemotePort":49664,"LocalIP":"127.0.0.1","LocalPort":80,"Referer":"","Type":"token-http"}

DNS

The trap will be triggered when a domain that matches a honeytoken is resolved (gocanary implements a DNS resolver).

Eg: someone resolves mycanary1.domain and this query reaches our gocanary resolver through NS delegation, i.e. domain is in reality subdomain.domain and domain nameservers delegate resolution of subdomain to our host

Beware that the remote ip will be typically the resolver that the client is using and not the IP of the potential attacker.

HTTP and HTTPS

The trap will be triggered when a URL that has either a token is defined that matches the last path component or the first component of the hostname.

Eg: A request is made to http://mycanary1.myhost.domain/whatever or a request is made to http://myhost.domain/whatever/mycanary1

Running

Gocanary is a single binary that accepts command line options. Gocanary also reads a config file (default config.yaml) where the same parameters that can be passed as arguments might alternatively be defined. It is intended to be run as root (to be able to bind to default DNS and WEB ports) and will drop privileges to nobody and sandbox file access using landlock (https://docs.kernel.org/userspace-api/landlock.html) It would be possible to run as nonroot and changing the different ports, and then using iptables/nftables to redirect traffic to it.

All configuration options can be defined in config.yaml. Example:

$ cat config.yaml
slack-hook: 'http://127.0.0.1/example'

For generating a self-signed certificate:

openssl req -new -newkey rsa:4096 -days 3650 -nodes -keyout cert.key -out cert.pem  -x509 -subj "/C=CH/ST=GE/L=Geneva/O=CERN/CN=localhost.cern.ch"

All options:

gocanary is a honeytoken/canary collector daemon that listens for http/https/dns requests.
Alerts will be generated when a predefined haystack/honeytoken is detected.

Usage:
  gocanary [flags]

Flags:
      --autocert-domain stringArray   Enable let's encrypt autocertificates (multiple accepted), https-cert and http-key will be ignored
  -b, --bind-address string           Ip address to bind servers to
      --cache-dir string              Writable directory for holding up autocertificates (default "./cache")
  -c, --canary-file string            File where canaries are defined (default "canary.yaml")
      --dns-answer-with string        IP address to give as an answer to DNS request matching a canary, if empty NXDOMAIN
      --dns-not-answer                Do not answer with any response, not even NXDOMAIN
      --domain stringArray            Only respond to this domain (multiple accepted)
      --enable-dns                    Enable DNS listeners (tcp and udp) (default true)
      --enable-hardening              Enable extra hardening measures (default true)
      --enable-http                   Enable HTTP listener (default true)
      --enable-https                  Enable HTTPS listener
      --enable-syslog                 Enable logging to syslog
  -h, --help                          help for gocanary
      --http-port uint16              Port for http server (default 80)
      --https-cert string             File containing the certificate in PEM format (default "cert.pem")
      --https-key string              File containing the certificate key in PEM format (default "cert.key")
      --https-port uint16             Port for https server (default 443)
  -s, --slack-hook string             Webhook for alerts
      --slack-silence uint16          Wait this many seconds between each slack alert (default 1)

The easiest way to run this is with docker compose.

The leanest way is to download the gocanary from the releases page and then use the docker-compose-inline.yml The most compatible way to run is using the docker-compose-with-build.yml, which will compile and run the project.

Except for the docker-compose-inline the compose file will need to be edited to at least bind only the public IPs and also to specify certificate options when using https support.