Повышение безопасности сервера RemoteApp

от автора

Ни для кого не секрет, что технология RemoteApp внедрённая в Windows 2008 это ответ Microsoft технологиям доступа к приложениям компании Citrix. Всё бы ничего, но для использования данной технологии в повседневной жизни, без наличия RD Gateway, нужен открытый наружу RDP Port tcp/3389. Наблюдая за своими терминальными серверами, я обнаружил что сервера постоянно подвергаются brute-force атакам подбора паролей различных пользователей.
Дабы не испытывать судьбу я немного модифицировал схему доступа к RDP.

Так как сервера в большинстве случаев находятся за роутером с которого пробрасывается порт на терминальный сервер, сделаем ход конём и будем динамически открывать порт 3389 для тех, кто корректно авторизовался.
Для этого правим файл Windows\Web\RDWeb\Pages\Default.aspx, добавляя ему внутрь некоторый новый функционал.

    void goToFolder(string getLangVal)     {         Response.Redirect(getLangVal + "/Default.aspx" + Request.Url.Query,true);     }      private float getInternetExplorerVersion()     { // Returns the version of Internet Explorer or a -1 // (indicating the use of another browser).     float rv = -1;     System.Web.HttpBrowserCapabilities browser = Request.Browser;     if (browser.Browser == "IE")       rv = (float)(browser.MajorVersion + browser.MinorVersion);     return rv;     }      void Page_Load(Object sender, EventArgs e)     { 	string UserIPAddress = Request.ServerVariables["REMOTE_ADDR"]; 	string UserName = Request.ServerVariables["AUTH_USER"]; 	string safeString = System.Security.SecurityElement.Escape(UserName);  	string url = "http://myrouter/cgi-bin/open.cgi?ip=" + UserIPAddress + "&user=" + safeString ; 	HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);             request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";             request.AllowAutoRedirect = false;             request.KeepAlive = true;             HttpWebResponse response = (HttpWebResponse)request.GetResponse();   	double ver = getInternetExplorerVersion(); 	if (ver > 0.0) 		{ 			if (ver < 7.0)  			Response.Redirect("TSWeb/Default.asp",true);  		} 	else 		{ 			Response.Redirect("Unsupported/Default.asp",true); 		}        string langCode = null;       System.Globalization.CultureInfo culture;        // For each request initialize the culture values with       // the user language as specified by the browser. 

При загрузке страницы портала со списком Remote Application используется внутренняя аутентификация iis. Вышеуказанный скрипт выполнится только в случае корректной авторизации.

На роутере устанавливаем «net-mgmt/pftabled».
создаём ключ

dd if=/dev/random bs=20 count=1 | md5 | cut -c 1-19 > /etc/pftabled.key 

и активируем сервис в rc.conf

pftabled_enable="YES" pftabled_flags="-d -k /etc/pftabled.key -t 432000" 

Далее поднимаем thttpd и создаём в cgi-bin скрипт open.cgi

#!/usr/bin/perl  use strict; use warnings; use CGI qw/:standard/; use IO::Socket; use Digest::HMAC_SHA1 qw(hmac_sha1); use Net::SMTP;  use vars qw/%macs $pftabled $key %mac_ip/;  use constant PFTBLPORT => 56789; use constant pfip => "127.0.0.1";  use constant PFTBLVERSION => 2; use constant PFTABLED_CMD_ADD => 1; use constant PFTABLED_CMD_DEL => 2; use constant PFTABLED_CMD_FLUSH => 3; use constant PFTBLCOMMAND => 1; use constant PFTBLMASK => 32; use constant SHA1_DIGEST_LENGTH => 20; use constant PFTBLNAME => "RDP"; my $keyfile = "/etc/pftabled.key";  if (! -r $keyfile) {   print STDERR "Cannot Read KeyFile $keyfile\n";   exit 1;   } open(KEY, "<$keyfile");   sysread KEY, $key, SHA1_DIGEST_LENGTH; close KEY;  $pftabled = IO::Socket::INET->new(Proto     => 'udp',   PeerPort  => PFTBLPORT,   PeerAddr  => pfip)   or die "Creating socket: $!\n";  #prepare struct for pftabled    my $command = '1';   my $iparray = param("ip"); #print @iparray;   my $addr = inet_aton($iparray);   my $time = time();   my $block = pack("C1 S1 C1",PFTBLVERSION,$command,PFTBLMASK).$addr.pack("a32 N*",PFTBLNAME,$time);   my $digest = hmac_sha1($block, $key);   $block .= $digest;   $pftabled->send($block);   print header();       my $smtp = Net::SMTP->new('mysmtpserver.mydomain.ru');     $smtp->mail('terminal_guard@mydomain.ru');     $smtp->to('account_admin@mydomain.ru');     $smtp->data();     $smtp->datasend("To: account_admin\@mydomain.ru\n");     $smtp->datasend("Subject: Terminal server logon detected\n");     $smtp->datasend("\n");     $smtp->datasend("User ".param("user")." logged on from ".param("ip")."\n");     $smtp->dataend();     $smtp->quit; exit(0);  

Теперь можно поправить конфигурацию pf.

external_addr="1.1.1.1" terminal_server_addr="192.168.1.1" table <RDP> persist {  } rdr on $ext_if proto tcp from <RDP> to $external_addr port 3389 -> $terminal_server_addr port 3389 # terminal pass in on $ext_if proto tcp from <RDP> to { $external_addr, $terminal_server_addr } port { 3389 } flags S/SA keep state 

При удачной аутентификации скрипту передаются имя зашедшего пользователя и IP адрес с которого осуществлялся запрос. Информация о IP адресе помещается в таблицу RDP и пользователь получает доступ к RDP подключению.
Включить windows аутентификацию на RDP сервере можно в файле C:\Windows\Web\RDWeb\Pages\Web.config

При желании можно задействовать custom errorpages и таким же образом блокировать адреса злоумышленников при нескольких неудачных попытках ввода логина пароля. Правда могут быть FP. Но без этого никуда не денешься.

© Aborche 2013

ссылка на оригинал статьи http://habrahabr.ru/post/176657/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *