Writing where no one can see
Challenge write-up for widthless from CSAW 2020 Qualifiers.
In this challenge, we revisit an old trick that, as the hint stated, is kind of funky. Diving into any web challenge can quickly turn into a unique experience and this challenge did not disappoint.
The challenge was a multistage challenge which presented a series of simple input webpages. On each page a password needed to be submitted to get access to the next webpage.
Discovering Zero Width Characters
After poking around the first webpage’s source, there is some HTML code that does not seem to have any effect on the appearance of the webpage. These character codes are a variety of zero width Unicode characters.
In the HTML, there was also another clue (not in the screenshot), “zwsp is fun!” After some web research, it became apparent this challenge would be about zero width character steganography. Essentially this means information is being hidden by encoding data with and within the zero width characters.
Null Byte had a really solid write up on this technique. In a short summary, there are Unicode characters mostly from languages other than English that do not appear in most normal output (there are cases where they appear).
Most surprisingly (for me), this technique goes back to the 1980s according to some of the commenters on a Hackaday post on the topic.
Finding the Solution
This challenge was a team effort of ideas to understanding the problem. Eventually, a GitHub repo by enodari popped up which looked like just the thing that was needed. Once the characters were copied over, we were able to remove the excess and extract the hidden message.
The tool we used has two different modes. MODE_ZWSP which uses Zero-Width Space (\u200b), Zero-Width Non-Joiner (\u200c), and Zero-Width Joiner (\u200d). MODE_FULL uses all of the MODE_ZWSP characters plus it includes Left-To-Right Mark (\u200e), Right-To-Left Mark (\u200f).
The output from the hidden text is: YWxtMHN0XzJfM3o=
This looks a lot like Base64. Using a Base64 decoder, we can get the result of alm0st_2_3z. Now just use this code word in the sign up form!
Doing so gives us another URL to visit. Traveling to the URL, we will scrape the entire HTML page from view-source (ctrl-a, ctrl-c, ctrl-v).
Remove the excess and get only the raw zero width characters. Again we put this into our script and…
Voilà! It returns this:
This time the decoded message, 755f756e6831645f6d33, looks like hexadecimal. Using a hex to ASCII translator, such as the one from Rapid Tables, we get the next password: u_unh1d_m3.
Yet another URL to explore! However, this time, it is the end! Getting to this 3rd webpage allows us to get the flag.
The flag being: flag{gu3ss_u_f0und_m3}. Overall this was a fun warm-up to web challenges where our team was able to learn about some different steganography techniques!