Gynvael Missions
Mission 46
Hello, Everyone.
if you watch Gynvael English (trying to be weekly) Stream, you can find it here.
In his #46 Stream, There was a mission about barcode decoding.
You can find the Archive Version of the Stream here, and the mission details here.
.
Now, Going to the link that contain details of the mission. start with start.png, this link. Its barcode image, lets use one of the online service to read what it say !, you can use this website onlinebarcodereader.com
and there is already a Enter url option, where you can enter a url to the barcode image, and then it will decode it for you, here is the content of the barcode image.
Calc value, add .png, repeat: 84905785,*577,-745,-342,*954,-672,+909,+644,-556,-524,*622
its simple calculation equation, you can use python to solve it.
We get a number as a result, lets add .png to it, as the message say, it will look like this: http://gynvael.coldwind.pl/qrmaze/29070456023771126.png
its a new image, and you will repeat the process of reading it’s content and solve calculation equation, and so on, i did around ~20 iteration, until i realize, that it should be automated, so lets see, how we can do it, we going to this with python, because python rocks :P .
We going to need the following:
1. Download an image.
2. Decode the image to get string.
3. Parse the string and solve the equation.
Im going to use these libraries, but there is always alternative: 1. Pyzbar 2. Pillow 3. Requests
By using request, you can simply download an image, or any other file if’s matter by:
|
|
Now, you have an image at /tmp/barcode.png, lets make it a function, because we going to download a lot of images, and we can overwrite the existence one, because there is no need to keep it.
|
|
Now that we have a function that will download an image, we need another function decode barcode images.
|
|
This function extract_str_from_barcode, will return a string, which is another equation, The only missing function for us, is a function to parse & solve the equation, Thankfully Gynvael has made the message properly formatted, so its easy to parse it:
Calc value, add .png, repeat: 84905785,*577,-745,-342,*954,-672,+909,+644,-556,-524,*622
notice the { : } in the middle of the equation, we can split by it, then each operation splited by { , }
|
|
This function will take Gynvael formatted equation, and solve it and return the next image number.
Add those function to a while loop, or for loop, and that’s it. check run.py
to see the full code.
Mission 48
Date: 2018-03-07
Hello, Everyone.
In Gynvael English (trying to be weekly) Stream, you can find it here.
In his #48 Stream, There was a mission about derive key.
You can find the Archive Version of the Stream here, and the mission details goo.gl/Cio3tV .
Big shout out to Guest011011 , he stayed with me in Gynvael English IRC channel in freenode, and we discussed the mission and we tried to walk our way to solve it, and here is my solution :).
|
|
goo.gl/nzXX7B opening this link, you will find C code that contain 3 functions:
1.check_password.
2.derive_key.
3.decrypt the data.
The main function simple take an input and call the other functions.
The check_password function take an input ( password ) and if its not 41 long, then return false.
and if you provide a 41 password long, then it will md5 hash it and compare to hash value:
57d9b1fd2552ff0b8e5aeb18754a9b03
if it does not match the hash then return false, or if it’s matched ( which is impoissible unless you are gynvael ) then return true.
second function is derive_key, and there is a uint64_t key = 0xf8a45191c23a75be.
it will go though that 41 byte password ( 41 character we know that from the if statement in the check_password function ) and add each value to this key, and it will hash the total value ( sum of the key and password ) with md5.
Finally the decrypt function, which will xor each element of the data array with 2 hex digit from the key ( 16 byte - 32 hex digit ), the data array has 78 element, but the key is only 16 byte long, so that’s probably why there is % 16.
Note that MD5Update has an argument length, first time in check_password, the length was strlen(password), but in dervie_key the length is 8 byte only.
So first i thought because its an md5 hash, There is possibility that the vulnerability is hash collision, so you try to generate the same hash value from different input.
But in the derive key function you will have the add ( sum ) the value of the password with the key, so you will need exactly the same value of the original key, and knowing that hash is one way function, you can get the same hash value for different input, but having the hash value and even if you know the input lenght, its impossible to get the original input.
I spent a couple of hours trying to brute force it, was silly way to get the solution.
but if you think about that derive_key function, the length in MD5Update is 8 byte, so it will take only 8 byte from the key.( try to play with MD5Update, declare two string with the same first 8 byte, after the 8th byte put random value, and try to hash them with length of 8 you will find out that they give the same hash ).
The maximum value of input to decrypt that data iss 0xffffffffffffffff ( mathematically speaking ) and the minimum value is 0xf8a45191c23a75be ( not really ).
substracting them from each other will get you: 530209169652156993 which is very big number to iterate through, even with i7 :P.
So another thing to put into consideration, that the password should be in the printable asci character range, which is from 32(0x20) - 128 (0x80). ( according to this page ) So minimum value of the password that we will add to the key is 1312 ( 41 * 32 ) but most important is the max value 5207 ( 41 * 127 ).
I made some changes to the original code, i removed the check_password function ( completely ).
and this is my modification to dervie_key:
|
|
Since we going to add the total value of password to the key, we dont need to loop over the string ( char array if that matter ) anymore.
|
|
Make an array for the output, so we store the result.
Decrypt function is the same but storing the result in output instead of data.
|
|
i made a custom print function, that will make sure to print only the array that all it’s element is in the printable character range, then you just need to loop over:
|
|
There is some clean up can be done, but since it’s working, doesnt really matter. ( yea lazy way).
Its funny that i was writing email to gynvael, telling him what is the solution after i spent long time trying to solve it, while writing the email and trying to explain my effort to gynvael i found that i have a mistake in the condition of the print function ( i kinda excluded all the right cases :$, yea it happen ).
You can compile my code with:
|
|
( you need to install openssl library ( google it ) ). It was fun mission after all. thank you for reading my write up and i hope you find it helpful.