Pull to refresh

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

Reading time4 min
Views21K
Ни для кого не секрет, что технология 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
Tags:
Hubs:
+8
Comments8

Articles