If I’m not already doing these writeups out of order, I will be soon. This post is about the Johannesburg level of Microcorruption.
Now we’re on software version 4:
Towards the bottom, we see:
This is Software Revision 04. We have improved the security of the lock by ensuring passwords that are too long will be rejected.
We’ll see about that.
Main isn’t very interesting:
Login looks like this:
452c <login> 452c: 3150 eeff add #0xffee, sp 4530: f140 4c00 1100 mov.b #0x4c, 0x11(sp) 4536: 3f40 7c44 mov #0x447c "Enter the password to continue.", r15 453a: b012 f845 call #0x45f8 <puts> 453e: 3f40 9c44 mov #0x449c "Remember: passwords are between 8 and 16 characters.", r15 4542: b012 f845 call #0x45f8 <puts> 4546: 3e40 3f00 mov #0x3f, r14 454a: 3f40 0024 mov #0x2400, r15 454e: b012 e845 call #0x45e8 <getsn> 4552: 3e40 0024 mov #0x2400, r14 4556: 0f41 mov sp, r15 4558: b012 2446 call #0x4624 <strcpy> 455c: 0f41 mov sp, r15 455e: b012 5244 call #0x4452 <test_password_valid> 4562: 0f93 tst r15 4564: 0524 jz #0x4570 <login+0x44> 4566: b012 4644 call #0x4446 <unlock_door> 456a: 3f40 d144 mov #0x44d1 "Access granted.", r15 456e: 023c jmp #0x4574 <login+0x48> 4570: 3f40 e144 mov #0x44e1 "That password is not correct.", r15 4574: b012 f845 call #0x45f8 <puts> 4578: f190 4c00 1100 cmp.b #0x4c, 0x11(sp) 457e: 0624 jeq #0x458c <login+0x60> 4580: 3f40 ff44 mov #0x44ff "Invalid Password Length: password too long.", r15 4584: b012 f845 call #0x45f8 <puts> 4588: 3040 3c44 br #0x443c <__stop_progExec__> 458c: 3150 1200 add #0x12, sp 4590: 3041 ret
For this (and other challenges), I ended up writing up notes for every single line of assembly because I was feeling very rusty. But for now, I’ll just share a general outline of this function.
- Move “0x4c” into a certain point in memory.
- Ask the user for their password, and remind them of password length requirements.
- Get the password input and strcpy it from 0x2400 (in memory) to a different location.
- Call test_password_valid
- Return from that function, and determine whether they should be granted access or not (based on the return value)
- Then, check the “0x4c” we left in memory. If it’s gone, chastise the user for having a too-long password.
- Add 0x12 to the stack pointer and then use the value at that address to return back to main (and end program execution).
Buffer Overflowing Ideas
This software revision technically has some changes to address buffer overflows. But it’s not a preventative measure. It’s a way of detecting it after the fact.
To verify this, I typed in “AAAABBBBCCCCDDDDEEEE” as the password, which is 20 chars long. You can see it copied into memory at 0x2400 and then strcpy’d elsewhere with all chars intact.
So, is there a way we can get through this challenge by using a buffer overflow to redirect the program flow, and also clean up our evidence afterwards?
Note: in case it’s not clear, the strategy here doesn’t involve guessing the password or getting it correct. I’ll be ignoring the “incorrect password” output from here on out.
Goal 1: Clean Up Buffer Overflow Evidence
If the program is expecting to see “0x4c” in a certain location, and isn’t stopping us from writing a too-long string let’s write a long string and make sure “4c” is in the correct place.
Where does it need to be? If we look at line 4530 of
login, we see that it’s expecting 0x4c at a point 11 bytes past the current
And where is that? If we look in the memory view:
The green box is where we need to stick the “4c” (technically on the righthand side).
I reset and reran the program with “AAAABBBBCCCCDDDD” and “4c4c” at the end. “4c” is “L” but you can also enter this in using the hex-encoded option. I threw 2 “E"s and 4 more “A"s on the end, too.
The hex encoded-option would look like: “4141 4141 4242 4242 4343 4343 4444 4444 4c4c 4545 4141 4141” (spacing only for readability).
And if we run the program up until line 4578:
4578: f190 4c00 1100 cmp.b #0x4c, 0x11(sp)
step over. We see that the
sr (status register, which holds flags that represent the result of a previous computation) is 0003, indicating that the equality comparison was successful:
Nice. Okay, what next?
Goal 2: Redirect Program Flow
From here, if you
step` over a few more times, you’ll skip the “Invalid password length” message because you tricked the program.
Step a few more times, and you’ll get to this line (458c).
If we look at the memory view at this point, we are here:
If we add 0x12 to this–which is 16 in decimal–we’ll end up here (
step once to see this in the debugger).
If we had been better people earlier, we wouldn’t have overwritten this part of memory with “E”. If you reset the program you can see that the value used to be “443c”:
If we check out the manual, you’ll see that this value (“443c”) is tellign the program where to return to. So where is 443c?
The end of program execution. Oh no, we don’t want that. We’re don’t have our door open yet!
Back to the EEAAAAs
In the example payload, I had “EEAAAA” at the end, after “4c4c”. The A’s are extraneous, so we can ignore those. But what about the E’s?
Reset the program if you need to and re-enter that payload.
Once you get to line 458c, and you have this memory view:
Step over a couple more times, so that you return from the login function to an address of 4545.
You’ll see this message in the I/O console:
insn address unaligned
Why? Because we went to an invalid address. So what address do we want to go to?
How about this
Address “4446”. Write that down, we’ll need it.
So, we have 16 chars of whatever, plus the “4c” check, plus the address we want to go. Don’t forget to consider endianness.
That looks like:
So, we successfully completed both goals. We tricked the overflow detection, and we re-routed the program flow from the “end execution” function to the “unlock door” function.
solve and then enter in the payload to complete this level.