Sets sp and then calls login.
Looks like it prompts for username at 0x458a, and then for password at 0x45b4. Ill break just after both. continue through and input test credentials.
Looks like my input is being placed at 0x2404 and then copied to 0x43a2 (username) and 0x43b5 (password)
Remainder of login function:
Looks like next immediate steps are moving some registers around, and then at 0x45da there is a tst.b call. break at that, and take a look at what's being tested.
Looks like it is confirming that r14 is \x00, r14 is pointed at 0x43b5 (Start of our password), and looking at memory, it is not \x00 and so the jnz will execute back up to 0x45d8, inc r14 retest and loop. this appears to be determining how long our password is. Break just after loop, continue through.
Next it moves r14 into r11, substracts r15 from r11, then moves the byte at 43b4 into r5, compares r15 to r11, and then jumps, Ill break at the cmp and look at register state at that time.
Looks like this compare will fail, and so we jump.
move byte at 0x43b3 into r15, and another cmp. This time, the registers match, and so the jc will execute.
Next up, there is a lot of moving of registers, lots of pushes, mov, and add. Of note though, is the push of 0x7d right before the call to INT function.
Im going to break at the tst.b just after the INT call, and continue through everything. After INT completes, it tests 0x43A0 which is \x00 currently, so the jz right after will execute. This puts password not correct to screen, and ultimately exit out of program cleanly.
So, nothing much there, nothing that I can look at to see the password compare to and no password in memory. So, blow up inputs with As and see if it is vulnerable to overflows.
RESET
New Username: (1000 As)
New Password: (1000 Bs)
After I input my username, inspecting memory, it does appear to accept >16 chars, but is eventually truncated.
After Password input, and strcpy, it does appear that password accepts > 16 chars too, and is also truncated.
Continue through and I get password length too long error and it cleanly exits.
My first thought, is that I do not get username too long, and since my password was shoved right on top of my username, maybe I can overflow username, input correct length password, and maybe the username will still crash out the app?
RESET
Username: 1000x As
Password: 16x Bs
Memory directly after password's strcpy
As I continue through the rest of the execution, I now get password length too short?
Reset
Same inputs, step through execution manually, and observe closer.
The first cmp passes, which it should. (If it doesnt pass, it doesnt jump, and carrys on downwards to the br right below.) So all good so far I believe.
However this time, the second cmp does
not match, so this will fail, it will
not jump, and exit out at the br just below. Found my issue?
It looks like r15 is set 2 instructions higher, via the mov.b instruction. -0x19r4 is currently located at 43B3 and is indeed 41
It is comparing it against \x10. So I count of that bytes location, looks like its the 18th bit, so can I just change the 18th char to \x10 and pass this jump?
RESET
New username: 4141414141414141414141414141414141104141414141414141414141414141414141414141414141414141414141414141414141414141414141414141
Password: 16x Bs
Continue through to those cmps again.
First cmp still fails, as it should.
Second cmp looks better now!
Looks like I got past the length checks, even with an overflowed username!
Ill step through the rest of the execution to see if I get a crash. But I do not. It cleanly exits. There are a few more jmps and tsts in the remaining execution, so Ill look at those closer.
RESET
Same username and pass.
Continue through to the first new tst.b / jz instruction.
Here we are testing the byte at 0x43A0 and if \x00, jumping. That byte is indeed \x00, so we jump to 0x4644. Unfortunately that Byte is
before the location of our username and password, it doesnt appear that I can affect this byte as of this point in program execution.
Step through to the next tst.b / jz instruction.
Here we are testing the byte at 0x43C6, if \x00 we jump to 0x465e which is just after the br instruction. If it is not \x00 we do not jump, and exit the program. Currently the byte at 0x43C6 is \x41 so this will not jump. But the byte just before is \x00, and I did not add any null bytes to my input, and this null byte is just after my password. So it looks like it is inserting a null byte after my password on its own.
Can I just make the password 1 char longer and push that \x00 into the right location to jump?
Reset
Same Username
New pass: 17x B's
Continue through to that tst.b instruction and it looks like 0x43C6 is now \x00. So I should jump to below the br.
And I do!
And when I step through the remainder of the program, I crash it out with PC pointed at 4141!
So now I got to find which pair of \x41 it is pointed to at time of crash, and I control pc. Looking at the sp at the time of crash, it is pointed to 0x43ce, which is in my over flowed As.
And is 45 bytes after the start of my username. Lets put \x4343 there and see if I got pc correct.
RESET
New username:
414141414141414141414141414141414110414141414141414141414141414141414141414141414141414143434444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
Pass: 17x Bs
NOPE! I was wrong. But it looks like It is in my As, and not my Cs or Ds. So Ill swap the As out just after the pass to Es and identify if pc is pointed to the As
before the password, or after.
RESET
New Username:
414141414141414141414141414141414110454545454545454545454545454545454545454545454545454543434444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
Pass: 17x Bs
And it looks like it is pointed to 0x4545, so I have narrowed down PC a little more.
Next, Ill change everything to As, except for the section of PC, which Ill increment. However my password overwrites 17x bytes, starting 1x byte after \x10, and then the null byte. So I can likely also ignore that part too, and increment only this section here...
RESET
New Username:
4141414141414141414141414141414141104545454545454545454545454545454545454545454646474748414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141
Pass: 17x Bs
Continue through to the end, and step once out of login, and pc is pointed to 0x4847
Cool, I have identified pc location and now control it. So in my username, I can replace the occurrence of \x4748 with anything I want.
Lets go find something to put there.
It looks like this revision contains the unlock door function, so my first thought is to just put in 0x444a at pc, and see if that works.
RESET
New Username:
4141414141414141414141414141414141104545454545454545454545454545454545454545454646474a44414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141
Pass: 17x Bs
Continue through until we ret out of login, and step once. pc is pointed at 444a as we wanted, and it looks correct!
Hit continue and see if we unlock.
Unlocked! All is right with the world...
Notes:
I thought this was a good challenge as well. Adding the Username field was a nice touch, it added a little complexity, but nothing that I wasn't able to overcome. Nothing through me for tooooo much of a loop, and the realization that I dont have to step through things like puts, strcpy, memset, int, and stuff like that has REALLY sped up RE time. Overall this was fun.