A friend of mine found this on his PC, but he can't remember what it is. It should contain juicy information. Can you recover it?
Solution
Given mv file which is a compiled move code. Trying to find disassembler or decompiler for given file i found this repository. The repository name has the same name with the challenge, so i tried to use the the released binary from the repository to decompile the mv file.
./revela-aarch64-apple-darwin-bsource.mv
module 0x1337::source { public fun a0() : vector<u8> {magic_1(b"etpkw", 4) } public fun a1() : vector<u8> {magic_2(b"zrn^", 1) } public fun a10() : vector<u8> {magic_2(b"bW", 10) } public fun a2() : vector<u8> {magic_3(b"_uoy") } public fun a3() : vector<u8> {magic_1(b"i`wd", 1) } public fun a4() : vector<u8> {magic_2(b"]jc_", 2) } public fun a5() : vector<u8> {magic_1(b"qmfg", 3) } public fun a6() : vector<u8> {magic_3(b"woh_") } public fun a7() : vector<u8> {magic_2(b"^sn^", 1) } public fun a8() : vector<u8> {magic_1(b"qwa[", 4) } public fun a9() : vector<u8> {magic_3(b"ever") } public fun get_flag() : vector<u8> {let v0 =a0();0x1::vector::append<u8>(&mut v0, a1());0x1::vector::append<u8>(&mut v0, a2());0x1::vector::append<u8>(&mut v0, a3());0x1::vector::append<u8>(&mut v0, a4());0x1::vector::append<u8>(&mut v0, a5());0x1::vector::append<u8>(&mut v0, a6());0x1::vector::append<u8>(&mut v0, a7());0x1::vector::append<u8>(&mut v0, a8());0x1::vector::append<u8>(&mut v0, a9());0x1::vector::append<u8>(&mut v0, a10());0x1::vector::append<u8>(&mut v0, b"}"); v0 } fun magic_1(arg0: vector<u8>, arg1:u8) : vector<u8> {let v0 =0x1::vector::empty<u8>();let v1 =0;while (v1 <0x1::vector::length<u8>(&arg0)) {0x1::vector::push_back<u8>(&mut v0, *0x1::vector::borrow<u8>(&arg0, v1) ^ arg1); v1 = v1 +1; }; v0 } fun magic_2(arg0: vector<u8>, arg1:u8) : vector<u8> {let v0 =0x1::vector::empty<u8>();let v1 =0;while (v1 <0x1::vector::length<u8>(&arg0)) {0x1::vector::push_back<u8>(&mut v0, *0x1::vector::borrow<u8>(&arg0, v1) + arg1); v1 = v1 +1; }; v0 } fun magic_3(arg0: vector<u8>) : vector<u8> {let v0 =0x1::vector::empty<u8>();let v1 =0x1::vector::length<u8>(&arg0);while (v1 >0) {let v2 = v1 -1; v1 = v2;0x1::vector::push_back<u8>(&mut v0, *0x1::vector::borrow<u8>(&arg0, v2)); }; v0 }// decompiled from Move bytecode v6}
From code above we can see that there are some function and there is one function named get_flag. So in this case our objective is to find the flag that created from get_flag function. My approach is to rewrite above code in python and then print out the flag.
defmagic_1(a,b): res = []for i in a: res.append(i ^ b)returnbytes(res)defmagic_2(a,b): res = []for i in a: res.append(i + b)returnbytes(res)defmagic_3(a):return a[::-1]flag = []flag.append(magic_1(b"etpkw", 4))flag.append(magic_2(b"zrn^", 1))flag.append(magic_3(b"_uoy"))flag.append(magic_1(b"i`wd", 1))flag.append(magic_2(b"]jc_", 2))flag.append(magic_1(b"qmfg", 3))flag.append(magic_3(b"woh_"))flag.append(magic_2(b"^sn^", 1))flag.append(magic_1(b"qwa[", 4))flag.append(magic_3(b"ever"))flag.append(magic_2(b"bW", 10))print(b''.join(flag) +b"}")
Given an archive file that consist of framework and framework-solve folder. Take a look on framework folder to get information about the challenge. We can see the challenge in file framework/challenge/sources/sage.move.
initialize is the first function executed in main.rs, after that we will interact with the server (framework folder). In this case we can call public function and because this is a RE challenge so our objective is to call the challenge function and send the valid m and n array. Build function seems like solvable using z3 but in this case we can directly solve by just putting the build function on z3. To solve the challenge we need to add some constraint and put the correct bit length. Below is my approach to solve it using z3
Information we know
next_text consist of static values (42,11,13,16,13,62,72,13,12) + m
array m and n consist of value with maximum size u64 (64 bit/8 bytes)
From information above i try to find value for m and n with size u8 (8 bit/1 byte)
If i put bit length of m and n in z3 with size of 8 it will automatically wrapped to 1 byte, so i can't use 8 as the bit length
The maximum bit length from the operation should be 19, we know it from below operation
Lets use maximum 1 byte value for each variable
((x11 + y31) * (x12 + y11) + (x13 * y21))
So to utilize approach above we will use bit length 19 and use ULE function to make sure that the value will be 1 byte.