wk2 - intro to rev
Theme: Reverse Engineering, casting, static debugging
Quasar (50)
Given
Program: "This quasar is the brightest object in the universe. Can you guess the mass of the black hole at its centre? (Note: Answer is a hex number)"
Solve
Run GDB on the quasar compiled binary file. Set assembly code to Intel style with set disassembly-flavor intel if needed. Set a breakpoint at main using b main and run the program using r. Run disass to see the assembly code of main. Pay attention to the part where user input is read. The flag is shown if user input is correct, and user input is checked using a cmp instruction. We trace the code and find that after user input is received, whatever is in RAX gets moved to rbp-0x8. This means rbp-0x8 contains user input. Then, the absolute value 0x3f5476a00 gets moved into RAX. Afterwards, RAX's value gets compared with rbp-0x8. This indicates that the correct answer is the value 0x3f5476a00.
Continue running the program and enter 0x3f5476a00 as the mass of the quasar. Obtain the flag!
Cosmic Distance (50)
Given
Program: "Can you tell me the distance from this quasar to Earth?"
Solve
Use Binary Ninja to decompile the code. Notice this function that initializes the distance:
void init()
{
distance = 0x2cb417800;
}Run the program and enter 0x2cb417800 to obtain the flag.
Secrets (50)
Given
Program: "Can you guess the key?"
Solve
Let's use Binary Ninja for static debugging.
The program contains a while loop and an iterable array of characters named secret. Each byte (one character) in secret gets XOR-ed with each character within user input. In other words, we are trying to input the correct cipher key. Our goal is that for every character in secret, when XOR-ed with user input, it should be equal to the corresponding character in the secret message.
Looking into read_key(), we find that the user input must be between 0-255, and it will be interpreted as a base-10 integer.
Because the secret message cannot be read even during GDB debugging, we can brute force the server with a python script, trying every possible key from 0-255:
Run the program. We switch to interactive mode when we get to key = 233, and the flag gets displayed.
Tools
myString.encode(): converts string into bytes
StrS (50)
Given
Program: "Give me the right answer and I'll give you the flag!"
Solve
Use Binary Ninja for static debugging. Head into main() to scope out what the program does. In main(), we see that the program takes in user input, changes it from \n-terminated to \0-terminated, and delivers the flag only if user input equals the value stored at var_2 (correct answer). This means we should find out what value var_2 holds. Look at disassembly code. Just before the string comparison function is called, user input's address is loaded into RAX register, and the correct answer's address is loaded into RSI register. Our strategy is to run the program using gdb, set a breakpoint right before string comparison, check the value in register RSI using info registers rsi. That should dump the memory address containing the correct answer. Then we use x\s [ADDRESS] to dump the value as a string at that memory address to see the correct answer.
The correct answer is: " SMSS J052915.80−435152.0 ". Enter this when prompted. Flag is obtained!
Numbers (100)
Given
Program (compiled binary) Goal
Answer 5 questions correctly to obtain flag
Solve
Use readelf -h numbers to get initial data about this compiled binary. We notice this is not a PIE file, which means all the addresses are absolute addresses, not offsets.
Use Binary Ninja for static debugging. Inspect main() to get an overall idea. We see that if the output from each question returns 0, we fail. This means we want each question to NOT return 0. Head into the functions for each question to see what goes on inside. Every question first prints out the question, then calls the input_answer() function, then checks a boolean condition if a var equals some other var. Since we want each question to NOT return 0, we want all the conditions to evaluate to true, i.e. the variables being compared should be equal.
Inspect input_answer() to see what occurs there. It asks for two inputs, the first being an address (must begin with 0x to be valid) and the second being the size to deref, interpreted as a string. Depending on the what we enter for size to deref, we can update the values for different variables. For example, if we enter "char" for size to deref, we get to update var1: var1 = (*input_addr).b
Begin with Question 1. We want data_404730.b to equal var1. var1 was initialized to have the value 0x0. In order for it to have a value equal to data_404730.b, we must update var1 inside input_answer(). We do that by inputting the address 0x404730 (houses the variable data_404730. and we know this is the absolute memory address because this binary is not PIE) and inputting size to deref as char. In this manner, var1 will have exactly data_404830.b as its value.
Next up, question 2. We want var4 to equal data_4042a0. This means that we must update var4 inside input_answer() by inputting address 0x4042a0 (houses the variable data_4042a0) and letting size to deref be "long long". This way, var4 will be set equal to data_4042a0.
Apply the same logic for the rest of the questions:
Question 3. Enter 0x404730 as address and "short" for size to deref
Question 4. Enter 0x4043c0 as address and "void*" for size to deref
Question 5. Enter 0x4044c8 as address and "long" for size to deref
Run the program and enter inputs as we reasoned above to obtain the flag.
Last updated