Статья Как узнать геолокацию удалённого пользователя

Попав на чужой узел шелл-коду полезно знать, куда именно забросила его судьба. В статье рассматриваются несколько основных (известных лично мне) методов для достижения этой цели, хотя в природе вполне могут быть и другие. Отметим, что речь пойдёт об идентификации узла именно из бинарного кода находясь уже на машине пользователя, а не посылая ему запросы из вне по сети. Вот 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,<10,' Language....:  %ls',0>,buff

Lang.webp


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

Time.webp


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

Zone.webp


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


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

Таким образом кое-что собрали, но этого явно мало. Добавим сюда ещё и некоторую инфу об узле, типа имя юзера и его машины, что даст возможность атаковать удалённо. Ну с именем машины всё просто - его возвращает функция GetComputerName() из либы Kernel32.dll. А вот чтобы получить имя самого пользователя, нужно запрашивать сервисы подсистемы сети, в частности пройти через либу Advapi32.dll, которая и выдаёт на экспорт GetUserName(). Одним словом для шелла это палево, тем более, что до сих пор мы использовали API только из либы Kernel32.dll (загружается во все процессы).

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

Envir.webp


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

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'
 

Вложения

  • UserID.zip
    UserID.zip
    948 байт · Просмотры: 14
  • Нравится
Реакции: Evgeny D и xzotique
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab