Skip to content

Token auth and COM forms support #144

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

Open
wants to merge 1 commit 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
44 changes: 24 additions & 20 deletions autodiscover/autodiscover.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ import (
"strings"
"text/template"

"github.com/sensepost/ruler/http-ntlm"
httpntlm "github.com/sensepost/ruler/http-ntlm"
"github.com/sensepost/ruler/utils"
)

//globals

//SessionConfig holds the configuration for this autodiscover session
// SessionConfig holds the configuration for this autodiscover session
var SessionConfig *utils.Session
var autodiscoverStep int
var secondaryEmail string //a secondary email to use, edge case seen in office365
var Transport http.Transport
var basicAuth = false

//the xml for the autodiscover service
// the xml for the autodiscover service
const autodiscoverXML = `<?xml version="1.0" encoding="utf-8"?><Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
<Request><EMailAddress>{{.Email}}</EMailAddress>
<AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
Expand All @@ -43,10 +43,10 @@ func parseTemplate(tmpl string) (string, error) {
return buff.String(), nil
}

//createAutodiscover generates a domain name of the format autodiscover.domain.com
//and checks if a DNS entry exists for it. If it doesn't it tries DNS for just the domain name.
//returns an empty string if no valid domain was found.
//returns the full (expected) autodiscover URL
// createAutodiscover generates a domain name of the format autodiscover.domain.com
// and checks if a DNS entry exists for it. If it doesn't it tries DNS for just the domain name.
// returns an empty string if no valid domain was found.
// returns the full (expected) autodiscover URL
func createAutodiscover(domain string, https bool) string {
_, err := net.LookupHost(domain)
if err != nil {
Expand All @@ -58,7 +58,7 @@ func createAutodiscover(domain string, https bool) string {
return fmt.Sprintf("http://%s/autodiscover/autodiscover.xml", domain)
}

//GetMapiHTTP gets the details for MAPI/HTTP
// GetMapiHTTP gets the details for MAPI/HTTP
func GetMapiHTTP(email, autoURLPtr string, resp *utils.AutodiscoverResp) (*utils.AutodiscoverResp, string, error) {
//var resp *utils.AutodiscoverResp
var err error
Expand Down Expand Up @@ -87,7 +87,7 @@ func GetMapiHTTP(email, autoURLPtr string, resp *utils.AutodiscoverResp) (*utils
return resp, rawAutodiscover, nil
}

//GetRPCHTTP exports the RPC details for RPC/HTTP
// GetRPCHTTP exports the RPC details for RPC/HTTP
func GetRPCHTTP(email, autoURLPtr string, resp *utils.AutodiscoverResp) (*utils.AutodiscoverResp, string, string, string, bool, error) {
//var resp *utils.AutodiscoverResp
var err error
Expand Down Expand Up @@ -190,7 +190,7 @@ func GetRPCHTTP(email, autoURLPtr string, resp *utils.AutodiscoverResp) (*utils.
return resp, rawAutodiscover, RPCURL, user, ntlmAuth, nil
}

//CheckCache checks to see if there is a stored copy of the autodiscover record
// CheckCache checks to see if there is a stored copy of the autodiscover record
func CheckCache(email string) *utils.AutodiscoverResp {
//check the cache folder for a stored autodiscover record
email = strings.Replace(email, "@", "_", -1)
Expand All @@ -215,7 +215,7 @@ func CheckCache(email string) *utils.AutodiscoverResp {
return &autodiscoverResp
}

//CreateCache function stores the raw autodiscover record to file
// CreateCache function stores the raw autodiscover record to file
func CreateCache(email, autodiscover string) {

if autodiscover == "" { //no autodiscover record passed in, don't try write
Expand All @@ -240,7 +240,7 @@ func CreateCache(email, autodiscover string) {
}
}

//Autodiscover function to retrieve mailbox details using the autodiscover mechanism from MS Exchange
// Autodiscover function to retrieve mailbox details using the autodiscover mechanism from MS Exchange
func Autodiscover(domain string) (*utils.AutodiscoverResp, string, error) {
if SessionConfig.Proxy == "" {
Transport = http.Transport{
Expand All @@ -258,8 +258,8 @@ func Autodiscover(domain string) (*utils.AutodiscoverResp, string, error) {
return autodiscover(domain, false)
}

//MAPIDiscover function to do the autodiscover request but specify the MAPI header
//indicating that the MAPI end-points should be returned
// MAPIDiscover function to do the autodiscover request but specify the MAPI header
// indicating that the MAPI end-points should be returned
func MAPIDiscover(domain string) (*utils.AutodiscoverResp, string, error) {
//set transport
if SessionConfig.Proxy == "" {
Expand All @@ -286,7 +286,7 @@ func autodiscover(domain string, mapi bool) (*utils.AutodiscoverResp, string, er
//var client http.Client
client := http.Client{Transport: &Transport}

if SessionConfig.Basic == false {
if SessionConfig.Basic == false && SessionConfig.BearerToken == "" {
//check if this is a first request or a redirect
//create an ntml http client

Expand Down Expand Up @@ -342,9 +342,13 @@ func autodiscover(domain string, mapi bool) (*utils.AutodiscoverResp, string, er
req.Header.Add("X-AnchorMailbox", SessionConfig.Email) //we want MAPI info
}

if SessionConfig.BearerToken != "" {
req.Header.Add("Authorization", "Bearer "+SessionConfig.BearerToken)
}

if SessionConfig.Basic == true {
if SessionConfig.Domain != "" {
req.SetBasicAuth(SessionConfig.Domain + "\\" + SessionConfig.User, SessionConfig.Pass)
req.SetBasicAuth(SessionConfig.Domain+"\\"+SessionConfig.User, SessionConfig.Pass)
} else {
req.SetBasicAuth(SessionConfig.Email, SessionConfig.Pass)
}
Expand Down Expand Up @@ -491,17 +495,17 @@ func redirectAutodiscover(redirdom string) (string, error) {
return resp.Header.Get("Location"), nil
}

//InsecureRedirectsO365 allows forwarding the Authorization header even when we shouldn't
// InsecureRedirectsO365 allows forwarding the Authorization header even when we shouldn't
type InsecureRedirectsO365 struct {
Transport http.RoundTripper
User string
Pass string
Insecure bool
}

//RoundTrip custom redirector that allows us to forward the auth header, even when the domain changes.
//This is needed as some office365 domains will redirect from autodiscover.domain.com to autodiscover.outlook.com
//and Go does not forward Sensitive headers such as Authorization (https://golang.org/src/net/http/client.go#41)
// RoundTrip custom redirector that allows us to forward the auth header, even when the domain changes.
// This is needed as some office365 domains will redirect from autodiscover.domain.com to autodiscover.outlook.com
// and Go does not forward Sensitive headers such as Authorization (https://golang.org/src/net/http/client.go#41)
func (l InsecureRedirectsO365) RoundTrip(req *http.Request) (resp *http.Response, err error) {
t := l.Transport

Expand Down
27 changes: 13 additions & 14 deletions autodiscover/brute.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import (
"io/ioutil"
"net/http"
"net/http/cookiejar"
"net/url"
"regexp"
"strings"
"time"
"net/url"

"github.com/sensepost/ruler/http-ntlm"
httpntlm "github.com/sensepost/ruler/http-ntlm"
"github.com/sensepost/ruler/utils"
)

//Result struct holds the result of a bruteforce attempt
// Result struct holds the result of a bruteforce attempt
type Result struct {
Username string
Password string
Expand Down Expand Up @@ -114,7 +114,7 @@ func autodiscoverDomain(domain string) string {
return ""
}

//Init function to setup the brute-force session
// Init function to setup the brute-force session
func Init(domain, usersFile, passwordsFile, userpassFile, pURL, u, n string, b, i, s, v bool, c, d, t int) error {
stopSuccess = s
insecure = i
Expand All @@ -133,7 +133,6 @@ func Init(domain, usersFile, passwordsFile, userpassFile, pURL, u, n string, b,
return fmt.Errorf("No autodiscover end-point found")
}


if autodiscoverURL == "https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml" {
basic = true
}
Expand All @@ -157,16 +156,16 @@ func Init(domain, usersFile, passwordsFile, userpassFile, pURL, u, n string, b,
return nil
}

//BruteForce function takes a domain/URL, file path to users and filepath to passwords whether to use BASIC auth and to trust insecure SSL
//And whether to stop on success
// BruteForce function takes a domain/URL, file path to users and filepath to passwords whether to use BASIC auth and to trust insecure SSL
// And whether to stop on success
func BruteForce() {

attempts := 0
stp := false

for index, p := range passwords {
if index % 10 == 0 {
utils.Info.Printf("%d of %d passwords checked",index,len(passwords))
if index%10 == 0 {
utils.Info.Printf("%d of %d passwords checked", index, len(passwords))
}
if p != "" {
attempts++
Expand Down Expand Up @@ -251,15 +250,15 @@ func BruteForce() {
}
}

//UserPassBruteForce function does a bruteforce using a supplied user:pass file
// UserPassBruteForce function does a bruteforce using a supplied user:pass file
func UserPassBruteForce() {

count := 0
sem := make(chan bool, concurrency)
stp := false
for index, up := range userpass {
if index % 10 == 0 {
utils.Info.Printf("%d of %d checked",index,len(userpass))
if index%10 == 0 {
utils.Info.Printf("%d of %d checked", index, len(userpass))
}
count++
if up == "" {
Expand Down Expand Up @@ -324,7 +323,7 @@ func readFile(filename string) []string {
return outputs
}

func connect(autodiscoverURL, user, password string, basic, insecure bool) Result {
func connect(autodiscoverURL, user string, password string, basic bool, insecure bool) Result {
result := Result{user, password, -1, -1, nil}

cookie, _ := cookiejar.New(nil)
Expand All @@ -339,7 +338,7 @@ func connect(autodiscoverURL, user, password string, basic, insecure bool) Resul
return result
}
tr = &http.Transport{Proxy: http.ProxyURL(proxy),
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
DisableKeepAlives: true,
}
}
Expand Down
Loading