Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
В Windows каждому пользователю при входе на устройство приписывается своя сессия. Как угнать сессию пользователя, если жертва решила зайти на уже взломанное устройство? В этой статье познакомимся еще с одним способом повышения привилегий — через кражу сессий с помощью COM-классов.
Давным‑давно, когда небо было голубее, деревья зеленее, а чай слаще, я писал статью «Поставщик небезопасности. Как Windows раскрывает пароль пользователя». В ней мы подробно рассмотрели этап входа пользователя в систему, начиная от приземления пятой точки за компьютер в офисе и заканчивая получением доступа к рабочему столу.
Впрочем, в той статье я перечислил далеко не все способы воздействия на пользователя. Существует еще одна атака — кража сессии. И осуществим мы ее с помощью COM!
Итак, начнем с небольшого ликбеза. Logon Session (она же просто сессия) — это как куки браузера. Вполне понятная вещица, по которой система может однозначно определить, какой пользователь к ней обращается.
Отличаются сессии по уникальному номеру, имя ему LUID (Locally Unique IDentifier). Собственно, это все, что нужно Windows для идентификации сессии пользователя.
typedef struct _LUID { ULONG LowPart; LONG HighPart;} LUID, *PLUID;
LowPart
— содержит необходимое числовое значение; HighPart
— обычно нолик. Изучить существующие Logon-сессии можно через API LsaEnumerateLogonSessions().
Я достаточно подробно описывал эту функцию и ее использование в статье про GIUDA. Для разнообразия перепишем на C#.
using System;using System.Runtime.InteropServices;using System.Security.Principal;class Program{ [DllImport("Secur32.dll", SetLastError = false)] private static extern int LsaEnumerateLogonSessions(out ulong LogonSessionCount, out IntPtr LogonSessionList); [DllImport("Secur32.dll", SetLastError = false)] private static extern int LsaGetLogonSessionData(IntPtr LogonSession, out IntPtr ppLogonSessionData); [DllImport("Secur32.dll")] private static extern uint LsaFreeReturnBuffer(IntPtr buffer); [StructLayout(LayoutKind.Sequential)] private struct LSA_UNICODE_STRING { public ushort Length; public ushort MaximumLength; public IntPtr Buffer; } [StructLayout(LayoutKind.Sequential)] private struct SECURITY_LOGON_SESSION_DATA { public uint Size; public LUID LogonId; public LSA_UNICODE_STRING UserName; public LSA_UNICODE_STRING LogonDomain; public LSA_UNICODE_STRING AuthenticationPackage; public uint LogonType; public uint Session; public IntPtr Sid; public long LogonTime; } [StructLayout(LayoutKind.Sequential)] private struct LUID { public uint LowPart; public int HighPart; } private static string GetString(LSA_UNICODE_STRING unicodeString) { return Marshal.PtrToStringUni(unicodeString.Buffer); } static void Main() { var result = LsaEnumerateLogonSessions(out var count, out var luidPtr); if (result != 0) { Console.WriteLine("LsaEnumerateLogonSessions failed"); return; } var iter = luidPtr; for (ulong i = 0; i < count; i++) { result = LsaGetLogonSessionData(iter, out var sessionDataPtr); if (result == 0) { var sessionData = Marshal.PtrToStructure<SECURITY_LOGON_SESSION_DATA>(sessionDataPtr); var userName = GetString(sessionData.UserName); var domainName = GetString(sessionData.LogonDomain); Console.WriteLine($"UserName: {userName}"); Console.WriteLine($"LogonDomain: {domainName}"); Console.WriteLine("---------------------------"); LsaFreeReturnBuffer(sessionDataPtr); } iter = IntPtr.Add(iter, Marshal.SizeOf(typeof(LUID))); } LsaFreeReturnBuffer(luidPtr); }}
Пример работы программы
Видим стандартный импорт необходимых функций через PInvoke
с последующим вызовом в определенном порядке.
Источник: xakep.ru