I recently attended my first BSides Las Vegas/DefCon week across the pond. Throughout the second day of BSides, Sarah, Ben and I decided to try our hands at solving the Intigriti challenge coin CTF, as it didn't appear to be a technology any of us had explored before.
WayBack Machine Attempt
Within the comments of the same blog, we were also able to locate someone hosting their own version of the tool online. This tool also appeared to be captured on the WayBackMachine.
Sadly, we were unable to extract a valid URL for the
DOWNLOAD QR CODE SCANNING TOOL ANDROID button, and therefore we moved on to other leads.
If you're unfamiliar with the technology, it may appear to be some sort of QR code that needs unravelling into the traditional square form factor, this lead to us searching for variations of "circular QR code with lines".
The above search prompted a variety of results within google images, including kik QR codes (which are similar, but not quite what we are looking for):
Finally, the following image appeared, which closely resembles the print on the challenge coin:
Essentially, the coin appears to be what's known as a Mini Program, which is a specific kind of scannable barcode developed and used by the Chinese messaging app "WeChat" (it also appears to be developed by the WeChat team, so we expected the majority of the documentation to originate from them).
WeChat has been described as China's "app for everything", used for messaging, social media, and payments, launching Mini Programs as a kind of way for businesses to create integrations within the WeChat application.
The main issue we faced throughout this challenge was the inability to find reliable documentation, as the whole Mini Program functionality appears to be closed-source.
Diving into decoding the program, and figuring out how to extract information from it was a matter of research, however, we tried a variety of approaches before turning to manual exploring.
From this page, we obtained most of the important information required to solve the challenge. Such as the following:
- According to this page, Mini Codes can be divided into 36, 54 or 72 lines.
- This page also states that each line is divided up into 13 identifiable data points (with some corner lines as exceptions).
- Most data is usually encrypted (however, for this challenge, we assumed it would be plain-text).
- The data should be read starting from the inner-most valid point of data (known as the encoding region in the image below), to the outer-most valid data point of the same line.
- For lines with no valid "encoding region" data points, simply skip the line and move to the next.
- We start reading from the left-most line (9 o'clock on the 72 lined codes, for 36 it's the next one up going clock-wise).
One more thing that should be noted, is that the 5 dots on the coin (central yellow dot, green dot in bottom right, and 3 black and white corner dots) can be ignored, as they are purely for aesthetic/placement guidance.
With all the required information to decode the coin, we took a picture and attempted to make it as central as possible (attached above). This image was then modified by python to plot lines to guide the 13 different data points on the coin.
# Kudos to Sarah for the code import cv2 import numpy import matplotlib img = cv2.imread("coin.PNG", cv2.IMREAD_COLOR) size = img.shape img_center_x = round(size / 2) img_center_y = round(size / 2) - 30 radius = 320 for i in range(0,13): if i == 0 or i == 3 or i == 12: print("skipping") else: img = cv2.circle(img, (img_center_x,img_center_y), radius, (255,0,0), 3) radius += 32 cv2.imshow("image", img) cv2.imwrite("coin_lines_new_adjust.png", img) cv2.waitKey(0) cv2.destroyAllWindows()
We can immediately disqualify all of the inner most points, as they do not belong to the encoded region (we are only looking for the small grey dot values within the legend above; the inner-most dots are all green, and are part of the logo area). We can also remove all of the points on the 4th inner-most blue line we placed on the image, as they belong to the metadata portion of the information. All dots on the outer-most line can also be ignored, as they belong to the "edge patch".
From here, the rest of the work was manual. Starting from the inner-most valid data point, on the line next along from 9 o'clock, moving along the lines in clock-wise order (notice the coin is slightly rotated clock-wise in the image, and the lines are marginally off center, this is purely due to human error).
When decoding the information, you may be required to go back and check the legend image, as there are certain lines that do not follow the standard pattern for valid and invalid data-points. Some examples of the abnormalities can be found below:
The coin should decode to the following, with the indented, darker areas being a 1, and the absence of an indentation being a 0.
From the following portion of the coin, we can extract the start of the URL (remember, in the image below you should start from the bottom-most line, as this represents 9 o'clock on a 36 line code):
This challenge was a great opportunity to dive into a technology that is almost completely unknown, with the only documentation being provided by other hobbyists who have dedicated their free time to decoding the mini program scheme.
It also provided an interesting topic of conversation with the Intigriti team who was present at DefCon/BSides Las Vegas; huge kudos to them for coming up with such a unique concept for a challenge coin.
For any questions, please feel free to contact me on Twitter.