Saturday, January 5, 2008

SetWindowsHookEx and Restricted Token

One easy way on Windows to inject a DLL is to use SetWindowsHookEx.

From MSDN:

The SetWindowsHookEx function installs an application-defined hook procedure
into a hook chain. You would install a hook procedure to monitor the system for
certain types of events. These events are associated either with a specific
thread or with all threads in the same desktop as the calling thread.




When the event you are interested in is triggered for the first time in a process, your DLL is going to get loaded and your hook procedure will be called. For example, if you set a mouse hook, the DLL is going to get loaded in the process as soon as you move the mouse over a window owned by this process.

But the desktop is not a perfect security boundary. You can have applications on the desktop running as a different users, with different rights. You can also have some applications running as a restricted version of yourself. How can we ensure that an application can't use SetWindowsHookEx to elevate it's privilege?

There are multiple answers.

First of all you can put this application on a job object and set the UILIMIT_HANDLES restriction. With this restriction a process in the job object can set hooks only on processes that are also in the job. But setting this flag also means that you can't access any user handles (HWND, etc) created by processes not associated with the job. If your application has some UI, then you have a lot of work to do if you want to fix everything that is going to break! (No icons, no cursors, can't access the desktop window). UserHandleGrantAccess can help you here...

On vista it's a little bit easier, you can run the application with a low integrity level token and User Interface Privilege Isolation (UIPI) will do the work for you. Internet Explorer 7 is using it to be more secure. It will prevent your application from setting hooks on other applications running with a higher integrity level.

What if you can't use any of them? Well, if your application is running with a restricted token, you may not have to worry about this at all. A restricted token is a stripped down version of your token created with the CreateRestrictedToken api. The SidsToRestrict array passed to the function must be non-null. In other words, IsTokenRestricted must return true. If this is the case, Windows will do the right thing and will not trust your application if you try to set a hook.

I haven't found any documentation on this... but during my tests I have seen two different behaviors:

  1. For some hooks (WH_MOUSE for example), when the event is received in another process, instead of loading the DLL, it sends a message to the thread that registered the hook. The message is handled internally and will cause the hook procedure to be called. Your application is now receiving and parsing all the events from all processes by itself in its own process. That does not sounds very efficient to me, but at least it's not a security flaw. (Don't quote me on this)
  2. For some other hooks (WH_CALLWNDPROC for example), the event seems to be ignored and the hook procedure is never called.

I haven't done a lot of testing so far on this, but it seems like a thread running with a restricted token can't inject a DLL using SetWindowsHookEx, which is good.

One warning: If you try to do this, there is a nasty side effect. Since the events are now sent to the calling thread using window messages, you must have a message loop, otherwise your system is going hang! I don't think there was any requirement before that the caller of SetWindowsHookEx have to peek messages.

3 comments:

JASON MICHAEL BARRY3533-11-568 said...

$CHICAGO$ CAME UP ON INSTALL NOTE PAD TYPELIKE STUFF. "I" NOT AT ALL,
RE:PROGRAMS,(WINDOWS NT)NUMBERS AND
LETTER'S THAT MADE SENCE TO ME.IEVEN HAD A PACK OF EAGLE CLAW FISHING HOOKS, I FOUND IN MY TACKEL BOX,THEY WERE 2IN. SHORTER
THAN REG.LENGHT,THE LINE WAS,THE KNOTES PERFECTLY TIED.USED ONE FISHING,HOOKED ONE SHALLOW WATER,2 FEET DEEP,EDGE OF CHANELL S.L.BAY
NEAR ALAMEDA GOLF COURSE, ALAMEDA CA, 94501.BROKEN CONECTION thinkcamping@att.net (started,raido,off the hook,imfo at 1715 chapin st.i am! unit B IN BACK,YOU WALK IN IF DOOR OPEN,SAY HI,I TEST YOU "ic" SCHOLAR,TYPE TEST,DONT LET DOWN YOURSELF,YOU THINK YOU UNDERSTAND WHAT "I" MEAM BY 1+1=1^,LIKE RELAY N/OFF N/ON.FULL TIME YOU RUN NOW,TAKE YOU
AND KEEP,NOT RAISED IN "PUB" "LIC".BEER AND LIC.JB3533

JASON MICHAEL BARRY3533-11-568 said...

ATT.NET ROUTER 2701HGV-B TURNS ON WIRELESS BY SELF,MY McAFEE ATT.UVERSE SECURTY SOFT WEAR CHANGED VERSIONS BY IT'S SELF,ROUTER SOFT WEAR VERSION CHANGED,MAP ROAD WENT FROM SR-13 TO US-13 IN 5MIN.I WENT BACK TO SEE IT AGAIN,AND IT WAS DIFFERENT.
I HAVE CALLED AND BEEN HUNG UP ON BY PEOPLE WHERE YOU WOULD THINK THEY WOULD DO THAT.JB3533

lauren said...

Thanks for sharing information.As you stated that events are associated either with a specific thread or with all threads in the same desktop as the calling thread.But the desktop is not a perfect security boundary. If your application has some UI, then you have a lot of work to do if you want to fix everything that is going to break.You are right that thread running with a restricted token can't inject a DLL using SetWindowsHookEx.So it really helps.
digital signatures