Skip to content

Instantly share code, notes, and snippets.

@jaybosamiya
Last active October 2, 2019 16:39
Show Gist options
  • Save jaybosamiya/f58ab390f3dc0aa311d438116b5fe3ce to your computer and use it in GitHub Desktop.
Save jaybosamiya/f58ab390f3dc0aa311d438116b5fe3ce to your computer and use it in GitHub Desktop.
IO Netgarage Level11 Solution

IO Netgarage Level 11

Whoo! This was a fun challenge with loads to learn. :)

Understanding the given code

The given code level11.c checks whether the two inputs (as argv[1] and argv[2]) both MD5 hash to the same value or not. If they do, it uses both inputs as brainfuck code, and executes them. Then it checks if the outputs differ. Upon differing outputs, they are checked against the strings "io.sts Rules!" and "io.sts Sucks!". If prog1's output is the first, and prog2's output is the second, we are granted shell.

Understanding the vulnerability

MD5 hashing is vulnerable to very fast generation of collisions. Note that this is not equivalent to a pre-image attack, or even a second pre-image attack (which are harder). Instead, a generation of a collision is merely finding x and y such that MD5(x) == MD5(y). Lots of literature and code exists to do the same. We will use this idea and the next in our exploit.

The other vulnerability of MD5 is that of a variant of hash length extension, that comes about as a consequence of the fact that the whole internal state is exposed as the hash. This means that if we have some x and y, such that MD5(x) == MD5(y), then we can concatenate (||) a message m to both, and the resultant hashes will be the same as each other (not same as before, but mutually equal). That is, we will have MD5(x || m) == MD5(y || m).

The above two properties can be used to pass 2 different programs into the code and have them execute differently. However, we need to understand what limitations such a method has, as well as how the brainfuck part of the code is vulnerable.

The brainfuck part of the code ignores all non-brainfuck characters. Additionally, it even ignores the , (which would have made the challenge dead simple). This means that we can have any non-brainfuck characters in the two parts x and y and it will skip past those immediately.

There is also a minor flaw in the [ and ] matching that might be abused, though I did not really use that flaw.

Attack

Since we have noticed that the code does an MD5 check before it does a running of the code, I split the code into 2 parts bf_exec.c and md5_check.c. Now, it is possible to work on both separately without nasty trouble. I also added some extra statements to help with debugging if need be.

Now, we need to generate the aforementioned x and y. For this, we can use Marc Steven's fastcoll tool. It generates collisions in mere seconds (I compiled it with -O4 -march=native to optimize it as much as possible). Not all such colliding blocks are useful though.

I define useful colliding blocks x and y (in code below, mentioned as d1 and d2) as the following: x and y are considered useful iff they differ by exactly one of either + or - or [. Note that the blocks must not have any nulls (\x00) either, otherwise they stop the strlen() and prevent the whole block from being MD5'd.

This is coded by the python script find_useful.py I wrote, which executes fastcoll until useful blocks are found.

This script was kept running for quite a while. In fact it was taking too long so I started to modify fastcoll and come up with different seeding for multiple instances, and then kept 4 instances of the above python script running parallelly to speed up finding useful collisions. The fastest one to complete, reached 101 rounds in 180 seconds, and found a useful collision. The first one that I had kept running ran for over 2000 seconds without finding any useful blocks, so luck matters a whole lot for this.

Using these initial blocks (prefix1.bin and prefix2.bin), we can now extend the blocks with a common suffix that abused this initial difference in code. The difference is that prefix2.bin has an extra - that prefix1.bin does not. We can test this using the ./md5_check and ./bf_exec:

jay@Jay-Ubuntu ~/i/i/level11> X='+++++++++++++++++++++++++++++++++++++++++++++++++.'
jay@Jay-Ubuntu ~/i/i/level11> ./bf_exec $(cat prefix1.bin)$X $(cat prefix2.bin)$X
output prog1 (len=  1): 1
output prog2 (len=  1): 0
jay@Jay-Ubuntu ~/i/i/level11> ./md5_check $(cat prefix1.bin)$X $(cat prefix2.bin)$X 
Len of prog1 = 178
Len of prog2 = 178
They are the same

Now, all that remains to be done is to come up with a $X (equivalent to the concatenation of m in the vulnerability discussion above) that abuses this difference.

A good resource for writing your own brainfuck code is to use the Brainfuck Algorithms page on Esolangs. Using the if-then-else construct there, I wrote a generic python script gen_differences.py that would let me pick 2 arbitrary outputs for prog1 and prog2 and output them.

By adding this suffix to the two prefixes, we generate attack1.bin and attack2.bin, which satisfy the MD5 constraints, as well as output the required outputs.

After testing them out on my ./bf_exec and ./md5_check programs just to be sure, I uploaded them onto a temporary folder on the server, and access to level12 was granted. :)

ꯒ撀⥇番闱└쮭៷呼ᑢ䅲놏㐅쒻딯柾䴹ﻋ龪말䄧엺糺꿁㡮︡䏿㳍堦䴰ﭘꂾ◹�왁숖ஸ춻唪妮ㆁ团⳪縃轨쇏炊鴤ោ偋쐎쫠둾붩Ӌ㹛ⵝ⬾嬭崼㱛㸾㸫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⸫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸼㰼㸭崾嬼㸾㸫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸼㰼㸭㹝㰼�
ꯒ撀⥇番闱└쬭៷呼ᑢ䅲놏㐅쒻딯柾䴹﹋ꂪ말䄧엺糺꿁㣮︡䏿㳍堦䴰ﭘꂾ◹�왁슖ஸ춻唪妮ㆁ团⳪縃轨쇏澊鴤ោ偋쐎쫠듾붩Ӌ㹛ⵝ⬾嬭崼㱛㸾㸫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⸫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸼㰼㸭崾嬼㸾㸫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸫⬫⬫⬫⬫⬫⬫⬮⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⬫⸼㰼㸭㹝㰼�
/*
Created by bla;
++edx
*/
#include <stdio.h>
#include <string.h>
#define MAX_NESTING 100
int bf(char *prog, char *result, int maxlen)
{
int output_len = 0;
char tape[4001];
int edi=0, eip=0;
unsigned long endless_loop_protection = 100000;
int loopstart[MAX_NESTING + 1], depth = 0, state;
memset(tape, 0, sizeof(tape));
while(eip < strlen(prog) && --endless_loop_protection)
{
switch(prog[eip])
{
case '<':
if(edi) --edi;
break;
case '>':
if(edi<4000) ++edi;
break;
case '+':
++tape[edi];
break;
case '-':
--tape[edi];
break;
case '.':
if (output_len < maxlen) result[output_len++] = tape[edi];
break;
case ',':
/* not implemented */
break;
case '[':
state=1;
if(!tape[edi])
while (state && ++eip < strlen(prog))
if (prog[eip] ==']') --state;
else if (prog[eip] == '[') ++state;
else;
else if (depth < MAX_NESTING)
loopstart[++depth] = eip;
break;
case ']' :
if(depth)
if(tape[edi] == 0)
--depth;
else
eip = loopstart[depth];
break;
}
++eip;
}
result[output_len]=0;
return output_len;
}
int main(int argc, char **argv, char **env)
{
int i;
char prog1_output[101];
char prog2_output[101];
int len1,len2;
if(argc!=3)
{
printf("USAGE:\n\t%s <prog1> <prog2>\n",argv[0]);
return 1;
}
len1=bf(argv[1],prog1_output,100);
len2=bf(argv[2],prog2_output,100);
printf("output prog1 (len=%3d): %s\n",len1,prog1_output);
printf("output prog2 (len=%3d): %s\n",len2,prog2_output);
return 0;
}
from os import system
i = 0
while True:
i += 1
with open('temp1.bin', 'rb') as f:
d1 = f.read()
with open('temp2.bin', 'rb') as f:
d2 = f.read()
if ('+' in d1 and '+' not in d2) or ('+' in d2 and '+' not in d1):
if all(a not in d1 and a not in d2 for a in '[.]-\x00'):
print "Found it!!! A plus!"
break
if ('-' in d1 and '-' not in d2) or ('-' in d2 and '-' not in d1):
if all(a not in d1 and a not in d2 for a in '[.]+\x00'):
print "Found it!!! A minus!"
break
if ('[' in d1 and '[' not in d2) or ('[' in d2 and '[' not in d1):
if all(a not in d1 and a not in d2 for a in '.]+-\x00'):
print "Found it!!! An open bracket!"
break
print "[+] Round %d" % i
system('./fastcoll -o temp1.bin temp2.bin')
str1 = raw_input().strip()
str2 = raw_input().strip()
def gen_code(s):
ret = ''
c = 0
for char in s:
v = ord(char)
diff = (v - c) % 256
ret += '+' * diff
ret += '.'
c = v
return ret
code = ""
code += ">[-]+"
code += ">[-]"
code += "<<["
code += ">>>"
code += gen_code(str2)
code += "<<<"
code += ">-]>"
code += "[<"
code += ">>>"
code += gen_code(str1)
code += "<<<"
code += ">->]<<"
print code
/*
Created by bla;
++edx
*/
#include <stdio.h>
#include <string.h>
#include <openssl/md5.h>
#define MAX_NESTING 100
int bf(char *prog, char *result, int maxlen)
{
int output_len = 0;
char tape[4001];
int edi=0, eip=0;
unsigned long endless_loop_protection = 100000;
int loopstart[MAX_NESTING + 1], depth = 0, state;
memset(tape, 0, sizeof(tape));
while(eip < strlen(prog) && --endless_loop_protection)
{
switch(prog[eip])
{
case '<':
if(edi) --edi;
break;
case '>':
if(edi<4000) ++edi;
break;
case '+':
++tape[edi];
break;
case '-':
--tape[edi];
break;
case '.':
if (output_len < maxlen) result[output_len++] = tape[edi];
break;
case ',':
/* not implemented */
break;
case '[':
state=1;
if(!tape[edi])
while (state && ++eip < strlen(prog))
if (prog[eip] ==']') --state;
else if (prog[eip] == '[') ++state;
else;
else if (depth < MAX_NESTING)
loopstart[++depth] = eip;
break;
case ']' :
if(depth)
if(tape[edi] == 0)
--depth;
else
eip = loopstart[depth];
break;
}
++eip;
}
result[output_len]=0;
return output_len;
}
int main(int argc, char **argv, char **env)
{
MD5_CTX prog1_md5;
MD5_CTX prog2_md5;
char prog1_hash[17];
char prog2_hash[17];
int i;
char prog1_output[101];
char prog2_output[101];
int len1,len2;
char *dropshell[] = {"/bin/sh", 0};
if(argc!=3)
{
printf("USAGE:\n\t%s <prog1> <prog2>\n",argv[0]);
return 1;
}
MD5_Init(&prog1_md5);
MD5_Update(&prog1_md5,argv[1],strlen(argv[1]));
MD5_Final(prog1_hash,&prog1_md5);
MD5_Init(&prog2_md5);
MD5_Update(&prog2_md5,argv[2],strlen(argv[2]));
MD5_Final(prog2_hash,&prog2_md5);
for (i = 0; i < 16; ++i)
if (prog1_hash[i] != prog2_hash[i] && printf("Prog1 and Prog2 are too different\n"))
return 1;
len1=bf(argv[1],prog1_output,100);
len2=bf(argv[2],prog2_output,100);
printf("output prog1: %s\n",prog1_output);
printf("output prog2: %s\n",prog2_output);
if (len1 != len2 || memcmp(prog1_output,prog2_output,len1)) {
if (!strcmp(prog1_output,"io.sts Rules!") && !strcmp(prog2_output,"io.sts Sucks!")){
printf("congrats you did it\n");
setresuid(geteuid(), geteuid(), geteuid());
execve(dropshell[0],dropshell,0);
} else
printf("That's good but not entirely what I want to see\n");
} else {
printf("Sorry both programs output the same, there is no"
"point in having two programs do the same task!\n");
}
return 0;
}
/*
Created by bla;
++edx
*/
#include <stdio.h>
#include <string.h>
#include <openssl/md5.h>
int main(int argc, char **argv, char **env)
{
MD5_CTX prog1_md5;
MD5_CTX prog2_md5;
char prog1_hash[17];
char prog2_hash[17];
int i;
char prog1_output[101];
char prog2_output[101];
int len1,len2;
if(argc!=3)
{
printf("USAGE:\n\t%s <prog1> <prog2>\n",argv[0]);
printf("Gave %d args instead\n", argc);
return 1;
}
printf("Len of prog1 = %d\n", strlen(argv[1]));
printf("Len of prog2 = %d\n", strlen(argv[2]));
MD5_Init(&prog1_md5);
MD5_Update(&prog1_md5,argv[1],strlen(argv[1]));
MD5_Final(prog1_hash,&prog1_md5);
MD5_Init(&prog2_md5);
MD5_Update(&prog2_md5,argv[2],strlen(argv[2]));
MD5_Final(prog2_hash,&prog2_md5);
for (i = 0; i < 16; ++i)
if (prog1_hash[i] != prog2_hash[i] && printf("Prog1 and Prog2 are too different\n"))
return 1;
printf("They are the same\n");
return 0;
}
ꯒ撀⥇番闱└쮭៷呼ᑢ䅲놏㐅쒻딯柾䴹ﻋ龪말䄧엺糺꿁㡮︡䏿㳍堦䴰ﭘꂾ◹�왁숖ஸ춻唪妮ㆁ团⳪縃轨쇏炊鴤ោ偋쐎쫠둾붩Ӌ
ꯒ撀⥇番闱└쬭៷呼ᑢ䅲놏㐅쒻딯柾䴹﹋ꂪ말䄧엺糺꿁㣮︡䏿㳍堦䴰ﭘꂾ◹�왁슖ஸ춻唪妮ㆁ团⳪縃轨쇏澊鴤ោ偋쐎쫠듾붩Ӌ
@AkshatGiri
Copy link

Thanks for sharing mate!

Awesome explanation and clean code 👍.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment