주의

지극히 개인적인 의견만 들어가 있습니다.

소개

이 문서에서는 QEMU USB에 대한 삽질 내용들을 다룬다. USB에 대한 퍼징 시도는 많지만 이를 VM 환경에서 수행한 사례가 많이 없기 때문에 USB 퍼저를 작성하려는 시도를 하려 한다. 또한, 그 시도에서 얻은 정보들을 이곳에 간략하게나마 정리하려 한다.

본문

VM 환경에서의 퍼징

VM 환경에서 퍼징하는데 많은 어려움이 있는데 이를 정리하면 아래와 같다.

  1. High Overhead : 현실적으로 VM을 매 테스트케이스마다 껐다가 킬 수 없다. 따라서 VM을 켜놓은 상태에서 지속적인 (Persistent) 방법으로 퍼징을 수행해야 한다.
    1. 지속적인 방법으로 퍼징을 하려 한다면 퍼징 루프를 잘 설계해서 상태를 매 루프마다 원래대로 복구시켜줄 필요가 있다. 이는 테스트를 진행하는 사람이 져야 하는 위험이다. (Risk)
    2. 지속적인 방법에서 피드백을 지속적으로 제공해줄 수 있는 프록시 시스템이 필요하다.
    3. 테스트 하고 싶은 함수를 따로 고립시켜서 테스트 하는 방법도 있을 수 있겠지만 이는 생각보다 어렵다. 타겟의 전체적인 구조를 파악한 뒤에 시도해볼 만한 방법이다.
  2. QEMU 모드 등을 사용 불가능하다. (Nested virtualization 환경에서 테스트를 제대로 할 수 있을까)
  3. Instrumentation을 하는데 어려움이 많다. 컴파일 오류 등 여러 문제가 발생한다.

Interaction (Kernel)

기본적으로 실행 옵션에 USB를 주면 /sys/devices 아래 pciXXX 라는 이름으로 폴더가 생성된다. USB와 인터랙션을 하려면 해당하는 pci 디바이스에 찾아가서 resourceN에 r/w를 수행하면 된다. 일반적인 경우에는 open :arrow_right: mmap :arrow_right: memory r/w를 수행하는 방식으로 USB를 사용한다. 추가로 DMA 버퍼를 두는 경우가 있는데, 이 경우에는 mmap으로 추가로 페이지를 할당받은 뒤 mlock을 이용하여 swap out이 되지 않도록 막는다. (DMA 버퍼로 사용한다)

참고 : https://www.kernel.org/doc/Documentation/filesystems/sysfs-pci.txt

어떤 PCI 디바이스가 원하는 USB 디바이스인지 확인하기 위해 lspci 명령어를 사용할 수 있다. 해당 명령어를 실행하면 아래처럼 결과가 나온다.

vm@vm:/sys/devices/pci0000:00/0000:00:01.0$ lspci
00:00.0 Host bridge: Intel Corporation 440FX - 82441FX PMC [Natoma] (rev 02)
00:01.0 ISA bridge: Intel Corporation 82371SB PIIX3 ISA [Natoma/Triton II]
00:01.1 IDE interface: Intel Corporation 82371SB PIIX3 IDE [Natoma/Triton II]
00:01.2 USB controller: Intel Corporation 82371SB PIIX3 USB [Natoma/Triton II] (rev 01)
00:01.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 03)
00:02.0 VGA compatible controller: Device 1234:1111 (rev 02)
00:03.0 Ethernet controller: Intel Corporation 82540EM Gigabit Ethernet Controller (rev 03)

우리가 원하는 디바이스는 USB 디바이스이므로 00:01.2 디바이스를 참조하면 된다. 위 경우에는 해당 디바이스가 /sys/devices/pci0000:00/0000:00:01.2에 위치하게 된다.

만약에 디바이스가 PCI가 아닌 캐릭터 디바이스 레벨로 접근을 하고 싶다면 /dev/bus/usb 폴더 안을 찾아보면 된다. 디바이스가 제대로 인식되는지 확인하려면 lsusb 명령어를 실행하여 리스트에 디바이스가 있는지 확인하면 된다. 캐릭터 디바이스도 PCI 디바이스와 마찬가지로 mmap과 메모리 연산을 통해 접근할 수 있다.

Analysis

Basic Structure

기본적으로 USB 에뮬레이터가 3가지 파트로 구성되어 있다.

  1. Raw data parsing
  2. State machine to track USB state
  3. Handler (read, can_read, event)

또한, 이들은 프런트엔드와 백엔드로 구성되어 있다. 아래 내용을 보자.

https://www.qemu.org/docs/master/qemu-doc.html#Character-device-options
A character device may be used in multiplexing mode by multiple front-ends. Specify mux=on to enable this mode. A multiplexer is a "1:N" device, and here the "1" end is your specified chardev backend, and the "N" end is the various parts of QEMU that can talk to a chardev. If you create a chardev with id=myid and mux=on, QEMU will create a multiplexer with your specified ID, and you can then configure multiple front ends to use that chardev ID for their input/output. Up to four different front ends can be connected to a single multiplexed chardev. (Without multiplexing enabled, a chardev can only be used by a single front end.) For instance you could use this to allow a single stdio chardev to be used by two serial ports and the QEMU monitor

프런트엔드와 백엔드 사이엔 MUX가 있어서 하나의 백엔드에 여러 프런트엔드를 연결할 수 있는 것으로 보인다. 즉, char device 하나로 두개의 디바이스를 제어할 수 있게 되는 것이다. 아래 링크의 단축키로 MUX를 제어할 수 있다.

https://www.qemu.org/docs/master/qemu-doc.html#mux_005fkeys

core

hw/usb/core.c에는 USB core 부분이 구현되어 있다. USB 탈부착이나 raw USB 패킷 파싱을 이 부분에서 진행한다.

dev-***, desc

각각의 디바이스에 해당하는 패킷을 처리하거나 특수한 에뮬레이션이 필요한 것들을 제공한다. 어떻게 보면 기본적인 드라이버 부분을 제공하는 것으로, 예를 들어 시리얼 통신의 경우 -serial 옵션을 주었을 경우 가상 디바이스를 생성해서 이를 에뮬레이션한다. 가상 디바이스에 들어오는 패킷들을 처리하거나 그에 맞는 동작들을 수행한다.

hcd-***

HCD (Host Controller Driver)에 해당하는 동작들을 수행한다. HCI 동작들을 수행하는 역할을 한다. USB 2.0, 3.0 등의 디바이스가 추가되었을 때 그에 알맞는 기능들을 수행한다.

Comment

전체적으로 state machine과 패킷 파싱 부분으로 깔끔하게 분리될 수 있고 각 부분이 워낙 명확하게 구현되어 있기 때문에 개발자가 실수할 부분이 많지가 않다. 그나마 취약점이 나올만한 부분이 HCD 쪽인데, 해당 부분을 테스트하기 힘들 뿐인 데다가 복잡도가 좀 있기 때문이다. 하지만 이 부분도 취약점이 나온 전적이 많지 않고 나왔더라도 임팩트가 낮은 취약점이어서 여기서 추가로 유의미한 취약점이 나올 수 있을지 의문이다.

결론

지금까지 USB에 대해 분석하였고, QEMU에서 어떤 부분들을, 또 어떻게 에뮬레이션해서 서비스를 제공하는지 알아보았다. USB는 기본적으로 좋은 벡터지만 QEMU의 경우 워낙 명확하게 패킷들을 처리하고 또 보안쪽으로 많이 신경썼기 때문에 (디바이스에 대한 퍼저가 따로 존재할 정도) 취약점이 나오기 힘들 것으로 사료된다.

'보안 > Bug Hunting' 카테고리의 다른 글

VirtualBox SVGA  (0) 2021.01.19

+ Recent posts