Skip to content

Latest commit

 

History

History
208 lines (167 loc) · 17.6 KB

File metadata and controls

208 lines (167 loc) · 17.6 KB

Here is the combined list of vulnerabilities, formatted as markdown, with duplicates removed and descriptions consolidated:

Combined Vulnerability List

Unsafe Deserialization with YAMLSerializer

  • Description:

    1. An attacker finds a way to inject data into the Redis cache. This could be through a separate vulnerability in the application using django-redis-cache or if the Redis instance is exposed and not properly secured.
    2. The attacker crafts a malicious YAML payload designed to execute arbitrary code upon deserialization. A sample payload could be: !!python/object/apply:os.system ["touch /tmp/pwned"].
    3. The attacker sets a cache key in Redis with this malicious YAML payload as the value, for example using redis-cli command SET malicious_key '!!python/object/apply:os.system ["touch /tmp/pwned"]'.
    4. The Django application, configured to use redis_cache.RedisCache with YAMLSerializer, attempts to retrieve and deserialize this cache key using cache.get('malicious_key').
    5. The YAMLSerializer's deserialize method in redis_cache/serializers.py uses yaml.load(value, Loader=yaml.FullLoader). yaml.FullLoader is known to be unsafe and vulnerable to arbitrary code execution. When processing the malicious YAML payload, arbitrary code execution occurs on the server. The vulnerability occurs because the YAMLSerializer in redis_cache/serializers.py uses yaml.FullLoader when deserializing YAML data. FullLoader is known to be unsafe and can execute arbitrary code if the YAML data contains malicious payloads. An attacker can exploit a YAML deserialization vulnerability if the application is configured to use the YAMLSerializer.
  • Impact: Arbitrary code execution on the server. An attacker can gain full control of the server, potentially leading to data breaches, service disruption, and further malicious activities. Successful exploitation allows an external attacker to achieve arbitrary code execution on the server hosting the Django application. This can lead to complete compromise of the server and the application, including data theft, data manipulation, and further attacks on internal systems.

  • Vulnerability Rank: Critical

  • Currently implemented mitigations: None. The django-redis-cache project provides the YAMLSerializer option without any specific warnings about its unsafe nature when handling potentially untrusted data. The code in redis_cache/serializers.py directly uses yaml.FullLoader without any safeguards.

  • Missing mitigations:

    • Remove or strongly discourage the use of YAMLSerializer with yaml.FullLoader due to its inherent unsafe deserialization properties.
    • If YAMLSerializer is to be kept, switch to using yaml.SafeLoader which is safer but has limited functionality. Alternatively, provide a very clear and prominent warning in the documentation about the severe security risks associated with using YAMLSerializer and yaml.FullLoader, especially when the Redis cache might store data that could be influenced by external actors.
    • Recommend and promote the use of safer serializers by default, such as JSONSerializer or PickleSerializer (while still noting the risks of pickle with untrusted input).
    • The YAMLSerializer should be changed to use yaml.SafeLoader instead of yaml.FullLoader. SafeLoader is designed to prevent the deserialization of unsafe YAML constructs that can lead to code execution.
    • Alternatively, the documentation should strongly warn against using YAMLSerializer in production environments, especially when caching potentially untrusted data, and recommend using safer serializers like JSONSerializer or PickleSerializer with appropriate security considerations.
  • Preconditions:

    1. A Django application is using django-redis-cache.
    2. The Django application's cache configuration is set to use YAMLSerializer (i.e., OPTIONS: {'SERIALIZER_CLASS': 'redis_cache.serializers.YAMLSerializer'}).
    3. An attacker is able to inject data into the Redis cache. This could arise from various scenarios, such as:
      • A separate vulnerability in the Django application that allows cache poisoning.
      • An improperly secured Redis instance that is accessible to the attacker.
      • Internal application logic that inadvertently stores attacker-influenced data in the cache. The Django application must be configured to use redis_cache.serializers.YAMLSerializer for caching. This is configured via the CACHES setting in Django's settings.py. An attacker must be able to influence or control the data that gets stored in the cache. This could happen if the application directly or indirectly caches user inputs, or if there is another vulnerability that allows cache poisoning.
  • Source Code Analysis:

    • File: /code/redis_cache/serializers.py
    • Class: YAMLSerializer
    • Method: deserialize(self, value)
    class YAMLSerializer(BaseSerializer):
        def serialize(self, value):
            return yaml.dump(value, encoding='utf-8', Dumper=yaml.Dumper)
    
        def deserialize(self, value):
            return yaml.load(value, Loader=yaml.FullLoader)
    • The deserialize method utilizes yaml.load(value, Loader=yaml.FullLoader). The use of yaml.FullLoader makes the deserialization process vulnerable to arbitrary code execution if the value originates from or is influenced by an untrusted source. Although in typical cache usage, data is serialized and deserialized within the application's control, scenarios where an attacker can inject data into the cache create a critical security vulnerability when YAMLSerializer is employed.
    • The deserialize method of the YAMLSerializer class uses yaml.load(value, Loader=yaml.FullLoader). yaml.FullLoader in PyYAML is known to be vulnerable to arbitrary code execution because it allows deserialization of arbitrary Python objects from the YAML stream, including those that can execute code upon instantiation. If an attacker can inject a specially crafted YAML payload into the cache and the application later deserializes this data using YAMLSerializer, the malicious YAML can trigger arbitrary code execution on the server.
  • Security Test Case:

    1. Set up a Django project and install the django-redis-cache library.
    2. Configure the Django cache settings in settings.py to use redis_cache.RedisCache with YAMLSerializer:
    CACHES = {
        'default': {
            'BACKEND': 'redis_cache.RedisCache',
            'LOCATION': '127.0.0.1:6381', # Or your Redis server location
            'OPTIONS': {
                'SERIALIZER_CLASS': 'redis_cache.serializers.YAMLSerializer'
            },
        }
    }
    1. Create a Django view in tests/views.py (or any suitable app) to retrieve and deserialize a cache key:
    from django.core.cache import caches
    from django.http import HttpResponse
    
    def vulnerable_view(request):
        cache = caches['default']
        key = 'yaml_injection_test_key'
        value_from_cache = cache.get(key)
        return HttpResponse(f"Attempted deserialization. Check server for side effects.")
    1. Add a URL pattern for this view in tests/urls.py (or your app's urls.py):
    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('vulnerable_yaml_view/', views.vulnerable_view, name='vulnerable_yaml_view'),
    ]
    1. Inject a malicious YAML payload into the Redis cache using redis-cli:
    redis-cli -p 6381 # Adjust port if necessary
    SET yaml_injection_test_key '!!python/object/apply:os.system ["touch /tmp/pwned_by_yaml_deserialize"]'
    1. Access the vulnerable view in a web browser or using curl: http://your_django_host/vulnerable_yaml_view/.
    2. Check if the file /tmp/pwned_by_yaml_deserialize has been created on the server. Successful creation of this file indicates arbitrary code execution due to unsafe YAML deserialization, confirming the vulnerability.

    Alternatively for test case from list 3:

    1. Modify the test settings file (/code/tests/settings.py) to configure the default cache to use YAMLSerializer as described in list 3 step 1.
    2. Create a new test view in /code/tests/views.py to set and retrieve a malicious YAML payload in the cache as described in list 3 step 2.
    3. Add these views to the test URLs in /code/tests/urls.py as described in list 3 step 3.
    4. Run the Django test server (e.g., using ./tests/runtests.py).
    5. Access the set_yaml/ URL in a browser or using curl (e.g., http://127.0.0.1:8000/set_yaml/). This will set the malicious YAML payload in the cache.
    6. Access the get_data/ URL (e.g., http://127.0.0.1:8000/get_data/). This will retrieve and deserialize the YAML data from the cache.
    7. Check if the file /tmp/pwned has been created on the server. If the file exists, it confirms that the malicious YAML payload was executed, demonstrating arbitrary code execution vulnerability. Expected result: After performing the test case steps, the file /tmp/pwned should be created, indicating successful arbitrary code execution due to YAML deserialization vulnerability.

Insecure Deserialization via PickleSerializer

  • Description: An attacker who gains access to the Redis cache (for example by exploiting network misconfiguration or weak authentication) can inject a malicious pickle payload into the cache. When the application later reads this key using the default PickleSerializer, the untrusted data is deserialized with Python’s pickle.loads() without any integrity or type checks. Since pickle may execute arbitrary code during deserialization, this process can cause arbitrary code execution on the server.

  • Impact: Arbitrary code execution on the host running the Django application. This can lead to a full compromise of the server, data theft, or further lateral movement within the network.

  • Vulnerability Rank: Critical

  • Currently Implemented Mitigations:

    • The project provides alternative serializer classes (e.g., JSONSerializer, MSGPackSerializer, YAMLSerializer) that do not allow arbitrary code execution by design.
    • However, by default the settings rely on the PickleSerializer when no override is provided.
  • Missing Mitigations:

    • No built‑in safeguard is implemented around pickle deserialization to verify the integrity or authenticity of cached data.
    • There is no strict enforcement (within the library) to prefer a safe serializer in public deployments.
  • Preconditions:

    • The Redis instance must be accessible to external attackers (for example, because of misconfiguration or weak network access controls).
    • The cache configuration is set to use the default PickleSerializer (or a configuration that enables it).
  • Source Code Analysis:

    • In /code/redis_cache/serializers.py, the PickleSerializer defines:
      • serialize(self, value) → uses pickle.dumps(value, self.pickle_version).
      • deserialize(self, value) → directly calls pickle.loads(force_bytes(value)).
    • In /code/redis_cache/backends/base.py, when a cache lookup is performed (for example, via the get() or get_or_set() methods), the retrieved raw value is processed by get_value(), which internally calls self.deserialize(value).
    • There is no additional validation or integrity check over the serialized data, so if an attacker injects a crafted pickle payload into Redis, it will be deserialized without any protection.
  • Security Test Case:

    1. Deploy the application in a test environment using the default settings (which use PickleSerializer).
    2. Reconfigure the Redis instance temporarily so that it is accessible on an external interface (or simulate attacker access via an open network channel) and note that its weak password is in use.
    3. Using a Redis client (for example, via redis-cli), connect to the Redis server at the configured location (e.g. 127.0.0.1:6381) with the password “yadayada”.
    4. Prepare and set a key with a malicious pickle payload. (For testing purposes, use a payload that triggers a benign action such as writing a marker file or toggling a debug flag.) – For example, set the key malicious_key to a pickle‑serialized payload that, when deserialized, executes a controlled script.
    5. In the application, trigger code that issues a cache lookup on the key (e.g. via a view that calls cache.get('malicious_key')).
    6. Observe that the malicious payload is executed (for instance, the marker file is created), confirming arbitrary code execution via deserialization.

Weak Default Redis Authentication

  • Description: The project’s configuration (especially in test settings such as in /code/tests/settings.py) hardcodes a weak Redis password (“yadayada”). If the same configuration is deployed (or if production settings are mis‐configured using these defaults) and the Redis instance is exposed to external networks, an attacker can connect to Redis using this password. Once connected, the attacker may read or write data to the cache, alter cached application data, or inject malicious payloads (which, when combined with the insecure deserialization issue, can lead to further compromise).

  • Impact: Unauthorized access to the caching backend can result in cache poisoning, leakage of sensitive application data, and may even pave the way toward arbitrary code execution.

  • Vulnerability Rank: High

  • Currently Implemented Mitigations:

    • A password is specified in the cache configuration; however, the chosen password (“yadayada”) is weak and predictable.
  • Missing Mitigations:

    • There is no mechanism enforcing the use of strong, randomly generated passwords.
    • No network-level access controls (such as firewall restrictions) are integrated into the project’s configuration to protect the Redis instance from exposure to untrusted networks.
  • Preconditions:

    • The Redis instance is deployed using the provided configuration with the weak password.
    • The Redis server is accessible from external networks (e.g. due to misconfiguration or overly permissive firewall settings).
  • Source Code Analysis:

    • In /code/tests/settings.py (as well as in other test case configuration files), the cache configuration under OPTIONS includes:
      • "PASSWORD": "yadayada".
    • In /code/redis_cache/connection.py, when establishing connections to Redis, this password is passed directly (via the keyword arguments to the connection pool) without any additional strengthening or verification.
  • Security Test Case:

    1. Deploy the application (or a test instance of the application) using the provided configuration.
    2. From an external network (or simulate external access), use a Redis client tool (for instance, redis-cli) to connect to the Redis instance at the configured address (e.g. 127.0.0.1:6381).
    3. Authenticate using the password “yadayada” and verify that the authentication succeeds.
    4. Issue basic Redis commands (such as GET, SET, and KEYS) to demonstrate that the attacker can view and modify cache data.
    5. Document the successful unauthorized access as confirmation of the vulnerability.

Hardcoded Weak Django SECRET_KEY

  • Description: In /code/tests/settings.py the Django setting SECRET_KEY is hardcoded as “shh...it's a seakret”. If this test configuration (or a similarly weak key) is inadvertently deployed in production, the predictable and publicly known secret key will compromise Django’s cryptographic signing. An attacker can use the known secret to forge session cookies, CSRF tokens, or other signed data, which may lead to session hijacking or other types of attacks against the web application.

  • Impact: The compromise of the Django secret key can result in session hijacking, authentication bypass, and CSRF attacks—all of which can lead to unauthorized access or data manipulation in the application.

  • Vulnerability Rank: High

  • Currently Implemented Mitigations:

    • The hardcoded key appears only in the test settings. It is assumed that production deployments will override this value.
  • Missing Mitigations:

    • There is no built‑in measure to enforce the use of a strong, unpredictable secret key.
    • No warning or check exists within the library code to prevent accidental deployment of a weak key.
  • Preconditions:

    • The application uses the test configuration (or any configuration with a similarly weak, hardcoded key) in production.
    • An attacker is able to craft or modify signed cookies or tokens using the known secret key.
  • Source Code Analysis:

    • In /code/tests/settings.py, the setting:
      • SECRET_KEY = "shh...it's a seakret" is defined without any randomness or obfuscation.
    • As Django relies on this key for signing session cookies, CSRF tokens, and other security‑critical data, any disclosure or use of this key in production inherently undermines the application’s security.
  • Security Test Case:

    1. Deploy the Django application using the test settings containing the hardcoded secret key.
    2. Using the known secret, an attacker can forge a session cookie (or CSRF token) that appears valid to the application.
    3. Submit requests with the forged cookie to access authenticated endpoints or perform state‑changing operations.
    4. Verify that the application accepts the forged tokens and grants access or performs unintended actions, confirming that the hardcoded key leads to exploitable weakness.