decoding an incomplete QRCode – Intigriti Hacking Challenge at bruCON

This year I was at bruCon in Ghent, BE. I usually either go to interesting talks or spend the conferences in challenges just like I did in Defcon back in 2017.

So during bruCON I stumbled upon this challenge with QR-code that says “first one to scan this gets 100€”; in my head I thought pff this is easy and I will probably not be the first one to scan this. So I popped my phone and scanned. Nothing happened. Then I was like oh wait .. a huge piece of this qr-code is missing.

So the first thing I thought of is to mark the squares randomly because I thought it must be redundant or error correction squars. Remember at this point I know nothing about qr-codes. So I drew a square with a pen and thought of going home and use photoshop to fill that square with random squares and it will probably read. but NOPE. that didn’t work either.

anyways, at this point I’m already home and very bored so I thought of working further on this.

First things first: understand how qr-codes work

this is better understood watching a video, so I went ahead to youtube and searched for manually decoding a qr-code. This video seemed to do alright.

so I popped up Photoshop, did some color correction and ended up with this image:

I converted this into excel, because I knew I will need some unmasking according to the video. At this point I thought the challenge won’t have any weird pattern masking that will make me suffer (oh boy what did I know).

So I drew the timings squares, highlited the white spaces so I don’t mess them up later and squared the mask bits (empty 3 squares).

The brutal masking and unmasking it.

If you read the wiki of qrcode you will quickly realize the masking is this one here:

that is: (i*j)%2+(i*j)%3=0
but what does that even mean? so after a lot of trail and error I figured that each time the above condition is correct you flip the square from white to black or vice versa. But then what is i and j? It is not clear from the wikipedia page.

(hours later after messing up the whole indexing and calculating wrong qrcodes for the 100 times)

I found this page mentioning clearly the indexes:

Bingo! Now we can move forward with excel’s magic.

first: mark all the squares to be changed as “X” and the ones not to touch as “N” this can be done with a simple formula “=IF((MOD($AF39J$69,2)+MOD($AF39J$69,3))=0,”X”,”N”)”

and this is exactly a translation of the masking equation we saw earlier ( (i*j)%2+(i*j)%3=0)

now I selected only the “X” because that what needs to be changed in the original qrcode, the “N” are not to be touched. So back to the original qrcode I copied and pasted the X,N and cleaned the timing squares because we don’t want to touch these

to this:

now all these “X” need to be flipped in color.

First I split this task into two tasks:

  1. Select only black squares to be flipped into white. This makes it easier with “conditional formatting” some googling will help you understand how do this. Basically the idea is to White-out every “X” square which is black.
  2. Do the same as #1 but the opposite, black-out the white squares with “X” in them.
  3. , after lot of trail and error again playing with macros I ended up here:

at this point I was hyped; I thought ok now I should be able to decode this MANUALLY. so I started with the square at the bottom right to read the encoding. That read: 0010 (byte encoding! great!) then the length 39 bytes (oh man this is going to be a long ride)

moving forward and backward with following this sheet here. I was able to decode the string

the x were garbage data that I thought it was a rabbit hole so I ignored, the Y were something I tried to guess “win???” winner!

this landed me to this page:


bummer someone else beat me to it! Ugh. Oh well at least I learned a lot about excel and qrcodes, which I always took for granted.

update1: they mentioned to me that this challenge can also be solved with Photoshop masks. If you know how please reply with a comment.

Leave a reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

This site uses Akismet to reduce spam. Learn how your comment data is processed.