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
At 0x800EDA07, the instruction being executed is
However, due to one delay slot in MIPS architecture, the faulty instruction
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,