What is the "Correct" way of blocking external usb connection (flash drive, WPD, etc) in 7+?

I have seen many different open source projects out there to block usb connection (other than the whitelisted deviceIDs) :

  1. An UpperFilter for different classes (wpd, disk, etc) to detect the connection of an external device in the AddDevice callback, and block it either in the arrival pnp callback or the IRP_MJ_READ, etc
  2. Minifilter drivers that detect USB connection in the instance setup callback that block it by blocking the read/write to it after attaching
  3. Some projects even use IoRegisterPlugPlayNotification to get notified when a usb device arrives and block it using IoRequestDeviceEject!

And perhaps there are even more approaches…

So my question is, what the “correct” way of doing it? I know that there will be always different approaches,
but in terms of being a stable and standard approach, what is the most optimal solution to blocking external USB devices such WPD devices and flash drives, in Windows 7+ using a kernel mode driver?

Basically, if you were given a task of creating such a driver that blocks all external USB connections, other than the whitelist devices (based on deviceid, etc), how would you implement it?

Hello,

There isn’t one approach that fits all, unfortunately :frowning: I found that
Upper/Lower filters approach will simply fail some devices, even if that is
not your intention (i.e. devices cannot be attached if your filter is
present). I did not have sufficient access (or customer interest :D) to
figure if some information query is the reason, and perhaps not querying
that works… but for some USB devices Upper filters work, for others Lower
filters… and at the time others recommended not to filter USB devices in
kernel mode at all.

I found that for companies, InTune seems to be the best solution (not
what a developer wants to hear :)). But a single solution will not work :frowning:
Unless your desire is to block all devices, and not allow any, in which
case - Upper/Lower filters works.

Kind regards, Dejan Maksimovic.
FS Lead: http://www.alfasp.com

@Dejan_Maksimovic said:
Hello,

I found that
Upper/Lower filters approach will simply fail some devices, even if that is
not your intention (i.e. devices cannot be attached if your filter is
present).

So are you saying there was a situation where you couldn’t attach to the device in your AddDevice? If so, why? What was the error? Or was it because the device failed a query (such as properties query) during AddDevice callback? Because In that case I guess you can still attach and do the query during arrival pnp right?

Also what about the other two approaches that I mentioned?

And is there any other kernel mode approach?

and at the time others recommended not to filter USB devices in kernel mode at all.

So are you saying the best approach is to have a device notification callback in user mode and disable the device when it arrives? If so, which usermode APIs do I need to use to register a callback and to block the device properly?

@Dejan_Maksimovic said:
Hello,

There isn’t one approach that fits all, unfortunately :frowning: I found that
Upper/Lower filters approach will simply fail some devices, even if that is
not your intention (i.e. devices cannot be attached if your filter is
present). I did not have sufficient access (or customer interest :D) to
figure if some information query is the reason, and perhaps not querying
that works… but for some USB devices Upper filters work, for others Lower
filters… and at the time others recommended not to filter USB devices in
kernel mode at all.

Also a side question regarding the UpperFilter approach:
Which classes do I need to register as a UpperFilter if I want to block external USB devices such as WPD (tablet, phones, etc) and flash drives? I guess only WPD class and Disk class is enough right?

The device just failed to start, it didm’t return an error to my filter.

I said for USB, user mode approach was suggested, but I did not try it.

You need to filter more than NPD and Disk class. We added at least 10 in
Win7 times.

@Dejan_Maksimovic said:
You need to filter more than NPD and Disk class. We added at least 10 in
Win7 times.

What else is there? Because I’m asking about external usb devices that can be used to copy files from the computer to them. Shouldn’t they all fall into either disk or WPD?

Also, in the AddDevice I would send a query IOCTL to the pdo asking if its a External device or not, my question is, is this guaranteed to be true? Or the driver developer for the flash drive can just send a invalid response back and tell me its not external?
For example can a malicious USB device with a rouge driver bypass this check that I’m doing? Because I am only attaching to external devices in my AddDevice.
Basically for example can any flash drive have a custom driver of its own that gets loaded when the flash drive is inserted, and that is the one which is responsible for responding to these type of queries, or this pdo is sent to a Microsoft driver that validates whether its actually a external device or not?

Yes, there is more, if you mean USB, but not as much if you mean USB
Storage.
E.g. Bluetooth can be used to copy files to it, as can NFC, Smart Cards,
FOBs, etc., even though they aren’t USB storage.

Apple devices have non MTP devices in some gadgets at least, so just MTP
protection isn’t enough.

I won’t list all (that is your job :), plus it changed simce Win 7 times
most likely).

Dejan

What else is there? Are you talking about webcam class, etc? Because I’m

@Dejan_Maksimovic said:
Yes, there is more, if you mean USB, but not as much if you mean USB
Storage.
E.g. Bluetooth can be used to copy files to it, as can NFC, Smart Cards,
FOBs, etc., even though they aren’t USB storage.

Apple devices have non MTP devices in some gadgets at least, so just MTP
protection isn’t enough.

I won’t list all (that is your job :), plus it changed simce Win 7 times
most likely).

Dejan

What else is there? Are you talking about webcam class, etc? Because I’m

Have you ever tried the IoRegisterPlugPlayNotification method? Can I catch everything that UpperFilter can (webcam, apple phones, WPD devices, flash drives, etc) with IoRegisterPlugPlayNotification? If so, then why not just use IoRegisterPlugPlayNotification, considering this one doesn’t have the headaches of an UpperFilter and the decision of which classes I need to filter

IIRC, it didn’t do enough, but I may not remember that right, it was long
ago.

Dejan.

Having done a LOT of work in this space (c.f. US20180365397A1) I can say it’s annoyingly complicated ?

If you’re up at the file system level you’re “too high” because you’ll miss things like MTP. If you’re down at the bus level you’re “too low” because it’s very difficult to know exactly how Windows is going to present an externally attached device to the user (i.e. just because the USB descriptors don’t say it’s mass storage doesn’t mean it isn’t). Then you add in things like eSATA and Thunderbolt and the problem space grows.

I personally wouldn’t trust a solution based on IoRegisterPlugPlayNotification because the eject can fail if the drive is in use. I’ve never tried to design one of these, but you could probably get around that solution by just plugging and unplugging the drive over and over and waiting for the one time the eject fails because some application is touching the drive. Though whether or not that’s OK really depends on your threat model.

Overall it’s pretty easy to come up with a simple solution that makes a cute demo but falls over in a security review.

@“Scott_Noone_(OSR)” said:
Having done a LOT of work in this space (c.f. US20180365397A1) I can say it’s annoyingly complicated ?

If you’re up at the file system level you’re “too high” because you’ll miss things like MTP. If you’re down at the bus level you’re “too low” because it’s very difficult to know exactly how Windows is going to present an externally attached device to the user (i.e. just because the USB descriptors don’t say it’s mass storage doesn’t mean it isn’t). Then you add in things like eSATA and Thunderbolt and the problem space grows.

I personally wouldn’t trust a solution based on IoRegisterPlugPlayNotification because the eject can fail if the drive is in use. I’ve never tried to design one of these, but you could probably get around that solution by just plugging and unplugging the drive over and over and waiting for the one time the eject fails because some application is touching the drive. Though whether or not that’s OK really depends on your threat model.

Overall it’s pretty easy to come up with a simple solution that makes a cute demo but falls over in a security review.

So if you had to implement a device control solution right now that blocks USB devices (Storage, flash drives, webcams, WPD, etc) and allow some based on DeviceId, I assume you would use an UpperFilter, correct?

But in that case, is there any other class that I need to attach to, other than the DiskDrive class and WPD? Note that for now I don’t care about other devices such as cd/dvd-roms, for now I just need to focus on USB devices.
For example do I also need to attach to Camera class? I have tested two different webcams, but weirdly enough both of them were registered as WPD so my AddDevice got called for them.

Is there any rule, or it’s up to the manufacturers of these devices to decide which class this device belongs to? For example, can a webcam manufacturer register its device as any class that it wants, and register it in a weird class like Battery or Modem and thus bypass this UpperFilter implementation? (Because I obviously cannot attach to every class)

Yes, manufacturers can use any clas they want.
Apple does, so you’re already not covering the second most common device
you want to cover for sure.

You will have to test whether you cover enough.

And again, both Upper and Lower filter approach will fail different devices
(prevent them from starting). E.g., IIRC, Apple devices fail with Upper and
Samsung with Lower filters.
And querying the name might be why it fails… querying properties surely is.
It obviously differs by (device) OS version.

Dejan.

@Dejan_Maksimovic said:
Apple does, so you’re already not covering the second most common device
you want to cover for sure.

That’s weird because I Have already tested iPhones (Although the older 7 version) and they were all registered as WPD, so my UpperFilter caught them. Which of their devices don’t fall under WPD or DiskDriver? And what’s the solution? Because I Can’t just register as a upper or lower filter in every class?

@Dejan_Maksimovic said:
Yes, manufacturers can use any clas they want.

So if this is the case that the device manufacturers can use any class they want, doesn’t that make the UpperFilter or LowerFilter approach useless? Because then a malicious actor can easily bypass this by creating a USB device that registers itself in a weird class that no one filters, therefore bypassing every device control app? How can I defend against this then? IoRegisterPlugPlayNotification approach is also useless based on what scott said which I agree with (Because I have seen device eject requests fail before, any driver on the stack can Fail it), So what approach is left?

@Dejan_Maksimovic said:
IIRC, Apple devices fail with Upper and Samsung with Lower filters.

Which apple device have you tested that failed the query and what class did it register in? Did you send the query in your AddDevice? I have tried iPhone 7 and it was a WPD device and there was no problem querying its deviceID and properties in my AddDevice?

Did you test 12 different iPhone,iPad and iPod generations?
Remember, none of them need a driver on Windows and if you don’t filter ONE
then security is broken.

Iirc, iPhone 7 was tested and it had 3 different classes, not just one.

Dejan.

@Dejan_Maksimovic said:
Did you test 12 different iPhone,iPad and iPod generations?

Not really, I am at the early stages of R&D so I only tested with an Iphone 7, but the thing is, my method of using an UpperFilter to block the connection worked without any problem when i tested it with an Iphone 7? I didn’t see any 3 classes, I was an UpperFilter at WPD class, and after attaching to the device, blocking it worked like a charm, no matter what mode of transfer i tried, the iphone could not get connected.

But I guess I will have to test it with other iPhones as well now.

But back to the real question:

Doesn’t this mean that using an UpperFilter approach is basically a useless approach, considering that the class that a device is in is up to the manufacturer, and considering that I can’t attach to everything, then this means that I can get easily bypassed?
So what’s the solution?

My solution was to change each system’s Upper vs Lower filters based on the
user :frowning:

Did you try Lower filters and does it work also for you?

Look up my posts from around 12 years back (just search Upper/LowerFilter
and my name on NTDEV), I think there is some trace of it and what didm’t
work and suggested alternatives for USB filtering.

Dejan

@Dejan_Maksimovic said:
My solution was to change each system’s Upper vs Lower filters based on the
user :frowning:

Did you try Lower filters and does it work also for you?

Look up my posts from around 12 years back (just search Upper/LowerFilter
and my name on NTDEV), I think there is some trace of it and what didm’t
work and suggested alternatives for USB filtering.

Dejan

But the thing is, even the Lower vs Upper filters based on user approach still doesn’t solve the problem of a malicious USB device which registers it self in a class that we are not filtering. So what’s the solution to that? Because if any device manufacturer can register its USB devices as anything they want, then they can use a random class that no one is filtering (lower or upper).

True :slight_smile:
Bur it has to have drivers present already. So you still don’t need to
filter unknown classes.

Remember the USB stick that has a keyboard device ID? Think around that,
and you have a product.

@Dejan_Maksimovic said:
True :slight_smile:
Bur it has to have drivers present already. So you still don’t need to
filter unknown classes.

Remember the USB stick that has a keyboard device ID? Think around that,
and you have a product.

I apologize in advance for rookie questions, as I am still learning, but I have three of them:

  1. Considering that there is a USB class {36fc9e60-c465-11cf-8056-444553540000}, also a USBDevice class {88bae032-5a81-49f0-bc3d-a4ff138216d6}, What is their difference, and also why can’t I just monitor every USB device by registering as an UpperFilter for the USB class? Aren’t all the USB devices no matter what they do (printer, mouse, webcam, etc), at the end a USB device, thus an UpperFilter for USB class should catch them all? If not, why?

  2. Is my understanding correct that when you connect a USB device, the Windows USB bus driver will detect the connection, and create a corresponding PDO for that new device, therefore even if a malicious USB device registers itself as something that its not, for example an Ethernet or keyboard (instead of what it actually is, which is a USB flash drive), then its limited to the functionality of that class right? I mean if it registers only as a keyboard, then it surely cannot act as a flash drive, right?!

  3. Is my understanding correct that when you connect a new USB device, the Windows will search for the corresponding driver file in its driverStore based on the deviceID, therefore a malicious USB device cannot load arbitrary drivers for its functionality, and windows will only load approved drivers from reliable sources, and will not load a driver that is sent to it from the USB device, right?

Sorry it got way too long, would you mind recommending me a Book or a blogpost that delves into these topics? Non of the Windows kernel programming that I found go into these topics in detail so I can understand the “big picture” that how all of these are connected to each other…

@brad_H said:

@Dejan_Maksimovic said:
True :slight_smile:
Bur it has to have drivers present already. So you still don’t need to
filter unknown classes.

Remember the USB stick that has a keyboard device ID? Think around that,
and you have a product.

I apologize in advance for rookie questions, as I am still learning, but I have three of them:

  1. Considering that there is a USB class {36fc9e60-c465-11cf-8056-444553540000}, also a USBDevice class {88bae032-5a81-49f0-bc3d-a4ff138216d6}, What is their difference, and also why can’t I just monitor every USB device by registering as an UpperFilter for the USB class? Aren’t all the USB devices no matter what they do (printer, mouse, webcam, etc), at the end a USB device, thus an UpperFilter for USB class should catch them all? If not, why?

  2. Is my understanding correct that when you connect a USB device, the Windows USB bus driver will detect the connection, and create a corresponding PDO for that new device, therefore even if a malicious USB device registers itself as something that its not, for example an Ethernet or keyboard (instead of what it actually is, which is a USB flash drive), then its limited to the functionality of that class right? I mean if it registers only as a keyboard, then it surely cannot act as a flash drive, right?!

  3. Is my understanding correct that when you connect a new USB device, the Windows will search for the corresponding driver file in its driverStore based on the deviceID, therefore a malicious USB device cannot load arbitrary drivers for its functionality, and windows will only load approved drivers from reliable sources, and will not load a driver that is sent to it from the USB device, right?

Sorry it got way too long, would you mind recommending me a Book or a blogpost that delves into these topics? Non of the Windows kernel programming that I found go into these topics in detail so I can understand the “big picture” that how all of these are connected to each other…

Hi, I’m also in this issue, any progress on this topic?