/*-----------------------------------------------------------------------*/
 /*                       R I N G 0,    I S S U E   # 1                   */
 /*-----------------------------------------------------------------------*/

                            Netbios и все все все...

                                                             by Bethoven

      Contents:

    Вступление.
    Winapi vs своя реализация.
    Получение списка ресурсов (wnetenum*).
    Подсоединение к ресурсу.
    Использование ресурсов, работа с файлами и директориями.
    Собственная реализация, nessus нам в помощь.
    Получение netbios имени хоста.
    Заключение и ссылки.



      ВСТУПЛЕНИЕ:

     Netbios  протокол  очень  широко  используется  в локальных сетях и
служит  не  только  для  передачи файлов между машинами, но и для многих
других  вещей.  В  особенности  это  касается  win сетей. И кстати можно
сказать,  что netbios самый быстрый из протоколов для обмена файлами. По
сравнению  с  raw  tcp (я не считаю более высокие http и ftp) или udp он
дает прирост скорости до 20% уже на 100 мбит езернете.Это достигается за
счет использования больших пакетов например.Но вернемся к сути, мы будем
рассматривать самое распространенное использование netbios в локальных и
глобальных  сетях  поверх tcp(сам netbios не обеспечивает роутинг). Этот
протокол  называется  NBT (NetBIOS через TCP/IP). А точнее использование
дисковых  ресурсов с общим доступом(расшаренные ресурсы(диски), шары). В
качестве  ресурсов  могут  выступать и другие объекты например: принтеры
или удаленное управление NT системами и многое другое.

      WINAPI VS СВОЯ РЕАЛИЗАЦИЯ:

     Системные   функции  windows  (winapi)  предоставляют  весь  нужный
сервис, но у такого подхода есть свои плюсы и минусы.

      Преимущества winapi:
     легкость  использования  и  полная  поддержка остальными системными
фун-ями  легкость  написания,  достаточно прочитать msdn полное описание
возвращаемых ошибок.

      Недостатки winapi:
     непереносимость  на  другие  платформы  не  на  всех  win  системах
нормальная  реализация  (под  win9x  возможные  зависания  , и вообще по
скорости работы win9x и winnt сильно различны) невозможность вмешиваться
в  работу  протокола,  например  при реализации любого рода уязвимостей.
невозможность определения скрытых ресурсов (с$ например)

     Я  рассмотрю  подробно  только  использование  winapi, а в качестве
примера собственной реализации приведу получение netbios имен.

      ПОЛУЧЕНИЕ СПИСКА РЕСУРСОВ (wnetenum*):

     И  так  у  нас  есть  IP  хоста, на котором мы предполагаем наличие
расшаренных ресурсов.

     Вначале  определим  список ресурсов, для этого используются функции
WnetOpenEnum, WnetEnumResource, WNetCloseEnum

        Nw: TnetResource;

        nw.dwScope:=RESOURCE_GLOBALNET;
        nw.dwType:=RESOURCETYPE_DISK; // нам нужны только дисковые ресурсы.
        nw.dwUsage:=RESOURCEUSAGE_CONTAINER;
        nw.lpLocalName:=nil;
        nw.lpRemoteName:='\\IP';
        nw.lpProvider:=nil;
        Начинаем enumerating
        Type
        pnetar=^netar;
        netar=array [0..64] of tnetresource;
        var
        Dwresult:integer;//код ошибки
        Henum:thandle;
        lpnrLocal:pnetar;
        dwNumEntries:cardinal;
        s:string;
        begin
          lpnrLocal:=@netrrr;// так проще будет вынимать ресурсы.
          DwNumEntries:=64;//кол-во ресурсов которые мы сможем принять.
          dwResult:=WNetOpenEnum(
            RESOURCE_GLOBALNET,
            RESOURCETYPE_DISK,
            0,
            @nw,
            henum //наш хендл
            );
          if dwResult=no_error then
          begin

            repeat
            dwResult:=WNetEnumResource(
              hEnum,
              dwNumEntries,
              lpnrLocal,//здесь и будут наши ресурсы.
              dwBufferSize
              );

            if dwResult=no_error then
            begin
              for dwIndex:=0 to dwNumEntries-1 do
              begin
              s:= (lpnrlocal^)[dwindex].lpRemoteName;
              //это и есть наш ресурс.
              end;
            end;
            //повторяем пока не исчерпаем все ресурсы.
            until dwResult=ERROR_NO_MORE_ITEMS;

          end;
          end;
          WNetCloseEnum(hEnum); //незабываем закрывать хендл.
        end;

      ПОДСОЕДИНЕНИЕ К РЕСУРСУ:

     Теперь    следующая   задача   подключение   к   ресурсу   фун-ция:
WNetAddConnection2   В  winapi  существует  несколько  модификаций  этой
функции,  например  фун-ция  WnetAddConnection3  позволит  вам  показать
пользователю  стандартный диалог подключения ресурса. Но в данном случае
нам просто надо подключить ресурс. Аналогично заполняем структуру:

        nw.dwScope:=0
        nw.dwType:=RESOURCETYPE_DISK; // нам нужны только дисковые ресурсы.
        nw.dwUsage:=0
        nw.lpLocalName:=nil;
        // здесь можно указать имя локального диска, на который будет
        //примонтирован ресурс , но нам это не нужно.
        nw.lpRemoteName:='\\IP\resource'; //тут уже пишем удаленный ресурс,
        полученный например с помощью функций wnetenum*
        nw.lpProvider:=nil;
        //пробуем подключиться указав логин и пароль (username and pass)
        Err:=WNetAddConnection2(nw,pass,username,0);
        //Или можно так когда мы не знаем логина и пароля , и пытаемся
        законектиться с пустым паролем. Имя //будет использоваться то с которым
        вы залогинились в системе.
        Err:=WNetAddConnection2(nw,nil,nil,0);

     Более  подробное  описание  по последнему параметру и использованию
логинов  и  паролей  смотрите  msdn.Также  на NT системах если вы имеете
права   администратора  домена  1  способом  возможно  подключать  любые
ресурсы, но это конечно зависит от конкретных настроек системы.

     Также  скажу  ,  что подключаться к ресурсу не обязательно: функции
копирования  в  winapi  позволяет  копировать  сразу с ресурсов тоесть с
\\ip\resource\file.ext

     Но подключаться нужно в тех случаях когда у ресурса есть пароль или
другой логин для доступа.

      ИСПОЛЬЗОВАНИЕ РЕСУРСОВ, РАБОТА С ФАЙЛАМИ И ДИРЕКТОРИЯМИ:

     Ну  и  последнее:  использование  ресурса.Вот  здесь  действительно
понимаешь  глобальность  и удобство winapi и сетевого стека win( хотя на
*nix  покруче  конечно;)  ).Любые  функции  работы  с файлами (открытые,
закрытие,  запись,  поиск итд) без проблем работают с удаленными файлами
(UNC) вида

      \\ip\resource\file.ext. То есть чтобы например скопировать файл
      autoexec.bat достаточно написать

      Copyfile('\\ip\c\autoexec.bat','c:\1.bat',0);

      СОБСТВЕННО РЕАЛИЗАЦИЯ, NESSUS НАМ В ПОМОЩЬ:

     В  качестве примера реализации собственного стека протокола отсылаю
на www.nessus.org.

     В   этом   сканере  есть  plugins(nessus-plugins-1.0.7-1.i386.rpm),
реализующие  практически все нужные функции. Они поставляются в исходных
кодах, на языке подобном перлу,и поэтому переделать под ваш любимый язык
программирования не составит труда.

      smb_accessible_shares.nasl (проверка на доступ R или RW)
      smb_enum_shares.nasl (получения списка ресурсов)
      smb_login.nasl (обычный логин)
      smb_login_as_users.nasl
      netbios_name_get.nasl (получение netbios имен хоста, использование в
      Delphi описано ниже)
      smb_bruteforce_pass.nasl (это самый интересный наверно ;) подбор
      паролей аналогично pqwak , 5-10 минут для 8 значного пароля)

      ... и много других тоже интересных

     Итак  к  примеру  нам  нужно  получить  нетбиос имена по IP хоста.В
поставке    windows   есть   стандартная   консольная   программка   для
этого-nbtstat.

      Вот пример запроса:

        Адрес IP узла: [200.0.0.2] Код области: []
        Таблица NetBIOS-имен удаленных компьютеров
        Имя Тип Состояние
        ----------------------------------------------------
        LMTA <00> UNIQUE Зарегистрирован
        WORKGROUP <00> GROUP Зарегистрирован
        LMTA <20> UNIQUE Зарегистрирован
        Адрес платы (MAC) = 02-00-4C-4F-4F-50

     Типов  этих  достаточно  много, но наиболее интересным является для
нас   03  который  обозначает  запущенный  сервис  shared  files.(Полное
описание  можно  посмотреть  к примеру в ENT3 или Languard) Также как вы
заметили   мы  можем  узнать  MAC  адрес  сетевого  интерфейса  машины и
определить например dialup это или eth адаптер.

      ПОЛУЧЕНИЕ NETBIOS ИМЕНИ ХОСТА:

     Далее      следует     переработанный     под     Delphi     плугин
(netbios_name_get.nasl)   из   nessus.   Отличается   от   оригинального
возвращением  только  имени  хоста, и возможностью указания таймаута для
соединения.

      function getname(host:string;timeout:Integer;addstr:string):string;
      var
      err,soc,subloc,name_copy,loc,name_count,num_of_names,
      location,res,netbios_len,group_found:Integer;
      name,sendata,candidate,r,hole_data,hole_answer:string;
      buf:array [1..4096] of Char;
      hostname_found:boolean;
      sockset:TFDSet;
      timeval:ttimeval;
      begin

        Result:='';
        try
        logsys(addstr+'Trying get name for host '+host);
        NETBIOS_LEN := 50;
     //пакет  запроса вот в такой форме ;) если захочется узнать , что в
полях пакета
     // читайте описание на протокол.
          sendata := raw_string([
          $01, $F8, $00, $10, $00,
          $01, $00, $00, $00, $00,
          $00, $00, $20, $43, $4B,
          $41, $41, $41, $41, $41,
          $41, $41, $41, $41, $41,
          $41, $41, $41, $41, $41,
          $41, $41, $41, $41, $41,
          $41, $41, $41, $41, $41,
          $41, $41, $41, $41, $41,
          $00, $00, $21, $00, $01
          ]);
        hostname_found := false;
        group_found := 0;
        candidate := '';
        Result:='';
        //открываем не блокирующий сокет.
        soc := open_sock_udp(host,137);
        if soc=invalid_socket then
        begin
              logsys(addstr+'Cant get host name (error alloc sock) '+host);
              Exit;
        end;

        zeromemory(@buf,4096);
        sockset.fd_count:=1;
        sockset.fd_array[0]:=soc;
        timeval.tv_sec:=0;
        timeval.tv_usec:=timeout*1000;
                                 //timeout задается мс поэтому умножаем
        err:=select(0,nil,@sockset,nil,@timeval);
                                 //ждем завершения коннекта, для
        Udp не критично

        if err<>1 then
        begin
             closesocket(soc);
             if err=0 then logsys(addstr+'Cant get host name (timeout conn)
        '+host);
             if err=-1 then logsys(addstr+'Cant get host name (send error)
        '+host);
             Exit;
        end;

        send(soc, sendata[1], netbios_len,0);//посылаем наш пакет.
        zeromemory(@buf,4096);
        sockset.fd_count:=1;
        sockset.fd_array[0]:=soc;
        timeval.tv_sec:=0;
        timeval.tv_usec:=timeout*1000;
        err:=select(0,@sockset,nil,nil,@timeval);
                                        //ждем пока придут какие либо
        данные

        if err<>1 then
        begin
             closesocket(soc);
             if err=0 then logsys(addstr+'Cant get host name (timeout) '+host);
             if err=-1 then logsys(addstr+'Cant get host name (socket error)
        '+host);
             Exit;
        end;
        res := recv(soc,buf,4096,0);// получаем ответ.
        err:=WSAGetLastError;
        if res<=0 then
        begin
             closesocket(soc);
             logsys(addstr+'Cant get host name (recv error '+IntToStr(err)+' )
        '+host);
             Exit;
        end;
        closesocket(soc);
        r:=string(buf);setlength(r,res);
      {переводим буфер в строку, в плугинах nessus используется
      вместо обычных массивов.}
      {теперь собственно разбор, оставлю без пояснений.
      decodedostowin используется потому, что русские имена приходят в dos
      кодировке.Но учтите во все функции куда вы будете передавать это имя
      нужно оставлять в той-же досовской кодировке.
      remsp удаляет пробелы в конце строки}

        if r<>'' then
        begin
        hole_answer := '';
        hole_data := r;
        location := 0;
        location := location + 56;
        num_of_names := ord(hole_data[location+1]);
        logsys(3,st_comp,addstr+'Found '+IntToStr(num_of_names)+' names on host
        '+host);
        location := location + 1;
        hostname_found:=False;
        for name_count:=0 to num_of_names-1 do
        begin
        name:='';
        for name_copy:=0 to 14 do
        begin
        loc := location+name_copy+name_count*18;
        end;
        loc := location+16+name_count*18;
        if(hole_data[loc+1] = raw_string([68])) then
        begin
        subloc := location+15+name_count*18;
        if(ord(hole_data[subloc+1])=32) then
        begin
        if(not hostname_found) then
        begin
        result:=remsp(Name);
        hostname_found := true;
        xlogsys(3,st_comp,addstr+'Name for host '+host + ' is '+
        Result+ ' (' +decodedostowin(result)+')');
        Exit;
        end;
        end
        else
        begin
        if(ord(hole_data[subloc+1])=0) then
        begin
        candidate := name;
        if(not ( name <> '~')) then
        begin
        if(not hostname_found) then
        begin
        Result:=remsp(Name);
        hostname_found := true;
        logsys(addstr+'Name for host '+host+' is '+result+'
        ('+decodedostowin(result)+')');
        Exit;
        end;
        end;
        end;
        end;
        end;
        if (hole_data[loc+1] = raw_string([4])) then
        begin
        subloc := location+15+name_count*18;
        if (hole_data[subloc+1] = raw_string([0])) then
        begin
        if( not hostname_found) then
        begin
        Result:=remsp(Name);
        hostname_found := true;
        logsys(addstr+'Name for host '+host+' is '+result+'
        ('+decodedostowin(result)+')');
        Exit;
        end;
        end;
        end;

        end;
        end;
        xlogsys(3,st_comp,addstr+'Cant get host name '+host);
        except

      end;

      //вспомогательная функция конвертирующая массив байт в строку.
      function raw_string(const a:array of byte):string;
      var
      i:Integer;
      ret:string;
      begin
      ret:='';
      for i:=0 to high(a) do
      begin
      ret:=ret+chr(a[i]);
      end;
      Result:=ret;
      end;

      ЗАКЛЮЧЕНИЕ И ССЫЛКИ:

     Естественно  использование  netbios  протокола  не заканчивается на
использовании расшаренных дисков, то что с ним сделали ребята из MS даст
вам работы на многие ночи вперед и быть может скоро найденная вами дырка
появиться в новостях багтрака.

     В заключение приведу несколько интересных ссылок по данной теме.

      Документация:

      MSDN
      http://msdn.microsoft.com
     Здесь  можно  найти  как описание winapi функций так и сам протокол
netbios.  Только  они  его  переименовали  и стали называть CIFS (common
internet file system)

      Nessus project
      http://www.nessus.org
     Это  очень хороший сканер безопасности для *nix систем, в том числе
и  netbios  уизвимостей.  Его  плугины поставляются в исходном коде, что
очень может помочь вам.

      Программы:
      Pandora ultimate scanner
      http://www.bethoven.f2s.com
      http://bethoven.pisem.net

     Это   мой  сайт  на  котором  ведется  разработка  нетбиос  сканера
Pandora.Он  имеет  множество  уникальных  возможностей, перечислю только
несколько:

     Полный автоматизм работы,укажите диапазоны IP все остальное Pandora
сделает сама.
     Автоматическое копирование файлов с расшаренных ресурсов.
     Автоматический подбор пароля анлогично pqwak.
     Работа в скрытом режиме как backdoors.
     Полный remote administrative control.
     и многое, многое другое.

      LANguard Network Scanner
      http://www.gfi.com/nsnetscan.shtml
     Этот  сканер хорош тем что дает возможность получать информацию обо
всех  ресурсах,  подключаться  указывая логин и пароль.А также проверять
открытые порты, тип операционной системы и делать snmp walk.

      ENT (Essential NetTools)
      http://www.tamos.com
     Довольно  шустро  получает  имена  хостов.Лучший  способ  проверить
правильно  ли  настроен  у  вас  netbios.  Также  встроена поддержка NAT
(network  auditing tool) порт с *nix утилиты, которая может подключаться
к ресурсам перебирая логины, и пароли из вордлиста.

      Contacts:
      mail:
      [email protected]
      [email protected]
      website:
      www.bethoven.f2s.com
      2001 (c) Bethoven