Discussion:
Getting information back out of low-integrity code? (or -- what does "protected mode IE" do to process rights?)
(too old to reply)
Dan Mitchell
2007-01-13 01:33:58 UTC
Permalink
My app needs to read cookies in IE7 on Vista, so I need to spawn a
separate low integrity process to read protected mode cookies. I'm doing
this as it says here:

http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/ietechcol/dnwebgen/protectedmode.asp

and it's working fine.

The problem is getting the result back to my main process. I tried
using named pipes, but I get E_ACCESSDENIED when I call CreateFile in
the slave process. I know I can't pass NULL as the last argument to
CreateNamedPipe, I'm creating a NULL DACL and passing that in, so in
theory absolutely everything should have access, but still no joy.

(and I know it's permissions, not CreateFile confusion in the slave,
because if I just do "echo foo > \\.\pipe\mypipe" from a cmd window, it
works and I get 'foo' showing up on my pipe -- just trying system() from
my slave process, no joy)


Currently, I'm using SHGetKnownFolderPath(FOLDERID_LocalAppDataLow...)
and writing to a temp file in the slave which I can then read in the
parent process -- that works, but is not a very clean solution. (I could
also use IEGetWriteableHKCU to get a safe bit of the registry, but
that's no better, really).


Is there a better approach? Is there something I'm missing about
security and named pipes? (or alternatively, is it the case that low
integrity processes on Vista are locked down more than I'm expecting?
CreateFile is in kernel32.dll, which is listed as a possibly problematic
DLL at the bottom of the docs page, but what does it mean by "securable
object", then?)

thanks,

-- dan
Dan Mitchell
2007-01-17 01:39:16 UTC
Permalink
=?Utf-8?B?RXJpYyBQZXJsaW4gW01TRlRd?=
You probably need to lower the IL of the pipe.
See the "Lowering Resource Integrity" section of the article you
pointed at.
Well, that certainly looks like what I'm after -- but after coding it
up, it turns out that I should have done some more research in the
documentation first. From MSDN, on SE_OBJECT_TYPE:

"The GetNamedSecurityInfo and SetNamedSecurityInfo functions work only
with the following kernel objects: semaphore, event, mutex, waitable
timer, and file mapping."

In other words, (and this is what happens when I try it), this approach
won't work with named pipes.

Hm, and it won't work with sockets, which would be another obvious
approach. I guess I could do some sort of ghastly communication by
sending Morse code by toggling a mutex at the right times or something,
but frankly, I'd argue that while my current RPC-over-files may be ugly,
it's not as ugly as that approach would be..

-- dan
Dan Mitchell
2007-01-17 20:01:26 UTC
Permalink
=?Utf-8?B?RXJpYyBQZXJsaW4gW01TRlRd?=
I'd use SE_FILE_OBJECT for pipes.
That's what I tried initally, and it gave me E_INVALIDARG back; so I
looked through the rest of the enum, and found them listed under kernel
objects (http://msdn2.microsoft.com/en-gb/library/ms724485.aspx).
The other option is to specify the security descriptor at object
creation time (in the security attributes).
Yep, and as I said in my original post, that doesn't work -- or, at
least, the standard trick of using passing in a NULL DACL to say
"everyone has access":

PSECURITY_DESCRIPTOR pSD;
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc
(LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH);
InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(pSD, TRUE, (PACL)NULL, FALSE);

doesn't work -- possibly there's another approach way to do this, but
the 'lowering integrity' stuff seems like it's meant to be used here,
but that only works on files.

-- dan
Paul Baker [MVP, Windows - Networking]
2007-01-17 21:57:36 UTC
Permalink
According to this page, you should (must?) call SetSecurityInfo for a pipe.
That means that you have to first open a handle to it.
http://msdn2.microsoft.com/en-us/library/aa365600.aspx

I doubt that you can treat it like a file in a call to SetNamedSecurityInfo,
because I don't think you can use CreateFile to *create* a pipe, only *open*
a pipe.

I would think that the best way to set the DACL of a pipe is to do so when
you create it. The documentation for the CreateNamedPipe function describes
the effect of passing NULL as lpSecurityAttributes. If the default DACL is
not what you want, you will need to build a "real" DACL.
http://msdn2.microsoft.com/en-us/library/aa365150.aspx

You can use Process Explorer from Sysinternals.com to see the DACL that is
actually used.

Passing NULL as lpSecurityAttributes is far from the the same thing as a
NULL DACL.
http://msdn2.microsoft.com/en-us/library/aa379286.aspx

Paul
Post by Dan Mitchell
=?Utf-8?B?RXJpYyBQZXJsaW4gW01TRlRd?=
I'd use SE_FILE_OBJECT for pipes.
That's what I tried initally, and it gave me E_INVALIDARG back; so I
looked through the rest of the enum, and found them listed under kernel
objects (http://msdn2.microsoft.com/en-gb/library/ms724485.aspx).
The other option is to specify the security descriptor at object
creation time (in the security attributes).
Yep, and as I said in my original post, that doesn't work -- or, at
least, the standard trick of using passing in a NULL DACL to say
PSECURITY_DESCRIPTOR pSD;
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc
(LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH);
InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(pSD, TRUE, (PACL)NULL, FALSE);
doesn't work -- possibly there's another approach way to do this, but
the 'lowering integrity' stuff seems like it's meant to be used here,
but that only works on files.
-- dan
Dan Mitchell
2007-01-17 23:01:38 UTC
Permalink
Post by Paul Baker [MVP, Windows - Networking]
According to this page, you should (must?) call SetSecurityInfo for a
pipe. That means that you have to first open a handle to it.
http://msdn2.microsoft.com/en-us/library/aa365600.aspx
How would that differ from passing in the correct SECURITY_ATTRIBUTES at
creation time?
Post by Paul Baker [MVP, Windows - Networking]
I would think that the best way to set the DACL of a pipe is to do so
when you create it.
That's what I did, and it doesn't grant access to the named pipe to low
integrity processes. (the pipe itself does work, as I said in my original
posting, because I can just do "echo foo > \\.\pipe\mypipe" from a command
window, and the pipe server gets "foo". It's just low integrity processes
that can't get at it).
Post by Paul Baker [MVP, Windows - Networking]
Passing NULL as lpSecurityAttributes is far from the the same thing as
a NULL DACL.
Yes, I know, I didn't pass NULL as lpSecurityAttributes, I just didn't
put in the remaining lines of code because they're trivial once you've got
a security descriptor. Here's the whole code I used to build the
SECURITY_ATTRIBUTES structure:

PSECURITY_DESCRIPTOR pSD; // Pointer to SD.
pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(pSD, TRUE, (PACL)NULL, FALSE);

SECURITY_ATTRIBUTES sa; // Security attributes.
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = TRUE; // changing this to FALSE doesn't help

// ... and then pass &sa as last argument to CreateNamedPipe.

-- dan
Dan Mitchell
2007-02-13 01:32:03 UTC
Permalink
=?Utf-8?B?RXJpYyBQZXJsaW4gW01TRlRd?=
I'm a little surprised about SetNamedSecurityInfo not working here but
specifying the label at creation time should work.
I suggest that the SACL (where IL on objects is specified) be built
from SDDL S:(ML;;NW;;;LW).
I finally had a change to try this, and it works just great.


Here's a (mostly)complete code snippet, for the sake of the archives --
to make sure all the keywords are in one post, my original problem was
how to get information out of a low integrity process on Vista to read
protected mode cookies from IE, given that CreateNamedPipe wasn't
working the way I'd expected.


#define LOW_INTEGRITY_SDDL_SACL "S:(ML;;NW;;;LW)"

PSECURITY_DESCRIPTOR pSD;
ConvertStringSecurityDescriptorToSecurityDescriptorA(
LOW_INTEGRITY_SDDL_SACL,
SDDL_REVISION_1,
&pSD,
NULL);

SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = TRUE;

HANDLE hp = CreateNamedPipe(_T("\\\\.\\pipe\\mypipe"),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1, // number of pipes that can exist
1024, // output buffer
1024, // input buffer
0, // timeout
&sa); // security attributes

Then I create my low-integrity process (from here:)
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/ietechcol/dnwebgen/protectedmode.asp

Then call ConnectNamedPipe() on hp to wait for the slave to connect,
and once that returns, call ReadFile() to pull data out.

Over in the (low integrity) slave process, I just use fopen("\\\\.
\\pipe\\mypipe", "w"), and fwrite to dump data onto the pipe, and that's
that.


Thanks for the help! This is _much_ nicer than the temp-file-in-my-
documents-Low stuff I was doing before.

-- dan
k***@vomba.com
2007-02-26 23:25:39 UTC
Permalink
Post by Dan Mitchell
My app needs to read cookies in IE7 on Vista, so I need to spawn a
separate low integrity process to read protected mode cookies. I'm doing
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/ietechcol/dnwebgen/protectedmode.asp
and it's working fine.
The problem is getting the result back to my main process. I tried
using named pipes, but I get E_ACCESSDENIED when I call CreateFile in
the slave process. I know I can't pass NULL as the last argument to
CreateNamedPipe, I'm creating a NULL DACL and passing that in, so in
theory absolutely everything should have access, but still no joy.
(and I know it's permissions, not CreateFile confusion in the slave,
because if I just do "echo foo > \\.\pipe\mypipe" from a cmd window, it
works and I get 'foo' showing up on my pipe -- just trying system() from
my slave process, no joy)
Currently, I'm using SHGetKnownFolderPath(FOLDERID_LocalAppDataLow...)
and writing to a temp file in the slave which I can then read in the
parent process -- that works, but is not a very clean solution. (I could
also use IEGetWriteableHKCU to get a safe bit of the registry, but
that's no better, really).
Is there a better approach? Is there something I'm missing about
security and named pipes? (or alternatively, is it the case that low
integrity processes on Vista are locked down more than I'm expecting?
CreateFile is in kernel32.dll, which is listed as a possibly problematic
DLL at the bottom of the docs page, but what does it mean by "securable
object", then?)
thanks,
-- dan
Hello Dan,

I was curious if you have found a solution to read cookies set in
Protected Mode?

One of teh solution we have been considering is parsing the cookie
files manually that are in
AppData\Roaming\Microsoft\Windows\Cookies\Low
Have you found a better way?

thanks,

Karl
Dan Mitchell
2007-02-27 00:42:24 UTC
Permalink
Post by k***@vomba.com
I was curious if you have found a solution to read cookies set in
Protected Mode?
Yes -- see my followup post in microsoft.public.platformsdk.security.
Actually, that post is still showing up in the thread in googlegroups if
you search for "protected mode cookies vista", so I'm not sure how you
found the original post without the solution.

Anyway, here's the post:

http://groups.google.com/group/microsoft.public.inetsdk.programming.winine
t/msg/d6bc53b314f341bc?dmode=source

You'll still need to implement stuff to read cookies, but that's just the
same as reading cookies under XP once you've got your code running in low
integrity mode.

-- dan

Loading...