From 56506cc902d1405a9967e7670610b630e0df74fe Mon Sep 17 00:00:00 2001 From: Alex Romero <ntalexio2@gmail.com> Date: Thu, 8 Dec 2022 16:49:51 -0500 Subject: [PATCH 1/3] add enumdesktops command to windows python meterpreter --- python/meterpreter/ext_server_stdapi.py | 109 +++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/python/meterpreter/ext_server_stdapi.py b/python/meterpreter/ext_server_stdapi.py index ef179ba1..350ddb4b 100644 --- a/python/meterpreter/ext_server_stdapi.py +++ b/python/meterpreter/ext_server_stdapi.py @@ -669,7 +669,11 @@ TLV_TYPE_TERMINAL_COLUMNS = TLV_META_TYPE_UINT | 2601 ## TLV_TYPE_IDLE_TIME = TLV_META_TYPE_UINT | 3000 TLV_TYPE_KEYS_DUMP = TLV_META_TYPE_STRING | 3001 -TLV_TYPE_DESKTOP = TLV_META_TYPE_STRING | 3002 + +TLV_TYPE_DESKTOP = TLV_META_TYPE_GROUP | 3004 +TLV_TYPE_DESKTOP_SESSION = TLV_META_TYPE_UINT | 3005 +TLV_TYPE_DESKTOP_STATION = TLV_META_TYPE_STRING | 3006 +TLV_TYPE_DESKTOP_NAME = TLV_META_TYPE_STRING | 3007 ## # Event Log @@ -744,6 +748,9 @@ VER_PLATFORM_WIN32s = 0x0000 VER_PLATFORM_WIN32_WINDOWS = 0x0001 VER_PLATFORM_WIN32_NT = 0x0002 +# Windows Access Controls +MAXIMUM_ALLOWED = 0x02000000 + WIN_AF_INET = 2 WIN_AF_INET6 = 23 @@ -2755,6 +2762,106 @@ def stdapi_ui_get_idle_time(request, response): response += tlv_pack(TLV_TYPE_IDLE_TIME, idle_time) return ERROR_SUCCESS, response +@register_function_if(has_windll) +def stdapi_ui_desktop_enum(request, response): + global ui_desktop_enum_RESPONSE + ui_desktop_enum_RESPONSE = response + + class EnumDesktops_Param(ctypes.Structure): + _fields_ = [ + ('sessionId', ctypes.c_ulong), + ('cpStationName', ctypes.c_char_p) + ] + + EnumDesktopCallbackPrototype = ctypes.WINFUNCTYPE(ctypes.c_long, ctypes.c_char_p, ctypes.POINTER(EnumDesktops_Param)) + EnumDesktopsA = ctypes.windll.user32.EnumDesktopsA + EnumDesktopsA.argtypes = [ctypes.c_void_p, EnumDesktopCallbackPrototype, ctypes.POINTER(EnumDesktops_Param)] + EnumDesktopsA.restype = ctypes.c_long + + WindowStationCallbackPrototype = ctypes.WINFUNCTYPE(ctypes.c_long, ctypes.c_char_p, ctypes.c_ulong) + EnumWindowStationsA = ctypes.windll.user32.EnumWindowStationsA + EnumWindowStationsA.argtypes = [WindowStationCallbackPrototype, ctypes.c_ulong] + EnumWindowStationsA.restype = ctypes.c_long + + OpenWindowStationA = ctypes.windll.user32.OpenWindowStationA + OpenWindowStationA.argtypes = [ctypes.c_char_p, ctypes.c_long, ctypes.c_ulong] + OpenWindowStationA.restype = ctypes.c_void_p + + CloseWindowStation = ctypes.windll.user32.CloseWindowStation + CloseWindowStation.argtypes = [ctypes.c_void_p] + CloseWindowStation.restype = ctypes.c_long + + GetCurrentProcessId = ctypes.windll.kernel32.GetCurrentProcessId + GetCurrentProcessId.restype = ctypes.c_ulong + + GetProcAddress = ctypes.windll.kernel32.GetProcAddress + GetProcAddress.argtypes = [ctypes.c_void_p, ctypes.c_char_p] + GetProcAddress.restype = ctypes.c_void_p + + ProcessIdToSessionIdPrototype = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_ulong, ctypes.POINTER(ctypes.c_ulong)) + + def get_session_id(pid): + pProcessIdToSessionId = None + dwSessionId = ctypes.c_ulong(0) + + hKernel = ctypes.WinDLL('kernel32.dll') + if hKernel: + pProcessIdToSessionId = GetProcAddress(hKernel._handle, ctypes.c_char_p(b"ProcessIdToSessionId")) + + if not pProcessIdToSessionId: + ctypes.windll.kernel32.FreeLibrary(None, handle=hKernel) + return dwSessionId + + pProcessIdToSessionId = ProcessIdToSessionIdPrototype(pProcessIdToSessionId) + if not pProcessIdToSessionId(ctypes.c_ulong(pid), ctypes.byref(dwSessionId)): + dwSessionId = ctypes.c_ulong(-1) + + ctypes.windll.kernel32.FreeLibrary(None, handle=hKernel) + return dwSessionId + + @EnumDesktopCallbackPrototype + def desktop_enumdesktops_callback(lpszDesktop, lParam): + if not lParam or not lpszDesktop: + return True + + if not lParam.contents.sessionId or not lParam.contents.cpStationName: + return True + + entry = bytes() + entry += tlv_pack(TLV_TYPE_DESKTOP_SESSION, lParam.contents.sessionId) + entry += tlv_pack(TLV_TYPE_DESKTOP_STATION, lParam.contents.cpStationName.decode()) + entry += tlv_pack(TLV_TYPE_DESKTOP_NAME, lpszDesktop.decode()) + + global ui_desktop_enum_RESPONSE + ui_desktop_enum_RESPONSE += tlv_pack(TLV_TYPE_DESKTOP, entry) + + return True + + @WindowStationCallbackPrototype + def desktop_enumstations_callback(lpszWindowStation, lParam): + hWindowStation = OpenWindowStationA(lpszWindowStation, False, MAXIMUM_ALLOWED) + if not hWindowStation: + return False + + param = EnumDesktops_Param() + param.sessionId = get_session_id(GetCurrentProcessId()) + param.cpStationName = lpszWindowStation + EnumDesktopsA(hWindowStation, desktop_enumdesktops_callback, ctypes.pointer(param)) + + if hWindowStation: + CloseWindowStation(hWindowStation) + + return True + + success = EnumWindowStationsA(desktop_enumstations_callback, 0) + if not success: + return error_result_windows(), response + + response = ui_desktop_enum_RESPONSE + del ui_desktop_enum_RESPONSE + + return ERROR_SUCCESS, response + @register_function_if(has_termios and has_fcntl) def stdapi_sys_process_set_term_size(request, response): channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value'] From 414f2208fc81625351dc30e75df5caf4888f300d Mon Sep 17 00:00:00 2001 From: Alex Romero <ntalexio2@gmail.com> Date: Wed, 11 Jan 2023 20:09:56 -0500 Subject: [PATCH 2/3] apply @smcintyre-r7 review changes --- python/meterpreter/ext_server_stdapi.py | 58 ++++++++++++------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/python/meterpreter/ext_server_stdapi.py b/python/meterpreter/ext_server_stdapi.py index 350ddb4b..7b72da30 100644 --- a/python/meterpreter/ext_server_stdapi.py +++ b/python/meterpreter/ext_server_stdapi.py @@ -2764,27 +2764,33 @@ def stdapi_ui_get_idle_time(request, response): @register_function_if(has_windll) def stdapi_ui_desktop_enum(request, response): - global ui_desktop_enum_RESPONSE - ui_desktop_enum_RESPONSE = response + + from functools import partial + response_parts = [] class EnumDesktops_Param(ctypes.Structure): _fields_ = [ ('sessionId', ctypes.c_ulong), ('cpStationName', ctypes.c_char_p) ] + + if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p): + LPARAM = ctypes.c_long + elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p): + LPARAM = ctypes.c_longlong - EnumDesktopCallbackPrototype = ctypes.WINFUNCTYPE(ctypes.c_long, ctypes.c_char_p, ctypes.POINTER(EnumDesktops_Param)) + DESKTOPENUMPROCA = ctypes.WINFUNCTYPE(ctypes.c_long, ctypes.c_char_p, ctypes.POINTER(EnumDesktops_Param)) EnumDesktopsA = ctypes.windll.user32.EnumDesktopsA - EnumDesktopsA.argtypes = [ctypes.c_void_p, EnumDesktopCallbackPrototype, ctypes.POINTER(EnumDesktops_Param)] + EnumDesktopsA.argtypes = [ctypes.c_void_p, DESKTOPENUMPROCA, ctypes.POINTER(EnumDesktops_Param)] EnumDesktopsA.restype = ctypes.c_long - WindowStationCallbackPrototype = ctypes.WINFUNCTYPE(ctypes.c_long, ctypes.c_char_p, ctypes.c_ulong) + WINSTAENUMPROCA = ctypes.WINFUNCTYPE(ctypes.c_long, ctypes.c_char_p, LPARAM) EnumWindowStationsA = ctypes.windll.user32.EnumWindowStationsA - EnumWindowStationsA.argtypes = [WindowStationCallbackPrototype, ctypes.c_ulong] + EnumWindowStationsA.argtypes = [WINSTAENUMPROCA, LPARAM] EnumWindowStationsA.restype = ctypes.c_long OpenWindowStationA = ctypes.windll.user32.OpenWindowStationA - OpenWindowStationA.argtypes = [ctypes.c_char_p, ctypes.c_long, ctypes.c_ulong] + OpenWindowStationA.argtypes = [ctypes.c_char_p, ctypes.c_long, ctypes.c_bool] OpenWindowStationA.restype = ctypes.c_void_p CloseWindowStation = ctypes.windll.user32.CloseWindowStation @@ -2798,29 +2804,20 @@ def stdapi_ui_desktop_enum(request, response): GetProcAddress.argtypes = [ctypes.c_void_p, ctypes.c_char_p] GetProcAddress.restype = ctypes.c_void_p - ProcessIdToSessionIdPrototype = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_ulong, ctypes.POINTER(ctypes.c_ulong)) - def get_session_id(pid): - pProcessIdToSessionId = None dwSessionId = ctypes.c_ulong(0) - hKernel = ctypes.WinDLL('kernel32.dll') - if hKernel: - pProcessIdToSessionId = GetProcAddress(hKernel._handle, ctypes.c_char_p(b"ProcessIdToSessionId")) - - if not pProcessIdToSessionId: - ctypes.windll.kernel32.FreeLibrary(None, handle=hKernel) - return dwSessionId - - pProcessIdToSessionId = ProcessIdToSessionIdPrototype(pProcessIdToSessionId) - if not pProcessIdToSessionId(ctypes.c_ulong(pid), ctypes.byref(dwSessionId)): + ProcessIdToSessionId = ctypes.windll.kernel32.ProcessIdToSessionId + ProcessIdToSessionId.argtypes = [ctypes.c_ulong, ctypes.POINTER(ctypes.c_ulong)] + ProcessIdToSessionId.restype = ctypes.c_bool + + if not ProcessIdToSessionId(ctypes.c_ulong(pid), ctypes.byref(dwSessionId)): dwSessionId = ctypes.c_ulong(-1) - ctypes.windll.kernel32.FreeLibrary(None, handle=hKernel) return dwSessionId - @EnumDesktopCallbackPrototype - def desktop_enumdesktops_callback(lpszDesktop, lParam): + + def desktop_enumdesktops_callback(response_parts, lpszDesktop, lParam): if not lParam or not lpszDesktop: return True @@ -2832,21 +2829,23 @@ def stdapi_ui_desktop_enum(request, response): entry += tlv_pack(TLV_TYPE_DESKTOP_STATION, lParam.contents.cpStationName.decode()) entry += tlv_pack(TLV_TYPE_DESKTOP_NAME, lpszDesktop.decode()) - global ui_desktop_enum_RESPONSE - ui_desktop_enum_RESPONSE += tlv_pack(TLV_TYPE_DESKTOP, entry) + response_parts.append(tlv_pack(TLV_TYPE_DESKTOP, entry)) return True - @WindowStationCallbackPrototype + @WINSTAENUMPROCA def desktop_enumstations_callback(lpszWindowStation, lParam): hWindowStation = OpenWindowStationA(lpszWindowStation, False, MAXIMUM_ALLOWED) if not hWindowStation: - return False + return True + + callback = partial(desktop_enumdesktops_callback, response_parts) + callback = DESKTOPENUMPROCA(callback) param = EnumDesktops_Param() param.sessionId = get_session_id(GetCurrentProcessId()) param.cpStationName = lpszWindowStation - EnumDesktopsA(hWindowStation, desktop_enumdesktops_callback, ctypes.pointer(param)) + EnumDesktopsA(hWindowStation, callback, ctypes.pointer(param)) if hWindowStation: CloseWindowStation(hWindowStation) @@ -2857,8 +2856,7 @@ def stdapi_ui_desktop_enum(request, response): if not success: return error_result_windows(), response - response = ui_desktop_enum_RESPONSE - del ui_desktop_enum_RESPONSE + response += bytes().join(response_parts) return ERROR_SUCCESS, response From 8c99076e9a9127fd0663f86bad02720f61c17939 Mon Sep 17 00:00:00 2001 From: Alex Romero <ntalexio2@gmail.com> Date: Thu, 12 Jan 2023 13:03:42 -0500 Subject: [PATCH 3/3] apply @smcintyre-r7 patch on station 0 bug for python enumdesktops --- python/meterpreter/ext_server_stdapi.py | 35 +++++++++---------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/python/meterpreter/ext_server_stdapi.py b/python/meterpreter/ext_server_stdapi.py index 7b72da30..597f3a94 100644 --- a/python/meterpreter/ext_server_stdapi.py +++ b/python/meterpreter/ext_server_stdapi.py @@ -1,4 +1,5 @@ import fnmatch +import functools import getpass import os import platform @@ -2765,23 +2766,15 @@ def stdapi_ui_get_idle_time(request, response): @register_function_if(has_windll) def stdapi_ui_desktop_enum(request, response): - from functools import partial - response_parts = [] - class EnumDesktops_Param(ctypes.Structure): - _fields_ = [ - ('sessionId', ctypes.c_ulong), - ('cpStationName', ctypes.c_char_p) - ] - if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p): LPARAM = ctypes.c_long elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p): LPARAM = ctypes.c_longlong - DESKTOPENUMPROCA = ctypes.WINFUNCTYPE(ctypes.c_long, ctypes.c_char_p, ctypes.POINTER(EnumDesktops_Param)) + DESKTOPENUMPROCA = ctypes.WINFUNCTYPE(ctypes.c_long, ctypes.c_char_p, LPARAM) EnumDesktopsA = ctypes.windll.user32.EnumDesktopsA - EnumDesktopsA.argtypes = [ctypes.c_void_p, DESKTOPENUMPROCA, ctypes.POINTER(EnumDesktops_Param)] + EnumDesktopsA.argtypes = [ctypes.c_void_p, DESKTOPENUMPROCA, LPARAM] EnumDesktopsA.restype = ctypes.c_long WINSTAENUMPROCA = ctypes.WINFUNCTYPE(ctypes.c_long, ctypes.c_char_p, LPARAM) @@ -2817,16 +2810,13 @@ def stdapi_ui_desktop_enum(request, response): return dwSessionId - def desktop_enumdesktops_callback(response_parts, lpszDesktop, lParam): - if not lParam or not lpszDesktop: - return True - - if not lParam.contents.sessionId or not lParam.contents.cpStationName: + def desktop_enumdesktops_callback(response_parts, session_id, station_name, lpszDesktop, lParam): + if not station_name or not lpszDesktop: return True entry = bytes() - entry += tlv_pack(TLV_TYPE_DESKTOP_SESSION, lParam.contents.sessionId) - entry += tlv_pack(TLV_TYPE_DESKTOP_STATION, lParam.contents.cpStationName.decode()) + entry += tlv_pack(TLV_TYPE_DESKTOP_SESSION, session_id) + entry += tlv_pack(TLV_TYPE_DESKTOP_STATION, station_name) entry += tlv_pack(TLV_TYPE_DESKTOP_NAME, lpszDesktop.decode()) response_parts.append(tlv_pack(TLV_TYPE_DESKTOP, entry)) @@ -2839,13 +2829,12 @@ def stdapi_ui_desktop_enum(request, response): if not hWindowStation: return True - callback = partial(desktop_enumdesktops_callback, response_parts) + callback = functools.partial(desktop_enumdesktops_callback, response_parts) + session_id = get_session_id(GetCurrentProcessId()).value + station_name = lpszWindowStation.decode() + callback = functools.partial(desktop_enumdesktops_callback, response_parts, session_id, station_name) callback = DESKTOPENUMPROCA(callback) - - param = EnumDesktops_Param() - param.sessionId = get_session_id(GetCurrentProcessId()) - param.cpStationName = lpszWindowStation - EnumDesktopsA(hWindowStation, callback, ctypes.pointer(param)) + EnumDesktopsA(hWindowStation, callback, 0) if hWindowStation: CloseWindowStation(hWindowStation)