CVE-2021-39685 Description and sample exploit for Linux USB Gadget overflow vulnerability

Overview

inspector-gadget

    Go Go Gadget Exploit!
     _..--"\  `|`""--.._
  .-'       \  |        `'-.
 /           \_|___...----'`\
|__,,..--""``(_)--..__      |
'\     _.--'`.I._     ''--..'
  `''"`,#JGS/_|_\###,---'`
    ,#'  _.:`___`:-._ '#,
   #'  ,~'-;(oIo);-'~, '#
   #   `~-(  |    )=~`  #
   #       | |_  |      #
   #       ; ._. ;      #
   #  _..-;|\ - /|;-._  #
   #-'   /_ \\_// _\  '-#
 /`#    ; /__\-'__\;    #`\
;  #\.--|  |O  O   |'-./#  ;
|__#/   \ _;O__O___/   \#__|
 | #\    [I_[_]__I]    /# |
 \_(#   /  |O  O   \   #)_/
       /   |        \
      /    |         \
     /    /\          \
    /     | `\         ;
   ;      \   '.       |
    \-._.__\     \_..-'/
     '.\  \-.._.-/  /'`
        \_.\    /._/
         \_.;  ;._/
       .-'-./  \.-'-.
      (___.'    '.___)

Summary

An attacker can access kernel memory bypassing valid buffer boundaries by exploiting implementation of control request handlers in the following usb gadgets - rndis, hid, uac1, uac1_legacy and uac2. Processing of malicious control transfer requests with unexpectedly large wLength lacks assurance that this value does not exceed the buffer size. Due to this fact one is capable of reading and/or writing (depending on particular case) up to 65k of kernel memory.

Description

Some execution paths of usb control transfer handlers of gadgets such as rndis, hid, uac1, uac1_legacy and uac2 do not include proper handling of request length (wLength). This value should be limited to buffer size to prevent buffer overflow vulnerabilities in the data transfer phase.

The buffer used by endpoint 0 is allocated in composite.c with size of USB_COMP_EP0_BUFSIZ (4096) bytes so setting wLength to a value greater than USB_COMP_EP0_BUFSIZ will result in a buffer overflow.

For example in the case of f_uac1.c, execution of the f_audio_setup function allows one to perform both reads and writes past buffer boundaries. Neither f_audio_setup nor none of the called functions - audio_set_endpoint_req, audio_get_endpoint_req, out_rq_cur, ac_rq_in limit the return value to be smaller than the buffer size. Consequently the data transfer phase uses req->length = value = ctrl->wLength which is controlled by the attacker. This allows one to either read or write up to 65k bytes of kernel memory depending on the control transfer direction.

bRequestType, ctrl->bRequest, w_value, w_index, w_length); } /* respond with data transfer or status phase? */ if (value >= 0) { DBG(cdev, "audio req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, w_value, w_index, w_length); req->zero = 0; req->length = value; value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); if (value < 0) ERROR(cdev, "audio response on err %d\n", value); } /* device either stalls (value < 0) or reports success */ return value; }">
    static int
    f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
    {
            struct usb_composite_dev *cdev = f->config->cdev;
            struct usb_request      *req = cdev->req;
            int                     value = -EOPNOTSUPP;
            u16                     w_index = le16_to_cpu(ctrl->wIndex);
            u16                     w_value = le16_to_cpu(ctrl->wValue);
            u16                     w_length = le16_to_cpu(ctrl->wLength);

            /* composite driver infrastructure handles everything; interface
             * activation uses set_alt().
             */
            switch (ctrl->bRequestType) {
            case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
                    value = audio_set_endpoint_req(f, ctrl);
                    break;

            case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
                    value = audio_get_endpoint_req(f, ctrl);
                    break;
            case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
                    if (ctrl->bRequest == UAC_SET_CUR)
                            value = out_rq_cur(f, ctrl);
                    break;
            case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
                    value = ac_rq_in(f, ctrl);
                    break;
            default:
                    ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
                            ctrl->bRequestType, ctrl->bRequest,
                            w_value, w_index, w_length);
            }

            /* respond with data transfer or status phase? */
            if (value >= 0) {
                    DBG(cdev, "audio req%02x.%02x v%04x i%04x l%d\n",
                            ctrl->bRequestType, ctrl->bRequest,
                            w_value, w_index, w_length);
                    req->zero = 0;
                    req->length = value;
                    value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);

                    if (value < 0)
                            ERROR(cdev, "audio response on err %d\n", value);
            }

            /* device either stalls (value < 0) or reports success */
            return value;
    }

Execution of the sample readout exploit allows dumping of up to 65k of memory.

    $ ./gadget.py -v 0x1b67 -p 0x400c -f uac1 | wc -c
    65535
    $ ./gadget.py -v 0x1b67 -p 0x400c -f uac1 | strings

    nsole=tty1 root=PARTUUID=e02024cb-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait modules-load=dwc2
    tem.slice/system-getty.slice/[email protected]
    !rE*
    ?& .4!
    0usb_composite_setup_continue
    composite_setup
    usb_gadget_get_string
    usb_otg_descriptor_init
    usb_otg_descriptor_alloc
    usb_free_all_descriptors
    usb_assign_descriptors
    usb_copy_descriptors

    usb_gadget_config_buf

On the other hand, execution of the overwrite exploit allows one to write arbitrary data past expected buffer boundaries.

    $ ./gadget.py -v 0x1b67 -p 0x400c -f uac1 -d write

    Message from [email protected] at Dec  6 19:56:01 ...
     kernel:[  103.850206] Internal error: Oops: 5 [#1] ARM

Similarly in case of the rndis gadget the rndis_setup function can be exploited to write past buffer boundaries using control transfer request with direction out, type class, recipient interface and bRequest set to USB_CDC_SEND_ENCAPSULATED_COMMAND.

bRequestType, ctrl->bRequest, w_value, w_index, w_length); req->zero = (value < w_length); req->length = value; value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); if (value < 0) ERROR(cdev, "rndis response on err %d\n", value); } /* device either stalls (value < 0) or reports success */ return value; }">
    static int
    rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
    {
            struct f_rndis          *rndis = func_to_rndis(f);
            struct usb_composite_dev *cdev = f->config->cdev;
            struct usb_request      *req = cdev->req;
            int                     value = -EOPNOTSUPP;
            u16                     w_index = le16_to_cpu(ctrl->wIndex);
            u16                     w_value = le16_to_cpu(ctrl->wValue);
            u16                     w_length = le16_to_cpu(ctrl->wLength);
            /* composite driver infrastructure handles everything except
             * CDC class messages; interface activation uses set_alt().
             */
            switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
            /* RNDIS uses the CDC command encapsulation mechanism to implement
             * an RPC scheme, with much getting/setting of attributes by OID.
             */
            case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
                            | USB_CDC_SEND_ENCAPSULATED_COMMAND:
                    if (w_value || w_index != rndis->ctrl_id)
                            goto invalid;
                    /* read the request; process it later */
                    value = w_length;
                    req->complete = rndis_command_complete;
                    req->context = rndis;
                    /* later, rndis_response_available() sends a notification */
                    break;

     ...

     ...

            /* respond with data transfer or status phase? */
            if (value >= 0) {
                    DBG(cdev, "rndis req%02x.%02x v%04x i%04x l%d\n",
                            ctrl->bRequestType, ctrl->bRequest,
                            w_value, w_index, w_length);
                    req->zero = (value < w_length);
                    req->length = value;
                    value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
                    if (value < 0)
                            ERROR(cdev, "rndis response on err %d\n", value);
            }
            /* device either stalls (value < 0) or reports success */
            return value;

    }

Vulnerable execution paths:

  • f_rndis.c
    • rndis_setup
  • f_uac1.c
    • out_rq_cur
    • ac_rq_in
    • audio_set_endpoint_req
    • audio_get_endpoint_req
  • f_uac1_legacy.c
    • audio_set_intf_req
    • audio_set_endpoint_req
    • audio_get_endpoint_req
  • f_uac2.c
    • out_rq_cur
  • f_hid.c
    • hid_gsetup for HID_REQ_SET_REPORT case

Impact

Devices implementing affected usb device gadget classes (rndis, hid, uac1, uac1_legacy, uac2) may be affected by buffer overflow vulnerabilities resulting in information disclosure, denial of service or execution of arbitrary code in kernel context.

Expected resolution

Limit the transfer phase size to min(len, buffer_size) in affected control request handlers to assure that a buffer overflow will not occur.

Key dates

  • 07.12.2021 - reported the issue to Kernel security team
  • 09.12.2021 - draft patch provided by Kernel security team
  • 12.12.2021 - fix merged to main Linux kernel tree (public)

CVE

CVE-2021-39685

Exploit

The gadget.py script requires pyusb. You can install this package via pip as below.

python3 -m pip install pyusb

Help can be accessed with -h or --help parameters.

usage: gadget.py [-h] -v VID -p PID [-l LENGTH] [-d {read,write}]
                 [-f {rndis,uac1,uac1_legacy,uac2,hid}]

Sample exploit for RNDIS gadget class

optional arguments:
  -h, --help            show this help message and exit
  -v VID, --vid VID     vendor id
  -p PID, --pid PID     product id
  -l LENGTH, --length LENGTH
                        lenght of data to write
  -d {read,write}, --direction {read,write}
                        direction of operation from host perspective
  -f {rndis,uac1,uac1_legacy,uac2,hid}, --function {rndis,uac1,uac1_legacy,uac2,hid}

Example invocations:

./gadget.py -v 0x1b67 -p 0x400c -f uac1
./gadget.py -v 0x1b67 -p 0x400c -f uac1 -d write
./gadget.py -v 0x18d1 -p 0x4e23 -f rndis

Final notes

Please update your kernel to the latest stable version.

Owner
The content of the repositories and any changes made to this user account are private and not related to my employer.
Huggingface transformers for discord

disformers Huggingface transformers for discord base source butyr/huggingface-transformer-chatbots install pip install -U disformers example see examp

SpaceDEVofficial 1 Nov 09, 2021
A Discord bot to allow people to create lists of random characters, with limit reroll options.

Mugen Bot A small bot I made to practice python and allow people to publically select random characters on a discord server. Uses py-cord, as that is

Haley 2 Feb 06, 2022
A better rename and convert bot with upload mode option and Auto detection

A better rename and convert bot with upload mode option and Auto detection

Code X Mania 2 Nov 09, 2021
An Simple Advance Auto Filter Bot Complete Rewritten Version Of Adv-Filter-Bot

Adv Auto Filter Bot V2 This Is Just An Simple Advance Auto Filter Bot Complete Rewritten Version Of Adv-Filter-Bot.. Just Sent Any Text As Query It Wi

0 Dec 18, 2021
Python Client for Yandex Cloud Logging

Python Client for Yandex Cloud Logging Installation pip3 install python-yandex-cloud-logging Creating a Yandex Cloud Logging Group yc logging group c

MCode 0 Dec 08, 2021
Manage Proxmox KVM Virtual Machines via Slack bot.

proxmox-slack-bot Create KVM Virtual Machines on Proxmox, the easy way. Not much works works here yet... Setup dev environment Setup fully editable st

Plenus Pyramis 3 Mar 20, 2022
This is a scalable system that reads messages from public Telegram channels using Telethon and stores the data in a PostgreSQL database.

This is a scalable system that reads messages from public Telegram channels using Telethon and stores the data in a PostgreSQL database. Its original intention is to monitor cryptocurrency related ch

Greg 3 Jun 07, 2022
Bitstamp API wrapper for Python

NOTICE: THIS REPOSITORY IS NO LONGER ACTIVELY MAINTAINED It is highly unlikely that I will respond to PRs and questions about usage. This library was

Jack Preston 53 Mar 09, 2022
Query Amalgamator over StackOverflow and YouTube

QASY Query Amalgamator over StackOverflow and YouTube Decription A software you can use to save your valuable time of googling the errors you encounte

1 Nov 07, 2021
A pyrogram simple bot for Educational purpose.

A pyrogram simple bot for Educational purpose. To Learn More check at @PyrogramBot or on Documentation Mandatory variables API_ID - Get It From my.tel

SpamShield 10 Dec 06, 2022
Data and a Twitter bot for the EPA's DOCUMERICA (1972-1977) program.

documerica This repository holds JSON(L) artifacts and a few scripts related to managing archival data from the EPA's DOCUMERICA program. Contents: Ma

William Woodruff 2 Oct 27, 2021
Web-music-bot - A telegram bot which get a *site Url* and sends all songs contain in the Url to telegram

web music bot this is a telegram bot which get a site Url and sends all songs co

Arya Shabane 4 Apr 02, 2022
Scratch2py or S2py is a easy to use, versatile tool to communicate with the Scratch API Based of Scratch2py

Scratch2py Scratch2py or S2py is a easy to use, versatile tool to communicate with the Scratch API Based of Scratch2py Installation Run this command i

2 Jan 13, 2022
Validate all your Customer IAM Policies against AWS Access Analyzer - Policy Validation

✅ Access Analyzer - Batch Policy Validator This script will analyze using AWS Access Analyzer - Policy Validation all your account customer managed IA

Victor GRENU 41 Dec 12, 2022
Python JIRA Library is the easiest way to automate JIRA. Support for py27 was dropped on 2019-10-14, do not raise bugs related to it.

Jira Python Library This library eases the use of the Jira REST API from Python and it has been used in production for years. As this is an open-sourc

PyContribs 1.7k Jan 06, 2023
Create Basic ERC20 token with Solidity, Brownie and Python

Create Basic ERC20 token with Solidity, Brownie and Python Demo Check out Cornell Token on Rinnkeby network with Etherscan. Installation Install brown

Ethan Huang 2 Feb 16, 2022
Apex lets you build, deploy, and manage AWS Lambda functions with ease.

No longer maintained This software is no longer being maintainted and should not be chosen for new projects. See this issue for more information Apex

Apex 25 Dec 23, 2022
Python wrapper for GitHub API v3

Squeezeit - Python CSS and Javascript minifier Copyright (C) 2011 Sam Rudge This program is free software: you can redistribute it and/or modify it un

David Medina 207 Oct 24, 2022
Utility for converting IP Fabric webhooks into a Teams format

IP Fabric Webhook Integration for Microsoft Teams and/or Slack Setup IP Fabric Setup Go to Settings Webhooks Add webhook Provide a name URL will b

Community Fabric 1 Jan 26, 2022
This is Instagram reposter that repost TikTok videos.

from-tiktok-to-instagram-reposter This script reposts videos from Tik Tok to your Instagram account. You must enter the username and password and slee

Mohammed 19 Dec 01, 2022