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)

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.recc
Decompiled 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.py
Based 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!}




Thanks for reading !...

Comments

Popular posts from this blog

Square CTF 2019 Writeup's

InCTF 2019 writeup's