Day 12 Blind SQL injection with conditional errors — Zero to Hero Blind Injection — Portswigger
文章详细描述了如何通过条件响应进行盲注SQL注入攻击的过程。作者Rayofhope展示了如何通过注入单引号、逻辑条件以及使用CASE语句触发错误来确认漏洞存在,并最终利用自动化工具提取出管理员密码“-7atmswkujntemnlzmxno”。 2025-7-1 10:26:11 Author: infosecwriteups.com(查看原文) 阅读量:11 收藏

RayofHope

Hi, my fellow hackers. This is Rayofhope. I have over 5 years of experience and am currently working as a consultant with a Big 4 firm.

It’s Day 12 of posting all the PortSwigger labs, not just the solutions. I’ll break down why we take each step, because once the ‘why’ is clear, the ‘how’ becomes easy.

Let’s Start:

Before you go for this blog, make sure to read the Previous one

Link to First Blog: https://arayofhope7.medium.com/blind-sql-injection-with-conditional-responses-zero-to-hero-blind-injection-portswigger-dad0cab48d57

Video Walkthrough — You can watch the video or read the blog, totally up to you. But if you ask me, start with the video, then read the blog to connect all the dots.

Deadliest Virus in the world.

This is how the application looks:

As we already know, the cookies parameter is vulnerable to Blind SQL Injection. So, let's intercept the request and explore what we can do with it.

Tried injecting a single quote ('), and it returned a 200 OK response. However, there's no clear indication, such as a true or false statement, to confirm the vulnerability. It could be that the Pets parameter is the one being affected.

Replaced the Tracking ID with rayofhope, and it still returned a 200 OK response. However, rayofhope doesn't appear anywhere in the response, and we aren't seeing any indicators that would confirm a true or false condition.

Used a single quote ('), and it returned a 500 Internal Server Error. This indicates that the single quote might be breaking the SQL query, which suggests that the query could be part of custom developer-written code.

There we go, this time, we didn’t get an error. We used ‘ and 1=1, which is a universal true condition, confirming that the single quote is now properly balancing the SQL query. This suggests that the parameter could potentially be vulnerable to Blind SQL Injection.

But wait a minute, we tried ' and 1=2, which is clearly a false condition (because, yeah, 1 is never equal to 2, not even in developer dreams). Yet, we still got a 200 OK response! No error, no change, no sign of rejection.

This is where things get tricky. When both true (' and 1=1) and false (' and 1=2) conditions return the same response, we can't rely on visual cues or error messages. Welcome to the world of Blind SQL Injection — where the injection is happening, but the app acts like nothing’s wrong. It's like trying to read a poker face... in the dark!

Inputs like '-- or '' are valid parts of an SQL query, so the database doesn’t throw an error, the query still runs, and we get a 200 OK in response.

But waiiih — we just saw that ‘’ is accepted, right? That might mean the input is being treated as part of a valid SQL string. Sooo… what if we try to concatenate something? Like ‘ || (SELECT ‘’)’

Oh nooo, we still got an error with '||(SELECT '')||'! Where are we messing up? Wait a sec… maybe it's not using a string concatenation operator like ||. Could it be an Oracle database? 🤔 Either way, getting an error now is actually a good thing — it means we’re poking the query in the right place!

We replaced dual with rayofhope,a table we know doesn’t exist, and boom, we got an error! But withdual, we get a clean 200 OK. That’s the confirmation we needed: the input is being executed, the equation is balanced, and yes, it's vulnerable to Blind SQL Injection.

What’s Next? — See Me Doin’ It! 🎥🔥

Why does '||(select '' from users)||' give an error even though the users table exists?

Let’s understand this way: —

If the users table has no rows (i.e., it's empty), the query SELECT '' FROM users will return no results. This means a 200 OK response, as the query completes successfully without returning any rows.

But wait, '||(select '' from users where rownum = 1)||' With this command, it returned 200 OK. Why? Why? Why? It is because ROWNUM is a special keyword in Oracle SQL that returns the first row from a query result. WHERE rownum = 1 ensures that only the first row from the users table is returned, and therefore, it returns 200 OK.

Since we know the users table exists, we tried to confirm whether the administrator user exists in the username column.

We tried using the username rayofhope, and in both cases, the application returned a 200 OK response. This suggests there's something off with our query — we're unable to verify true or false conditions, which is the foundation of Blind SQL Injection testing.

Used '||(SELECT CASE WHEN (1=0) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||', got 200 OK, which means the condition was false, so no error happened.

Used '||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||', got an error because the condition was true, causing a divide-by-zero error, which confirms that the SQL query is being executed and that the application is vulnerable to error-based Blind SQL Injection.

But what is CASE , TO_CHAR: —

Note: —

CASE WHEN (1=1) is a logical condition. Always true. If you replace this with 1=0, the behaviour will change.
THEN TO_CHAR(1/0) forces a divide by zero error (crash) to confirm the condition is true.
ELSE ‘’ If statement is false, just return empty string quietly — no error, no noise.
END — If we use case when we use end to close it

Used '||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'. As per the above theory, you may now understand that if it is giving an error, it means the administrator account exists.

Used '||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='rayofhope')||' as the username, and it returned a 200 OK response. This means the condition was false (as the rayofhope username doesn't exist), so the error was avoided and the query executed successfully without triggering any error.

  • Now, we are sure that the admin user exists.

I used the following syntax.

'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator' AND length(password)>1)||'

, and it returned an error. This means the condition was true, indicating that the length of the administrator password is greater than 1.

I used the following syntax.

'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator' AND length(password)>25)||'

, and it gave a 200 OK response. This means the length of the administrator password is less than 25 characters. We can either manually try different values like 24, 23, 22, and so on to determine the password length, or simply use a tool like Burp Suite Intruder to automate the process.

Send the request to Intruder, select the parameter for the password length, and set the payload range from 1 to 25. Start the attack to automate the process of discovering the correct password length.

You can see that at payload number 20, the response behaviour changed. Remember one rule: brute-force attacks often rely on changes in response length or behaviour. This indicates that the password is 20 characters long.

Since this is an Oracle database, I’m using SUBSTR instead of SUBSTRING to manually extract the password. I used the following payload:

'||(SELECT CASE WHEN (SUBSTR(password,1,1)='r') THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'

This helps confirm whether the first character of the password is 'r' by triggering a divide-by-zero error. Manually finding all 20 characters is possible, but it could take hours, so let's automate the process!

Send the request to Intruder, and configure the payload positions:

  1. For the first payload position (to represent the character position in the password), select “Numbers” as the payload type and set the range from 1 to 20.
  2. For the second payload position (to guess the password character), select “Simple list” or “Brute forcer”, and include lowercase letters and numbers.

Once configured, start the attack to brute-force each character of the password, one position at a time.

We have the correct password now, let's collect it

This is the password: -7atmswkujntemnlzmxno


文章来源: https://infosecwriteups.com/day-12-blind-sql-injection-with-conditional-errors-zero-to-hero-blind-injection-portswigger-e94f9e3977a5?source=rss----7b722bfd1b8d---4
如有侵权请联系:admin#unsafe.sh