home

posts

notes

rss

Inferno CTF — Write-Up

In this short write-up, we will go over two challenges in the Misc category of Inferno CTF, which was hosted by Dc1ph3R. The challenges that we will discuss are “Color Blind” (which can be solved with a simple one-liner) and “Registering X” (which was a bit more complex). I completed these challenges with our CTF team, U+1F966.


Color Blind

In this challenge, we are provided with a PNG image with a resolution of $64 \times 1$. Running strings, binwalk, and foremost on the given file does not give us any useful information.

Looking closer at this image, we can see that each pixel has a specific colour. A teammate mentioned that the actual colours of the pixels could be the key to our flag. Each pixel has a colour code that can be expressed in RGB or in HEX. Stringing together all the HEX values is the key to obtaining our flag.

Opening an image, retrieving all the HEX values of the pixels, and stringing them together is a trivial task that can be done with a simple one-liner in the Julia programming language:

using FileIO, Colors
join(map(hex, load("colorblind.png")))

This works because images in Julia are simple arrays containing the RGB value of each pixel. We map the hex function (provided to us by Colors) over the color values, which returns an array with HEX values. We then join all the values together, which gives us the following string:

626C6168626C6168626C61685F68656C6C6F5F686F775F6172655F796F755F746F6461795F695F686F70655F796F755F6172655F6E6F745F646F696E675F746869735F6D616E75616C6C795F696E6665726E6F4354467B6833795F3130306B5F7930755F3472335F6E30375F6833785F626C316E445F3A4F7D5F646F696E675F746869735F6D616E75616C6C795F776F756C645F62655F615F6261645F696465615F796F755F73686F756C646E745F646F5F69745F6D616E75616C6C795F6F6B

This string can probably be translated to readable text using Julia, but it was quicker to copy this output and paste it in an online hex to string converter:

blahblahblah_hello_how_are_you_today_i_hope_you_are_not_doing_this_manually_infernoCTF{h3y_100k_y0u_4r3_n07_h3x_bl1nD_:O}_doing_this_manually_would_be_a_bad_idea_you_shouldnt_do_it_manually_ok

The output above contains the flag:

infernoCTF{h3y_100k_y0u_4r3_n07_h3x_bl1nd_:O}

Registering X

The goal of this challenge was to construct a string that matches the regex given to us in the challenge attachment:

infernoCTF{.(?<=H){21}.[a-z](?<=\+a){1024}[a-z][a-j](?<!([a-u]|[w-z])(j|[a-h])).{2,64}(?<!\S){255}n.{2}(?<=\s)g_fUn\W(?<=[A-z])}(?<=\..{14})(?<=^.{33})

The given regex is complex at first glance, but the challenge itself is very straightforward. We did not find a way to automate the solution of this challenge, so we solved it by hand. First, we simplified the regex by removing the quantifiers after the lookbehinds, because they do not serve a purpose. Removing these quantifiers will give us an equivalent, but shorter, regex:

infernoCTF{.(?<=H).[a-z](?<=\+a)[a-z][a-j](?<!([a-u]|[w-z])(j|[a-h])).{2,64}(?<!\S)n.{2}(?<=\s)g_fUn\W(?<=[A-z])}(?<=\..{14})(?<=^.{33})

We start by learning about lookbehinds. Positive lookbehinds (e.g, "(?<=a)b" ) match the character after the parenthesis, but only if the character is followed by the character in the parenthesis, after the =. Negative lookbehinds (e.g, "(?<!a)b" ) match the character after the parenthesis, but only if they are not followed by the character in the parenthesis, after the !. Knowing this, we can start constructing our flag.

Our flag starts with infernoCTF{, because the given regex states that we have to match these characters literally. . in our regex matches any character in our flag, so we will put an X as a placeholder. We now have to match the positive lookbehind (?<=H)., which means that our string will only match the regex when we have a character following the character H. We could try adding H+ to our flag (making our flag infernoCTF{XH+), but this will not match the given regex. The cause of this mismatch is the fact that lookbehinds only match the character after the parenthesis. It will not match the character in the parenthesis.

The solution for this problem is replacing our previous X with an H. We now have infernoCTF{H+, which matches the first part of our regex. The rest of the regex follows the same principle: we have a bunch of lookbehinds that force us to precede a character with another character. Around those lookbehinds we have more common regex symbols that make it possible to match the character in the parenthesis. Now that we got the gist of the challenge, we will quickly go over the solution:

  • infernoCTF{ forces us to start our flag with infernoCTF{
  • .(?<=H).[a-z](?<=\+a) forces us to add H+a
  • [a-z][a-j](?<!([a-u]|[w-z)(j|[a-h])).{2,64} makes us add vi to our flag, followed by an unspecified amount (between two and sixty-four, which will be constrained later in the regex) of placeholder characters
  • (?<!\S)n forces us to add an n after a whitespace character
  • .{2}(?<=\s)g forces us to add a g after a whitespace character
  • _fUn forces us to add _fUn to our flag
  • \W(?<=[A-z])} forces us to add a } after a non-word character between A and z in the ASCII table (e.g., ])

(?<=\..{14}) forces us to count fourteen characters back and add a .. We can safely put our . in the collection of unspecified characters mentioned in the third step above.

The last part of our regex forces us to make the flag exactly thirty-three characters long. This can be achieved by adding or removing a bunch of unspecified characters (which were mentioned in the same third step). One of the possible solutions is infernoCTF{H+avi . ng no g_fUn]}.

Because of a lack of knowledge about tools that generate strings based on given regex (that also support lookbehinds!), we decided to solve this challenge by hand. Although it is a bit of tedious work, it certainly is possible to construct the flag manually.