This is my writeup for the last blockchain challenge in the
Cairo ICT CTF qualifications this year.
Hello hackers, this isn’t my first time to try to solve
blockchain challenges. I got some basic understanding of how it
works in terms of smart contracts and the cryptography involved,
but this time I was lucky to give it a big try even after the
qualification round.
Smart CrackMe
The challenge was given a public deployed contract with address
0x31678C496E63BcEbd1398D25C9B21cDcb3cc5e23
on
Etherscan
along with its ABI. It has only one transaction and nothing else
but the contract bytecode.
And the contract ABI:
First thing noticed that the contract section has a button to
decompile the bytecode and after decompiling, it gives us the
following code:
The website uses
Panoramix
python decompiler and as we see there’re only 3 functions
owner,
withdraw, and the last one
check_flag
that had been decompiled into this weird name
unknown08c5dc7f.
owner: Returns only the address of the contract owner.
withdraw: Checks if the method caller address same as the contract
owner address. If so withdraw the ballance, if not it aborts.
check_flag: It takes 8-bit integer value, does some calculations on the
defined array of size 2 and lastly it checks if the final
array value has the correct flag format.
I was stuck at the decompiled line inside the loop. It has weird
syntax and didn’t know how represent the first part. Actualy,
I’ve tried to assume that some parts are useless and tweak the
others but nothing worked. So, I decided to look at the
decompiler repo and see if there’s any options that I could use
to help me decompile the bytecode correctly, but unfortunately
still nothing.
I asked one of my teammates if he knows any smart contract
decompiler and he told me I could use
JEB. I
started off and loaded the bytecode into JEB, it shows me the
opcode instructions and when I tried to decompile to the source
code it gives a decompilation error. I’ve tried to read the
instructions and map it to what I’ve in the code above, but
still no luck.
On the next day, I asked our reverse mate to take another look
on the decompiled weird instructions, but he couldn’t understand
a thing from it. He decided to decompile it using his own JEB
version and this time the source code showed up on his screen.
First, we know that
storage
variable has size 2 from the previous decompiled code and now
the code has flatten out the iterations one by one. He tried to
run the 48 lines above and the result wasn’t usefull, we tried
to play with it, but still empty hand. The competition has ended
and we still couldn’t figure it out. After a day I decided to
give it another try and this time look a bit closer on the last
decompiled code. I ran it and did a bruteforce xoring over the
result and I noticed the reversed flag appeared with byte
0x99
🙂.