Skip to content

Latest commit

 

History

History
190 lines (151 loc) · 13.9 KB

File metadata and controls

190 lines (151 loc) · 13.9 KB

Here is the combined list of vulnerabilities, formatted as markdown, removing duplicates and merging descriptions where necessary:

Combined Vulnerability List

This document outlines the identified vulnerabilities, their descriptions, impacts, ranks, mitigations, preconditions, source code analysis, and security test cases.

1. Host Header Injection in Admin Email Link

Vulnerability Name: Host Header Injection in Admin Email Link

Description: The notify_admins listener in admin_honeypot/listeners.py generates a URL to the admin detail page of a login attempt and includes it in the email sent to administrators. This URL is constructed using request.get_host(). If the application is behind a proxy or load balancer and doesn't properly validate the Host header, an attacker can manipulate the Host header in their request to the honeypot login page. This will cause request.get_host() to return the attacker-controlled host, leading to a malicious link in the admin email. When an administrator clicks this link, they might be redirected to a phishing site or another malicious domain.

Steps to trigger the vulnerability:

  1. Attacker sends a request to the honeypot login page (e.g., /admin/) or /admin/login/ with a manipulated Host header, for example, Host: malicious.example.com.
  2. Attacker fills in the honeypot login form with arbitrary credentials and submits it.
  3. The admin_honeypot application logs the login attempt and the notify_admins function is triggered via a signal.
  4. The notify_admins function constructs an admin detail URL by concatenating the value returned by request.get_host() with a URL generated by Django’s reverse() function.
  5. Because the code does not sanitize the Host header before using it, the generated admin_detail_url in the email will include the attacker-controlled host.
  6. An email notification is sent to administrators containing the malicious link.
  7. Administrator receives the email with the malicious link. If the administrator clicks on this link, they will be redirected to malicious.example.com instead of the legitimate admin site.

Impact: Phishing attack, potential compromise of admin credentials or system through a malicious link. An attacker can trick administrators into visiting a malicious site, potentially leading to credential theft or further attacks if the administrator interacts with the malicious site assuming it's legitimate. This may pave the way for social engineering attacks or other malicious activities based on administrator misdirection.

Vulnerability Rank: high

Currently Implemented Mitigations: None. The code uses request.get_host() directly without any validation, which is susceptible to Host header injection if the application is behind a vulnerable proxy or load balancer. While Django’s built-in request.get_host() can validate the Host header under proper production settings (with correctly configured ALLOWED_HOSTS), there is no explicit sanitization in the project’s code itself.

Missing Mitigations: Host header validation should be implemented to prevent the injection of malicious hostnames. This can be done at the Django application level or at the proxy/load balancer level.

At the Django level, USE_X_FORWARDED_HOST = True and ALLOWED_HOSTS settings should be properly configured in Django settings. This will instruct Django to use the X-Forwarded-Host header (if set by the proxy) and validate the host against ALLOWED_HOSTS. If the proxy is not setting X-Forwarded-Host, then Django's default host header validation should be sufficient if ALLOWED_HOSTS is correctly configured.

At the proxy/load balancer level, the proxy should be configured to validate and sanitize the Host header before forwarding requests to the Django application.

Additionally, the code lacks a fallback mechanism to use a trusted, static hostname for building URLs in notification emails, which could be a robust mitigation in case of misconfiguration.

Preconditions:

  1. The Django application is deployed behind a proxy or load balancer that forwards the Host header without proper validation.
  2. The ADMIN_HONEYPOT_EMAIL_ADMINS setting is set to True in the Django settings, enabling email notifications to administrators for honeypot login attempts.
  3. An attacker can send requests to the publicly accessible honeypot login page.
  4. The application is deployed in an environment where the ALLOWED_HOSTS setting is misconfigured or where DEBUG mode is enabled, allowing arbitrary Host header values.

Source Code Analysis: File: /code/admin_honeypot/listeners.py

from admin_honeypot.signals import honeypot
from django.conf import settings
from django.core.mail import mail_admins
from django.template.loader import render_to_string
from django.urls import reverse


def notify_admins(instance, request, **kwargs):
    path = reverse('admin:admin_honeypot_loginattempt_change', args=(instance.pk,))
    admin_detail_url = 'http://{0}{1}'.format(request.get_host(), path) # Vulnerable line
    context = {
        'request': request,
        'instance': instance,
        'admin_detail_url': admin_detail_url,
    }
    subject = render_to_string('admin_honeypot/email_subject.txt', context).strip()
    message = render_to_string('admin_honeypot/email_message.txt', context).strip()
    mail_admins(subject=subject, message=message)

if getattr(settings, 'ADMIN_HONEYPOT_EMAIL_ADMINS', True):
    honeypot.connect(notify_admins)

The vulnerability lies in the line: admin_detail_url = 'http://{0}{1}'.format(request.get_host(), path)

request.get_host() retrieves the hostname from the HTTP Host header. If the application is behind a proxy and the Host header is not validated by the proxy or Django itself, an attacker can inject a malicious hostname by manipulating the Host header in their request. This injected hostname will be used to construct the admin_detail_url, leading to a malicious link in the admin email.

Visualization:

Attacker's Browser --> (Manipulated Host Header: malicious.example.com) --> Proxy/Load Balancer (No Host Validation) --> Django Application (admin-honeypot) --> Email to Admin (Link contains malicious.example.com) --> Admin clicks link --> Redirected to malicious.example.com

Security Test Case:

  1. Setup: a. Set up a Django application with django-admin-honeypot installed. b. Ensure ADMIN_HONEYPOT_EMAIL_ADMINS = True is set in settings.py. c. Configure email backend to django.core.mail.backends.locmem.EmailBackend in settings.py for testing emails locally.

    EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
  2. Action: a. Access the honeypot login URL (e.g., /admin/) or /admin/login/ in a browser or using curl. b. Using curl or a similar tool, send a POST request to the honeypot login URL with a manipulated Host header and arbitrary username/password:

    curl -X POST -H "Host: malicious.example.com" http://localhost:8000/admin/login/ -d "username=test&password=test"

    (Replace http://localhost:8000/admin/login/ with your honeypot login URL if different).

  3. Verification: a. In your Django application, inspect the sent emails using mail.outbox. You can do this in a Django shell:

    from django.core import mail
    print(mail.outbox)

    b. Examine the content of the email. Verify that the admin_detail_url within the email message contains the malicious host http://malicious.example.com instead of the expected legitimate hostname of your application. For example, the email message might look like:

    A login attempt to the admin honeypot occurred.
    
    Username: test
    IP Address: 127.0.0.1
    User Agent: curl/7.64.1
    Timestamp: ...
    URL: /admin/login/
    Admin Detail URL: http://malicious.example.com/admin/admin_honeypot/loginattempt/1/change/
    

    If the Admin Detail URL points to http://malicious.example.com, the vulnerability is confirmed.

2. Real Admin URL Leakage via Referer Header in Email Notifications

Vulnerability Name: Real Admin URL Leakage via Referer Header in Email Notifications

Description: If an attacker navigates to the Django admin honeypot login page after visiting the real Django admin login page, the browser automatically sends a Referer header containing the URL of the real admin page. If the email template used for honeypot login attempt notifications includes the Referer header from the request, the real Django admin login URL will be exposed in the email sent to administrators. This allows an attacker who triggers the honeypot to learn the actual, intended Django admin login URL, defeating the purpose of the honeypot.

Steps to trigger the vulnerability:

  1. Attacker navigates to the real Django admin login page (e.g., /secret/admin/login/).
  2. Attacker then navigates to the Django admin honeypot login page (e.g., /admin/login/). This can be done by manually changing the URL or clicking a link.
  3. The browser sends a request to the honeypot login page, including a Referer header that contains the real admin login URL.
  4. The Django admin honeypot application logs this login attempt and sends an email notification to administrators (if enabled).
  5. If the email template includes request.META.HTTP_REFERER, the Referer header value, containing the real admin URL, will be included in the email.
  6. Administrators receive an email that unintentionally reveals the real admin login URL.

Impact: Information Leakage: The real Django admin login URL is exposed to potential attackers. Reduced Honeypot Effectiveness: Knowing the real admin URL allows attackers to bypass the honeypot and directly target the legitimate login page, making brute-force attacks or other malicious activities against the real admin panel more focused and potentially successful.

Vulnerability Rank: High

Currently Implemented Mitigations: None. The code currently captures and potentially uses the Referer header in email notifications without any sanitization or filtering if the email template is configured to include it.

Missing Mitigations: The email template for admin notifications should be reviewed and modified to exclude the Referer header. If the Referer header is deemed necessary for debugging or other purposes, it should be carefully sanitized or stripped of sensitive information like the domain and path before being included in the email. Alternatively, consider not including the Referer header in emails at all, as it is not essential for the core functionality of a login attempt notification.

Preconditions:

  1. ADMIN_HONEYPOT_EMAIL_ADMINS setting is set to True (or defaults to True).
  2. The email template admin_honeypot/email_message.txt (or equivalent template used for email body) includes {{ request.META.HTTP_REFERER }} in its content.
  3. An attacker is able to navigate from the real Django admin login page to the honeypot login page, causing the Referer header to contain the real admin URL.

Source Code Analysis:

  1. File: /code/admin_honeypot/listeners.py
def notify_admins(instance, request, **kwargs):
    path = reverse('admin:admin_honeypot_loginattempt_change', args=(instance.pk,))
    admin_detail_url = 'http://{0}{1}'.format(request.get_host(), path)
    context = {
        'request': request,
        'instance': instance,
        'admin_detail_url': admin_detail_url,
    }
    subject = render_to_string('admin_honeypot/email_subject.txt', context).strip()
    message = render_to_string('admin_honeypot/email_message.txt', context).strip()
    mail_admins(subject=subject, message=message)
  • The notify_admins function prepares a context dictionary that includes the request object, which contains request metadata including headers.
  • This context is passed to render_to_string to render the email message from the admin_honeypot/email_message.txt template.
  1. (Assumption) File: /code/admin_honeypot/templates/admin_honeypot/email_message.txt (Example Template Content)
Login attempt detected!

Username: {{ instance.username }}
IP Address: {{ instance.ip_address }}
User Agent: {{ instance.user_agent }}
Timestamp: {{ instance.timestamp }}
Path: {{ instance.path }}
Referer: {{ request.META.HTTP_REFERER }}  {# Potential vulnerability: Leaks Referer header #}
Admin Detail URL: {{ admin_detail_url }}
  • If the template includes {{ request.META.HTTP_REFERER }}, it will directly output the Referer header value in the email.

Security Test Case:

  1. Setup: Setup a Django project with django-admin-honeypot installed and configured. Ensure that email sending is configured to output to the console or a file for testing purposes (e.g., using Django's console email backend or filebased.EmailBackend). Configure ADMIN_HONEYPOT_EMAIL_ADMINS = True in your Django settings. Ensure that the email template admin_honeypot/email_message.txt (or the template being used) includes {{ request.META.HTTP_REFERER }}. If the template does not exist, you may need to create it in templates/admin_honeypot/email_message.txt within your app directory.

  2. Action: a. Access the real Django admin login page. Let's assume your real admin URL is /secret/admin/login/. Open this URL in a browser. b. From the real admin login page (e.g., /secret/admin/login/), navigate to the honeypot login page (e.g., /admin/login/). You can manually change the browser's address bar to the honeypot login URL (e.g., /admin/login/) while still on the real admin page. c. Submit any dummy username and password on the honeypot login form and submit it.

  3. Verification: a. Check the email output in your console or the designated file. b. Verify if the email body contains a "Referer" field. c. If the "Referer" field is present, check if its value is the real Django admin login URL (e.g., http://yourdomain.com/secret/admin/login/). If it is, the vulnerability is confirmed.