Tuesday, March 24, 2020

Solving CAPTCHA using Burp suite proxy and mitmproxy.

Few days back I was facing an issue in one of my tests. The web application was logging my session off every few minutes and also it was logging me out in case of an exception, as a request that Burp was sending and couldn't be handled. 

Initial idea was to go and instruct Burp proxy to use macro and re-authenticate the session but the application was using an additional captcha challenge that had to be solved.

Overall there were 2 issues to overcome:

  • Keep the session authenticated through Burp's proxy scan (automated and manual)
  • Find a way to solve the captcha.

For these items went ahead with the following setup, Burp proxy -> mitmproxy -> Website.

Burp proxy is configured to use an upstream proxy and pass all requests through there as shown in the image below:

Burp itself is listening on port 8082 and I'm using firefox with FoxyProxy pointing to it.

Mitmproxy's script is very simple and essentially is handling this pattern that exist during the login phase.

Script is running with mitmproxy -s mitm.py

The script it self can be something as the one below:

This example shows how to parse a call and execute an external script
which will re-authorize the user on the web application.
from mitmproxy import http
import subprocess 
def response(flow: http.HTTPFlow) -> None:
    # Redirect is issued on the response, this is only used in the application for sending back the user to /logout. Match the response and call script.
    if (flow.response.status_code == 302):
        subprocess.call("python3 ./imagedecode.py", shell=True)
def request(flow: http.HTTPFlow) -> None:
    if flow.request.pretty_url.startswith("domain.com/user/index/login"):

The script 'imagedecode.py' is a script which is using tesseract OCR to process the captcha values and submit them to the website together with the login credentials.

The captcha images are simple as the ones below in the specific setup:

The script itself:

from PIL import Image
import subprocess
import requests
import cv2 
# I need to define a static cookie as it's used for verification on the captcha
# this cookie is set as valid if you pass the auth 
cookies = { "PHPSESSID": "8jadummyecookiefu12erm1923a;" }
url = 'https://domain.com/UiUser/secure?sid=0.6974342321354128' 
r = requests.get(url, cookies=cookies)
with open('im.png', 'wb') as f:
# Tesseract to the rescue
    r = subprocess.check_output(["tesseract", "im.png", "-", "--psm", "13", "--dpi", "70"]).decode('utf8').strip()
    # Got the captcha we need to authorize the same session that was used
    params = {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}
    datapost = "login-email=user%40domain.com&login-pwd=mypasswordhere%3D%3D&login-yanzheng="+r+"&memory=false"
    r2 = requests.post( "https://domain.com/user/index/verify", headers=params, data=datapost, cookies= cookies, timeout=35)
    print("Couldn't get captcha")
There are some things that could be optimised on the script as checking proper return code of the request and re-issue in case is not successful the login, but overall it has a rough 90-95% accuracy. 

No comments:

Post a Comment