Just because there is a "I am not a robot" checkbox doesn't mean the server is actually checking. Here is how I brute-forced a Forgot Password page behind a broken CAPTCHA.

Introduction: The "Look but Don't Touch" Security

When we browse the web, we are trained to trust certain symbols. The Green Lock means "Secure." The "I am not a robot" checkbox means "No Bots Allowed."

But as Bug Bounty hunters, our job is to question these symbols.

Recently, I was testing a hosting provider, RedactedHost.com. I navigated to their Forgot Password page. It looked solid. It required an email address and had a Google reCAPTCHA widget to prevent bots from spamming the form.

Most hackers see a CAPTCHA and move on, assuming the path is blocked. I didn't. I decided to test if the "bouncer" at the door was actually checking IDs or just pretending to.

It turned out, the bouncer was asleep.

This write-up details how I discovered a CAPTCHA Bypass combined with User Enumeration, leading to a potential P4 vulnerability. Although this report ultimately ended as a Duplicate, the methodology is a perfect lesson for new hunters on why you should always test the CAPTCHA parameter.

The Vulnerability: Server-Side Misconfiguration

Before we dive into the exploit, let's understand the bug.

How CAPTCHA Should Work

  1. Client: You click the checkbox. Google gives you a token (a long string of characters).
  2. Request: Your browser sends the form data (email) + the token (g-recaptcha-response) to the server.
  3. Server: The server takes that token and asks Google: "Hey, is this token valid?"
  4. Google: Replies "Yes" or "No."
  5. Action: If Yes, the password reset email is sent.

The Flaw

The vulnerability occurs when Step 3 is missing.

The developer puts the CAPTCHA on the front end (the visual checkbox), but the back end code forgets to validate the token with Google. It just accepts any request, as long as the parameter exists.

This means I can send "g-recaptcha-response": "blahblahblah" and the server says, "Looks good to me!"

Phase 1: Reconnaissance

I navigated to the target endpoint:

https://my.redactedhost.com/pwreset/email

I entered a valid test email and clicked the CAPTCHA. I intercepted the request using Burp Suite.

The Request Header:

POST /pwreset/email HTTP/1.1
Host: my.redactedhost.com
Content-Type: application/x-www-form-urlencoded
...

The Request Body:=

authenticity_token=9oO0iwTzC...&email=test@example.com&g-recaptcha-response=03AFcWeA5BJuMTbb...

I saw the g-recaptcha-response parameter. This was my target.

Phase 2: The Bypass (Proof of Concept)

To prove the vulnerability, I needed to show that I could send multiple requests with invalid or random CAPTCHA tokens, and the server would still process them.

Step 1: Send to Intruder

I right-clicked the request and sent it to Burp Intruder.

Step 2: Configure Attack Type

I wanted to test two things at once:

  • Can I enumerate different emails? (User Enumeration)
  • Can I use random CAPTCHA tokens? (Bypass)

I selected the Pitchfork attack type.

  • Why Pitchfork? This allows us to use multiple payload sets simultaneously. Payload 1 goes into Position 1, Payload 2 goes into Position 2.

Step 3: Set Positions

I highlighted the email and the captcha token:

email=§test@example.com§&g-recaptcha-response=§TOKEN§

Step 4: Configure Payloads

  • Payload Set 1 (Email): I loaded a list of 50 random email addresses (some valid, some invalid).
  • Payload Set 2 (Captcha): I selected "Character Fuzzing" or simply a list of random words. I didn't need real Google tokens; I just needed random text to prove the server didn't care what the value was.

Step 5: Launch the Attack

I clicked "Start Attack".

Usually, if a CAPTCHA is working, the first request (with the real token) works, and the rest fail with 403 Forbidden or Invalid Captcha.

The Result:

  • Request 1: 200 OK
  • Request 2: 200 OK
  • Request 3: 200 OK
  • Request 50: 200 OK

The server accepted every single request. The CAPTCHA was completely cosmetic. It was there to scare humans, not to stop hackers.

Phase 3: The Impact (User Enumeration)

Why is this dangerous?

If I can bypass the CAPTCHA, I can automate thousands of requests. I noticed something else in the response.

  • Valid Email Response: "If this email exists, we have sent a reset link." (Size: 1540 bytes)
  • Invalid Email Response: "Email not found." (Size: 1200 bytes)

(Note: In many modern apps, the message is generic, but the Response Time or Content Length often differs.)

By bypassing the CAPTCHA, I could now launch a Brute Force attack to verify which users had accounts on this hosting platform.

  • Phishing: I can build a list of valid customer emails and send them fake "Server Payment Overdue" emails.
  • Spam: I can trigger the "Reset Password" email mechanism to flood a victim's inbox (Email Bombing).

A Note on WAFs (The 429 Error)

During the attack, I noticed that after about 50 rapid requests, the server returned a 429 Too Many Requests.

This wasn't the CAPTCHA stopping me; it was a generic Rate Limiter (WAF).

However, a 429 error is just a speed bump, not a wall.

  • The Fix: I simply paused the Intruder attack for 2 seconds and resumed it.
  • The Lesson: A simple rate limit is not a replacement for a functioning CAPTCHA. An attacker can just slow down their script to 1 request per second and still check 86,400 emails in a day.

The Report and The Verdict

I wrote up the report clearly:

  • Vulnerability: CAPTCHA Bypass + User Enumeration.
  • Method: Changing g-recaptcha-response to random values.
  • Impact: Attacker can enumerate users and spam the email service.

I hit submit.

The Response:

Status: Closed (Duplicate)

Another researcher had reported this exact misconfiguration weeks earlier.

Was it a failure?

No.

Finding a Duplicate proves that your methodology is correct. It means you are finding real bugs that real security teams care about. You just need to be faster next time.

Key Takeaways for Bug Hunters

  • Never Trust the Frontend: Just because you see a CAPTCHA logo, don't assume it works. Always try to repeat the request with a garbage token.
  • Combine Vulnerabilities: A CAPTCHA bypass is okay. A CAPTCHA bypass that allows User Enumeration is much better. Always look for the "So What?" factor.
  • Check for "Fail Open" Logic: Sometimes developers write code that says: If (token == valid) { pass }. But they forget to write: Else { block }. If you send no token or a weird token, the code might just default to letting you in.

Keep hunting, keep fuzzing parameters, and don't let the "I am not a robot" box fool you.