Compare commits

10 Commits

Author SHA1 Message Date
3a4c42f9c0 [readme] fix config example 2023-11-12 01:14:55 +01:00
99529579fe rm binary 2023-11-11 22:07:41 +01:00
49f6a3d26a [triggers/receive_telegram] fix type 2023-11-11 22:04:53 +01:00
60598566d0 [readme] update 2023-11-11 22:04:44 +01:00
15f8793e2f [actions/unix_command] fix typo 2023-11-11 22:04:31 +01:00
d574902919 [actions/remove_files] init 2023-11-11 22:03:26 +01:00
a08de8a553 [go mod] rename module 2023-11-11 15:28:35 +01:00
0b2bba5d77 [gitignore] update && rm binary file 2023-11-11 03:22:10 +01:00
398e16e724 [readme] WIP 2023-11-11 03:20:03 +01:00
e93346f646 [nixpkgs] update 2023-11-11 03:19:41 +01:00
24 changed files with 232 additions and 74 deletions

3
.gitignore vendored
View File

@@ -2,6 +2,7 @@
.envrc
result
example.json
./gokill
gokill
output.md
thoughts.md
deb-single*

109
README.md
View File

@@ -1,45 +1,52 @@
# gokill
gokill is aimed at activists, journalists and others that need to protect their data against access under all circumstances.
gokill falls under the category of anti-forensic tools, helping you to protect yourself against repression.
It is built for worst case scenarios when intruders physical gaining access to a device.
In such heated situations gokill helps you automatically executing tasks like:
gokill is a [software dead man's switch](https://en.wikipedia.org/wiki/Dead_man%27s_switch#Software) that empowers users to configure various events. If these events occur, they trigger predefined actions.
The tool is designed for activists, journalists, and individuals who require robust protection for their data, ensuring it remains inaccessible under any circumstances. It belongs to the category of anti-forensic tools, providing a means to safeguard against potential repression. It is specifically crafted for worst-case scenarios, such as when intruders gain physical access to a device. In these intense situations, gokill can automatically perform tasks to enhance your security. Those could be:
- locking the screen
- sending a chat message
- sending chat messages
- deleting data
- encrypting partitions
- destroying encrypted partitions
- and many more
- ect
the tasks gokill executes could be done by hand using shellscripts, cronjobs, daemons ect.
but that means everyone needs to figure it out for themselves, and eventually make mistakes.
the idea of gokill is to provide a wide variarity of possibilities out of the box while making sure they are well tested.
#### documentation
A full list of Triggers and Actions with all their configuration options can be found here:
gokill aims to be highly configurable and easily extendable.
## usage
If you use NixOS gokill can easily be integrated into your system configuration - scroll down for more info on that.
'gokill' is a tool that completes some actions when a certain event occurs.
actions can vary from shuting down the machine to sending mails over erasing data.
actions can be triggert by certain conditions like specific outcomes of unix
comands or not having internet connection.
For all other linux distributions gokill currently needs to be built and setup manually. This is supposed to change.
Iam currently working/researching on publishing gokill as [ppa](https://help.launchpad.net/Packaging/PPA) and as snap.
If you have other recommendations let me know.
actions and triggers should be easy to extend and handled like plugins. they
also should be self documenting.
every action and trigger should be testable at anytime as a 'dry-run'.
actions can have a 'stage' defined. the lowest stage is started first,
and only when all actions on that stage are finished next stage is triggered
gokill should run as daemon. config should be read from /etc/somename/config.json
``` bash
# Clone the gokill repository
git clone https://github.com/k4lipso/gokill
cd gokill
# Build gokill - requires libolm
go build github.com/k4lipso/gokill
# Create a config.json and run gokill
./gokill -c config.json
# Running gokill manually is annoying, it is acutally meant to run as systemd unit.
```
## Config Example
gokill is configured using a json file. it consists of a list of triggers, where each of the triggers as a list of
actions that will be executed once triggered.
``` json
[ //list of triggers
{
"type": "UsbDisconnect",
"type": "UsbDisconnect", //triggers when the given device is disconnected
"name": "First Trigger",
"options": {
"deviceId": "ata-Samsung_SSD_860_EVO_1TB_S4AALKWJDI102",
"waitTillConnected": true //only trigger when usb drive was actually attached before
}
},
"actions": [ //list of actions that will be executed when triggered
{
"name": "unixCommand",
@@ -49,17 +56,15 @@ gokill should run as daemon. config should be read from /etc/somename/config.jso
"stage": 2 // defines the order in which actions are triggered.
},
{
"type": "sendMail",
"options": {
"smtpserver": "domain.org",
"port": 667,
"recipients": [ "mail1@host.org", "mail2@host.org" ],
"message": "kill switch was triggered",
"attachments": [ "/path/atachments" ],
"pubkeys": "/path/to/keys.pub"
},
"type": "SendTelegram",
"options": {
"token": "3345823487:FFGdEFxc1pA18d02Akslw-lkwjdA92KAH2",
"chatId": -832325872,
"message": "attention, intruders got my device!",
"testMessage": "this is just a test, no worries"
},
"stage": 1 //this event is triggered first, then the shutdown
},
}
]
},
{
@@ -67,12 +72,12 @@ gokill should run as daemon. config should be read from /etc/somename/config.jso
"name": "Second Trigger",
"options": {
"interfaceName": "eth0",
}
},
"actions": [
{
"name": "unixCommand",
"options": {
"command": "env DISPLAY=:0 sudo su -c i3lock someUser"
"command": "env DISPLAY=:0 sudo su -c i3lock someUser" //example of locking someUser's screen as root
}
}
]
@@ -81,9 +86,10 @@ gokill should run as daemon. config should be read from /etc/somename/config.jso
```
## nix support
gokill enjoys full nix support. gokill exposes a nix flakes that outputs a gokill package, a nixosModule and more.
That means you can super easily incorporate gokill into your existing nixosConfigurations.
### NixOS Module
Here is a small example config:
``` nix
@@ -112,25 +118,48 @@ Here is a small example config:
This will automatically configure and enable a systemd running gokill as root user in the background
## actions
### Build Documentation locally
``` bash
nix run github:k4lipso/gokill#docs
```
### Run integrations tests
``` bash
nix flake check github:k4lipso/gokill
```
## todos
- export snap
- export ppa
### actions
- [x] shutdown
- [ ] wipe ram
- [ ] send mail
- [ ] ~~send mail~~
- send chat message
- [x] telegram
- [x] matrix
- [ ] delete data
- [ ] shred area
- [x] random command
- [x] run command
- [ ] wordpress post
- [ ] ipfs command
- [ ] [buskill 'triggers'](https://github.com/BusKill/awesome-buskill-triggers)
- [buskill 'triggers'](https://github.com/BusKill/awesome-buskill-triggers)
- [x] [lock-screen](https://github.com/BusKill/buskill-linux/tree/master/triggers)
- [x] shutdown
- [ ] luks header shredder
- [ ] veracrypt self-destruct
## Triggers
### triggers
- [ ] no internet
- [x] [pull usb stick](https://github.com/deepakjois/gousbdrivedetector/blob/master/usbdrivedetector_linux.go)
- [x] ethernet unplugged
- receive specific chat message
- [x] telegram
- [ ] matrix
- [ ] power adapter disconnected
- [ ] unix command
- anyOf

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"sort"
"unknown.com/gokill/internal"
"github.com/k4lipso/gokill/internal"
)
type ActionResultChan chan error
@@ -121,6 +121,7 @@ func GetAllActions() []DocumentedAction {
return []DocumentedAction{
Command{},
Printer{},
RemoveFiles{},
ShellScript{},
Shutdown{},
SendMatrix{},

View File

@@ -3,7 +3,7 @@ package actions
import (
"encoding/json"
"unknown.com/gokill/internal"
"github.com/k4lipso/gokill/internal"
)
type Printer struct {

130
actions/remove_files.go Normal file
View File

@@ -0,0 +1,130 @@
package actions
import (
"encoding/json"
"fmt"
"os/exec"
"github.com/k4lipso/gokill/internal"
)
type RemoveFiles struct {
Files []string `json:"files"`
Directories []string `json:"directories"`
ActionChan ActionResultChan
}
func (c RemoveFiles) getRemoveCommand() string {
command := "srm"
isAvailable := isCommandAvailable(command)
if !isAvailable {
internal.LogDoc(c).Warningf("Command %s not found, falling back to 'rm'", command)
command = "rm"
}
return command
}
func (c RemoveFiles) DryExecute() {
internal.LogDoc(c).Infof("Test Execute")
command := c.getRemoveCommand()
internal.LogDoc(c).Info("The following commands would have been executed:")
for _, file := range c.Files {
internal.LogDoc(c).Noticef("%s -f %s", command, file)
}
for _, dir := range c.Directories {
internal.LogDoc(c).Noticef("%s -rf %s", command, dir)
}
c.ActionChan <- nil
}
func (c RemoveFiles) Execute() {
internal.LogDoc(c).Infof("Execute")
command := c.getRemoveCommand()
for _, file := range c.Files {
cmd := exec.Command(command, "-fv", file)
stdout, err := cmd.Output()
if err != nil {
internal.LogDoc(c).Errorf("%s", err.Error())
}
internal.LogDoc(c).Notice(string(stdout))
}
for _, dir := range c.Directories {
cmd := exec.Command(command, "-rfv", dir)
stdout, err := cmd.Output()
if err != nil {
internal.LogDoc(c).Errorf("%s", err.Error())
}
internal.LogDoc(c).Notice(string(stdout))
}
c.ActionChan <- nil
}
func CreateRemoveFiles(config internal.ActionConfig, c ActionResultChan) (RemoveFiles, error) {
result := RemoveFiles{}
err := json.Unmarshal(config.Options, &result)
if err != nil {
return RemoveFiles{}, fmt.Errorf("Error parsing RemoveFiles: %s", err)
}
result.ActionChan = c
return result, nil
}
func (cc RemoveFiles) Create(config internal.ActionConfig, c ActionResultChan) (Action, error) {
return CreateRemoveFiles(config, c)
}
func (p RemoveFiles) GetName() string {
return "RemoveFiles"
}
func (p RemoveFiles) GetDescription() string {
return `
RemoveFiles deletes the given files and directories.
If available "srm" is used, otherwise RemoveFiles falls back to "rm"
`
}
func (p RemoveFiles) GetExample() string {
return `
{
"type": "RemoveFiles",
"options": {
"files": [
"/home/user/secrets.txt"
],
"directories": [
"/home/user/.gpg",
"/home/user/.ssh",
"/home/user/.thunderbird"
]
}
}
`
}
func (p RemoveFiles) GetOptions() []internal.ConfigOption {
return []internal.ConfigOption{
{"files", "[]string", "list of absolute paths of files that should be deleted.", ""},
{"directories", "[]string", "list of absolute paths of directories that should be deleted.", ""},
}
}

View File

@@ -15,7 +15,7 @@ import (
"maunium.net/go/mautrix/id"
"maunium.net/go/mautrix/crypto/cryptohelper"
"unknown.com/gokill/internal"
"github.com/k4lipso/gokill/internal"
)
type SendMatrix struct {

View File

@@ -7,7 +7,7 @@ import (
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
"unknown.com/gokill/internal"
"github.com/k4lipso/gokill/internal"
)
type SendTelegram struct {

View File

@@ -6,7 +6,7 @@ import (
"os/exec"
"os"
"unknown.com/gokill/internal"
"github.com/k4lipso/gokill/internal"
)
type ShellScript struct {

View File

@@ -4,7 +4,7 @@ import (
"os/exec"
"encoding/json"
"unknown.com/gokill/internal"
"github.com/k4lipso/gokill/internal"
)
type Shutdown struct {

View File

@@ -4,7 +4,7 @@ import (
"encoding/json"
"time"
"unknown.com/gokill/internal"
"github.com/k4lipso/gokill/internal"
)
type TimeOut struct {

View File

@@ -6,7 +6,7 @@ import (
"os/exec"
"strings"
"unknown.com/gokill/internal"
"github.com/k4lipso/gokill/internal"
)
type Command struct {
@@ -108,7 +108,7 @@ func (p Command) GetName() string {
}
func (p Command) GetDescription() string {
return "Invoces given command using exec."
return "Invokes given command using exec."
}
func (p Command) GetExample() string {

View File

@@ -6,9 +6,9 @@ import (
"os"
"flag"
"unknown.com/gokill/actions"
"unknown.com/gokill/triggers"
"unknown.com/gokill/internal"
"github.com/k4lipso/gokill/actions"
"github.com/k4lipso/gokill/triggers"
"github.com/k4lipso/gokill/internal"
)
func getMarkdown(documenter internal.Documenter) string {

View File

@@ -6,9 +6,9 @@ import (
"fmt"
"os"
"unknown.com/gokill/actions"
"unknown.com/gokill/internal"
"unknown.com/gokill/triggers"
"github.com/k4lipso/gokill/actions"
"github.com/k4lipso/gokill/internal"
"github.com/k4lipso/gokill/triggers"
)
func GetDocumentation() string {

Binary file not shown.

6
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1698553279,
"narHash": "sha256-T/9P8yBSLcqo/v+FTOBK+0rjzjPMctVymZydbvR/Fak=",
"lastModified": 1699343069,
"narHash": "sha256-s7BBhyLA6MI6FuJgs4F/SgpntHBzz40/qV0xLPW6A1Q=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "90e85bc7c1a6fc0760a94ace129d3a1c61c3d035",
"rev": "ec750fd01963ab6b20ee1f0cb488754e8036d89d",
"type": "github"
},
"original": {

2
go.mod
View File

@@ -1,4 +1,4 @@
module unknown.com/gokill
module github.com/k4lipso/gokill
go 1.21.3

BIN
gokill

Binary file not shown.

View File

@@ -1,2 +0,0 @@
#/bin/sh
echo "hello world"

View File

@@ -6,8 +6,8 @@ import (
"os"
"time"
"unknown.com/gokill/actions"
"unknown.com/gokill/internal"
"github.com/k4lipso/gokill/actions"
"github.com/k4lipso/gokill/internal"
)
type EthernetDisconnect struct {

View File

@@ -3,7 +3,7 @@ package triggers
import (
"testing"
"unknown.com/gokill/internal"
"github.com/k4lipso/gokill/internal"
)
func TestEthernetDisconnetConfig(t *testing.T) {

View File

@@ -6,8 +6,8 @@ import (
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
"unknown.com/gokill/internal"
"unknown.com/gokill/actions"
"github.com/k4lipso/gokill/internal"
"github.com/k4lipso/gokill/actions"
)
type ReceiveTelegram struct {
@@ -36,7 +36,7 @@ func (s ReceiveTelegram) Listen() {
for update := range updates {
if update.Message != nil { // If we got a message
if(update.Message.Chat.ID != chatId) {
internal.LogDoc(s).Debugf("ReceiveTelegram received wrong ChatId. Got %s, wanted %s", update.Message.Chat.ID, s.ChatId)
internal.LogDoc(s).Debugf("ReceiveTelegram received wrong ChatId. Got %d, wanted %d", update.Message.Chat.ID, s.ChatId)
continue
}
@@ -52,7 +52,6 @@ func (s ReceiveTelegram) Listen() {
}
func CreateReceiveTelegram(config internal.KillSwitchConfig) (ReceiveTelegram, error) {
result := ReceiveTelegram{
ChatId: 0,

View File

@@ -3,8 +3,8 @@ import (
"encoding/json"
"time"
"unknown.com/gokill/actions"
"unknown.com/gokill/internal"
"github.com/k4lipso/gokill/actions"
"github.com/k4lipso/gokill/internal"
)
type TimeOut struct {

View File

@@ -3,7 +3,7 @@ package triggers
import (
"fmt"
"unknown.com/gokill/internal"
"github.com/k4lipso/gokill/internal"
)
type Trigger interface {

View File

@@ -6,8 +6,8 @@ import (
"os"
"time"
"unknown.com/gokill/actions"
"unknown.com/gokill/internal"
"github.com/k4lipso/gokill/actions"
"github.com/k4lipso/gokill/internal"
)
type UsbDisconnect struct {