I've been away from Microcorruption CTF for a while now, but I've taken a quick look at the Lagos level and haven't figured it out yet. I know there is a failure to check the bounds of user input, which is basically our "in", but I haven't successfully exploited it yet. You can pretty easily enter enough characters to overwrite code, and I suspect that you can manage to write enough code with instructions that happen to fall in the valid alphanumeric ranges to pull it off, but I haven't done the work to figure it out yet.
Here is my annotated source so far:
455e <login>
455e: 0b12 push r11
4560: 3150 f0ff add #0xfff0, sp
4564: 3f40 7044 mov #0x4470 "Enter the password to continue.", r15
4568: b012 6046 call #0x4660 <puts>
456c: 3f40 9044 mov #0x4490 "Remember: passwords are between 8 and 16 characters.", r15
4570: b012 6046 call #0x4660 <puts>
4574: 3f40 c544 mov #0x44c5 "Due to some users abusing our login system, we have", r15
4578: b012 6046 call #0x4660 <puts>
457c: 3f40 f944 mov #0x44f9 "restricted passwords to only alphanumeric characters.", r15
4580: b012 6046 call #0x4660 <puts>
4584: 3e40 0002 mov #0x200, r14
4588: 3f40 0024 mov #0x2400, r15
458c: b012 5046 call #0x4650 <getsn>
4590: 5f42 0024 mov.b &0x2400, r15 ; read a byte of input
4594: 0e43 clr r14 ; set index to zero
4596: 7c40 0900 mov.b #0x9, r12
459a: 7d40 1900 mov.b #0x19, r13
459e: 073c jmp #0x45ae <login+0x50>
45a0: 0b41 mov sp, r11
45a2: 0b5e add r14, r11 ; r11 is stack pointer + index
45a4: cb4f 0000 mov.b r15, 0x0(r11) ; write input byte to stack pointer + index
45a8: 5f4e 0024 mov.b 0x2400(r14), r15 ; load a byte of input to r15
45ac: 1e53 inc r14 ; move r14 to the next byte of input
45ae: 4b4f mov.b r15, r11 ; put the input in r11
45b0: 7b50 d0ff add.b #0xffd0, r11 ; subtract 47 from input
45b4: 4c9b cmp.b r11, r12 ; compare to 9 (check if it's one of 10 valid digits)
45b6: f42f jc #0x45a0 <login+0x42> ; then go to read next input byte
45b8: 7b50 efff add.b #0xffef, r11 ; subtract another 17 from input (now 64)
45bc: 4d9b cmp.b r11, r13 ; compare to 25 (check if it's one of 26 valid uppercase characters)
45be: f02f jc #0x45a0 <login+0x42> ; then go to read next input byte
45c0: 7b50 e0ff add.b #0xffe0, r11 ; subtract another 32 from input (now 96)
45c4: 4d9b cmp.b r11, r13 ; compare to 25 (check if it's one of 26 valid lowercase characters)
45c6: ec2f jc #0x45a0 <login+0x42> ; then go to read next input byte
45c8: c143 0000 mov.b #0x0, 0x0(sp) ; else write zero to sp
45cc: 3d40 0002 mov #0x200, r13
45d0: 0e43 clr r14
45d2: 3f40 0024 mov #0x2400, r15
45d6: b012 8c46 call #0x468c <memset> ; zap 512 bytes to zero
45da: 0f41 mov sp, r15
45dc: b012 4644 call #0x4446 <conditional_unlock_door> ; test the password
45e0: 0f93 tst r15
45e2: 0324 jz #0x45ea <login+0x8c>
45e4: 3f40 2f45 mov #0x452f "Access granted.", r15
45e8: 023c jmp #0x45ee <login+0x90>
45ea: 3f40 3f45 mov #0x453f "That password is not correct.", r15
45ee: b012 6046 call #0x4660 <puts>
45f2: 3150 1000 add #0x10, sp
45f6: 3b41 pop r11
45f8: 3041 ret
And here is some reference I pulled from the system's user guide:
Double Operand Instructions
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
Opcode S-Reg Ad B/W As D-Reg
- MOV(.B) src,dst src → dst
- ADD(.B) src,dst src + dst → dst
- ADDC(.B) src,dst src + dst + C → dst
- SUB(.B) src,dst dst + .not.src + 1 → dst
- SUBC(.B) src,dst dst + .not.src + C → dst
- CMP(.B) src,dst dst − src
- DADD(.B) src,dst src + dst + C → dst (decimally)
- BIT(.B) src,dst src .and. dst
- BIC(.B) src,dst .not.src .and. dst → dst
- BIS(.B) src,dst src .or. dst → dst
- XOR(.B) src,dst src .xor. dst → dst
- AND(.B) src,dst src .and. dst → dst
mov 0x4000 add 0x5000 addc 0x6000 sub 0x8000 subc 0x7000 cmp 0x9000 dadd 0xa000 bit 0xb000 bic 0xc000 bis 0xd000 xor 0xe000 and 0xf000
Single Operand Instructions
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
Opcode B/W Ad D/S-Reg
- RRC(.B) dst C → MSB →.......LSB → C
- RRA(.B) dst MSB → MSB →....LSB → C
- PUSH(.B) src SP − 2 → SP, src → @SP
- SWPB dst Swap bytes
- CALL dst SP − 2 → SP, PC+2 → @SP
- dst → PC
- RETI TOS → SR, SP + 2 → SP
- TOS → PC,SP + 2 → SP
- SXT dst Bit 7 → Bit 8........Bit 15
rrc 0x1000 rra 0x1100 push 0x1200 swpb 0x1080 call 0x1280 reti 0x1300 sxt 0x1180
There are obviously a lot more operators than that, so I'll be looking through those next.