TSG CTF 2024 Reverse WriteUp
Champion 🥇
Misbehave
The logic of program is simple. The flag xor with a number generated by gen_rand function.
It is worth noting that the memcmp in PLT is modified to sub_13A3 during the operation. The encrypted flag will xor with the state of random number generator before the comparison.
It can help you avoid many unnecessary mistakes using the c code generated by IDA directly.
1 |
|
Warmup SQLite
Firstly, we need to decompile the bytecode of SQLite. According to this site, we can get the meaning of each command.
1 | | id | opcode | p1 | p2 | p3 | p4 | p5 | Comment | |
By analyzing the bytecode, it just splits the flag into characters, transforms them into unicode, and modifies each value $x$ to $(7x + 2) \bmod 256$.
1 | flag_enc = [100, 115, 39, 99, 100, 54, 27, 115, 69, 220, 69, 99, 100, 191, 56, 161, 131, 11, 101, 162, 191, 54, 130, 175, 205, 191, 222, 101, 162, 116, 147, 191, 55, 24, 69, 130, 69, 191, 252, 101, 102, 101, 252, 189, 82, 116, 41, 147, 161, 147, 132, 101, 162, 82, 191, 220, 9, 205, 9, 100, 191, 38, 68, 253] |
TSGDBinary
First of all, we need to deobfuscate the tsgdbinary.py to check what it does during the operation.
1 | import gdb |
The program will break before calling the memcmp. The flag input will be modified by the debugger and then the program will jump to 0x404340. The code at 0x404340 in binary is encrypted, we need to decrypt it first.
1 | code = idc.get_bytes(0x404340, 0x6000) |
The code at 0x404340 is sevaral mapping functions. We can find the original value manually and then decrypt the flag.
1 | import struct |
serverless
We extract all the regex rules from the compose.yaml and divide them into two parts: ones are expanding the length, and the others are reducing.
Focus on the reducing part first.
1 | [ |
It is easy to find that the rules are removing an uppercase letter with a corresponding lowercase letter. We know the flag starts with TSGCTF. If we want to remove all the characters, we need to construct (f)(t)(c)(g)(s)(t) within {}.
Pay attention to the expanding part next.
1 | [ |
It can be noticed that an underscore _ will be replaced by )(, which creates a new group. If we want to create 6 groups, we need to contain 5 underscores with in {}. The regex rules will generate a / right after the {, using it to replate the pattern one by one from left to right.
The pattern rules can be divided into three categories:
- Replace a pattern to
(a)(b)(c)DEF. - Replace a pattern to
(a)(b)(c), which is the end of a group. - Replace a pattern to
aDEF, which is the start of a group.
We can build a graph to represent the rules and use BFS to find the path.
1 | rules = [ |