Line 44:
Line 44:
Unfortunately, because of how the garbage collector works, it will also attempt to follow a "pointer" at the value previously there, which means it is important to make sure the chain does not go past there. It turns out that the chain handles 6 objects at a time, which means the 6th object needs to be at the place to overwrite. Because the beginning of the object is overwritten with a zero, while the second integer is overwritten with a previous pointer, the location of this "object" must be placed 4 bytes before the address to be overwritten. The 5th object must then have the address to be overwritten, followed directly by the data that should be present when the overwritten pointer is dereferenced. With this, there are still 4 more iterations that must be done. The first iteration is when the garbage collector handles the trashed text field and moves toward the custom chain, leaving 3 more that require attention. For these three, a simple chain of pointers pointing to the next object are put to use up the remaining parts of the loop. A buffer of junk bytes is placed in between to prevent the garbage collector from overwriting the pointer after it, providing a method to overwrite a single address.
Unfortunately, because of how the garbage collector works, it will also attempt to follow a "pointer" at the value previously there, which means it is important to make sure the chain does not go past there. It turns out that the chain handles 6 objects at a time, which means the 6th object needs to be at the place to overwrite. Because the beginning of the object is overwritten with a zero, while the second integer is overwritten with a previous pointer, the location of this "object" must be placed 4 bytes before the address to be overwritten. The 5th object must then have the address to be overwritten, followed directly by the data that should be present when the overwritten pointer is dereferenced. With this, there are still 4 more iterations that must be done. The first iteration is when the garbage collector handles the trashed text field and moves toward the custom chain, leaving 3 more that require attention. For these three, a simple chain of pointers pointing to the next object are put to use up the remaining parts of the loop. A buffer of junk bytes is placed in between to prevent the garbage collector from overwriting the pointer after it, providing a method to overwrite a single address.
−
Now, an address to overwrite must be chosen. It makes sense to overwrite a pointer, since a pointer will be put in place of it. At first, it seems like a function pointer or return address should be overwritten to pass code execution to FlashHax, however, Opera does enforce DEP, so a code buffer cannot simply be added. A more useful place to overwrite is a pointer to an [[Revolution OS#Context switching|OSContext]].
+
Now, an address to overwrite must be chosen. It makes sense to overwrite a pointer, since a pointer will be put in place of it. At first, it seems like a function pointer or return address should be overwritten to pass code execution to FlashHax, however, Opera does enforce DEP, so a code buffer cannot simply be added. A more useful place to overwrite is a pointer to an [[Revolution OS#Threads|OSThread]].
−
With OSContext in control, one might think to set up a ROP chain by overwriting the stack pointer. However, this is not possible, because the stack pointer is stored in register r1, which is overwritten by the trash bytes that come after the previous pointer on the garbage collector chain. In fact, r6 is the first register that can be controlled. Luckily, the other special-purpose registers such as the program counter and the link register are higher up in the context, so they can be controlled. The program counter can be used to load one gadget, and the link register can hold a second gadget assuming the first gadget is not from a function that saves and loads the link register (i.e. a function that calls another function). However, no more ROP gadgets can be run this way, so a way to load a longer ROP chain is needed.
+
With OSThread (and therefore [[Revolution OS#Context saving|OSContext]]) in control, one might think to set up a ROP chain by overwriting the stack pointer. However, this is not possible, because the stack pointer is stored in register r1, which is overwritten by the trash bytes that come after the previous pointer on the garbage collector chain. In fact, r6 is the first register that can be controlled. Luckily, the other special-purpose registers such as the program counter and the link register are higher up in the context, so they can be controlled. The program counter can be used to load one gadget, and the link register can hold a second gadget assuming the first gadget is not from a function that saves and loads the link register (i.e. a function that calls another function). However, no more ROP gadgets can be run this way, so a way to load a longer ROP chain is needed.
The problem is now reduced to placing the stack pointer at a controlled location, using up to two ROP gadgets. The stack pointer is currently set at a low value due to the garbage collector setting r1 to that, so it may appear that starting a ROP gadget in the middle of a function is not useful, since it will attempt to free the stack into negative memory. This is actually not the case, because on PowerPC, the stack grows downward, meaning there is actually plenty of space for the stack to be freed, but not much to grow. Because of this, the first ROP gadget can be at the part of a function that is freeing however much of the stack it previously allocated, which is stored in r28, one in the controllable area. Once this is done, the stack pointer is in control. The function chosen happens to save and load the link register, which means the link register can be preloaded with dummy data.
The problem is now reduced to placing the stack pointer at a controlled location, using up to two ROP gadgets. The stack pointer is currently set at a low value due to the garbage collector setting r1 to that, so it may appear that starting a ROP gadget in the middle of a function is not useful, since it will attempt to free the stack into negative memory. This is actually not the case, because on PowerPC, the stack grows downward, meaning there is actually plenty of space for the stack to be freed, but not much to grow. Because of this, the first ROP gadget can be at the part of a function that is freeing however much of the stack it previously allocated, which is stored in r28, one in the controllable area. Once this is done, the stack pointer is in control. The function chosen happens to save and load the link register, which means the link register can be preloaded with dummy data.
−
With this in mind, a sequence of bytes can be crafted to meet the needs stated above. First, there needs to be a chain of 3 pointers that point forward to the next. After this, the address to be overwritten must be present, which is the fake OSContext, and the last pointer in the previous chain points to this pointer. When the pointer is overwritten, it points directly at the target address, meaning the rest of OSContext, after the trash bytes, need to be placed there. Finally, after the fake OSContext, the ROP chain is present, which the ROP gadget in OSContext loads.
+
At this point, the OSContext is complete; the other part of the OSThread that must be properly set is the pointer to an OSThreadQueue when context switching. This is simply set to 0x80000004, the location of a few disc metadata values that are not relevant to the Internet Channel, as the queue is only written to in an attempt to move the old thread to the end of the linked list.
+
+
With this in mind, a sequence of bytes can be crafted to meet the needs stated above. First, there needs to be a chain of 3 pointers that point forward to the next. After this, the address to be overwritten must be present, which is the fake OSThread, and the last pointer in the previous chain points to this pointer. When the pointer is overwritten, it points directly at the target address, meaning the rest of OSThread, after the trash bytes, need to be placed there. Finally, after the fake OSThread, the ROP chain is present, which the ROP gadget in OSContext loads.
Now that a payload is built, there needs to be a way to place it directly in memory. Flash does not keep array elements together in memory, so an array is not an option. The other option is a string, which is available, but it has its own issues. Similar to C strings, Flash strings are terminated by null characters, but unlike in C, characters are 2 bytes wide in Flash, meaning strings are terminated by double null bytes. There are several points in the hax string that require padding, such as between the garbage collector iterations, that would normally be set to 0. Since this is not possible here, the <code>\u4141</code> and <code>\u4242</code> characters are used instead. These values are also placed into all of the unused registers in OSContext to prevent the string from terminating prematurely.
Now that a payload is built, there needs to be a way to place it directly in memory. Flash does not keep array elements together in memory, so an array is not an option. The other option is a string, which is available, but it has its own issues. Similar to C strings, Flash strings are terminated by null characters, but unlike in C, characters are 2 bytes wide in Flash, meaning strings are terminated by double null bytes. There are several points in the hax string that require padding, such as between the garbage collector iterations, that would normally be set to 0. Since this is not possible here, the <code>\u4141</code> and <code>\u4242</code> characters are used instead. These values are also placed into all of the unused registers in OSContext to prevent the string from terminating prematurely.