K3RN3L CTF 2021 Rev - `Recurso & Rasm ` writeups
Our Team zh3ro ended up at 9 th position in `K3RN3LCTF - 2021`.
These Reverse engineering challs are interesting
-> Both are based on one vm only (Recurso), different compiled scripts . (leFlag.recc , rasm.recc)
These Reverse engineering challs are interesting
-> Both are based on one vm only (Recurso), different compiled scripts . (leFlag.recc , rasm.recc)
Recurso
Given a Recurso Execuatable which can compile, run recurso sccrips.And a leFlag.recc (a recurso compiled file) containing a flag checking logic, can be run by given Recurso executable.
The Goal of the challenge is to get the flag checking logic in leFlag.recc and steal flag
Decompile and Analyse -> Recurso
First we have to get to know about how the Recurso is running this byte code in order to get the logic of leFlag.reccDecompiled the Code, changed the variable names based on code execuation, to ease my work.
Main function :
runProgram is the Function we need to focus It is first Initiating the functions then Executing the code .
By analysing the initializeFunctions code, got to know the format of bytes in the .recc files
First 4 bytes
0x11 [function name] 0x12 [4 bytes of buff size] [4 bytes of function pointer]
0x11 [function name] 0x12 [4 bytes of buff size] [4 bytes of function pointer]
..
0x11 [function name] 0x12 [4 bytes of buff size] [4 bytes of function pointer]
(code bytes to be executed ...)
4 Bytes buffer size for function call stack record size (num of local variables).4 Bytes function pointer for location of the function code in code bytes.
Each function is given a index, function call is handled by that index only
Code bytes are executed by switch case in runProgram function with 26 size instruction set.
By Analysing runProgram, initFunctions -> wrote the Disassembler, Emulator to make things easier on working with recurso sricpts(leFlag.recc)
More about disassembler or Chall files : https://github.com/D1r3Wolf/Recurso-Disassembler
DisAssembled leFlag.recc
By using above disassembler-> disassembled code of leFlag.recc is Note : Each Instructions work is scripted in detailed manner in disassembler.pyBased on that Reconstructed relevent python code
Reversing the logic in leFlag.recc
There is nothing but number inputs and checks in the code.Finally removed all functions by focusing only on checks.
As the last 6 number are straight forward, by some trials we got to know that long_to_bytes on those numbers will give us parts of flag
Based on the checks, written z3 script and got all the 20 input numbers.
Guessing part :( Especially for i5, i6 it became so difficult because of Too many possibilities.
My teammates helped me in this a lot, Placed all the character restrictions, guessed a last letter of i6 -> D based on i7, i8 number strings (3c0mp_3z!_).
Then seeing the possibilites noticed a string 'R3c' in i5, then it might be 'Recurso'. By going in that way got i5 -> R3cu and i6 -> r50_D
Finally by getting all the numbers
Flag : flag{R3cUr50_D3c0mp_3z!_Gu3s5_u_sh0u1d_g37_g08d_71k3_m3}
Rasm
Given the Same Recurso Execuatable with recurso compiled file rasm.recc containing a flag checking logic.The Goal of the challenge is to get the flag checking logic in rasm.recc and steal flag
Disassembling
Tried to run the code took an input and given segmentation error. Then tried decompiling using the old script -> given error due to (Invalid Opcode)It seems like there is an error in Code bytes, just to know all the instructions, skipped all the errors. Then found interesting at the end of the disassembly
Note : I have skipped much of assembly which looks uneven from (0x19 to 0x235). for complete dissambly : rasm-full.asm
Code from 0x0237 to 0x0300 makes sense now, The assembly code is encoded some how, the code below is to decode that above code bytes and jump there.
There are some instructions in Recurso lang which can modify the execution code bytes at run time. So Rasm is having self modifying logic.
Decoding the Bytecode
The code below (0x237 to 0x300) is decoding the above code (0x015 to 0x237) by decrementing every byte by 1.And found a code at above (0x0 to 0x14) which is causing Segmentation fault .
0000 -> pushInt64 0x13f
0009 -> inputd
000a -> pushInt64 0x109
0013 -> add
0014 -> jumpPop
The code above is to , take an input and jump to (265 + input_val)Jump address should be 0x237. So input = 0x237 - 265 = 302 (in decimal)
$ ./Recurso rasm.recc
302
2
If we give the input 302, segmentation fault won't come, It decodes above code and prints(2) and jump to above. Asks again a input address to jump.Analyzing Decoded Bytecode
Decoded the rasm.recc into drasm.recc by a script and then disassembled.Things i have noticed in the flag checking logic.
- 0x013e to 0x01e0 : Pushing a 8 byte numbers (Alternatively a flag number and a dummy number) to the stack
- On each flag number : by doing long_to_bytes -> 7 bytes of flag is coming, in reverse order and one char is wrong.
- 0x0033 to 0x0139 : A loop, in each iteration, it can update one flag num and move to other flag num address.
- On each flag number : reverse one number (flag 7 bytes , in same space of 8 bytes) which leads to 5th byte null (0).
- loop variables, other variables are maintained on code bytes only, they are accessed and modified using the instructions
- No of times the above loop will run depends on local var 0. we can set that varible by input, at address 0x001a
- So second input (used for second jump) is input + 265 = 0x001a. So input = 0x1a - 265 = -239
- Third input (no of iterations of the loop) has to be 10. As there are 10 such flag numbers
- 0x01e9 to 0x0236 : A loop to take numbers (which are combined together can form flag) and check them and return 1
- On each iteration (i) : It checks input ^ i*0x100 == stackTop(flag number), and pops dummy number once.
Taking those 10 flag numbers in disassembly from 0x013e alternatively in the instructions.
Flag : flag{ra5m_!s_s0_c3wl_bUT_k1nb4_5c4ry_wh7_mUSt_!7_4lway5_ch4nG3!1!}
Comments
Post a Comment