diff --git a/autodiscover/autodiscover.go b/autodiscover/autodiscover.go index 23c4401..4e081db 100644 --- a/autodiscover/autodiscover.go +++ b/autodiscover/autodiscover.go @@ -295,7 +295,7 @@ func autodiscover(domain string, mapi bool) (*utils.AutodiscoverResp, string, er req, err := http.NewRequest("POST", autodiscoverURL, strings.NewReader(r)) req.Header.Add("Content-Type", "text/xml") - req.Header.Add("User-Agent", "ruler") + req.Header.Add("User-Agent", SessionConfig.UserAgent) if mapi == true { req.Header.Add("X-MapiHttpCapability", "1") //we want MAPI info @@ -453,7 +453,7 @@ func (l InsecureRedirectsO365) RoundTrip(req *http.Request) (resp *http.Response req, err = http.NewRequest("POST", URL.String(), strings.NewReader(r)) req.Header.Add("Content-Type", "text/xml") - req.Header.Add("User-Agent", "ruler") + req.Header.Add("User-Agent", SessionConfig.UserAgent) req.Header.Add("X-MapiHttpCapability", "1") //we want MAPI info req.Header.Add("X-AnchorMailbox", l.User) //we want MAPI info diff --git a/autodiscover/brute.go b/autodiscover/brute.go index 76e249e..5c6c455 100644 --- a/autodiscover/brute.go +++ b/autodiscover/brute.go @@ -37,6 +37,7 @@ var verbose = false var insecure = false var stopSuccess = false var proxyURL string +var userAgent string var user_as_pass = true func autodiscoverDomain(domain string) string { @@ -74,6 +75,7 @@ func autodiscoverDomain(domain string) string { req, err := http.NewRequest("GET", autodiscoverURL, nil) req.Header.Add("Content-Type", "text/xml") + req.Header.Add("User-Agent", userAgent) tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, @@ -113,7 +115,7 @@ func autodiscoverDomain(domain string) string { } //Init function to setup the brute-force session -func Init(domain, usersFile, passwordsFile, userpassFile, pURL string, b, i, s, v bool, c, d, t int) error { +func Init(domain, usersFile, passwordsFile, userpassFile, pURL, u string, b, i, s, v bool, c, d, t int) error { stopSuccess = s insecure = i basic = b @@ -122,6 +124,7 @@ func Init(domain, usersFile, passwordsFile, userpassFile, pURL string, b, i, s, consc = c concurrency = t proxyURL = pURL + userAgent = u autodiscoverURL = autodiscoverDomain(domain) @@ -332,7 +335,7 @@ func connect(autodiscoverURL, user, password string, basic, insecure bool) Resul proxy, err := url.Parse(proxyURL) if err != nil { result.Error = err - return result + return result } tr = &http.Transport{Proxy: http.ProxyURL(proxy), TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, @@ -357,6 +360,7 @@ func connect(autodiscoverURL, user, password string, basic, insecure bool) Resul req, err := http.NewRequest("GET", autodiscoverURL, nil) req.Header.Add("Content-Type", "text/xml") + req.Header.Add("User-Agent", userAgent) //if basic authi is required, set auth header if basic == true { diff --git a/http-ntlm/ntlmtransport.go b/http-ntlm/ntlmtransport.go index d57dc77..ee178a0 100644 --- a/http-ntlm/ntlmtransport.go +++ b/http-ntlm/ntlmtransport.go @@ -53,7 +53,8 @@ func (t NtlmTransport) RoundTrip(req *http.Request) (res *http.Response, err err b, _ := session.GenerateNegotiateMessage() // first send NTLM Negotiate header r, _ := http.NewRequest("GET", req.URL.String(), strings.NewReader("")) - r.Header.Add("Authorization", "NTLM "+utils.EncBase64(b.Bytes())) + r.Header.Add("Authorization", "NTLM " + utils.EncBase64(b.Bytes())) + r.Header.Add("User-Agent", req.UserAgent()) if t.Proxy == "" { Transport = http.Transport{ @@ -125,10 +126,9 @@ func (t NtlmTransport) RoundTrip(req *http.Request) (res *http.Response, err err } // set NTLM Authorization header - req.Header.Set("Authorization", "NTLM "+utils.EncBase64(authenticate.Bytes())) + req.Header.Set("Authorization", "NTLM " + utils.EncBase64(authenticate.Bytes())) resp, err = client.Do(req) - } return resp, err } diff --git a/mapi/mapi.go b/mapi/mapi.go index 20f9c66..866470f 100644 --- a/mapi/mapi.go +++ b/mapi/mapi.go @@ -176,6 +176,7 @@ func mapiRequestHTTP(URL, mapiType string, body []byte) ([]byte, error) { req, err := http.NewRequest("POST", URL, bytes.NewReader(body)) addMapiHeaders(req, mapiType) + req.Header.Add("User-Agent", AuthSession.UserAgent) req.SetBasicAuth(AuthSession.Email, AuthSession.Pass) req.Close = true diff --git a/ruler.go b/ruler.go index 8d73cfc..992551c 100644 --- a/ruler.go +++ b/ruler.go @@ -92,6 +92,7 @@ func discover(c *cli.Context) error { config.RPCEncrypt = !c.GlobalBool("noencrypt") config.CookieJar, _ = cookiejar.New(nil) config.Proxy = c.GlobalString("proxy") + config.UserAgent = c.GlobalString("useragent") url := c.GlobalString("url") if url == "" { @@ -164,7 +165,7 @@ func brute(c *cli.Context) error { if c.GlobalBool("o365") == true { domain = "https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml" } - if e := autodiscover.Init(domain, c.String("users"), c.String("passwords"), c.String("userpass"), c.GlobalString("proxy"), c.GlobalBool("basic"), c.GlobalBool("insecure"), c.Bool("stop"), c.Bool("verbose"), c.Int("attempts"), c.Int("delay"), c.Int("threads")); e != nil { + if e := autodiscover.Init(domain, c.String("users"), c.String("passwords"), c.String("userpass"), c.GlobalString("proxy"), c.GlobalString("useragent"), c.GlobalBool("basic"), c.GlobalBool("insecure"), c.Bool("stop"), c.Bool("verbose"), c.Int("attempts"), c.Int("delay"), c.Int("threads")); e != nil { return e } @@ -313,6 +314,7 @@ func connect(c *cli.Context) error { config.RPCEncrypt = !c.GlobalBool("noencrypt") config.CookieJar, _ = cookiejar.New(nil) config.Proxy = c.GlobalString("proxy") + config.UserAgent = c.GlobalString("useragent") //add supplied cookie to the cookie jar if c.GlobalString("cookie") != "" { //split into cookies and then into name : value @@ -1189,6 +1191,11 @@ A tool by @_staaldraad from @sensepost to abuse Exchange Services.` Value: "", Usage: "If you need to use an upstream proxy. Works with https://user:pass@ip:port or https://ip:port", }, + cli.StringFlag{ + Name: "useragent", + Value: "ruler", + Usage: "Custom User-Agent string", + }, cli.BoolFlag{ Name: "insecure,k", Usage: "Ignore server SSL certificate errors", diff --git a/utils/datatypes.go b/utils/datatypes.go index fadaf1a..7da41cf 100644 --- a/utils/datatypes.go +++ b/utils/datatypes.go @@ -9,15 +9,16 @@ import ( //Config containing the session variables type Config struct { - Domain string - User string - Pass string - Email string - Basic bool - Insecure bool - Verbose bool - Admin bool - Proxy string + Domain string + User string + Pass string + Email string + Basic bool + Insecure bool + Verbose bool + Admin bool + Proxy string + UserAgent string } //Session stores authentication cookies ect @@ -27,6 +28,7 @@ type Session struct { Email string Domain string Proxy string + UserAgent string Basic bool Insecure bool Verbose bool