Here is the combined list of vulnerabilities, formatted as markdown, removing duplicates and merging descriptions where necessary:
This document outlines the identified vulnerabilities, their descriptions, impacts, ranks, mitigations, preconditions, source code analysis, and security test cases.
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:
- Attacker sends a request to the honeypot login page (e.g.,
/admin/
) or/admin/login/
with a manipulatedHost
header, for example,Host: malicious.example.com
. - Attacker fills in the honeypot login form with arbitrary credentials and submits it.
- The
admin_honeypot
application logs the login attempt and thenotify_admins
function is triggered via a signal. - The
notify_admins
function constructs an admin detail URL by concatenating the value returned byrequest.get_host()
with a URL generated by Django’sreverse()
function. - 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. - An email notification is sent to administrators containing the malicious link.
- 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:
- The Django application is deployed behind a proxy or load balancer that forwards the Host header without proper validation.
- The
ADMIN_HONEYPOT_EMAIL_ADMINS
setting is set toTrue
in the Django settings, enabling email notifications to administrators for honeypot login attempts. - An attacker can send requests to the publicly accessible honeypot login page.
- The application is deployed in an environment where the
ALLOWED_HOSTS
setting is misconfigured or whereDEBUG
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:
-
Setup: a. Set up a Django application with
django-admin-honeypot
installed. b. EnsureADMIN_HONEYPOT_EMAIL_ADMINS = True
is set insettings.py
. c. Configure email backend todjango.core.mail.backends.locmem.EmailBackend
insettings.py
for testing emails locally.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
-
Action: a. Access the honeypot login URL (e.g.,
/admin/
) or/admin/login/
in a browser or usingcurl
. b. Usingcurl
or a similar tool, send a POST request to the honeypot login URL with a manipulatedHost
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). -
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 hosthttp://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 tohttp://malicious.example.com
, the vulnerability is confirmed.
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:
- Attacker navigates to the real Django admin login page (e.g.,
/secret/admin/login/
). - 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. - The browser sends a request to the honeypot login page, including a
Referer
header that contains the real admin login URL. - The Django admin honeypot application logs this login attempt and sends an email notification to administrators (if enabled).
- If the email template includes
request.META.HTTP_REFERER
, the Referer header value, containing the real admin URL, will be included in the email. - 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:
ADMIN_HONEYPOT_EMAIL_ADMINS
setting is set toTrue
(or defaults toTrue
).- The email template
admin_honeypot/email_message.txt
(or equivalent template used for email body) includes{{ request.META.HTTP_REFERER }}
in its content. - 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:
- 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 acontext
dictionary that includes therequest
object, which contains request metadata including headers. - This
context
is passed torender_to_string
to render the email message from theadmin_honeypot/email_message.txt
template.
- (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:
-
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'sconsole
email backend orfilebased.EmailBackend
). ConfigureADMIN_HONEYPOT_EMAIL_ADMINS = True
in your Django settings. Ensure that the email templateadmin_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 intemplates/admin_honeypot/email_message.txt
within your app directory. -
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. -
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.