avatar Windows Журнал успешных входов пользователей в систему (Windows) и запись в MySQL(Linux)

Тут недавно, мне потребовалось, вести статистику какие пользователи и где входят в систему, вот стукнуло руководству в голову мысль из серии: «А давайте, будем ВСЕ записывать!», ну все так все, а что конкретно не знает, быстро загуглив и не найдя, готового решения, пришлось написать свой велосипед. В общем я решил поделиться собственной наработкой с общественностью, думаю что не я один с такой проблемой столкнулся.
Средства операционной системы Windows позволяют это делать, через настройку аудита успеха, но проблема в том что руководство хотело все это видеть в упрощенном виде и загонять генерального детектора в увлекательное чтение журналов системы, мне совершенно не хотелось.
На основной работе у нас реализовано через MSSQL, правда там реализовано все по другому принципу, все работает довольно надежно и позволяет выяснить какой пользователь когда и где заходил в систему т.е. записывается -дата, время, имя машины, логин. Это сильно облегчает жизнь при расследовании инцидентов, хоть и не часто, но они случаются, тут проблема в том что MSSQL стоит, сказать честно, «дохренища денег»…
Да и контора, которую я поддерживаю намного меньше, чем моя основная работа и ради ведения журналов покупать MSSQL не имеет смысла, а ставить без лицензии, тоже не правильно, т.к. возможностей MySQL и PHP тут хватит за глаза, а кому их покажется мало, можно все это перевести на PostgreSQL, но это уже сами.
В начале проконсультировавшись с коллегами, как это лучше реализовать, мне сказали что нужно ставить curl, он отлично отправляет данные, но это требует установки дополнительного софта, чего мне делать не хотелось и я добился того чтобы все работало используя штатные средства операционной системы Windows, а именно VBS.

Что требуется получить на выходе:
Собственно задача, поднять Web сервер, на котором можно установить Nginx + PHP5-FPM + MySQL.
В качестве примера, настройки WEB сервера NGINX, можно воспользоваться статьей: Настройка Nginx с поддержкой PHP-FPM
Ну а для установки phpMyAdmin, посмотрите статью: Установка phpMyAdmin на Nginx

Как все это будет работать
Есть WEB сервер, на котором работает СУБД, также там установлен Nginx, и один php скрипт, который принимает внешние параметры, а именно host -имя системы где заходит пользователь и логин пользователя, все остальные данные, а именно, дата, время, будут добавляться самой MySQL, при условии что часы, на сервере Linux, синхронизированны с контроллером домена, чтобы в записях не было расхождения во времени.
сервер принимает запросы вида:
logsrv.example.org\log.php?host=%hostname%&user=%username%

Думаю что, из названия переменных понятно, за что они отвечают.
Пользователю, входящему в систему, в logon_script мы засунем наш маленький VBS скрипт, который отправит данные на сервер, php скрипт их примет и сохранит в базе данных, откуда их потом можно извлечь и использовать по своему усмотрению.

Ну и переходим к реализации.
Для начала создадим базу данных и таблицу в ней, чтобы не взрывать мозг, я ее назвал test, а фигли… ;)
Ну и создал таблицу, я ее назвал userlog со следующими полями:
CREATE TABLE IF NOT EXISTS `userlog` (
  `date` date NOT NULL,
  `time` time NOT NULL,
  `host` varchar(50) NOT NULL,
  `user` varchar(50) NOT NULL,
  `client_ip` varchar(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;


Где есть следующие поля:
date — Дата (заполняется MySQL сервером)
time — Время (заполняется MySQL сервером)
host — Имя машины где зашел пользователь (передается скриптом с рабочей станции)
user — Логин пользователя (передается скриптом с рабочей станции)
client_ip -IP адрес рабочей станции (передается php скриптом на WEB сервере)

Столько полей было сделано для того чтобы можно было делать выборку по разным параметрам, по времени, по дате, по пользователю, или по IP, а может и сразу по нескольким.
Переходим к нашему php скрипту:
<?php
//адрес хоста
$dbhost = 'localhost';
//Имя пользовтаеля
$dbuser = 'test';
//пароль для подключения к Mysql
$dbpass = 'password';
//имя базы данных
$dbname = 'test';
// сохраняем IP на всякий случай
$client_ip = $_SERVER['REMOTE_ADDR'];
// получение значения переменной hostname
$host = $_GET["host"];
// получение значения username
$user = $_GET["user"];

//устанавливаем подключение к MySQL
$connect = mysql_connect($dbhost, $dbuser, $dbpass);
// проверяем состояние подключения
if(! $connect )
{
  die('Could not connect: ' . mysql_error());
}
// Выбираем базу данных
mysql_select_db ($dbname, $connect);

//Отправляем данные в таблицу
$sql = "INSERT INTO userlog VALUES (NOW(), NOW(), '$host', '$user', '$client_ip')";

// проверяем состояние отправки
if(!mysql_query($sql))
{echo '<p><b>Data upload error!</b></p>';}
else
{echo '<p><b>OK</b></p>';}
// закрываем соединение с базой
mysql_close($connect);
?>

Те кто периодически читает мои статьи уже догадались, что этот скрипт является доработанной версией из статьи: Собираем статистику изменений температуры и влажности с помощью Arduino и записываем ее в MySQL Так что старые наработки продолжают жить и дальше… :)

Ну и теперь VBS скрипт, который будет отправлять данные в таблицу, выполняя GET запрос.
Dim userLog
Set wshNetwork = WScript.CreateObject( "WScript.Network" )
strComputerName = wshNetwork.ComputerName
strUserName = wshNetwork.UserName

Set userLog = CreateObject("MSXML2.XMLHTTP")
userLog.open "GET", "http://logsrv.example.org/log.php?host=" & strComputerName & "&user="& strUserName, False
userLog.send


Где:
httр://logsrv.example.org -адрес сервера который ведет логи
log.php -скрипт который принимает запрос и отправляет его в MySQL
host=" & strComputerName & — переменная которая определяет имя машины
user=" & strUserName — переменная которая определяет логин пользователя
Я не буду расписывать значение переменных, думаю что имена говорят сами за себя.
Собственно, засовываем данный скрипт, чтобы он запускался при входе пользователя в систему. После этого наслаждаемся результатом.
Таблица будет иметь вид:
таблица MySQL

На основной работе, у нас 2 домена в лесу и необходимо записывать помимо логина, еще и имя домена в котором находится учетная запись пользователя т.к. пользователь с логином Ivanov может быть например в домене contoso.com и совершенно другой пользователь в домене vladivostok.contoso.com
чтобы запись имела вид contoso/ivanov или vladivostok/ivanov для реализации этой задачи я немного модифицировал VBS скрипт:
Dim userLog
Set wshNetwork = WScript.CreateObject( "WScript.Network" )
strDomain = wshNetwork.UserDomain
strComputerName = wshNetwork.ComputerName
strUserName = wshNetwork.UserName

Set userLog = CreateObject("MSXML2.XMLHTTP")
userLog.open "GET", "http://logsrv.example.org/log.php?host=" & strComputerName & "&user="& strDomain & "/" & strUserName, False
userLog.send

Тогда записи в таблице принимают вид:


Думаю, данная наработка, окажется полезной. Пользуйтесь…
Если возникли вопросы, то прошу в комментарии, если нашли ошибку, то стучитесь в личку.

18 комментариев

avatar
Спасибо за скрипт, работает на ура!
Но тут такой вопрос появился, а можно как то добавить в этот скрипт возможность показывать IP внешней машины?
У меня есть сервер RDP, он находиться за NAT в проксе и когда я захожу на RDP то у меня скрипт отправляет IP прокси, а не самой машины.
Заранее спасибо!
avatar
Вы хотите получить IP адрес клиента подключающегося по RDP в серверу?
avatar
да, только бы желанельно внешний, если это возможно.
А то в друг он за роутером седит и у него 192.168.0.*
avatar
Думаю что в такой ситуации, нужно заходить со стороны шлюза т.к. даже netstat на сервере терминалов покажет что соединения с ним, идут от NAT, а не с внешних IP адресов.
avatar
У NAT именно такая задача…
avatar
На всякий случай немного переписал скрипт, чтобы комп сам передавал свой IP адрес, а не сервер брал адрес отправителя пакета.
VBS
Dim userLog
strcomputer = "."
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery ("Select * From Win32_NetworkAdapterConfiguration Where IPEnabled = True")
Set wshNetwork = WScript.CreateObject( "WScript.Network" )

for each objitem in colitems

strComputerName = wshNetwork.ComputerName
strUserName = wshNetwork.UserName


strIPAddress = Join(objitem.IPAddress, ",")


Set userLog = CreateObject("MSXML2.XMLHTTP")
userLog.open "GET", "http://logsrv.example.org/log.php?host=" & strComputerName & "&user="& strDomain & "/" & strUserName & "&ip=" & strIPAddress, False
next
userLog.send


Тогда скрипт PHP Будет иметь вид:
<?php
//адрес хоста
$dbhost = 'localhost';
//Имя пользовтаеля
$dbuser = 'test';
//пароль для подключения к Mysql
$dbpass = 'password';
//имя базы данных
$dbname = 'test';
// сохраняем IP на всякий случай
$client_ip = $_GET["ip"];
// получение значения переменной hostname
$host = $_GET["host"];
// получение значения username
$user = $_GET["user"];

//устанавливаем подключение к MySQL
$connect = mysql_connect($dbhost, $dbuser, $dbpass);
// проверяем состояние подключения
if(! $connect )
{
  die('Could not connect: ' . mysql_error());
}
// Выбираем базу данных
mysql_select_db ($dbname, $connect);

//Отправляем данные в таблицу
$sql = "INSERT INTO userlog VALUES (NOW(), NOW(), '$host', '$user', '$client_ip')";

// проверяем состояние отправки
if(!mysql_query($sql))
{echo '<p><b>Data upload error!</b></p>';}
else
{echo '<p><b>OK</b></p>';}
// закрываем соединение с базой
mysql_close($connect);
?>


З.Ы. Я его не тестировал, но ошибок, вроде, не выдает при запуске… ;)
avatar
ок, спасибо, сейчас попробую отпишу.
да кста ти, с праздничком :)
avatar
Выдало вот такой ответ:

time host user client_ip
16:08:15 CA /Администратор 192.168.15.159

****
192.168.15.* — это имя IP моего сервера
— сеть очень простая.
I-net -> Linux (Ipitables (NAT)) -> 192.168.15.159
— 1. первый скрипт выдавал внешний адрес Linux
2. сейчас выдаёт адрес самого сервера к которому подключались.
avatar
Ну у вас ведь скрипт на сервере терминалов работает?! Так что все правильно.
avatar
ето да, есле бы он ещё и внешние IP снимал, цены бы не было иму ;)
avatar
ну, чисто технически, RDS сервер не видит внешние IP, так что, без вариантов, тут только крутить NAT
avatar
ок, спасибо, будем пробовать
avatar
Народ подскажите что исправить в скрипте чтобы при его выполнение отображалось кто и восколько входил в систему (пк в домене), но нужно чтобы показывало залогиненых локальных и доменных юзеров! Спасибо!
avatar
Так в статье есть пример с двумя доменами:
На основной работе, у нас 2 домена в лесу и необходимо записывать помимо логина, еще и имя домена в котором находится учетная запись пользователя т.к. пользователь с логином Ivanov может быть например в домене contoso.com и совершенно другой пользователь в домене vladivostok.contoso.com
чтобы запись имела вид contoso/ivanov или vladivostok/ivanov для реализации этой задачи я немного модифицировал VBS скрипт:

Dim userLog
Set wshNetwork = WScript.CreateObject( "WScript.Network" )
strDomain = wshNetwork.UserDomain
strComputerName = wshNetwork.ComputerName
strUserName = wshNetwork.UserName

Set userLog = CreateObject("MSXML2.XMLHTTP")
userLog.open "GET", "http://logsrv.example.org/log.php?host=" & strComputerName & "&user="& strDomain & "/" & strUserName, False
userLog.send

Чтобы отображались пользователи которые заходят локально, нужно сделать так чтобы скрипт выполнялся через локальные политики безопасности в дополнение к доменным, так что при таком раскладе скрипт пилить нет необходимости.
avatar
А вы не реализовывли задачу писать логи аудита?
Кто и когда, создал или удалил файл или папку?
Т.е в читабельном виде?
avatar
У Microsoft была какая-то тулза, которая показывает логи в читабельном виде, но давно не сталкивался уже и не помню.
Хотя у нас было самописное решение на IIS + ASP + MSSQL в которое складывались логи аудита
avatar
Было бы интересно посмотреть
avatar
не могу показать, соглашение о неразглашении…
Есть что добавить? Регистрируйся и оставляй комментарии!