Попав на чужой узел шелл-коду полезно знать, куда именно забросила его судьба. В статье рассматриваются несколько основных (известных лично мне) методов для достижения этой цели, хотя в природе вполне могут быть и другие. Отметим, что речь пойдёт об идентификации узла именно из бинарного кода находясь уже на машине пользователя, а не посылая ему запросы из вне по сети. Вот 2 варианта, которые имеет смысл держать про запас:
А вот ещё 2, которые никогда не дают осечки:
Здесь мы рассмотрим только последние 2 варианта, т.к. в большинстве случаях шеллу совсем необязательно знать улицу и квартиру юзера.
1. Текущий язык ОС
Возвращающих язык API не много, ..а очень много, что вносит путаницу.
• Во-первых Win32API с суффиксами LCID (Language Code Identifier) можно получить идентификаторы языков, общее число которых превышает кол-во звёзд на небе – одной из них является например
• Во-вторых можно запросить язык, который активен на данный момент из списка выбранных (см.трей возле часов) – эти языки перечисляют функции с суффиксами UIL (User Interface Language), типа
• Ну и в третьих имеется удобная функция
2. Локальное время и часовой пояс
Win хранит время в двух форматах - системное и локальное. Отличаются они тем, что если
Так мы сможем узнать только время, когда наш шелл активировался на машине юзера, которое в принципе не несёт полезной для нас нагрузки. Другое дело запрос часового пояса функцией GetTimeZoneInformation(). Как и предыдущем случае, она ожидает на входе всего один аргумент - это указатель на структуру TIME_ZONE_INFORMATION с таким прототипом.
Приведённый выше фрагмент кода вернёт уже более информативную строку (по сравнению с лок.временем), в которой ключевую роль будет играть "GTM +5. Западная Азия". Обратите внимание, что в скобках указано "лето", хотя на дворе зима. Это потому, что как оказалось, не для всех регионов Win может осуществлять авто-перевод с зимнего на летнее время и обратно. По этой причине в конфигурации часов в дефолте всегда стоит галка "Синхронизация с Интернет", в чём можно убедиться просто щёлкнув по часам и заглянуть в настройки.
3. Прочие сведения о пользователе
Таким образом кое-что собрали, но этого явно мало. Добавим сюда ещё и некоторую инфу об узле, типа имя юзера и его машины, что даст возможность атаковать удалённо. Ну с именем машины всё просто - его возвращает функция
Чтобы обойти это ограничение и остаться незаметным, разумно тупо прочитать "Переменные среды" системы, что на англ.манер звучит как "Environment". Это кладезь информации в формате "Ключ : Значение", и соответственно чтобы запросить конкретную инфу, функции
Для примера я возьму только имя юзера и машины по коду ниже, хотя вы можете вытащить намного больше инфы из этой базы:
4. Эпилог
Как показывает практика, находясь внутри периметра получить местоположение юзера не так просто, поскольку по понятным причинам это не афишируется. В тушке Kernel32.dll имеется ещё одна интересная функция
Выше упоминалось, что в большинстве случаях шелл-коду достаточно распознать лишь регион жертвы, чтобы осуществить какие-либо действия, например, только в Японии GTM+9, игнорируя Россию GTM+3.
В идеале шелл должен сбросить всю нарытую инфу в файл, и посредством
Суть сей басни такова, что если при дизассме исполняемого EXE вы обнаружите функции типа
1. GPS (Global Position System) актуальна для буков и телефонов, однако требует разрешение от пользователя на его обнаружение, а потому нам не подходит.
2. IP-адрес узла сдаёт местоположение юзера с потрохами. Но проблема в том, что находясь внутри сети невозможно получить реальный IP узла, и запрос должен поступать к серверу снаружи.
А вот ещё 2, которые никогда не дают осечки:
1. Текущий язык операционной системы, хотя вероятность тоже 50/50.
2. Временная зона GTM системы – хорошее подспорье всем остальным, хотя и расширяет область аж до региона.
Здесь мы рассмотрим только последние 2 варианта, т.к. в большинстве случаях шеллу совсем необязательно знать улицу и квартиру юзера.
1. Текущий язык ОС
Возвращающих язык API не много, ..а очень много, что вносит путаницу.
• Во-первых Win32API с суффиксами LCID (Language Code Identifier) можно получить идентификаторы языков, общее число которых превышает кол-во звёзд на небе – одной из них является например
GetUserDefaultLCID(). Более детальные сведения об ID-языков можно получить
Ссылка скрыта от гостей
.• Во-вторых можно запросить язык, который активен на данный момент из списка выбранных (см.трей возле часов) – эти языки перечисляют функции с суффиксами UIL (User Interface Language), типа
GetUserPreferredUILanguages().• Ну и в третьих имеется удобная функция
GetUserDefaultLocaleName(), которая возвращает язык/локаль в текстовом виде (не идентификатор) на момент установки ОС. В общем здесь есть из чего выбирать, а мы будем использовать именно её. Обратите внимание, что функция возвращает Unicode-строку:
C-подобный:
;//----- Инфа о языке системы ------------------
invoke GetUserDefaultLocaleName,buff,128
cinvoke printf,<10,' Language....: %ls',0>,buff
2. Локальное время и часовой пояс
Win хранит время в двух форматах - системное и локальное. Отличаются они тем, что если
GetSystemTime() возвращает всемирное время UTF, то GetLocalTime() уже с поправкой в местном регионе, которое отображается в правом углу на панели задач. Обе эти функи принимают на вход всего один аргумент - это линк на структуру SYSTEMTIME, где можно будет найти текущее время вплоть до миллисекунд:
C-подобный:
struct SYSTEMTIME
wYear dw 0
wMonth dw 0
wDayOfWeek dw 0
wDay dw 0
wHour dw 0
wMinute dw 0
wSecond dw 0
wMilliseconds dw 0
ends
;//----- Инфа о лок.времени ------------------
invoke GetLocalTime, SysTime
movzx eax,[SysTime.wDay]
movzx ebx,[SysTime.wMonth]
movzx ecx,[SysTime.wYear]
movzx edx,[SysTime.wHour]
movzx ebp,[SysTime.wMinute]
movzx edi,[SysTime.wSecond]
cinvoke printf,<10,' Local Time..: %02d.%02d.%d. %02d:%02d:%02d',0>,\
eax,ebx,ecx,edx,ebp,edi
Так мы сможем узнать только время, когда наш шелл активировался на машине юзера, которое в принципе не несёт полезной для нас нагрузки. Другое дело запрос часового пояса функцией GetTimeZoneInformation(). Как и предыдущем случае, она ожидает на входе всего один аргумент - это указатель на структуру TIME_ZONE_INFORMATION с таким прототипом.
C-подобный:
struct TIME_ZONE_INFORMATION
Bias dd 0 ;// разница в минутах между временем (UTC) и местным
StandardName rb 64 ;// описание времени, например "EST" = восточное время
StandardDate SYSTEMTIME ;// при переходе от летнего времени к стд.времени
StandardBias dd 0 ;// значение добавляется к Bias
DaylightName rb 64 ;// описание летнего времени
DaylightDate SYSTEMTIME ;// дата/время при переходе к летнему времени
DaylightBias dd 0 ;// добавляется к Bias для формирования смещения
ends
;//----------------------------------------
.data
tZone db 10,' TimeZoneInfo: GTM +%d. %s',0
.code
;//----- Инфа о часовом поясе --------------
invoke GetTimeZoneInformation,tzInfo
mov eax,[tzInfo.Bias]
or eax,eax
jns @f
mov byte[tZone+21],'+'
neg eax
@@: mov ecx,60
xor edx,edx
div ecx
push eax
lea ebx,[tzInfo.DaylightName]
invoke CharToOemW,ebx,buff
pop eax
cinvoke printf,tZone,eax,buff
Приведённый выше фрагмент кода вернёт уже более информативную строку (по сравнению с лок.временем), в которой ключевую роль будет играть "GTM +5. Западная Азия". Обратите внимание, что в скобках указано "лето", хотя на дворе зима. Это потому, что как оказалось, не для всех регионов Win может осуществлять авто-перевод с зимнего на летнее время и обратно. По этой причине в конфигурации часов в дефолте всегда стоит галка "Синхронизация с Интернет", в чём можно убедиться просто щёлкнув по часам и заглянуть в настройки.
3. Прочие сведения о пользователе
Таким образом кое-что собрали, но этого явно мало. Добавим сюда ещё и некоторую инфу об узле, типа имя юзера и его машины, что даст возможность атаковать удалённо. Ну с именем машины всё просто - его возвращает функция
GetComputerName() из либы Kernel32.dll. А вот чтобы получить имя самого пользователя, нужно запрашивать сервисы подсистемы сети, в частности пройти через либу Advapi32.dll, которая и выдаёт на экспорт GetUserName(). Одним словом для шелла это палево, тем более, что до сих пор мы использовали API только из либы Kernel32.dll (загружается во все процессы).Чтобы обойти это ограничение и остаться незаметным, разумно тупо прочитать "Переменные среды" системы, что на англ.манер звучит как "Environment". Это кладезь информации в формате "Ключ : Значение", и соответственно чтобы запросить конкретную инфу, функции
GetEnvironmentVariable() мы должны указать требуемый ключ. С полным списком этих ключей можно ознакомиться или в свойствах системы, или-же обратиться за помощью к софту
Ссылка скрыта от гостей
, что более наглядно (жмякнуть Enter на любой программе в списке). Для примера я возьму только имя юзера и машины по коду ниже, хотя вы можете вытащить намного больше инфы из этой базы:
C-подобный:
;//----- Имя машины и юзера ----------------
invoke GetEnvironmentVariable,'COMPUTERNAME',buff,128
cinvoke printf,<10,' Comp Name...: %s'>,buff
invoke GetEnvironmentVariable,'USERNAME',buff,128
cinvoke printf,<10,' User Name...: %s'>,buff
4. Эпилог
Как показывает практика, находясь внутри периметра получить местоположение юзера не так просто, поскольку по понятным причинам это не афишируется. В тушке Kernel32.dll имеется ещё одна интересная функция
GetUserGeoID(), которая как и следует из её названия призвана определять геолокацию в виде государства. В её широких штанинах припрятан список из 300+ регионов, однако судя по описанию она возвращает валидные данные только в том случае, если локация была предварительно определена родственной SetUserGeoID(). Непонятно кто и когда должен устанавливать(Set) эту инфу, но в дефолте GetUserGeoID() возвращает лично у меня "Россия", хотя я нахожусь в "Азии". То-есть всецело доверять этой функции нельзя, т.к. с вероятностью 99% она даст осечку.Выше упоминалось, что в большинстве случаях шелл-коду достаточно распознать лишь регион жертвы, чтобы осуществить какие-либо действия, например, только в Японии GTM+9, игнорируя Россию GTM+3.
В идеале шелл должен сбросить всю нарытую инфу в файл, и посредством
HttpSendRequest() из WinInet.dll, или WinHttpWriteData() из WinHttp.dll отправить её на наш сервер для анализа. С другой стороны он может сам принимать решения прямо не покидая машину пользователя, чтобы лишний раз не привлекать к себе внимание.Суть сей басни такова, что если при дизассме исполняемого EXE вы обнаружите функции типа
GetTimeZoneInformation() или GetUserGeoID(), это должно настораживать, т.к. налицо явная попытка рассчёта вашей "геостационарной орбиты", со всеми вытекающими последствиями. Как минимум проверьте, что делает код с полученными данными, и лишь потом запускайте его на исполнение. А вот собственно и полный исходник для сборки в fasm'ом - его готовый бинарь для тестов найдёте в скрепке. Всем удачи, пока!
C-подобный:
format pe console 6.0
include 'win32ax.inc'
entry start
;//----------
.data
SysTime SYSTEMTIME
tzInfo TIME_ZONE_INFORMATION
tZone db 10,' TimeZoneInfo: GTM -%d. %s',0
buff db 0
;//----------
section '.code' code readable executable
start:
;//----- Инфа о лок.времени ------------------
invoke GetUserDefaultLocaleName,buff,128
cinvoke printf,<10,' Language....: %ls',0>,buff
;//----- Инфа лок.времени ------------------
invoke GetLocalTime, SysTime
movzx eax,[SysTime.wDay]
movzx ebx,[SysTime.wMonth]
movzx ecx,[SysTime.wYear]
movzx edx,[SysTime.wHour]
movzx ebp,[SysTime.wMinute]
movzx edi,[SysTime.wSecond]
cinvoke printf,<10,' Local Time..: %02d.%02d.%d. %02d:%02d:%02d',0>,\
eax,ebx,ecx,edx,ebp,edi
;//----- Инфа о часовом поясе --------------
invoke GetTimeZoneInformation,tzInfo
mov eax,[tzInfo.Bias]
or eax,eax
jns @f
mov byte[tZone+21],'+'
neg eax
@@: mov ecx,60
xor edx,edx
div ecx
push eax
lea ebx,[tzInfo.DaylightName]
invoke CharToOemW,ebx,buff
pop eax
cinvoke printf,tZone,eax,buff
;//----- Имя машины и юзера ----------------
invoke GetEnvironmentVariable,'COMPUTERNAME',buff,128
cinvoke printf,<10,10,' Comp Name...: %s'>,buff
invoke GetEnvironmentVariable,'USERNAME',buff,128
cinvoke printf,<10,' User Name...: %s'>,buff
cinvoke getch
cinvoke exit,0
;//----------
section '.idata' import data readable
library user32,'user32.dll', kernel32,'kernel32.dll', msvcrt,'msvcrt.dll'
include 'api\user32.inc'
include 'api\kernel32.inc'
import msvcrt, printf,'printf', getch,'_getch', exit,'exit'