PDA

Просмотр полной версии : Как узнать геолокацию удалённого пользователя


Marylin
14.01.2026, 17:41
Попав на чужой узел шелл-коду полезно знать, куда именно забросила его судьба. В статье рассматриваются несколько основных (известных лично мне) методов для достижения этой цели, хотя в природе вполне могут быть и другие. Отметим, что речь пойдёт об идентификации узла именно из бинарного кода находясь уже на машине пользователя, а не посылая ему запросы из вне по сети. Вот 2 варианта, которые имеет смысл держать про запас:

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
,

,
buff


https://forum.antichat.xyz/attachments/4950470/img_4fa519ce00.png

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
,

,
\
eax
,
ebx
,
ecx
,
edx
,
ebp
,
edi


https://forum.antichat.xyz/attachments/4950470/img_1640de60d1.png

Так мы сможем узнать только время, когда наш шелл активировался на машине юзера, которое в принципе не несёт полезной для нас нагрузки. Другое дело запрос часового пояса функцией 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


https://forum.antichat.xyz/attachments/4950470/img_295e609d4a.png

Приведённый выше фрагмент кода вернёт уже более информативную строку (по сравнению с лок.временем), в которой ключевую роль будет играть "GTM +5. Западная Азия". Обратите внимание, что в скобках указано "лето", хотя на дворе зима. Это потому, что как оказалось, не для всех регионов Win может осуществлять авто-перевод с зимнего на летнее время и обратно. По этой причине в конфигурации часов в дефолте всегда стоит галка "Синхронизация с Интернет", в чём можно убедиться просто щёлкнув по часам и заглянуть в настройки.

3. Прочие сведения о пользователе

Таким образом кое-что собрали, но этого явно мало. Добавим сюда ещё и некоторую инфу об узле, типа имя юзера и его машины, что даст возможность атаковать удалённо. Ну с именем машины всё просто - его возвращает функция

GetComputerName()

из либы Kernel32.dll. А вот чтобы получить имя самого пользователя, нужно запрашивать сервисы подсистемы сети, в частности пройти через либу Advapi32.dll, которая и выдаёт на экспорт

GetUserName()

. Одним словом для шелла это палево, тем более, что до сих пор мы использовали API только из либы Kernel32.dll (загружается во все процессы).

Чтобы обойти это ограничение и остаться незаметным, разумно тупо прочитать "Переменные среды" системы, что на англ.манер звучит как "Environment". Это кладезь информации в формате "Ключ : Значение", и соответственно чтобы запросить конкретную инфу, функции

GetEnvironmentVariable()

мы должны указать требуемый ключ. С полным списком этих ключей можно ознакомиться или в свойствах системы, или-же обратиться за помощью к софту "ProcessHacker", что более наглядно (жмякнуть Enter на любой программе в списке).

https://forum.antichat.xyz/attachments/4950470/img_1ecb6c7a9a.png

Для примера я возьму только имя юзера и машины по коду ниже, хотя вы можете вытащить намного больше инфы из этой базы:

C-подобный:



;
//----- Имя машины и юзера ----------------
invoke GetEnvironmentVariable
,
'COMPUTERNAME'
,
buff
,
128
cinvoke printf
,

,
buff

invoke GetEnvironmentVariable
,
'USERNAME'
,
buff
,
128
cinvoke printf
,

,
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
,

,
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
,

,
\
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
,

,
buff

invoke GetEnvironmentVariable
,
'USERNAME'
,
buff
,
128
cinvoke printf
,

,
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'