Post Page Advertisement [Top]



Click here to send WhatsApp On Unsaved Mobile Numbers For Free

 

Ethical Hacking SQL Injection Deep Dive: Detection, Confirmation & Secure Code Review | Day 17
Ethical Hacking

🛡️ Ethical Hacking — Day 17

SQL Injection Deep Dive: Detection, Confirmation & Secure Code Review

⚠️ LEARNING PURPOSE ONLY: Today's practical work is strictly for your local OWASP Juice Shop lab or another system you explicitly own or have permission to test. Do not apply these techniques to public websites, production databases, or other people's accounts.

Welcome to Day 17.

Yesterday you learned the fundamentals of SQL Injection. Today we'll move from "What is SQLi?" to:

How can I systematically determine whether an input is influencing a database query, without blindly attacking the application?

OWASP's current guidance identifies parameterized queries/prepared statements as the primary defense and recommends least privilege and appropriate allow-list validation as additional defenses. (OWASP Cheat Sheet Series)


🎯 Today's Objectives

You'll learn:

  • Baseline vs abnormal responses

  • SQLi indicators

  • Error-based analysis

  • Boolean-based concepts

  • Response comparison

  • Query parameters vs body parameters

  • Burp Repeater methodology

  • URL encoding

  • SQLi code review

  • Java/JDBC secure coding

  • Spring/JPA secure coding

  • Laravel/PHP secure coding

  • PostgreSQL/MySQL parameterization

  • Linux practical commands

  • Windows PowerShell practical commands

  • macOS practical commands

  • How to document a finding

  • How developers remediate SQL Injection


1. The SQL Injection Mental Model

Keep this model in your head:

USER INPUT
    │
    ▼
WEB APPLICATION
    │
    ▼
SQL QUERY
    │
    ▼
DATABASE
    │
    ▼
DATABASE RESULT
    │
    ▼
HTTP RESPONSE

Your job as a security learner is to understand:

Where does my input go?
        ↓
Does it remain data?
        ↓
Or can it influence SQL structure?

2. Normal Application Behavior

Suppose a search endpoint receives:

q=laptop

The normal workflow might be:

Browser
   ↓
q=laptop
   ↓
Application
   ↓
Database query
   ↓
Matching products
   ↓
JSON response

Record this before testing anything unusual.

This is your:

Baseline


3. What Is a Baseline?

A baseline is the application's normal behavior.

Example:

InputStatusResponseLength
laptop200Normal results2,340

Then you can compare:

Normal
   VS
Test

Without a baseline, it's difficult to determine whether something actually changed.


4. SQLi Indicators

Possible indicators include:

  • SQL/database error messages

  • Unexpected HTTP 500 responses

  • Significant response-length changes

  • Unexpected result counts

  • Different behavior for logically different inputs

  • Database-related information appearing in responses

But remember:

An indicator is not proof.

For example:

500 Internal Server Error

could simply be an ordinary application bug.

OWASP's secure-code-review guidance also recommends preventing sensitive information from being disclosed through error responses. (OWASP Cheat Sheet Series)


5. Start Your Lab

Linux

docker ps

Windows

docker ps

macOS

docker ps

If Juice Shop is stopped:

docker start <container-id>

Then verify:

Linux/macOS

curl -I http://127.0.0.1:3000

Windows

curl.exe -I http://127.0.0.1:3000

6. Start Burp

Open:

Burp Suite
   ↓
Proxy
   ↓
Open Browser

Visit:

http://127.0.0.1:3000

Keep your Burp scope limited to:

127.0.0.1:3000

7. Find a Search Request

Use Juice Shop normally.

Search for:

apple

Then open:

Proxy
   ↓
HTTP history

Find the request generated by the search.

Your version may use a route similar to:

GET /rest/products/search?q=apple HTTP/1.1
Host: 127.0.0.1:3000

Do not assume the endpoint.

Find the actual request in your installation.


8. Send It to Repeater

Right-click:

Send to Repeater

Then:

Repeater

Send the original request.

Record:

Method:
Endpoint:
Parameter:
Status:
Length:
Content-Type:

9. Establish Your Baseline

For example:

Parameter:
q

Normal value:
apple

Status:
200

Length:
______

Result:
Normal product results

Now you have something to compare against.


🧪 Practical Exercise 1

Ordinary Input Comparison

Test several normal values.

For example:

apple
test
phone
laptop

Record:

InputStatusLengthResults
apple_________
test_________
phone_________
laptop_________

You're learning the application's normal behavior.


10. Special-Character Test

Inside your local lab, test a single quote:

'

So conceptually:

q='

Observe:

Status
Response length
Error
Response body

Don't immediately assume SQLi.


11. Why Does a Quote Matter?

Suppose the developer wrote:

SELECT *
FROM products
WHERE name = 'USER_INPUT';

The quotes define a SQL string.

If user input is concatenated directly into the query, a quote can potentially interfere with that structure.

This is why special characters can be useful diagnostic inputs.


12. Compare

Create:

TestStatusLengthObservation
apple200___Normal
'_________

Possible results:

Case A

Both return normal responses

Interesting, but not conclusive.

Case B

Quote causes validation error

Could indicate input validation.

Case C

Quote causes database-related error

Worth investigating.

Case D

Quote causes 500

Interesting, but still not proof.


13. Error-Based Analysis

Suppose:

Normal:
200 OK

Quote:
500 Internal Server Error

Now inspect the response carefully.

Look for:

SQL syntax
Database
SQLException
PostgreSQL
MySQL
SQLite
ORM
Stack trace

If sensitive internal details appear, document them—but don't exploit further.


14. Don't Over-Test

Suppose you discover:

q='

causes a database error.

Don't immediately:

❌ Dump tables
❌ Extract passwords
❌ Extract customer data
❌ Modify database records
❌ Delete data

Instead:

Detect
 ↓
Confirm minimally
 ↓
Document
 ↓
Recommend fix

Professional testing is not about collecting the maximum amount of data.


15. Boolean-Based Concept

Now let's understand a more advanced idea.

Imagine an application evaluates:

Condition A

and:

Condition B

If the database evaluates them differently and the application's response changes accordingly, that behavior can indicate that input is influencing the query logic.

Conceptually:

Input
 ↓
SQL condition
 ↓
Database
 ├── TRUE
 │     ↓
 │   Response A
 │
 └── FALSE
       ↓
     Response B

This is the basic idea behind blind/inferential SQL Injection.

OWASP classifies blind SQLi as an inferential technique where information is inferred from application/database behavior rather than directly returned. (OWASP Cheat Sheet Series)


16. Response Comparison

This is the skill I want you to develop.

Compare:

Status
Length
Headers
Body
Number of results
Error messages
Response time

Example:

TestStatusLengthResults
Baseline2002,3005
Test A2002,3005
Test B2004,10020

A significant difference deserves investigation.


17. But Differences Can Have Many Causes

A response change doesn't necessarily mean SQL Injection.

It could be:

Different search result
Caching
Application logic
Input validation
Database state
Random data
Authentication state

Therefore:

Evidence must be interpreted in context.


18. Query Parameter vs Body Parameter

SQL Injection can occur through different input locations.

Query parameter

GET /search?q=apple

Form body

POST /search

q=apple

JSON body

{
  "q": "apple"
}

HTTP header

Some application architectures may use request headers as inputs.

The important question is always:

Does untrusted input reach a database query unsafely?


19. JSON Example

Suppose your local lab produces:

POST /api/search HTTP/1.1
Content-Type: application/json

{
  "search": "apple"
}

The input is:

search

You would analyze it the same way:

Normal
 ↓
Baseline
 ↓
Controlled test
 ↓
Compare

20. URL Encoding

The browser may encode special characters.

For example:

'

can appear as:

%27

So you might see:

?q=%27

rather than:

?q='

This is why understanding HTTP encoding matters.


🧪 Practical Exercise 2 — Encoding

Test your local endpoint with:

q=apple

Then:

q=%27

Compare the results.

Record:

Raw input:
'

Encoded input:
%27

Same response?
Yes / No

Difference:
____________

21. curl — Linux

Use your actual endpoint discovered in Burp.

For example:

curl -i "http://127.0.0.1:3000/rest/products/search?q=apple"

Verbose:

curl -v "http://127.0.0.1:3000/rest/products/search?q=apple"

Encoded character:

curl -i "http://127.0.0.1:3000/rest/products/search?q=%27"

Only use the endpoint if it exists in your local Juice Shop instance.


22. curl — macOS

curl -i "http://127.0.0.1:3000/rest/products/search?q=apple"

Verbose:

curl -v "http://127.0.0.1:3000/rest/products/search?q=apple"

Encoded input:

curl -i "http://127.0.0.1:3000/rest/products/search?q=%27"

23. curl — Windows

PowerShell:

curl.exe -i "http://127.0.0.1:3000/rest/products/search?q=apple"

Verbose:

curl.exe -v "http://127.0.0.1:3000/rest/products/search?q=apple"

Encoded:

curl.exe -i "http://127.0.0.1:3000/rest/products/search?q=%27"

24. curl Through Burp

You can also send your local request through Burp.

Linux/macOS

curl -x http://127.0.0.1:8080 \
"http://127.0.0.1:3000/"

Windows

curl.exe -x http://127.0.0.1:8080 `
"http://127.0.0.1:3000/"

Flow:

curl
 ↓
Burp :8080
 ↓
Juice Shop :3000

This is useful for understanding how command-line clients interact with your proxy.


25. Code Review — The Most Valuable Skill

You can often identify SQL Injection faster from source code than by testing.

Look for:

User Input
     ↓
String Concatenation
     ↓
SQL Execution

For example:

String sql =
    "SELECT * FROM users WHERE email = '" + email + "'";

🚨 This deserves review.


26. Safe Java Version

Use:

String sql =
    "SELECT * FROM users WHERE email = ?";

PreparedStatement ps =
    connection.prepareStatement(sql);

ps.setString(1, email);

ResultSet rs =
    ps.executeQuery();

The parameter is bound separately.

OWASP recommends this approach because parameterized queries keep SQL code and data separate. (OWASP Cheat Sheet Series)


27. Spring Boot/JPA

Since you work with Spring Boot, avoid dynamically constructing JPQL/HQL with user input.

❌ Unsafe pattern

String jpql =
    "FROM User u WHERE u.email = '" + email + "'";

entityManager.createQuery(jpql);

✅ Better

String jpql =
    "FROM User u WHERE u.email = :email";

entityManager
    .createQuery(jpql, User.class)
    .setParameter("email", email);

Or use a repository method:

Optional<User> findByEmail(String email);

28. Laravel

❌ Unsafe

$sql = "SELECT *
        FROM users
        WHERE email = '$email'";

✅ Parameterized

$sql = "SELECT *
        FROM users
        WHERE email = ?";

DB::select($sql, [$email]);

✅ Query Builder

User::where('email', $email)->first();

29. PostgreSQL

Use parameter placeholders supported by your database driver.

Conceptually:

SELECT *
FROM users
WHERE email = $1;

Then:

$1 = user-provided email

The important part isn't the placeholder syntax itself.

The important principle is:

SQL code ≠ User data

30. MySQL

For drivers that use ? placeholders:

SELECT *
FROM users
WHERE email = ?;

Bind the value separately.

Don't construct:

"... WHERE email = '" + email + "'"

31. What About ORM?

ORMs such as:

Hibernate
JPA
Eloquent
SQLAlchemy

can make secure database access easier.

But:

ORM does not automatically make every query safe.

Raw SQL and dynamic query construction can still introduce injection vulnerabilities.

OWASP explicitly notes that ORM/HQL usage can still be unsafe when dynamic query construction is used. (OWASP Cheat Sheet Series)


32. Dynamic ORDER BY

Here's an important special case.

Suppose the application lets the user select:

Sort:
Price
Name
Date

You generally cannot parameterize a SQL column identifier in exactly the same way as a normal value.

Instead, use an allow-list.

Example:

String column;

switch (sort) {
    case "price":
        column = "price";
        break;

    case "name":
        column = "name";
        break;

    default:
        throw new IllegalArgumentException();
}

Then construct the query from known safe values.

OWASP recommends allow-list validation or redesign for SQL elements such as table/column names and sort directions where bind variables aren't applicable. (OWASP Cheat Sheet Series)


33. Why Escaping Isn't the Primary Defense

You may hear:

"Just escape the quotes."

Don't rely on this as your main defense.

OWASP classifies escaping all user input as strongly discouraged compared with parameterization because it is fragile and context/database dependent. (OWASP Cheat Sheet Series)

Prefer:

1. Parameterization
2. Safe stored procedures where appropriate
3. Allow-list validation where necessary
4. Least privilege

34. Least-Privilege Database Account

Suppose your application only needs to read product data.

Its database account shouldn't automatically have:

DROP
ALTER
CREATE USER
GRANT
SUPERUSER

permissions.

Instead, give it only what it needs.

OWASP recommends least privilege as an additional defense so that even if a vulnerability exists, its impact is reduced. (OWASP Cheat Sheet Series)


35. Error Handling

Bad:

500

PostgreSQL error:
relation "users" does not exist
at /var/www/app/database/...

Better:

500

Something went wrong.

Detailed technical information should go to protected server-side logs rather than the user.


36. SQLi Testing Methodology

Memorize:

              SCOPE
                ↓
        Identify Input
                ↓
          Baseline
                ↓
       Harmless Variation
                ↓
          Observe
                ↓
       Compare Responses
                ↓
        Investigate Signal
                ↓
       Confirm Minimally
                ↓
         Document
                ↓
        Recommend Fix

This is much better than:

"Try random payloads until something breaks."

🧪 Day 17 Main Lab

Mission

Investigate one input parameter in your local Juice Shop installation.

Step 1

Start Juice Shop:

docker ps

Step 2

Open:

http://127.0.0.1:3000

Step 3

Start Burp.

Step 4

Browse the application normally.

Step 5

Find an input that reaches the server.

Step 6

Capture it in:

Proxy → HTTP history

Step 7

Send it to:

Repeater

Step 8

Record baseline.

Step 9

Change one value.

Step 10

Test a harmless special character.

Step 11

Compare:

Status
Length
Body
Headers
Errors

Step 12

Document your conclusion.


📊 Day 17 Investigation Sheet

╔══════════════════════════════════╗
║       DAY 17 SQLi LAB            ║
╚══════════════════════════════════╝

Target:
127.0.0.1:3000

Feature:
________________________

Endpoint:
________________________

HTTP Method:
________________________

Parameter:
________________________

Normal Input:
________________________

Baseline Status:
________________________

Baseline Length:
________________________

Test Input:
________________________

Test Status:
________________________

Test Length:
________________________

Response Difference:
________________________

Database Error?
Yes / No

SQLi Indicator?
Yes / No / Unclear

Evidence:
________________________

Conclusion:
________________________

Recommended Fix:
________________________

🔍 Day 17 Evidence Standard

Don't write:

"I found SQL Injection."

unless you actually have sufficient evidence.

Instead use:

Weak evidence

"A special character produced a different response."

Better evidence

"A special character consistently produces a database-related error while normal input produces a normal response."

Stronger conclusion

"Controlled testing demonstrates that user input changes database query behavior in the authorized lab."

Your report should distinguish:

Observation

from:

Conclusion

🧪 Practical Exercise — Code Review

Create these two files locally.

unsafe.java

String email = request.getParameter("email");

String sql =
    "SELECT * FROM users WHERE email = '" + email + "'";

Statement statement =
    connection.createStatement();

ResultSet result =
    statement.executeQuery(sql);

Identify the problem.


safe.java

String email = request.getParameter("email");

String sql =
    "SELECT * FROM users WHERE email = ?";

PreparedStatement ps =
    connection.prepareStatement(sql);

ps.setString(1, email);

ResultSet result =
    ps.executeQuery();

Identify why the second version is safer.


🧠 Day 17 Key Concept

Compare these:

❌ USER INPUT
       ↓
STRING CONCATENATION
       ↓
SQL
       ↓
DATABASE

with:

✅ SQL TEMPLATE
       +
   PARAMETER
       ↓
PREPARED STATEMENT
       ↓
DATABASE

That separation is the heart of SQL Injection prevention.


📝 Day 17 Assignment

Answer these:

1.

What is a baseline?

2.

Why should you establish a baseline before testing?

3.

Does a 500 response prove SQL Injection?

4.

Name five things you can compare between two HTTP responses.

5.

Why can URL encoding matter during testing?

6.

What is the difference between query parameters and JSON body parameters?

7.

What is error-based SQL Injection?

8.

What is blind/inferential SQL Injection?

9.

Why should SQL Injection findings be confirmed minimally?

10.

What is the primary defense against SQL Injection?

11.

Why isn't escaping user input the preferred primary defense?

12.

Why should a database account have minimum privileges?

13.

Can an ORM still contain SQL Injection vulnerabilities?

14.

How should dynamic sort fields be handled safely?

15.

Why should detailed database errors generally not be shown to users?


🏆 Day 17 Challenge

Create a SQL Injection Detection Flowchart:

User Input
    ↓
Baseline
    ↓
Controlled Variation
    ↓
Response Changed?
   /       \
 NO         YES
 │           │
Continue    Investigate
             ↓
       Database Indicator?
          /        \
        NO          YES
        │            │
    Document       Confirm
                     ↓
               Minimal Evidence
                     ↓
                  Report
                     ↓
                    Fix

Then write a one-paragraph report for your local lab.


🔐 Day 17 Ethical Rule

LEARNING PURPOSE ONLY: If your test produces unexpected database behavior, stop at the minimum evidence needed to understand the issue. Do not turn a controlled SQLi test into database extraction, credential harvesting, data modification, or destructive activity.

Professional security testing is:

Permission
   ↓
Scope
   ↓
Minimal Testing
   ↓
Evidence
   ↓
Report
   ↓
Remediation

📚 Official References


✅ Day 17 Summary

Today you learned:

  • Baseline methodology

  • SQLi indicators

  • Error-based analysis

  • Boolean/blind SQLi concepts

  • Response comparison

  • Query/body parameters

  • URL encoding

  • Burp Repeater methodology

  • SQLi code review

  • Java/JDBC prevention

  • Spring/JPA prevention

  • Laravel/PHP prevention

  • PostgreSQL/MySQL parameterization

  • Dynamic SQL risks

  • Allow-list validation

  • Least privilege

  • Secure error handling

  • Linux commands

  • Windows commands

  • macOS commands

  • Professional vulnerability documentation

🔑 Most Important Lesson

Don't learn SQL Injection by memorizing payloads. Learn to trace data from HTTP input → application code → SQL query → database → response, then use parameterization to keep data separate from SQL code.


🔜 Day 18 — Cross-Site Scripting (XSS) Fundamentals

Tomorrow we'll move from server-side SQL Injection to a major client-side/web-output vulnerability: XSS.

We'll cover:

  • What XSS is

  • Reflected XSS

  • Stored XSS

  • DOM-based XSS

  • HTML/JavaScript contexts

  • Input vs output encoding

  • Browser security model

  • Burp Suite testing

  • Safe Juice Shop exercises

  • XSS prevention

  • Content Security Policy

  • JavaScript security basics

  • Linux, Windows & macOS practical sessions

🔐 LEARN → PRACTICE IN YOUR LAB → UNDERSTAND → FIX → SECURE.

No comments:

Post a Comment

Bottom Ad [Post Page]

rrkksinha.