Wooo, another CTF level. This time it’s Cusco. Again, I’m not sure I’m doing these in order, but that’s alright.
What does this level have for us? More software updates!
This is Software Revision 02. We have improved the security of the lock by removing a conditional flag that could accidentally get set by passwords that were too long.
Clearly, I’m doing things out of order, because yesterday’s post is for Johannesburg, which had software version 4. Oop.
Cusco Codeflow
Once again, main
is a one-way trip to the login
function.
If we look at the login function:
What’s going on here? We are:
- Prompting the user for their password, and reminding them of the length restriction.
- We’re putting 0x30 into r14, which we’ll use as an argument to the
getsn
function - We’ll call test_password_valid and look at the results of that in r15
- From there, we’ll either grant or deny access, then add 0x10 to the stack pointer and return to that address.
If you read the post for Johannesburg, you know that we had two goals for that level: trick the overflow detection, and reroute program flow.
Since it doesn’t look like there’s overflow detection here, we just have to reroute the program flow (I think?)
Let’s give it a try.
Testing Out Password Length
The program says we can’t use more than 16 characters, yet it’s passing an argument of “0x30” (decimal 48) to the gets function… soooooooo 🤷♀️
Let’s try out a longer input.
First, I put a breakpoint at 453a. Then, I entered in “AAAABBBBCCCCDDDDEEEE” (length 20) to see what might happen:
After we’ve stopped at our breakpoint, we can see that it copied the entire string over. If it were enforcing the 16-char length, the “E"s would get cut off.
As with Johannesburg, we’ve kind of abandoned the idea of getting the password right. Instead, we’re trying to use the return
statement at the end of login
to re-route the program to a different function, instead of just ending execution.
What does that mean for you, reader? Type s
to step once, and you’ll see that we’ve added 0x10 to the stack pointer, and which is now pointing to:
We’re one instruction away from returning, and we’re headed straight towards *squints* “EE”.
If you step again, you’ll get a message like so:
insn address unaligned
That’s because 0x4545 (“EE”) isn’t a valid place to go to. So let’s find out somewhere else to go.
How about the unlock function? It doesn’t take any arguments, it just… unlocks the door. Seems like a poor design choice but okay.
Its address is “4446”. Instead of messing around with the “AAAABBBB…” etc nonsense, we could just send the address repeatedly. Or not. It’s up to you. I mistyped the input too many times and lost patience, so repeated-address-input it is.
Cusco Solution
I repeated the “new” address of “4644”* 9 times:
464446444644464446444644464446444644
*adjusted for endianness
If you stop at the end of login, you’ll see that we’ve overwritten the return address, and now we’re on our way to 4446 (unlock_door
)
To complete this level, type solve
and then enter the payload of “464446444644464446444644464446444644”.