Rufus
The problem was described in the following way:
"Rufus, down dog!" commands Captain Crypto. But, Rufus the fun-loving dog wants a pet.
"All right, Rufus, I told you three times. That's enough! Now you're going into your crate..."
He's a cute little dog; don't worry, he won't byte. :-)
Your mini-mission: free Rufus!
SSH to challenges.ctfd.io on port 30060 Login with username rufus and password rufus
After ssh-ing to the server, I found an executable file and a file which I could not access due to file permissions. My assumption is that the flag was in the inaccessible file and that running the executable successfully would give access to the flag. Using scp, I copied the executable to my local computer.
scp -P 30060 rufus@challenges.ctfd.io:rufus ./
Running the executable locally, I observed that I needed to provide input when prompted.
Entering "3" resulted in failure. So, using gdb enhanced with PEDA, I opened the executable in the debugger. Before starting, I changed the display of the disassembler to intel.
Then I disassembled main as a starting point. There I saw some very interesting function calls.
- compareLowerByte
- compareHigherByte
- comparesMiddleByte
- winnerWinnerChickenDinner
My assumption is that winnerWinnerChickenDinner
was the function that was called when the correct value is provided. The other 3 functions looked suspiciously like functions that performed the checks on the entered value. I disassembled each of the compare...
functions and added a breakpoint at the only cmp
statements in those functions. I wanted to inspect the values that were being compared. Each of the functions had a similar cmp
call. This is an example from compareLowerByte
.
As can be seen, there is a comparison between the value that was stored in register eax
and the DWORD
at the address stored in the rbp
register minus the value 0xc
(in all cases, the resulting address was0x7fffffffdb74
).
Running the program and stopping at the cmp instructions, I observed the values against which my entered value was compared. The following was discovered:
compareLowerByte
It looks like I need to somehow pass a 4 byte value. The value that I need has 0x21
in the 4th byte position.
compareHigherByte
The value that I need has 0x12
in the 1st byte position.
compareMiddleBytes
The values that I need to pass has 0x3443
in the 2nd and 3rd byte positions.
Put together, this value is 0x12344321. Somehow I needed to get this value into the program. As ASCII, this value has unprintable values. I took a quick look at the program to see if I needed to write a python script to pass the non-printable values to the program, and I noticed a very interesting function call, atoi
.
According to https://www.tutorialspoint.com/c_standard_library/c_function_atoi.htm, atoi converts a number represented as a string into the integer represented by the string. So, string '255' would become the integer value 255
and would be stored as 0xFF
in memory. So, I tried entering the value 305414945
(integer value of 0x12344321
) into the program. This resulted in a failure.
I stepped through the program, and I noticed that my value that I entered was modified at some point. After the atoi
function, eax
register contained 0x12344321
. But, one instruction later, there is an xor operation.
0x555555554a50 <main+98>: xor eax,0x84ff
This xor operation modifies my inputted value to something slightly different and stores it in eax.
EAX: 0x1234c7de
This eax value remained the constant value that was used for comparison through the rest of that program. Since xor is a two way function, I prepared my value by xor-ing the compare value 0x12344321 by 0x84ff and then converted to an integer. The result was:
0x12344321 ^ 0x84ff
305448926
Passing the integer value to the program on the server resulted in the successful running of the program and access to the flag file contents.
Yay!