mirror of
https://github.com/naksyn/PythonMemoryModule
synced 2026-06-06 16:24:25 +00:00
command line support (partial) via PEB stomping
This update include support to passing command line parameters to unmanaged exe via PEB stomping. This technique is not working with every executable since it depends on which functions are used to pass arguments. Generally, to get a universally working technique would be required to hook GetCommandlineA GetCommandlineW __getmainargs and __wgetmainargs since PEB stomping won't cover all cases, more details here: https://blog-30cm-tw.translate.goog/2020/08/windows-c-mainargc-argv.html?_x_tr_sl=auto&_x_tr_tl=en&_x_tr_hl=it&_x_tr_pto=wapp However, during my testing I found that mimikatz and several go binaries are working just by doing PEB stomping. On the other hand, cmdline passing via PEB stomping alone to mingw and VS compiled binaries won't likely work.
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
import ctypes
|
||||
|
||||
from windows import winproxy
|
||||
import windows.generated_def as gdef
|
||||
import windows.crypto
|
||||
|
||||
class CryptMessage(gdef.HCRYPTMSG):
|
||||
"""Represent a PKCS #7 message
|
||||
(see `Low-level Message Functions <https://msdn.microsoft.com/en-us/library/windows/desktop/aa380252(v=vs.85).aspx#low_level_message_functions>`_)
|
||||
"""
|
||||
MSG_PARAM_KNOW_TYPES = {gdef.CMSG_SIGNER_INFO_PARAM: gdef.CMSG_SIGNER_INFO,
|
||||
gdef.CMSG_SIGNER_COUNT_PARAM: gdef.DWORD,
|
||||
gdef.CMSG_CERT_COUNT_PARAM: gdef.DWORD,
|
||||
gdef.CMSG_ENVELOPE_ALGORITHM_PARAM: gdef.CRYPT_ALGORITHM_IDENTIFIER,
|
||||
gdef.CMSG_RECIPIENT_COUNT_PARAM: gdef.DWORD,
|
||||
gdef.CMSG_RECIPIENT_INFO_PARAM: gdef.CERT_INFO,
|
||||
}
|
||||
|
||||
|
||||
def get_param(self, param_type, index=0, raw=False):
|
||||
data_size = gdef.DWORD()
|
||||
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa380227(v=vs.85).aspx
|
||||
winproxy.CryptMsgGetParam(self, param_type, index, None, data_size)
|
||||
buffer = ctypes.c_buffer(data_size.value)
|
||||
winproxy.CryptMsgGetParam(self, param_type, index, buffer, data_size)
|
||||
if raw:
|
||||
return (buffer, data_size)
|
||||
|
||||
if param_type in self.MSG_PARAM_KNOW_TYPES:
|
||||
buffer = self.MSG_PARAM_KNOW_TYPES[param_type].from_buffer(buffer)
|
||||
if isinstance(buffer, gdef.DWORD): # DWORD -> return the Python int
|
||||
return buffer.value
|
||||
return buffer
|
||||
|
||||
# Certificate accessors
|
||||
|
||||
@property
|
||||
def nb_cert(self):
|
||||
"""The number of certificate embded in the :class:`CryptObject`
|
||||
|
||||
:type: :class:`int`
|
||||
"""
|
||||
return self.get_param(gdef.CMSG_CERT_COUNT_PARAM)
|
||||
|
||||
def get_raw_cert(self, index=0):
|
||||
return self.get_param(gdef.CMSG_CERT_PARAM, index)
|
||||
|
||||
def get_cert(self, index=0):
|
||||
"""Return embded :class:`Certificate` number ``index``.
|
||||
|
||||
.. note::
|
||||
|
||||
Not all embded certificate are directly used to sign the :class:`CryptObject`.
|
||||
"""
|
||||
return windows.crypto.Certificate.from_buffer(self.get_raw_cert(index))
|
||||
|
||||
@property
|
||||
def certs(self):
|
||||
"""The list of :class:`Certificate` embded in the message"""
|
||||
return [self.get_cert(i) for i in range(self.nb_cert)]
|
||||
|
||||
# Signers accessors
|
||||
|
||||
@property
|
||||
def nb_signer(self):
|
||||
"""The number of signers for the CryptObject
|
||||
|
||||
:type: :class:`int`
|
||||
"""
|
||||
try:
|
||||
return self.get_param(gdef.CMSG_SIGNER_COUNT_PARAM)
|
||||
except WindowsError as e:
|
||||
if (e.winerror & 0xffffffff) == gdef.CRYPT_E_INVALID_MSG_TYPE:
|
||||
return 0
|
||||
raise
|
||||
|
||||
|
||||
def get_signer_data(self, index=0):
|
||||
"""Returns the signer informations for signer nb ``index``
|
||||
|
||||
:return: :class:`~windows.generated_def.winstructs.CMSG_SIGNER_INFO`
|
||||
"""
|
||||
return self.get_param(gdef.CMSG_SIGNER_INFO_PARAM, index)
|
||||
|
||||
@property
|
||||
def signers(self):
|
||||
"""The list of :class:`~windows.generated_def.winstructs.CMSG_SIGNER_INFO` embed in the message"""
|
||||
return [self.get_signer_data(i) for i in range(self.nb_signer)]
|
||||
|
||||
@property
|
||||
def nb_recipient(self):
|
||||
"""TODO: DOC"""
|
||||
return self.get_param(gdef.CMSG_RECIPIENT_COUNT_PARAM)
|
||||
|
||||
|
||||
def get_recipient_data(self, index=0):
|
||||
"""TODO: DOC"""
|
||||
return self.get_param(gdef.CMSG_RECIPIENT_INFO_PARAM, index)
|
||||
|
||||
@property
|
||||
def recipients(self):
|
||||
"""TODO: DOC"""
|
||||
return [self.get_recipient_data(i) for i in range(self.nb_recipient)]
|
||||
|
||||
@property
|
||||
def content(self):
|
||||
return self.get_param(gdef.CMSG_CONTENT_PARAM)[:]
|
||||
|
||||
@property
|
||||
def content_type(self):
|
||||
data = self.get_param(gdef.CMSG_INNER_CONTENT_TYPE_PARAM)
|
||||
assert data[-1] == "\x00", "CMSG_INNER_CONTENT_TYPE_PARAM not NULL TERMINATED"
|
||||
return data[:-1]
|
||||
|
||||
|
||||
def update(self, blob, final):
|
||||
# Test isinstance string ?
|
||||
if isinstance(blob, (windows.pycompat.anybuff, bytearray)):
|
||||
blob = windows.pycompat.raw_encode(blob)
|
||||
buffer = windows.utils.BUFFER(gdef.BYTE).from_buffer_copy(blob)
|
||||
return winproxy.CryptMsgUpdate(self, buffer, len(blob), final)
|
||||
return winproxy.CryptMsgUpdate(self, blob.pbData, blob.cbData, final)
|
||||
|
||||
# constructor
|
||||
@classmethod
|
||||
def from_buffer(self, data):
|
||||
hmsg = winproxy.CryptMsgOpenToDecode(windows.crypto.DEFAULT_ENCODING, 0, 0, None, None, None)
|
||||
newmsg = CryptMessage(hmsg)
|
||||
newmsg.update(data, final=True)
|
||||
return newmsg
|
||||
|
||||
def __del__(self):
|
||||
return winproxy.CryptMsgClose(self)
|
||||
Reference in New Issue
Block a user