In this challenge, we are given a remote oracle and is allowed to perform the below operations:
sign [key_client] [message]
: Signs an arbitrary message that does not contain the substring flag
.verify [signature]
: Verifies the signature for the message gib flag pls
.Let
Note that gib flag pls
while fixing
In this challenge, the XOR operation of two operands,
def xor(a, b):
return bytes(u^v for u, v in zip(a, b))
Specifically, when the two strings are of different lengths, the output string has a length of the shorter input string. For example,
Now assume that
then we know the first byte of
🤔 Imaginations only. In this part, we will assume that we have infinite oracle calls to the server. We unfortunately only have 10 calls in reality.
We can recover the secret byte-by-byte with the above behaviour. This is how we leak the first byte with 256 calls:
Subsequently, if we want the second byte of
We can repeat the above process until
You can read solve.py
that implements the algorithm.
We can actually use one remote call to retrieve one byte. This effectively reduces the number of oracle calls from 4096 to 16. This is how we leak the first byte of
We can repeat the process 16 times to fully reveal
In this challenge, we are asked to write a commentless program to read flag.txt
. However, there is a catch: There is a checker that validates whether each line of the input program starts with a JMP
.
Let's first have a look at the below ISA code:
0x400000: JMP 0x40000d; JMP 0x400000
⬆️
0x40001b: NOP
The program control (PC
) would be 0x400000
(i.e., beginning of the code) when we run the program. In this case, the instruction to be executed would be JMP 0x40000d
.
Although 0x40000d
is not a address of the beginning of an instruction, similar to a large number of interpreters available in real life, the interpreter simply parses the instruction starting from PC
. In this case, 0x40000d
points at the beginning of the JMP 0x400000
(which is intended to be a comment). The interpreter thinks that this would be the next instruction and decided to run JMP 0x400000
afterwards.
0x400000: JMP 0x40000d; JMP 0x400000
⬆️
0x40001b: NOP
In this case, we can actually "write" two instructions in one line, and the comment is could be executed during runtime.
We will want to execute some other commands than JMP
in the challenge. How do we achieve that? We can leverage the JMP
instruction and jump to the address you want… Maybe into the middle of an instruction?
Alas, the checker does not allow us to write comments. Fortunately the interpreter does not check whether the instructions are valid at the beginning. It would be fine as long as we are not invalid instructions. This would be handy in our case.
In this challenge, we are asked to reverse a program written in Bauhinia ISA and get the flag. If you directly load the challenge and run, you will see the program terminated with exit code 65 (STEP COUNT EXCEEDED). You need to understand why this happens and see where the flag is.
You can copy the code and load it into the "Debug Playground". There, you can add breakpoint (by clicking the line you want to stop), and step line by line after breakpoint.
To see what happened, we add a breakpoint at the first line, run the program, and click step multiple time to see where the program runs.
We notice the program never runs after line 5: it jumps back and forth at line 3-5.
Remove the breakpoint and click continue, we can see the final states of the registers: it shows the final value of PC is 0x40003b
, which is the start of line 6. Notice this does not mean it finish running line 6, but instead means it finish running line 5 (as PC is set to the next line start after execution of the line).
Let's first look at the code block it loops and never exit:
ADD R1, 1;
LT R1, 100000;
JNZ -35;
This is a simple loop structure, adding 1 to R1 each loop, and if R1 < 100000, it loops. As the runner can only run 131072 instruction, this makes this exceed the step count.
Next, you have to find a method to optimize this: Such that the edited code does the same thing, but without running that many instructions. This act of editing the assembly code is called "patching", and it is a very useful technique for dynamic analysis in reverse engineering. We can use patching to run different things to make us understand the program more, bypass some restriction and so on.
After you patch the code to bypass the STEP COUNT EXCEEDED error, you should be able to make the program runs without errors. (i.e. with exit code 0). However, there is still no output in the terminal.
There are multiple options for you now: