Ocena bezpieczeństwa kontrolek SAP GUI przy użyciu Windows API w Pythonie

Podczas przeprowadzania oceny bezpieczeństwa lub testów penetracyjnych w środowiskach SAP GUI, interakcja z elementami sterującymi systemu Windows jest często konieczna do wyodrębnienia informacji lub automatyzacji. Windows API zapewnia potężne metody dostępu do elementów GUI i manipulowania nimi, umożliwiając specjalistom ds. bezpieczeństwa skuteczniejszą analizę aplikacji SAP GUI.
W tym wpisie pokażemy, w jaki sposób Python, w połączeniu z funkcjami Windows API, takimi jak GetWindowTextA
i WM_GETTEXT
, może być wykorzystywany do testowania i automatyzacji bezpieczeństwa SAP GUI.
Interakcja z SAP GUI przy użyciu Windows API
SAP GUI działa jako aplikacja oparta na systemie Windows, co oznacza, że dostęp do elementów interfejsu użytkownika można uzyskać za pomocą wywołań API na poziomie systemu. Jest to szczególnie przydatne w testach penetracyjnych, w których wymagane jest pobieranie poufnych informacji lub automatyzacja kontroli bezpieczeństwa. Powszechnie używane funkcje API obejmują:
FindWindow / FindWindowEx
– lokalizuje główne okno SAP GUI i jego elementy potomne.GetWindowTextA
– pobiera tekst z kontrolek okna, co jest przydatne do wyodrębniania tytułów okien lub komunikatów dialogowych.SendMessage(WM_GETTEXT)
– wyodrębnia zawartość z pól tekstowych, które nie udostępniają danych przezGetWindowTextA
.
Interakcja z Windows API może być zrealizowana z wykorzystaniem pythonowych modułów: ctypes
i win32gui
. Są one niezbędnymi narzędziami do interakcji z Windows API, co czyni je cennymi przy przeprowadzaniu testów penetracyjnych obejmujących aplikacje GUI, takie jak SAP. Moduł ctypes
pozwala na bezpośredni dostęp do bibliotek DLL systemu Windows, umożliwiając interakcję z komponentami systemu poprzez wywoływanie funkcji niskiego poziomu w celu pobierania tekstu okna, wysyłania naciśnięć klawiszy lub manipulowania pamięcią. Z drugiej strony, win32gui
, część pakietu pywin32
, zapewnia bardziej Pythoniczny sposób interakcji z interfejsem graficznym użytkownika systemu Windows, oferując funkcje do enumracji okien, pobierania uchwytów i wyodrębniania informacji z kontrolek. Razem moduły te umożliwiają badaczom bezpieczeństwa analizę zachowania SAP GUI, automatyzację testów bezpieczeństwa i identyfikację luk, które mogą zostać wykorzystane przez atakujących.
Dostęp do SAP GUI można uzyskać za pomocą funkcji Windows API, co ma kluczowe znaczenie dla testów penetracyjnych. Moduły pythona
ctypes
iwin32gui
umożliwiają automatyzację interakcji z SAP GUI, pomagając w wydobywaniu danych, analizowaniu luk i automatyzacji testów bezpieczeństwa.
Wyodrębnianie tekstu z kontrolek okna SAP
Poniższy skrypt napisany w języku Python pokazuje, jak pobrać tytuł okna SAP GUI, który może być przydatny w ocenie bezpieczeństwa w celu identyfikacji otwartych sesji lub nieautoryzowanego dostępu:
import ctypes
import win32gui
# Pobranie uchwytu do okna SAP
hwnd = win32gui.FindWindow(None, "SAP Logon 760") # Dostosuj tytuł do swojego przypadku
if hwnd:
length = win32gui.GetWindowTextLength(hwnd)
buffer = ctypes.create_string_buffer(length + 1)
ctypes.windll.user32.GetWindowTextA(hwnd, buffer, length + 1)
print("SAP Window Title:", buffer.value.decode('utf-8'))
else:
print("SAP GUI not found.")
Code language: PHP (php)
Uzyskanie dostępu do kontrolek z wykorzystaniem WM_GETTEXT
Podczas testów penetracyjnych możemy napotkać scenariusze, w których GetWindowTextA
nie działa na niektórych elementach interfejsu użytkownika, takich jak pola haseł lub dynamicznie aktualizowane dane wejściowe. W takich przypadkach, do wyodrębnienia ukrytych informacji w celu dalszej analizy bezpieczeństwa, można użyć SendMessage(WM_GETTEXT)
.
import ctypes
from ctypes import wintypes
user32 = ctypes.WinDLL("user32", use_last_error=True)
WM_GETTEXT = 0x000D
WM_GETTEXTLENGTH = 0x000E
def get_control_text(hwnd):
length = user32.SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0)
buffer = ctypes.create_unicode_buffer(length + 1)
user32.SendMessageW(hwnd, WM_GETTEXT, length + 1, ctypes.byref(buffer))
return buffer.value
# Przykładowe użycie:
hwnd_sap_field = win32gui.FindWindowEx(hwnd, None, "Edit", None) # Odnalezienie pola wejściowego
if hwnd_sap_field:
print("SAP Input Field Text:", get_control_text(hwnd_sap_field))
Code language: PHP (php)
Praktyczny przykład: Wykorzystanie Windows API do wstrzyknięcia transakcji SAP
Możemy zastosować tę teorię w praktyce podczas oceny bezpieczeństwa lub testów penetracyjnych aplikacji SAP. Poniższy skrypt Pythona został zaprojektowany do automatyzacji interakcji z graficznym interfejsem użytkownika SAP przy użyciu funkcji Windows API. Wykorzystuje on moduł ctypes
do bezpośredniego łączenia się z bibliotekami systemowymi Windows, umożliwiając lokalizowanie okien SAP, interakcję z polami tekstowymi i symulowanie wprowadzania danych przez użytkownika. Takie techniki automatyzacji mogą być bardzo przydatne, ponieważ umożliwiają badaczom bezpieczeństwa ocenę kontroli dostępu, identyfikację nieautoryzowanych transakcji i usprawnienie analizy luk w zabezpieczeniach.
import ctypes, sys
from ctypes import wintypes
import time, string
# Wczytanie wymaganych bibliotek Windows API
user32 = ctypes.windll.user32
# Define constants
WM_KEYDOWN = 0x0100
WM_KEYUP = 0x0101
VK_RETURN = 0x0D
# Constants for messages
WM_CHAR = 0x0102
# Definicja funkcji callback dla EnumWindows
EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, wintypes.HWND, wintypes.LPARAM)
def find_window_by_title(target_title):
found_hwnd = []
def callback(hwnd, lParam):
length = user32.GetWindowTextLengthW(hwnd)
if length > 0:
buffer = ctypes.create_unicode_buffer(length + 1)
user32.GetWindowTextW(hwnd, buffer, length + 1)
if target_title in buffer.value:
print(buffer.value)
found_hwnd.append(hwnd)
return False # Stop enumeration when the window is found
return True # kontynuacja enumeracji
tmp=user32.EnumWindows(EnumWindowsProc(callback), 0)
return found_hwnd[0] if found_hwnd else None
WM_GETTEXT = 0x000D
WM_GETTEXTLENGTH = 0x000E
def get_window_caption(hwnd):
"""Pozyskanie tekstu/caption dla okna z wykorzystaniem SendMessage."""
# pobranie długości tekstu:
text_length = user32.SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0)
if text_length > 0:
# Alokacja bufora dla odebranego tekstu
buffer = ctypes.create_unicode_buffer(text_length + 1)
# użycie SendMessage w celu pobrania tekstu
user32.SendMessageW(hwnd, WM_GETTEXT, text_length + 1, ctypes.byref(buffer))
return buffer.value
return ""
def find_child_window(parent_hwnd, target_text):
"""Odnajduje potomne okno na podstawie tekstu dla wskazanego okna."""
found_child_hwnd = []
def callback(hwnd, lParam):
length = user32.GetWindowTextLengthW(hwnd)
#print(hex(hwnd))
window_caption=get_window_caption(hwnd)
if length > 0:
buffer = ctypes.create_unicode_buffer(length + 1)
user32.GetWindowTextW(hwnd, buffer, length + 1)
#print(buffer.value)
if target_text in buffer.value:
#print(buffer.value)
found_child_hwnd.append(hwnd)
return False # zatrzymanie enumeracji jeżeli okno zostało odnalezione
if window_caption and len(window_caption) > 0:
#print(window_caption)
if target_text in window_caption:
found_child_hwnd.append(hwnd)
return False
return True # kontynuacja enumeracji
user32.EnumChildWindows(parent_hwnd, EnumWindowsProc(callback), 0)
return found_child_hwnd[0] if found_child_hwnd else None
def send_enter_key(hwnd):
"""Wysłanie wartości przycisku ENTER do wskazanego okna."""
# Wyciągnięcie okna na wierzch
user32.SetForegroundWindow(hwnd)
time.sleep(0.1) # Odczekanie aby okno stało się aktywne
# Wysłanie wiadomości WM_KEYDOWN i WM_KEYUP dla przycisku ENTER
user32.PostMessageW(hwnd, WM_KEYDOWN, VK_RETURN, 0)
user32.PostMessageW(hwnd, WM_KEYUP, VK_RETURN, 0)
def send_chars_to_window(hwnd, string):
for char in string:
user32.SendMessageW(hwnd, WM_CHAR, ord(char), 0)
# Główna funkcja programu
if __name__ == "__main__":
print("\nSAP Transaction Check via Error Message Helper Tool v0.2.1 by Michał Majchrowicz AFINE Team\n")
if len(sys.argv) < 2:
print(f"{sys.argv[0]} <text_field_text> [<value_prefix>]\n");
exit(-1)
found_str=""
if len(sys.argv) > 2:
found_str=sys.argv[2]
#main_window_title = "SAP Easy Access -"
main_window_title = "110 SAP Easy Access"
child_window_text=sys.argv[1]
mainHwnd = find_window_by_title(main_window_title)
if mainHwnd:
print(f"Main Window found: {hex(mainHwnd)}")
# Odnalezienie okna potomka na podstawie tekstu
child_window_hwnd = find_child_window(mainHwnd, child_window_text)
if child_window_hwnd:
print(f"Text field with text '{child_window_text}' found: {hex(child_window_hwnd)}")
# Wysłanie symulacji wciśnięcia przycisku ENTER do okna potomnego
send_chars_to_window(child_window_hwnd,"/nSAP_404")
send_enter_key(child_window_hwnd)
time.sleep(2)
footer_window_hwnd = find_child_window(mainHwnd, "Footer")
if footer_window_hwnd:
print(f"Footer found: {hex(footer_window_hwnd)}")
results_label_hwnd = find_child_window(footer_window_hwnd, "Transaction SAP_404")
if results_label_hwnd:
print(f"Results label found: {hex(results_label_hwnd)}\n")
with open("C:\\Users\\Public\\Documents\\list.txt","r") as file:
transaction_list=[line.strip() for line in file.readlines()]
#transaction_name="SAP_TEST_404"
for transaction_name in transaction_list:
send_chars_to_window(child_window_hwnd,"/n"+transaction_name)
send_enter_key(child_window_hwnd)
time.sleep(2)
results_window_caption = get_window_caption(results_label_hwnd)
if not "does not exist" in results_window_caption:
print(transaction_name)
print("")
Code language: PHP (php)
Znajdowanie okien i elementów sterujących SAP
Skrypt rozpoczyna działanie od zdefiniowania funkcji do wyszukiwania okien SAP i ich elementów podrzędnych na podstawie ich tytułów lub wyświetlanego tekstu. Korzystając z funkcji EnumWindows
oraz EnumChildWindows
iteruje przez otwarte okna, aby znaleźć główne okno SAP GUI i odpowiednie pola wejściowe. W celu wyodrębnienia tekstu wykorzystuje komunikat WM_GETTEXT
upewniając się, że interakcja następuje z prawidłowymi elementami. Funkcja jest przydatna w testach penetracyjnych, w których specjaliści ds. bezpieczeństwa mogą potrzebować przeanalizować mechanizmy uwierzytelniania i autoryzacji oparte na GUI.
Symulowanie wprowadzania danych przez użytkownika w systemie SAP
Gdy skrypt zlokalizuje niezbędne komponenty SAP GUI, automatyzuje interakcję z nimi wysyłając symulowane naciśnięcia klawiszy oraz polecenia. Funkcja SendMessageW
służy do wprowadzania tekstu, podczas gdy PostMessageW
symuluje naciśnięcie klawisza ENTER. Dzięki temu, skrypt może automatycznie wprowadzać kody transakcji oraz weryfikować czy określone transakcje są dozwolone lub ograniczone na podstawie odpowiedzi. Taka automatyzacja może pomóc zidentyfikować błędnie skonfigurowane prawa dostępu, w których użytkownicy posiadają uprawnienia do wykonania operacji, których nie powinni móc wykonać.
Poszukiwanie nieautoryzowanych transakcji
Skrypt odczytuje z pliku listę kodów transakcji i iteruje po nich, próbując uzyskać dostęp do każdej z nich w interfejsie SAP GUI. Sprawdzając komunikaty odpowiedzi określa, czy transakcja jest dostępna, czy niedozwolona. Jeśli transakcja jest nieoczekiwanie dostępna, może to wskazywać na błędną konfigurację zabezpieczeń lub potencjalne ryzyko eskalacji uprawnień.
Wykorzystując funkcje Windows API do interakcji z SAP GUI, skrypt ten stanowi użyteczne narzędzie dla specjalistów ds. bezpieczeństwa do automatyzacji ocen bezpieczeństwa opartych na GUI.
W tym rozdziale wyjaśniono, w jaki sposób skrypt automatyzuje walidację transakcji w interfejsie graficznym SAP, odczytując listę kodów i sprawdzając odpowiedzi dostępu.
Uruchomienie skryptu
Skrypt wymaga pliku wejściowego zawierającego listę kodów transakcji SAP. Każdy wiersz pliku powinien zawierać jeden kod transakcji. Poniżej znajduje się przykład takiego pliku wejściowego:
SU3
PPOSE
SU53
SU56
TEST
FOOBAR
SUIM
AFINE
Aby uruchomić skrypt, należy wykonać następujące polecenie:
PS C:\Program Files\Python312> .\python.exe .\sap_transaction_check.py FOOBAR
Code language: CSS (css)
Powyższe polecenie uruchamia skrypt i używa „FOOBAR” jako tekstu do wyszukania w interfejsie graficznym SAP. Następnie skrypt próbuje zlokalizować okno SAP GUI, znaleźć odpowiednie pole wejściowe, wprowadzić kody transakcji i przeanalizować odpowiedzi.
Wyniki
Po wykonaniu skryptu wygenerowano następujący output:
SAP Transaction Check via Error Message Helper Tool v0.2.1 by Michał Majchrowicz AFINE Team
SAP Easy Access - User Menu for AFINE
Main Window found: 0x704a4
Text field with text 'FOOBAR' found: 0x60470
Footer found: 0x5048c
Results label found: 0x6047a
SU3
PPOSE
SU53
SU56
SUIM
Code language: JavaScript (javascript)
Skrypt pomyślnie wykrył główne okno SAP, zidentyfikował docelowe pole wejściowe oraz odnalazł stopkę, w której wyświetlane są wyniki transakcji. Następnie sprawdził każdą transakcję z pliku wejściowego. Wynik przedstawia listę kodów transakcji, które istnieją i są dostępne w systemie.
Co ciekawe, niektóre transakcje z pliku wejściowego – takie jak „TEST”, „FOOBAR” i „AFINE” – nie pojawiły się w wynikach. Oznacza to, że albo nie istnieją, albo ich dostępność jest ograniczona.
Podsumowanie
Wykorzystanie wywołań Windows API w Pythonie umożliwia interakcję z kontrolkami SAP GUI, co czyni tę technikę skutecznym narzędziem do oceny bezpieczeństwa. Niezależnie od tego, czy chodzi o ekstrakcję tekstu, identyfikację nieautoryzowanych punktów dostępu, metody te dostarczają cennych informacji specjalistom ds. bezpieczeństwa SAP. Aby jeszcze bardziej zwiększyć poziom zabezpieczeń SAP, połączenie technik opartych na Windows API z SAP GUI Scripting lub narzędziami automatyzacji, takimi jak pywinauto
, może pomóc w wykrywaniu podatności i poprawie ogólnego bezpieczeństwa systemu.