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. 

Thursday, March 12, 2020

Using Burp Intruder for auth bypass - CTF, root-me.org / BSCorp - Linux

This is a small post on using Burp's Intruder to bypass login authentication.

The idea for this post is from a CTF challenge on root-me.org.

I will not be sharing information about how one will reach on this state as I wouldn't like to spoil the fun on it.

The initial page that the user will see after proceeding in the challenge will be the following:

With no apparent information about the login, trying with 'abc' as username and password will give the following result:

It's clear that there is some filtering implemented that are blocking some characters.  

The first thing is to identify which characters are allowed. This can be done on Burp using intruder. 

Intercept your login request and pass it to intruder as shown below:

On the intruder tab select sub-tab 'Positions' and clear all selections. Select the 'abc' value on the log= and add it as payload position.

Browse to the sub tab, select Payload set 1, Payload type 'List' and populate the list with. Simply use a notepad and input all possible characters one by one. I used a notepad and copy paste the entries on Burp.

Start the attack and observe the results.

As you can see above some requests are passing and some are giving an error message' Bad characters detected'

The next step will be to exclude these bad characters and keep the valid ones.  One can choose to select all remaining characters or limit the set to specific ones.

References: https://pentestlab.blog/2012/12/24/sql-injection-authentication-bypass-cheat-sheet/http://www.lifeoverpentest.com/2018/03/sql-injection-login-bypass-cheat-sheet.html .

From the links above the set of 19 characters could be reduced to 6, which are the followings, "# (  | ' / 1" .  The rest characters that are valid as possible entries have no value to as for a potential auth bypass.

To create an iteration of these values in the intruder, change the payload type to 'Custom iterator' and paste the values.

As we don't know how many characters will be needed for the attack we can start with 2 positions and increase them adding the same values to each position.

Start the attack and check on the output. If you don't see it successful, try adjusting the Position count by increasing it and repeating the values. 

In these case you are creating random values with all 6 characters which are used as attack patterns. 

For our attack on the specific environment a value of length 5 was the one that was successful. 

This can be seen on intruder on the following way:

The login request that is created with payload '||1# is giving a 302 redirect. 

Trying the value on the web page itself, 

Will allow us to bypass authentication and login on the portal.