You've got tired to type commands? But this chapter needs more efforts and knowledges.
You should be able to read MIPS assembly. However,
try at first even if you have never read MIPS.
Explanation
At first, you should understand the calling convention. I'll explain easily what you should do.
Functions use stack to store data temporarily.
Code: Select all
+------------------------+ 0x0AAAAAAA - Lowest Address
| |
| |
| | - Free space
| |
| |
+------------------------+ - The address stored in stack pointer
| data A | - Data used by function A
~~~~~~~~~~~~~~~~~~~~~~~~~~
| data X |
+------------------------+ (0x0AAAAAAA + 0x00CCCCCC) - Highest Address
Stack pointer has the current top address of the stack.
If function A call function B, function B will
decrease stack pointer and save "return address," the address it should be back after function B has finishes, if necessary.
Code: Select all
+------------------------+ 0x0AAAAAAA - Lowest Address
| | - Free space
+------------------------+ - The address stored in stack pointer
| data B | - Other data used by function B
| |
| data b | - Other data used by function B
| return address | - The address to go back
| data A | - Data used by function A
~~~~~~~~~~~~~~~~~~~~~~~~~~
| data X |
+-------------------+ (0x0AAAAAAA + 0x00CCCCCC) - Highest Address
Now, function B loads your long string to the stack. (e.g. The spartaaaaaaa...)
Code: Select all
+------------------------+ 0x0AAAAAAA - Lowest Address
| | - Free space
+------------------------+ - The address stored in stack pointer
| data B | - Other data used by function B
|The spartaaaaaaaaaaaaaaa| 0x0EEEEEEE - Your string
|aaaaaaaaaaaaaaaaaaaaaaaa| - Other data used by function B
|aaaaaaaaaaaaaaaaaaaaaaaa| - The address to go back
| data A | - Data used by function A
~~~~~~~~~~~~~~~~~~~~~~~~~~
| data X |
+------------------------+ (0x0AAAAAAA + 0x00CCCCCC) - Highest Address
OMG! data B and return address got overwritten!
Then, why don't you store the address of your code as return address? Replace the last part of your string with the address. It should go to your code after function B finishes.
Code: Select all
+------------------------+ 0x0AAAAAAA - Lowest Address
| | - Free space
+------------------------+ - The address stored in stack pointer
| data B | - Other data used by function B
|The spartaaaaaaaaaaaaaaa| 0x0EEEEEEE - Your string
|aaaaaaaaaaaaaaaaaaaaaaaa| - Other data used by function B
|The address of your code| - The address to go back
| data A | - Data used by function A
~~~~~~~~~~~~~~~~~~~~~~~~~~
| data X |
+------------------------+ (0x0AAAAAAA + 0x00CCCCCC) - Highest Address
Nice. But corrupted
data b can cause crashes before function B finishes. Replace "aaaa..." with modified data b which don't cause crash and can be recognized as a part of string.
Code: Select all
+------------------------+ 0x0AAAAAAA - Lowest Address
| | - Free space
+------------------------+ - The address stored in stack pointer
| data B | - Other data used by function B
|The spartaaaaaaaaaaaaaaa| 0x0EEEEEEE - Your string
| Modified data b | - Other data used by function B
|The address of your code| - The address to go back
| data A | - Data used by function A
~~~~~~~~~~~~~~~~~~~~~~~~~~
| data X |
+------------------------+ (0x0AAAAAAA + 0x00CCCCCC) - Highest Address
Finally your code will be executed. Let's practice!
1. Make your thread crash
In chapter 1, you have found it copies your string to the address 0x0EEEEEEE in the stack of the thread whose UID is 0xDDDDDDDD.
We should crash the thread when the stack pointer is lower than the address of your string somehow. There are two ways.
One of them is
bpth command. It can make the thread crash very easily.
Replace 0xDDDDDDDD with your UID.
If it crashes, the exception will be shown on pspsh.
Code: Select all
Exception - Breakpoint
Thread ID - 0xDDDDDDDD
Th Name - user_main
Module ID - 0x%08X
Mod Name - %s
EPC - 0x0CCCCCCC
Cause - 0x%08X
BadVAddr - 0x%08X
Status - 0x%08X
zr:0x00000000 at:0xDEADBEEF v0:0xDEADBEEF v1:0xDEADBEEF
a0:0xDEADBEEF a1:0xDEADBEEF a2:0xDEADBEEF a3:0xDEADBEEF
t0:0xDEADBEEF t1:0xDEADBEEF t2:0xDEADBEEF t3:0xDEADBEEF
t4:0xDEADBEEF t5:0xDEADBEEF t6:0xDEADBEEF t7:0xDEADBEEF
s0:0xDEADBEEF s1:0xDEADBEEF s2:0xDEADBEEF s3:0xDEADBEEF
s4:0xDEADBEEF s5:0xDEADBEEF s6:0xDEADBEEF s7:0xDEADBEEF
t8:0xDEADBEEF t9:0xDEADBEEF k0:0xDEADBEEF k1:0x00000000
gp:0xDEADBEEF sp:0x0FFFFFFF fp:0xDEADBEEF ra:0xDEADBEEF
0x0CCCCCCC: 0x0000000D '....' - break 0
See the value of sp (stack pointer). 0x0FFFFFFF is larger than 0x0EEEEEEE. It seems failed.
If you failed with the way, you should try another way. It's explained as a tip in chapter 1. See the tip.
If you succeed, you'll see a exception like this:
Code: Select all
Exception - Breakpoint
Thread ID - 0xDDDDDDDD
Th Name - user_main
Module ID - 0x%08X
Mod Name - %s
EPC - 0x08888888
Cause - 0x%08X
BadVAddr - 0x%08X
Status - 0x%08X
zr:0x00000000 at:0xDEADBEEF v0:0xDEADBEEF v1:0xDEADBEEF
a0:0xDEADBEEF a1:0xDEADBEEF a2:0xDEADBEEF a3:0xDEADBEEF
t0:0xDEADBEEF t1:0xDEADBEEF t2:0xDEADBEEF t3:0xDEADBEEF
t4:0xDEADBEEF t5:0xDEADBEEF t6:0xDEADBEEF t7:0xDEADBEEF
s0:0xDEADBEEF s1:0xDEADBEEF s2:0xDEADBEEF s3:0xDEADBEEF
s4:0xDEADBEEF s5:0xDEADBEEF s6:0xDEADBEEF s7:0xDEADBEEF
t8:0xDEADBEEF t9:0xDEADBEEF k0:0xDEADBEEF k1:0x00000000
gp:0xDEADBEEF sp:0x0EEEEEE0 fp:0xDEADBEEF ra:0xDEADBEEF
0x08888888: 0x0000000D '....' - break 0
0x0EEEEEEE0 is a little smaller than 0x0EEEEEEE. Dump stack to confirm your string has copied.
Code: Select all
- 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f - 0123456789abcdef
-----------------------------------------------------------------------------
0EEEEEEE - 54 68 65 20 73 70 61 72 74 61 00 00 00 00 00 00 - The sparta......
0EEEEEFE - FF 00 00 00 00 00 98 99 99 09 00 00 00 00 00 00 - ................
0EEEEF0E - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - ................
0EEEEF1E - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - ................
0EEEEF2E - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - ................
0EEEEF3E - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - ................
0EEEEF4E - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - ................
0EEEEF5E - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - ................
0EEEEF6E - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - ................
0EEEEF7E - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - ................
0EEEEF8E - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - ................
0EEEEF9E - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - ................
0EEEEFAE - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - ................
0EEEEFBE - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - ................
0EEEEFCE - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - ................
0EEEEFDE - 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - ................
Yes, it seems copied. Note EPC (0x08888888 in the example).
2. Disassemble the code
Now, we should understand how code written at 0x08888888 works. This part needs knowledge of MIPS assembly.
Disassemble the part with this command (Replace SIZE with the number of instructions you want to see.):
If you got disassembled code, find
jr or
jalr instruction at first. For example, this instruction means it jumps to the address stored in $ra.
Second, find the code which stores the address in $ra. It may refer to the stack.
The address seems stored at $sp+32 in this exmaple. Confirm with the following commands.
Code: Select all
0x09999990: 0x0C222220 - ' "".' jal 0x08888880
Yes, it's the address. So, we can say the string whose length is ($sp+32)-0x0EEEEEEE+4 can exploit.
3. Dump the stack
You got enough information to exploit. Let's make a string to exploit.
At first, you may need the base data (data b in the first explanation). Load savegame which don't cause crash and operate to copy the string to stack.
JUST BEFORE it copies the string, set breakpoint at the point which you found in 2 (0x08888888 in the example).
And it will crash.
Code: Select all
0x08888888: 0x0000000D - "...." break 0
It's time to dump the stack.
4. Modify the dumped data to make it recognized as a string and write the address to your code.
Open memdump.bin with a hex editor and replace 0x00 with 0x20. 0x00 is recognized as the end of string. And replace with the end of string with 67 45 23 01. Note that MIPS is little endian. At the last, add 0x00 to the end of file and terminate the string.
Your file will be like this:
Code: Select all
- 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f - 0123456789abcdef
-----------------------------------------------------------------------------
00000000 - 54 68 65 20 73 70 61 72 74 61 20 20 20 20 20 20 - The sparta
00000010 - FF 20 20 20 20 20 67 45 23 01 00 - ÿ gE#..
Now, you've got a string to exploit. Insert the string to your savegame. The way is explained simply at the tip in chapter 1.
Let's try to exploit with your savegame.
If you fail, you'll see an exception like this:
Code: Select all
Exception - Bus error (data)
Thread ID - 0xDDDDDDDD
Th Name - user_main
Module ID - 0x%08X
Mod Name - %s
EPC - 0x0888888C
Cause - 0x%08X
BadVAddr - 0x20202020
Status - 0x%08X
zr:0x00000000 at:0xDEADBEEF v0:0xDEADBEEF v1:0xDEADBEEF
a0:0x20202020 a1:0xDEADBEEF a2:0xDEADBEEF a3:0xDEADBEEF
t0:0xDEADBEEF t1:0xDEADBEEF t2:0xDEADBEEF t3:0xDEADBEEF
t4:0xDEADBEEF t5:0xDEADBEEF t6:0xDEADBEEF t7:0xDEADBEEF
s0:0xDEADBEEF s1:0xDEADBEEF s2:0xDEADBEEF s3:0xDEADBEEF
s4:0xDEADBEEF s5:0xDEADBEEF s6:0xDEADBEEF s7:0xDEADBEEF
t8:0xDEADBEEF t9:0xDEADBEEF k0:0xDEADBEEF k1:0x00000000
gp:0xDEADBEEF sp:0x0EEEEEE0 fp:0xDEADBEEF ra:0xDEADBEEF
0x0888888C: 0x8C840000 '....„Œ' - lw $a0, 0($a0)
Your game crashed before you exploit it. Understand the exception and fix it.
If you succeed, you'll see a exception like this:
Code: Select all
Exception - Bus error (instr) # <- Important
Thread ID - 0xDDDDDDDD
Th Name - user_main
Module ID - 0x%08X
Mod Name - %s
EPC - 0x01234567 # <- Important
Cause - 0x%08X
BadVAddr - 0x01234567
Status - 0x%08X
zr:0x00000000 at:0xDEADBEEF v0:0xDEADBEEF v1:0xDEADBEEF
a0:0xDEADBEEF a1:0xDEADBEEF a2:0xDEADBEEF a3:0xDEADBEEF
t0:0xDEADBEEF t1:0xDEADBEEF t2:0xDEADBEEF t3:0xDEADBEEF
t4:0xDEADBEEF t5:0xDEADBEEF t6:0xDEADBEEF t7:0xDEADBEEF
s0:0xDEADBEEF s1:0xDEADBEEF s2:0xDEADBEEF s3:0xDEADBEEF
s4:0xDEADBEEF s5:0xDEADBEEF s6:0xDEADBEEF s7:0xDEADBEEF
t8:0xDEADBEEF t9:0xDEADBEEF k0:0xDEADBEEF k1:0x00000000
gp:0xDEADBEEF sp:0x0EEEEEE0 fp:0xDEADBEEF ra:0x01234567
"instr" means instruction. You've got it!