Peter Wieland informed me that you can actually find the security descriptor (SD) using !object, you just have to work harder to get at it. It relies on an undocumented structure, but since this is not being used at runtime and !object also uses it, I think it is OK to show. Once you have the SD, you can use the !sd command to view the SD's contents.

What we want to look at is the object header. The header is given when you run !object on any valid path or name. Not all objects have a security descriptor; I picked an object (the \Device directory object) that I knew had an SD assigned to it. While the header pointer is supplied, its type is not. The header's type is nt!_OBJECT_HEADER.

0: kd> !object \Device
Object: e1011670  Type: (822f91f0) Directory
    ObjectHeader: e1011658
    HandleCount: 0  PointerCount: 206
    Directory Object: e10023e0  Name: Device
    12 symbolic links snapped through this directory

    Hash Address  Type          Name
    ---- -------  ----          ----
     00  8228a9c0 Device        KsecDD
         820d94f0 Device        Beep
     [...]

0: kd> dt e1011658 nt!_OBJECT_HEADER
   +0x000 PointerCount     : 0xce
   +0x004 HandleCount      : 0
   +0x004 NextToFree       : (null)
   +0x008 Type             : 0x822f91f0 _OBJECT_TYPE
   +0x00c NameInfoOffset   : 0x10 ''
   +0x00d HandleInfoOffset : 0 ''
   +0x00e QuotaInfoOffset  : 0 ''
   +0x00f Flags            : 0x32 '2'
   +0x010 ObjectCreateInfo : 0x00000001 _OBJECT_CREATE_INFORMATION
   +0x010 QuotaBlockCharged : 0x00000001
   +0x014 SecurityDescriptor : 0xe1008f71 
   +0x018 Body             : _QUAD

The SecurityDescriptor pointer value 0xe1008f71 cannot be used as is. The kernel uses the bottom three bits for other purposes (this works because all allocations are at least 8 byte aligned, so the bottom three bits will always be 0x0), so we must mask of the bottom three bits with the inverse of 0x7. To do this I use the C++ expression evaluator command "@@." @@ is the same as ?? except that you can use it in the middle of an expression. We will pass that masked off address to !sd to see the contents. Unfortunately !sd does not map well known SIDs to their canonical names, but I can live with that.

0: kd> !sd @@(0xe1008f71 & ~0x7)
->Revision: 0x1
->Sbz1    : 0x0
->Control : 0x8004
            SE_DACL_PRESENT
            SE_SELF_RELATIVE
->Owner   : S-1-5-32-544
->Group   : S-1-5-18
->Dacl    :
->Dacl    : ->AclRevision: 0x2
->Dacl    : ->Sbz1       : 0x0
->Dacl    : ->AclSize    : 0x5c
->Dacl    : ->AceCount   : 0x4
->Dacl    : ->Sbz2       : 0x0
->Dacl    : ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[0]: ->AceFlags: 0x0
->Dacl    : ->Ace[0]: ->AceSize: 0x14
->Dacl    : ->Ace[0]: ->Mask : 0x00020003
->Dacl    : ->Ace[0]: ->SID: S-1-1-0

->Dacl    : ->Ace[1]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[1]: ->AceFlags: 0x0
->Dacl    : ->Ace[1]: ->AceSize: 0x14
->Dacl    : ->Ace[1]: ->Mask : 0x000f000f
->Dacl    : ->Ace[1]: ->SID: S-1-5-18

->Dacl    : ->Ace[2]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[2]: ->AceFlags: 0x0
->Dacl    : ->Ace[2]: ->AceSize: 0x18
->Dacl    : ->Ace[2]: ->Mask : 0x000f000f
->Dacl    : ->Ace[2]: ->SID: S-1-5-32-544

->Dacl    : ->Ace[3]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[3]: ->AceFlags: 0x0
->Dacl    : ->Ace[3]: ->AceSize: 0x14
->Dacl    : ->Ace[3]: ->Mask : 0x00020003
->Dacl    : ->Ace[3]: ->SID: S-1-5-12

->Sacl    :  is NULL