TD-W8901N V2 is a new release of ADSL router to supersede the previous V1 with the first version of firmware being published on 3rd Nov 2014. I expect it should have some remedies to rom-0 and misfortune cookie bugs. Let’s have a look.
Well, rom-0 bug is fixed in this version. Now, let’s try with misfortune cookie bug.
At console, it shows,
Unfortunately, the misfortune cookie bug is still there. By using the method that I have mentioned in my previous paper, the exploit should easily be developed. However, there is an interesting issue in this version of firmware which is worth to discuss, MIPS16. In all the firmwares with misfortune cookie bug that I have studied before, all of them are running in MIPS32, so this is the first time I get a firmware which is running in MIPS16, or the hybrid of MIPS16 and MIPS32. How to know it is running in MIPS16 ? Simple, the EPC is crashed at an odd number value, 0x800EDA07. In MIPS32, the first 2 bits from LSB is normally set as zero, because each instruction is with fixed length of 32-bit. However, in MIPS16, the first bit from LSB is set as one, while the second bit is in used for addressing and keep toggling with one and zero. Now, let’s have a look to the code snippet around 0x800EDA07.
At 0x800EDA07, the instruction being executed is
However, due to one delay slot in MIPS architecture, the faulty instruction should be
The reason is $s1 is getting from $v0, which is the return value of sub_80130928. When not passing any parameter in misfortune cookie, sub_80130928 will return a null, and eventually will cause a write operation to address 0x00000000, which is invalid, and in turn crashing the system. Now, to develop an exploit for this version of firmware, the value of $v1 at ROM:800EDA22 is necessary. With the method as mentioned in my previous paper, an instruction should be injected at that address to duplicate the value of $v1 into $s7, following by another instruction to crash the system and print the value of $s7 via the console as crash log. The reason I choose $s7 is because it is not being used by sysreset() in system crashing, so it will not be overridden, and I can get the exact value of $v1 from crash log. But, in MIPS16, $s7 is unavailable. The registers which are available in MIPS16 are $s0, $s1, $v0, $v1, $a0, $a1, $a2, and $a3, where all of them will be overridden by sysreset(). I get this conclusion by trying all of them in MIPS16, but not going to reverse sysreset().
Well, it is necessary to switch from MIPS16 into MIPS32 first before getting $s7 ready to show the value of $v1. In order to switch from MIPS16 to MIPS32, jalx instruction should be used. By referring  page 83, it is possible to create a special jalx instruction to get the job done. Let’s assume the jalx instruction can be located at any specific address to switch MIPS16 into MIPS32 and then divert the instruction flow to another address which is patched with instruction to duplicate the value of specific register into $s7 and then crash immediately. So, if we need to get the value of $v1 at ROM:800EDA22, we can patch the address with “jalx 0x800eda34” and at ROM:800EDA34, we can patch it with “jr $zero”, and at ROM:800EDA38, we patch it with “add $s7, $v1, $zero”. Why “add $s7, $v1, $zero” is after “jr $zero” ? Please keep delay slot in mind. Let’s do it now.
running romfile and backup romfile is the same
So, the value of $v1 is 0x803B12A8 and $a3 is 0x803B12A8 + 0x6B28 = 0x803B7DD0. On the other hand, since the EPC is stopped at 0x00000000, which is not an odd number value, it shows the system has been switched from MIPS16 into MIPS32 before getting crashed. So, it is ready to create our exploit right now. Let’s do it.
Cool, the exploit works like a charm.
There are quite a number of peoples are questioning to the usefulness of misfortune cookie bug by assuming all of them must come with rom-0 bug. In reality, rom-0 bug can simply be removed or fixed by those who having html to c utility, which is normally in the disposal of majority downstream manufacturer. However, httpd.a is usually obtained from upstream in binary format which is almost impossible to be modified by downstream in proper condition. On the other hand, someone might argue again while the new version has using web login without the popup box which indicate the model number of the router, then how to determine the model number of the target router now ? The answer is in fact fairly simple,
When target = 0x800eda34, since it is located at kseg0, and the MSB will always reset to 0 while mapping to physical address. So, it can be neglected and assume it is 0x000eda34. Because each instruction taking 32-bit or 4-byte, the target should be converted to (0x000eda34 / 4) = 0x3b68d. Hence,
Thus, the “jalx 0x800eda34” in hex format is,