520 lines
14 KiB
Markdown
520 lines
14 KiB
Markdown
# Security Testing Guide
|
|
|
|
This guide provides step-by-step instructions for performing the manual security tests from `references/MANUAL_SECURITY_TESTING_CHECKLIST.md`.
|
|
|
|
## Prerequisites
|
|
|
|
- You are logged in as **User A (ID: 5195)**
|
|
- **User B (ID: 5196)** exists as the victim account
|
|
- **Organization A** and **Organization B** exist
|
|
- **Bank A** exists (optional)
|
|
|
|
## Test Accounts
|
|
|
|
| Profile | ID | Email |
|
|
|---------|-------|-------|
|
|
| User A (you) | 5195 | user-a@test.nl |
|
|
| User B (victim) | 5196 | user-b@test.nl |
|
|
| Organization A | TBD | TBD |
|
|
| Organization B | TBD | TBD |
|
|
|
|
## How to Manipulate Session
|
|
|
|
Since Laravel stores sessions server-side (not in browser Session Storage), use this command:
|
|
|
|
```bash
|
|
cd /home/r/Websites/timebank_cc_2
|
|
php manipulate-session.php <profile_id> <type>
|
|
```
|
|
|
|
**Examples:**
|
|
```bash
|
|
# Change to User B
|
|
php manipulate-session.php 5196 user
|
|
|
|
# Change to Organization A (ID 1)
|
|
php manipulate-session.php 1 org
|
|
|
|
# Change to Bank A (ID 1)
|
|
php manipulate-session.php 1 bank
|
|
|
|
# Change back to User A
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
After running the command, **refresh your browser** to apply the changes.
|
|
|
|
---
|
|
|
|
## Test Category 1: Profile Deletion Authorization
|
|
|
|
### Test 1.1: Unauthorized User Profile Deletion
|
|
**Risk Level:** CRITICAL
|
|
|
|
**Steps:**
|
|
1. Login as User A (already done)
|
|
2. Note User A's profile ID: **5195**
|
|
3. Run session manipulation:
|
|
```bash
|
|
php manipulate-session.php 5196 user
|
|
```
|
|
4. Refresh browser
|
|
5. Navigate to Settings → Delete Account
|
|
6. Attempt to delete the profile
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden error
|
|
**Security Failure:** ❌ Profile deletion succeeds
|
|
|
|
**Log Verification:**
|
|
```bash
|
|
tail -f storage/logs/laravel.log | grep "ProfileAuthorizationHelper"
|
|
```
|
|
Should show: "Unauthorized User access attempt"
|
|
|
|
**Reset Session After Test:**
|
|
```bash
|
|
php manipulate-session.php 5195 user # Change back to User A
|
|
```
|
|
|
|
---
|
|
|
|
### Test 1.2: Unauthorized Organization Profile Deletion
|
|
**Risk Level:** CRITICAL
|
|
|
|
**Prerequisites:** Find Organization A and B IDs first:
|
|
```bash
|
|
mysql -u timebank_cc_dev -p'zea2A8sd{QA,9^pS*2^@Xcltuk.vgV' timebank_cc_2 -e \
|
|
"SELECT id, name, email FROM organizations WHERE name LIKE '%Organization%' LIMIT 5;"
|
|
```
|
|
|
|
**Steps:**
|
|
1. Login as User A (member of Organization A)
|
|
2. Switch to Organization A profile using the profile switcher
|
|
3. Note Organization A's ID
|
|
4. Run session manipulation:
|
|
```bash
|
|
php manipulate-session.php <org_b_id> org
|
|
```
|
|
5. Refresh browser
|
|
6. Navigate to organization settings → Delete Account
|
|
7. Attempt deletion
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ Organization B deleted
|
|
|
|
**Reset:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 1.3: Legitimate Profile Deletion (Control Test)
|
|
**Purpose:** Verify legitimate operations still work
|
|
|
|
**Steps:**
|
|
1. Login as User A
|
|
2. Ensure session is NOT manipulated (reset if needed):
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
3. Refresh browser
|
|
4. Navigate to Settings → Delete Account
|
|
5. Complete deletion process (⚠️ Use a test account, not your main account!)
|
|
|
|
**Expected Result:** ✅ Profile deletion succeeds
|
|
**Security Failure:** ❌ Legitimate deletion blocked
|
|
|
|
---
|
|
|
|
## Test Category 2: Profile Modification Authorization
|
|
|
|
### Test 2.1: Unauthorized Profile Settings Modification
|
|
**Risk Level:** CRITICAL
|
|
|
|
**Steps:**
|
|
1. Login as User A
|
|
2. Navigate to profile settings page
|
|
3. Run session manipulation:
|
|
```bash
|
|
php manipulate-session.php 5196 user
|
|
```
|
|
4. Refresh browser
|
|
5. Attempt to modify profile details (name, email, about, etc.)
|
|
6. Click Save
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ User B's profile modified
|
|
|
|
**Reset:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 2.2: Unauthorized Organization Settings Modification
|
|
**Risk Level:** CRITICAL
|
|
|
|
**Steps:**
|
|
1. Login as User A
|
|
2. Switch to Organization A
|
|
3. Run session manipulation:
|
|
```bash
|
|
php manipulate-session.php <org_b_id> org
|
|
```
|
|
4. Refresh browser
|
|
5. Navigate to organization settings
|
|
6. Attempt to modify organization details
|
|
7. Click Save
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ Organization B modified
|
|
|
|
**Reset:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
## Test Category 3: Message Settings Authorization
|
|
|
|
### Test 3.1: Unauthorized Message Settings Access
|
|
**Risk Level:** CRITICAL
|
|
|
|
**Steps:**
|
|
1. Login as User A
|
|
2. Navigate to Settings → Message Settings
|
|
3. Note current notification preferences
|
|
4. Run session manipulation:
|
|
```bash
|
|
php manipulate-session.php 5196 user
|
|
```
|
|
5. Refresh browser
|
|
6. Toggle notification settings (email, push, etc.)
|
|
7. Click Save
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ User B's message settings changed
|
|
|
|
**Reset:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
## Test Category 4: Chat/Conversation Authorization
|
|
|
|
### Test 4.1: Unauthorized Conversation Access
|
|
**Risk Level:** HIGH
|
|
|
|
**Prerequisites:**
|
|
1. Create a conversation between User B and another user
|
|
2. Note the conversation ID from the URL
|
|
|
|
**Steps:**
|
|
1. Login as User A
|
|
2. Manually navigate to: `/chat/{conversation_id}`
|
|
3. Attempt to view conversation
|
|
4. Attempt to send messages
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden or redirect
|
|
**Security Failure:** ❌ User A can read/send messages
|
|
|
|
---
|
|
|
|
## Test Category 5: Transaction/Payment Authorization
|
|
|
|
### Test 5.1: Unauthorized Transaction Viewing
|
|
**Risk Level:** HIGH
|
|
|
|
**Prerequisites:**
|
|
1. User B creates transaction with User C
|
|
2. Note transaction ID
|
|
|
|
**Steps:**
|
|
1. Login as User A
|
|
2. Navigate to `/transaction/{transaction_id}`
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ User A can view transaction
|
|
|
|
---
|
|
|
|
### Test 5.2: Session Manipulation for Transaction Access
|
|
**Risk Level:** CRITICAL
|
|
|
|
**Steps:**
|
|
1. Login as User A
|
|
2. Run session manipulation:
|
|
```bash
|
|
php manipulate-session.php 5196 user
|
|
```
|
|
3. Refresh browser
|
|
4. Navigate to Transactions page
|
|
5. Check which transactions are visible
|
|
|
|
**Expected Result:** ✅ Only User A's transactions visible (or 403 error)
|
|
**Security Failure:** ❌ User B's transactions visible
|
|
|
|
**Reset:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
## Useful Commands
|
|
|
|
### View Current Sessions
|
|
```bash
|
|
mysql -u timebank_cc_dev -p'zea2A8sd{QA,9^pS*2^@Xcltuk.vgV' timebank_cc_2 -e \
|
|
"SELECT id, user_id, ip_address, FROM_UNIXTIME(last_activity) as last_active \
|
|
FROM sessions WHERE last_activity > UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 2 HOUR)) \
|
|
ORDER BY last_activity DESC LIMIT 5;"
|
|
```
|
|
|
|
### Find Profile IDs
|
|
```bash
|
|
# Users
|
|
mysql -u timebank_cc_dev -p'zea2A8sd{QA,9^pS*2^@Xcltuk.vgV' timebank_cc_2 -e \
|
|
"SELECT id, name, email FROM users WHERE name LIKE '%User%' ORDER BY id LIMIT 10;"
|
|
|
|
# Organizations
|
|
mysql -u timebank_cc_dev -p'zea2A8sd{QA,9^pS*2^@Xcltuk.vgV' timebank_cc_2 -e \
|
|
"SELECT id, name, email FROM organizations WHERE name LIKE '%Organization%' LIMIT 10;"
|
|
|
|
# Banks
|
|
mysql -u timebank_cc_dev -p'zea2A8sd{QA,9^pS*2^@Xcltuk.vgV' timebank_cc_2 -e \
|
|
"SELECT id, name, email FROM banks LIMIT 10;"
|
|
```
|
|
|
|
### Monitor Authorization Logs
|
|
```bash
|
|
# Watch for authorization attempts
|
|
tail -f storage/logs/laravel.log | grep "ProfileAuthorizationHelper"
|
|
|
|
# Watch for unauthorized access attempts
|
|
tail -f storage/logs/laravel.log | grep -i "Unauthorized.*access attempt"
|
|
```
|
|
|
|
### Reset Session to User A
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
**Problem:** Session manipulation doesn't work
|
|
**Solution:** Make sure you refresh the browser after running the command
|
|
|
|
**Problem:** Can't find profile IDs
|
|
**Solution:** Use the MySQL commands above to query the database
|
|
|
|
**Problem:** Script permission denied
|
|
**Solution:** Run `chmod +x manipulate-session.php`
|
|
|
|
**Problem:** Need to restore your original session
|
|
**Solution:** Run `php manipulate-session.php 5195 user` and refresh browser
|
|
|
|
---
|
|
|
|
## Important Notes
|
|
|
|
1. **Always refresh your browser** after manipulating the session
|
|
2. **Reset your session** back to User A after each test: `php manipulate-session.php 5195 user`
|
|
3. **Monitor logs** during testing: `tail -f storage/logs/laravel.log | grep ProfileAuthorizationHelper`
|
|
4. **Don't delete important accounts** - use test accounts for deletion tests
|
|
5. These tests are for **security testing only** - never use in production
|
|
|
|
---
|
|
|
|
## Test Category 6: AccountInfoModal — IDOR (Balance Leakage)
|
|
|
|
### Test 6.1: Unauthorized Balance Viewing via Session Manipulation
|
|
**Risk Level:** HIGH — **Fixed 2026-03-23**
|
|
**Component:** `app/Http/Livewire/AccountInfoModal.php`
|
|
**Fix:** `ProfileAuthorizationHelper::authorize($profile)` added to `loadAccounts()` after profile resolution. Manipulated session now returns HTTP 403.
|
|
|
|
**Steps:**
|
|
1. Login as User A
|
|
2. Open the Account Info modal (click the balance link in the navigation) — note your own balances
|
|
3. Run session manipulation:
|
|
```bash
|
|
php manipulate-session.php 5196 user
|
|
```
|
|
4. Refresh browser
|
|
5. Open the Account Info modal again
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden OR modal shows zero/no accounts
|
|
**Security Failure:** ❌ User B's account balances are visible
|
|
|
|
**Log Verification:**
|
|
```bash
|
|
tail -f storage/logs/laravel.log | grep "ProfileAuthorizationHelper"
|
|
```
|
|
|
|
**Reset:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 6.2: Cross-Profile-Type Balance Leakage (Organization)
|
|
**Risk Level:** HIGH
|
|
|
|
**Steps:**
|
|
1. Login as User A
|
|
2. Run session manipulation to switch to an organization you are NOT a member of:
|
|
```bash
|
|
php manipulate-session.php <org_b_id> org
|
|
```
|
|
3. Refresh browser
|
|
4. Open the Account Info modal
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden OR modal shows zero accounts
|
|
**Security Failure:** ❌ Organization B's account balances are visible
|
|
|
|
**Reset:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
## Test Category 7: Reports — Arbitrary File Write
|
|
|
|
### Test 7.1: Malformed Base64 Chart Image Upload
|
|
**Risk Level:** MEDIUM — **Fixed 2026-03-23**
|
|
**Component:** `app/Http/Livewire/Reports.php` — `exportPdfWithChart()` / `exportPdfWithCharts()`
|
|
**Fix:** `decodeChartImage()` helper validates PNG/JPEG magic bytes before writing. `base64_decode(..., strict: true)` used to reject malformed input. Non-image payloads abort with HTTP 422 and are logged.
|
|
|
|
**Steps:**
|
|
1. Login as User A
|
|
2. Navigate to the Reports page
|
|
3. Open browser DevTools → Network tab
|
|
4. Trigger any PDF export that invokes `exportPdfWithChart`
|
|
5. Locate the Livewire POST request and copy the payload
|
|
6. Modify the `chartImage` parameter to contain a PHP webshell encoded as base64:
|
|
```
|
|
data:image/png;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8+
|
|
```
|
|
(This decodes to `<?php system($_GET['cmd']); ?>`)
|
|
7. Re-send the modified request (use DevTools "Copy as fetch" then paste in Console)
|
|
|
|
**Expected Result:** ✅ Request rejected (invalid MIME type), or file written but not web-executable
|
|
**Security Failure:** ❌ PHP file written to an accessible path and the application executes it
|
|
|
|
**Verify storage is not web-accessible:**
|
|
```bash
|
|
curl -I http://localhost/storage/temp/
|
|
# Should return 404 or 403, not 200
|
|
```
|
|
|
|
---
|
|
|
|
### Test 7.2: Unauthenticated Livewire Chart Export Action
|
|
**Risk Level:** MEDIUM — **Fixed 2026-03-23** (`abort_unless(Auth::check(), 403)` added)
|
|
|
|
**Steps:**
|
|
1. Log out entirely
|
|
2. POST a Livewire request to `exportPdfWithChart` with a valid-looking base64 payload
|
|
|
|
**Expected Result:** ✅ Redirected to login, or 401/403 response
|
|
**Security Failure:** ❌ File written to temp storage without authentication
|
|
|
|
---
|
|
|
|
## Test Category 8: ExportProfileData — Authorization Verification
|
|
|
|
### Test 8.1: Unauthorized Transaction Export via Session Manipulation
|
|
**Risk Level:** HIGH
|
|
**Component:** `app/Http/Livewire/Profile/ExportProfileData.php` — `exportTransactions()`
|
|
**Note:** This component DOES call `ProfileAuthorizationHelper::authorize()`. This test verifies the protection works correctly.
|
|
|
|
**Steps:**
|
|
1. Login as User A
|
|
2. Navigate to Profile → Export Data
|
|
3. Run session manipulation:
|
|
```bash
|
|
php manipulate-session.php 5196 user
|
|
```
|
|
4. Refresh browser
|
|
5. Attempt to export transactions (any format)
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ User B's transactions are exported
|
|
|
|
**Log Verification:**
|
|
```bash
|
|
tail -f storage/logs/laravel.log | grep "ProfileAuthorizationHelper"
|
|
```
|
|
Should show: "Unauthorized User profile access attempt"
|
|
|
|
**Reset:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 8.2: Unauthorized Messages Export
|
|
**Risk Level:** HIGH
|
|
|
|
**Steps:**
|
|
1. Login as User A
|
|
2. Run session manipulation:
|
|
```bash
|
|
php manipulate-session.php 5196 user
|
|
```
|
|
3. Refresh browser
|
|
4. Attempt to export messages
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ User B's private messages exported
|
|
|
|
**Reset:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
### Test 8.3: Unauthorized Contacts Export
|
|
**Risk Level:** MEDIUM
|
|
|
|
**Steps:**
|
|
1. Login as User A
|
|
2. Run session manipulation:
|
|
```bash
|
|
php manipulate-session.php 5196 user
|
|
```
|
|
3. Refresh browser
|
|
4. Attempt to export contacts
|
|
|
|
**Expected Result:** ✅ HTTP 403 Forbidden
|
|
**Security Failure:** ❌ User B's contact list exported
|
|
|
|
**Reset:**
|
|
```bash
|
|
php manipulate-session.php 5195 user
|
|
```
|
|
|
|
---
|
|
|
|
## Quick Reference
|
|
|
|
| Action | Command |
|
|
|--------|---------|
|
|
| Change to User B | `php manipulate-session.php 5196 user` |
|
|
| Change to Org B (ID 1) | `php manipulate-session.php 1 org` |
|
|
| Change to Bank A (ID 1) | `php manipulate-session.php 1 bank` |
|
|
| Reset to User A | `php manipulate-session.php 5195 user` |
|
|
| Monitor logs | `tail -f storage/logs/laravel.log \| grep ProfileAuthorizationHelper` |
|
|
| Check temp dir not web-accessible | `curl -I http://localhost/storage/temp/` |
|