├── hbconf.yaml ├── .gitignore ├── LICENSE ├── README.md └── honeybits-win.go /hbconf.yaml: -------------------------------------------------------------------------------- 1 | # Windows Credential Manager 2 | wincreds: 3 | enabled: true 4 | generic-creds: 5 | - 192.168.1.66:user01:pass123 6 | - realco-AWS_SECRET_ACCESS_KEY-david:AKIAI44QH8DHBEXAMPLE:je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY 7 | domain-creds: 8 | - domain01:adel\dc:pass123 9 | - winsrv:administrator:54657 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Adel Karimi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Honeybits-win 2 | A simple tool to create breadcrumbs and honeytokens, to lead the attackers to your honeypots! 3 | 4 | The Linux version of this project: [honeybits](https://github.com/0x4D31/honeybits) 5 | 6 | _Author: Adel "0x4D31" Karimi._ 7 | 8 | ## Features: 9 | * Creating fake credentials in Windows Credential Manager 10 | * Reading config from a remote Key/Value Store such as Consule or etcd 11 | 12 | ## Requirements: 13 | * [Go Lang 1.7+](https://golang.org/dl/) 14 | * Viper (```go get github.com/spf13/viper```) 15 | * crypt (```go get github.com/xordataexchange/crypt/config```) 16 | 17 | ## Usage: 18 | ``` 19 | > go run honeybits-win.go 20 | 21 | /\ /\___ _ __ ___ _ _| |__ (_) |_ ___ 22 | / /_/ / _ \| '_ \ / _ \ | | | '_ \| | __/ __| 23 | / __ / (_) | | | | __/ |_| | |_) | | |_\__ \ 24 | \/ /_/ \___/|_| |_|\___|\__, |_.__/|_|\__|___/ 25 | ========================|___/================= 26 | 27 | Failed reading remote config. Reading the local config file... 28 | Local config file loaded. 29 | 30 | [+] Generic credential created (192.168.1.66) 31 | [+] Generic credential created (realco-AWS_SECRET_ACCESS_KEY-david) 32 | [+] Domain credential created (domain01) 33 | [+] Domain credential created (winsrv) 34 | ``` 35 | 36 | ## TODO: 37 | * Honeyfiles 38 | + Type 1 - honeytoken (monitored) 39 | + Type 2 - breadcrumb (containing false information) 40 | + Type 3 - beacon docs 41 | * Content generator module for honeyfiles 42 | * More traps, including: 43 | + AWS credentials file 44 | + Fake entries in CMD/PowerShell commands history 45 | + Fake browser history, bookmarks and saved passwords 46 | + Database files/backups: SQLite, MySQL 47 | + Confoguration, backup, and connection files such as RDP and VPN 48 | + MS Outlook Data file (.ost/.pst) 49 | + Hosts files (hosts, lmhosts) 50 | + Fake ARP entries 51 | + KeePass file with fake entries (.kdbx) 52 | + Registery keys (WinSCP, PuTTY, etc.) 53 | + Injected fake credentials in LSASS 54 | * Documentation -------------------------------------------------------------------------------- /honeybits-win.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | "github.com/danieljoos/wincred" 8 | "github.com/spf13/viper" 9 | _ "github.com/spf13/viper/remote" 10 | ) 11 | 12 | 13 | var ASCII = ` 14 | /\ /\___ _ __ ___ _ _| |__ (_) |_ ___ 15 | / /_/ / _ \| '_ \ / _ \ | | | '_ \| | __/ __| 16 | / __ / (_) | | | | __/ |_| | |_) | | |_\__ \ 17 | \/ /_/ \___/|_| |_|\___|\__, |_.__/|_|\__|___/ 18 | ========================|___/================= 19 | 20 | ` 21 | 22 | func check(e error) { 23 | if e != nil { 24 | os.Stderr.WriteString(fmt.Sprintf("Error: %s\n", e.Error())) 25 | } 26 | } 27 | 28 | // Load the local or remore config file. For remote config: 29 | // Read the config values from environment variables and then load 30 | // the remote config (remote Key/Value store such as etcd or Consul) 31 | // e.g. $ export HBITS_KVSPROVIDER="consul" 32 | // $ export HBITS_KVSADDR="127.0.0.1:32775" 33 | // $ export HBITS_KVSDIR="/config/hbconf.yaml" 34 | // $ export HBITS_KVSKEY="/etc/secrets/mykeyring.gpg" 35 | func loadCon() (*viper.Viper, error) { 36 | conf := viper.New() 37 | conf.SetEnvPrefix("hbits") 38 | conf.AutomaticEnv() 39 | 40 | conf.SetDefault("kvsprovider", "consul") 41 | conf.SetDefault("kvsdir", "/config/hbconf.yaml") 42 | //conf.SetDefault("path.bashhistory", "~/.bash_history") 43 | 44 | kvsaddr := conf.GetString("kvsaddr") 45 | kvsprovider := conf.GetString("kvsprovider") 46 | kvsdir := conf.GetString("kvsdir") 47 | 48 | // If HBITS_KVSKEY is set, use encryption for the remote Key/Value Store 49 | if conf.IsSet("kvskey") { 50 | kvskey := conf.GetString("kvskey") 51 | conf.AddSecureRemoteProvider(kvsprovider, kvsaddr, kvsdir, kvskey) 52 | } else { 53 | conf.AddRemoteProvider(kvsprovider, kvsaddr, kvsdir) 54 | } 55 | conf.SetConfigType("yaml") 56 | 57 | if err := conf.ReadRemoteConfig(); err != nil { 58 | // Reading local config file 59 | fmt.Print("Failed reading remote config. Reading the local config file...\n") 60 | conf.SetConfigName("hbconf") 61 | conf.AddConfigPath(".") 62 | if err := conf.ReadInConfig(); err != nil { 63 | return nil, err 64 | } 65 | fmt.Print("Local config file loaded.\n\n") 66 | return conf, nil 67 | } 68 | fmt.Print("Remote config file loaded\n\n") 69 | return conf, nil 70 | } 71 | 72 | func cred_check(ctype string, ctarget string, cuser string) bool { 73 | var res bool 74 | if ctype == "generic" { 75 | if cred, err := wincred.GetGenericCredential(ctarget); err == nil && cred.UserName == cuser { 76 | res = true 77 | } 78 | } else if ctype == "domain" { 79 | if cred, err := wincred.GetDomainPassword(ctarget); err == nil && cred.UserName == cuser { 80 | res = true 81 | } 82 | } 83 | return res 84 | } 85 | 86 | func cred_create(ctype string, ctarget string, cuser string, cpass string) { 87 | if ctype == "generic" { 88 | cred := wincred.NewGenericCredential(ctarget) 89 | cred.CredentialBlob = []byte(cpass) 90 | cred.UserName = cuser 91 | err := cred.Write() 92 | if err != nil { 93 | fmt.Println(err) 94 | } else { 95 | fmt.Printf("[+] Generic credential created (%s)\n", ctarget) 96 | } 97 | } else if ctype == "domain" { 98 | cred := wincred.NewDomainPassword(ctarget) 99 | // cred.CredentialBlob = []byte(cpass) 100 | // error: The parameter is incorrect. 101 | // Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa380517(v=vs.85).aspx#domain_credentials 102 | cred.UserName = cuser 103 | err := cred.Write() 104 | if err != nil { 105 | fmt.Println(err) 106 | } else { 107 | fmt.Printf("[+] Domain credential created (%s)\n", ctarget) 108 | } 109 | } 110 | } 111 | 112 | func main() { 113 | fmt.Print(ASCII) 114 | 115 | conf, err := loadCon() 116 | check(err) 117 | 118 | //Windows Credential Manager 119 | if conf.GetString("wincreds.enabled") == "true" { 120 | if gcreds := conf.GetStringSlice("wincreds.generic-creds"); len(gcreds) != 0 { 121 | for _, g := range gcreds { 122 | gconf := strings.Split(g, ":") 123 | if cred_check("generic", gconf[0], gconf[1]) { 124 | fmt.Printf("Error: generic credential exists (%s)\n", gconf[0]) 125 | } else { 126 | cred_create("generic", gconf[0], gconf[1], gconf[2]) 127 | } 128 | } 129 | } 130 | if dcreds := conf.GetStringSlice("wincreds.domain-creds"); len(dcreds) != 0 { 131 | for _, d := range dcreds { 132 | dconf := strings.Split(d, ":") 133 | if cred_check("domain", dconf[0], dconf[1]) { 134 | fmt.Printf("Error: domain credential exists (%s)\n", dconf[0]) 135 | } else { 136 | cred_create("domain", dconf[0], dconf[1], dconf[2]) 137 | } 138 | } 139 | } 140 | } 141 | } --------------------------------------------------------------------------------