📜 ⬆️ ⬇️

Kaspersky Security Center - the struggle for automation

Oddly enough, I found on Habré just one article on this subject - and that one in the sandbox and a heavily unfinished, actually containing in itself a small piece of slightly altered product reference. Yes, and Google on request klakaut is silent.

I'm not going to tell you how to administer the hierarchy of Kaspersky Security Center (hereinafter referred to as KSC) from the command line — I haven't needed it yet. I just want to share some thoughts about automation with those who may need it, and I’ll take one case I’ve had to deal with. If you,% habrauser%, this topic will be interesting - welcome under cat.

Historically, as a means of anti-virus protection at work, I prefer Kaspersky Lab products (hereinafter referred to as LC). The reasons and other sacred wars of personal opinions, perhaps, leave behind the scenes.

Naturally, I would like to centrally deploy, protect, shield, and not let out to draw beautiful graphics, integrate into existing monitoring systems, and deal with shifting work from a sore head to a healthy server. And if with deployment and protection everything is more or less in order (LC even has some online courses on products ), then with integration it is already much sadder: in the latest version of KSC 10.2.434 at the moment, there was integration with two SIEM: Arcsight and Qradar. That's all.
')
For integration into something your KSC provides already 2 interfaces:


On both points there is documentation in the KSC, as it is indicated in the articles to which I have given links. True, this documentation raises a number of questions that can be asked to the support service of corporate products of CompanyAccount and get an answer like “Clarified information. Unfortunately, there is no script support for klakaut. ”

The cons of klakdb are obvious: in order to directly access the database, you need to have access to this database, which leads to the need for extra gestures to create access rules in firewalls, setting access rights on DBMS servers and other extremely unattractive pastime. Well, plus monitoring the relevance of all these rules, of course. It becomes especially interesting when there are 20+ servers - and all in different branches, each with its own administrators.

Well, the cherries on this cake: access only Read Only and, to put it mildly, incomplete information about the environment. The advantages are not so obvious, but they are also there: you can download statistical information on the number of hosts, versions of antiviruses and anti-virus databases very quickly, and most importantly, you can work very conveniently (depending on SQL knowledge) with events registered on the KSC .

klakaut in this regard is much more interesting: having connected to the root server of the hierarchy, it is possible by means of the KSC itself to walk through this hierarchy and get access to all the necessary data. For example, build a tree of KSC servers with a note, which of them is alive and who is not, start tasks, move computers and give free rein to fantasy.

Cons, too, of course: long and difficult. If you need to collect some statistics, you will first need to write a script for a long time, and then catch bugs for a long time, wait for it to work.

Naturally, no one forbids (at least I don’t know about it) using both mechanisms together: for example, go through the server hierarchy using klakaut, get a full list of KSC servers with information about the databases used, and then transfer this information to more others automation tools that remove outdated rules from firewalls, create new ones, give access permissions and bring coffee to bed, edit the list of data sources in your monitoring system, which in turn polls the list and detects by making any deviations, with klakaut will do something good. Well, or just register the incident in the tracker. Then the administrators will do something good in manual mode.

Inspired by all these considerations, I wrote my first script:

Here he is
 $Params = New-Object -ComObject 'klakaut.KlAkParams'; $Params.Add('Address', 'localhost:13000'); $Params.Add('UseSSL', $true); $Proxy = New-Object -ComObject 'klakaut.KlAkProxy'; try { $Proxy.Connect($Params); $Proxy.Disconnect(); } catch { $_; } Remove-Variable -Name 'Params'; Remove-Variable -Name 'Proxy'; 


And run it on the server:

 Exception calling "Connect" with "1" argument(s): "Transport level error while connecting to http://localhost:13000: authentication failure" At line:7 char:5 + $Proxy.Connect($Params); + ~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : ComMethodTargetInvocation 

The start is good.

Hostess note
If you use js, this error does not occur. I wonder why.

Having opened the KSC console, I made sure that everything is in order with my rights.

Unfortunately, KSC does not log failed login attempts. Correspondence with the vendor showed that logging failed login attempts could be enabled (it was a separate fascinating story, which, by the way, was not over yet), but this particular attempt refused to get into the logs anyway.

It would seem that you can do this:

Wrong script
 $ Params = New-Object -ComObject 'klakaut.KlAkParams';
 $ Params.Add ('Address', 'localhost: 13000');
 $ Params.Add ('UseSSL', $ true);

 # ------------ We set explicitly the login data ------------------------------ -
 $ Params.Add ('User', 'kavadmin');
 $ Params.Add ('Password', 'P @ ssw0rd');
 $ Params.Add ('Domain', 'test');
 # ------------------------------------------------- ----------------------------------

 $ Proxy = New-Object -ComObject 'klakaut.KlAkProxy';
 try {
     $ Proxy.Connect ($ Params);
     $ Proxy.Disconnect ();
 }

 Remove-Variable -Name 'Params';
 Remove-Variable -Name 'Proxy';


In this case, there will be no errors, but it did not seem to me a great idea to specify a login with a password in clear text in the script. New correspondence with tech support LC gave me the following recommendation:

It is necessary to set in the settings of COM, in the tab Default Properties:
Default Authentication Level: Packet
Default Impersonation Level: Delegate

This instruction made the original script work, but it seemed to me dubious in terms of security, so I decided to dig a little deeper. After some time searching, I found a kind person who told me how to set the specified levels of authentication and impersonation for a particular object, rather than allowing everyone and everything at once:

Correct script
 $ Params = New-Object -ComObject 'klakaut.KlAkParams';
 $ Params.Add ('Address', 'localhost: 13000');
 $ Params.Add ('UseSSL', $ true);

 $ Proxy = New-Object -ComObject 'klakaut.KlAkProxy';

 $ code = @ "
 using System;
 using System.Runtime.InteropServices;

 public class PowershellComSecurity
 {
    [DllImport ("Ole32.dll", CharSet = CharSet.Auto)]
    public static extern int CoSetProxyBlanket (IntPtr p0, uint p1, uint p2, uint p3, uint p4, uint p5, IntPtr p6, uint p7);

    public static int EnableImpersonation (object objDCOM) {return CoSetProxyBlanket (Marshal.GetIDispatchForObject (objDCOM), 10, 0, 0, 0, 3, IntPtr.Zero, 0);  }
 }
 "@
 Add-Type -TypeDefinition $ code;
 Remove-Variable -Name 'code';

 [PowershellComSecurity] :: EnableImpersonation ($ Proxy) |  Out-null;

 try {
     $ Proxy.Connect ($ Params);
     # <- here we will insert the code
     $ Proxy.Disconnect ();
 } catch {
     $ _;
 }

 Remove-Variable -Name 'Params';
 Remove-Variable -Name 'Proxy';


So the script did not issue any errors. The first quest is completed.

Hostess note
In general, in a combat environment, it would be nice to check the return value for errors when calling EnableImpersonation, and not to redirect it to nowhere, as I did.

The next task is to obtain from the KSC data on the database used.

But here everything is complicated: the documentation on how to do this is silent. The study of the KlAkProxy class did not reveal anything interesting, except for the parameter KLADMSRV_SERVER_HOSTNAME, which turned out to be the identifier of the computer on which KSC is installed.

Then we go to the computer, for this there is a special class KlAkHosts2. To reduce the amount of code, I will cite only the contents of the try block:

try block
 try {
     $ Proxy.Connect ($ Params);
     $ KSCHost = New-Object -ComObject 'klakaut.KlAkHosts2';
     $ KSCHost.AdmServer = $ Proxy;
     $ HostParams = New-Object -ComObject 'klakaut.KlAkCollection';
     $ HostParams.SetSize (1);
     $ HostParams.SetAt (0, 'KLHST_WKS_DN');
     ($ KSCHost.GetHostInfo ($ Proxy.GetProp ('KLADMSRV_SERVER_HOSTNAME'), $ HostParams)). Item ('KLHST_WKS_DN');
     Remove-Variable -Name 'HostParams';
     Remove-Variable -Name 'KSCHost';
     $ Proxy.Disconnect ();
 }


Note: the $ Params variable that I used when connecting to KSC is an instance of the KlAkParams class. And the $ HostParams variable with, in my opinion, similar functionality, is an instance of the KlAkCollection class. Why different classes are used - I'm afraid to even imagine. Apparently, the fact that SetAt takes only integer values ​​as the first argument is a very fundamental point.

This code returned the value "KSC", which means I'm on the right track.

The GetHostInfo method of the KlAkHosts2 class is well documented, but it does not contain the information I need. Alas and ah. But there is a method GetHostSettings. The whole description for which comes down to the following:

Returns host's settings as setting storage.

Let's take a look inside:

try
 try {
     $ Proxy.Connect ($ Params);
     $ KSCHost = New-Object -ComObject 'klakaut.KlAkHosts2';
     $ KSCHost.AdmServer = $ Proxy;
     $ KSCSettings = $ KSCHost.GetHostSettings ($ Proxy.GetProp ('KLADMSRV_SERVER_HOSTNAME'), 'SS_SETTINGS');
     $ KSCSettings.Enum () |  % {
         '------------------------';
         $ tmp = $ _;
         $ tmp |  % {"$ _ = $ ($ tmp.Item ($ _))";};
         Remove-Variable -Name 'tmp';
     };
     Remove-Variable -Name 'KSCSettings';
     Remove-Variable -Name 'KSCHost';
     $ Proxy.Disconnect ();
 }


Result
 ------------------------
 PRODUCT = .core
 SECTION = SubscriptionData
 VERSION = .independent
 ------------------------
 PRODUCT = 1093
 SECTION = 85
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1093
 SECTION = 87
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1093
 SECTION = KLEVP_NF_SECTION
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1093
 SECTION = KLNAG_SECTION_DPNS
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1093
 SECTION = KLSRV_CONSRVINIT
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1093
 SECTION = KLSRV_CONSRVUPGRADE
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1093
 SECTION = KLSRV_DEF_NAGENT_PACKAGE
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1093
 SECTION = KLSRV_MASTER_SRV
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1093
 SECTION = KLSRV_NETSIZE_SECTION
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1093
 SECTION = KLSRV_PKG_ANDROID_CERT_SECTION
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1093
 SECTION = KLSRV_PROXY_SECTION
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1093
 SECTION = KLSRV_SRVLIC_SECTION
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1093
 SECTION = KLSRV_USER_ACCOUNTS_SECTION
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1093
 SECTION = KSNPROXY_KEY_STORAGE
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1093
 SECTION = KSNPROXY_SETTINGS
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1093
 SECTION = Packages
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1093
 SECTION = Updater
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1103
 SECTION = 85
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1103
 SECTION = 86
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1103
 SECTION = FileTransfer
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1103
 SECTION = KLEVP_NF_SECTION
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1103
 SECTION = KLNAG_KLNLA_DATA
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1103
 SECTION = KLNAG_SECTION_NETSCAN
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1103
 SECTION = KLNAG_SECTION_SERVERDATA
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = 1103
 SECTION = Updater
 VERSION = 1.0.0.0
 ------------------------
 PRODUCT = KAVFSEE
 SECTION = .KLNAG_SECTION_REBOOT_REQUEST
 VERSION = 8.0.0.0
 ------------------------
 PRODUCT = KAVFSEE
 SECTION = 85
 VERSION = 8.0.0.0
 ------------------------
 PRODUCT = KAVFSEE
 SECTION = Backup section
 VERSION = 8.0.0.0
 ------------------------
 PRODUCT = KAVFSEE
 SECTION = Business logic section
 VERSION = 8.0.0.0
 ------------------------
 PRODUCT = KAVFSEE
 SECTION = HSM system section
 VERSION = 8.0.0.0
 ------------------------
 PRODUCT = KAVFSEE
 SECTION = Internal product info
 VERSION = 8.0.0.0
 ------------------------
 PRODUCT = KAVFSEE
 SECTION = KLEVP_NF_SECTION
 VERSION = 8.0.0.0
 ------------------------
 PRODUCT = KAVFSEE
 SECTION = Notification section
 VERSION = 8.0.0.0
 ------------------------
 PRODUCT = KAVFSEE
 SECTION = Predefined tasks section
 VERSION = 8.0.0.0
 ------------------------
 PRODUCT = KAVFSEE
 SECTION = Quarantine section
 VERSION = 8.0.0.0
 ------------------------
 PRODUCT = KAVFSEE
 SECTION = Reporting section
 VERSION = 8.0.0.0
 ------------------------
 PRODUCT = KAVFSEE
 SECTION = Trusted processes section
 VERSION = 8.0.0.0


In klakaut.chm there is a section “List of KLHST_WKS_PRODUCT_NAME and KLHST_WKS_PRODUCT_VERSION values ​​for products”, where you can see that the field PRODUCT for KSC should be 1093, respectively, everything else can be safely ignored. For now at least.

Having run my eyes over the section titles, I decided to look at 85 and 87, since the others were not very similar to what I wanted.

try
 try {
     $ Proxy.Connect ($ Params);
     $ KSCHost = New-Object -ComObject 'klakaut.KlAkHosts2';
     $ KSCHost.AdmServer = $ Proxy;
     $ KSCSettings = $ KSCHost.GetHostSettings ($ Proxy.GetProp ('KLADMSRV_SERVER_HOSTNAME'), 'SS_SETTINGS');
     $ KSCSettings.Read ('1093', '1.0.0.0', '85');
     '-----------------';
     $ KSCSettings.Read ('1093', '1.0.0.0', '87');
     Remove-Variable -Name 'KSCSettings';
     Remove-Variable -Name 'KSCHost';
     $ Proxy.Disconnect ();
 }


Result
 Eventfolder
 EventStoragePath
 KLAG_WAIT_SCHED_FOR_START_EVENT
 TaskStoragePath
 -----------------
 KLSRV_AD_SCAN_ENABLED
 KLSRV_CONNECTION_DATA
 KLSRV_DATABASENAME
 KLSRV_NET_SCAN_ENABLED
 KLSRV_SERVERINSTANCENAME
 KLSRV_SP_DPNS_ENABLE
 KLSRV_SP_FASTUPDATENET_PERIOD
 KLSRV_SP_FULLUPDATENET_PERIOD
 KLSRV_SP_INSTANCE_ID
 KLSRV_SP_MAX_EVENTS_IN_DB
 KLSRV_SP_OPEN_AKLWNGT_PORT
 KLSRV_SP_SCAN_AD
 KLSRV_SP_SERVERID
 KLSRV_SP_SERVERID_DPE
 KLSRV_SP_SERVER_AKLWNGT_PORTS_ARRAY
 KLSRV_SP_SERVER_PORTS_ARRAY
 KLSRV_SP_SERVER_SSL_PORTS_ARRAY
 KLSRV_SP_SERVER_SSL_PORTS_ARRAY_GUI
 KLSRV_SP_SYNC_LIFETIME
 KLSRV_SP_SYNC_LOCKTIME
 KLSRV_SP_SYNC_SEC_PACKET_SIZE
 KLSRV_SSL_CERT_RSA_BIT_NUMBER


Section 85, apparently, is responsible for the events and now we are not interested. But in 87 there is something worth paying attention to:

try
 try {
     $ Proxy.Connect ($ Params);
     $ KSCHost = New-Object -ComObject 'klakaut.KlAkHosts2';
     $ KSCHost.AdmServer = $ Proxy;
     $ KSCSettings = $ KSCHost.GetHostSettings ($ Proxy.GetProp ('KLADMSRV_SERVER_HOSTNAME'), 'SS_SETTINGS');
     $ 87 = $ KSCSettings.Read ('1093', '1.0.0.0', '87');
     "KLSRV_SERVERINSTANCENAME = $ ($ 87.Item ('KLSRV_SERVERINSTANCENAME'))";
     "KLSRV_DATABASENAME = $ ($ 87.Item ('KLSRV_DATABASENAME'))";
     "KLSRV_CONNECTION_DATA =` r`n $ ($ 87.Item ('KLSRV_CONNECTION_DATA') |% {"` t $ _ = $ ($ 87.Item ('KLSRV_CONNECTION_DATA'). Item ($ _)) `r`n";} ) ";
     Remove-Variable -Name '87';
     Remove-Variable -Name 'KSCSettings';
     Remove-Variable -Name 'KSCHost';
     $ Proxy.Disconnect ();
 }


Result
 KLSRV_SERVERINSTANCENAME =.
 KLSRV_DATABASENAME = KAV
 KLSRV_CONNECTION_DATA =
	 KLDBCON_DB = KAV
 	 KLDBCON_DBTYPE = MSSQLSRV
 	 KLDBCON_HOST =.


Here I used one of the previous cases, where it was mentioned that the necessary data should be taken from KLSRV_CONNECTION_DATA (at that time I didn’t know what it was, it was simply postponed).

Well, here, in general, that's all. Data on the database used is obtained. Quest is passed.

Probably, it would be nice to write a script for passing through the server hierarchy. There was nothing mysterious here, everything was completely according to the documentation. I wrote a script that selects the UID of the parent, the UID of the server itself, the instance of the DBMS and the name of the database and outputs them to stdout through the separator.

Script
 $ SrvAddr = 'localhost: 13291'

 function EnumSrv (
     $ Pxy,
     [bool] $ IsAlive = $ true,
     [string] $ ParentPxyId = 'Root'
 )
 {
     [string] $ result = "$ ParentPxyId";
     if ($ IsAlive) {
         $ result + = "| $ ($ Pxy.GetProp ('KLADMSRV_SERVER_HOSTNAME'))";
        
         $ Hosts = New-Object -ComObject 'klakaut.KlAkHosts2';
         $ Hosts.AdmServer = $ Pxy;
        
         $ Settings = $ Hosts. GetHostSettings ($ Pxy. GetProp ('KLADMSRV_SERVER_HOSTNAME'), 'SS_SETTINGS'). Read ('1093', '1.0.0.0', '87'). Item ('KLSRV_CONNECTION_DATA');
         Remove-Variable -Name 'Hosts';
    
         # '--------> DB Info <--------';
         $ result + = "| $ ($ Settings.Item ('KLDBCON_HOST'))";
         $ result + = "| $ ($ Settings.Item ('KLDBCON_DB'))";
         # '-----------------------------';
        
         Remove-Variable -Name 'Settings';
        
         $ SlaveSrvEnum = New-Object -ComObject 'klakaut.KlAkSlaveServers';
         $ SlaveSrvEnum.AdmServer = $ Pxy;
         $ SlaveServers = $ SlaveSrvEnum. GetServers (-1);
        
         $ SlaveServers |  % {
             $ Child = $ _;
             $ TmpSrvId = $ Child.Item ('KLSRVH_SRV_ID');
             $ HostActive = $ true;
             try
             {
                 $ TmpSrv = $ SlaveSrvEnum.Connect ($ TmpSrvId, -1);
             }
             catch
             {
                 $ HostActive = $ false;
             };
             if ($ HostActive) {$ HostActive = ($ TmpSrv.GetProp ('IsAlive') -eq 1);};
             $ result + = "` r`n $ (EnumSrv -Pxy $ TmpSrv -IsAlive $ HostActive -ParentPxyId $ Pxy.GetProp ('KLADMSRV_SERVER_HOSTNAME')) "";
         };
         Remove-Variable -Name 'SlaveServers';
         Remove-Variable -Name 'SlaveSrvEnum';
     };
     return ("$ result`r`n");
 }

 Clear host

 $ Params = New-Object -ComObject 'klakaut.KlAkParams'
 $ Params.Add ('Address', $ SrvAddr)
 $ Params.Add ('UseSSL', $ true)

 $ code = @ "
 using System;
 using System.Runtime.InteropServices;

 public class PowershellComSecurity
 {
    [DllImport ("Ole32.dll", CharSet = CharSet.Auto)]
    public static extern int CoSetProxyBlanket (IntPtr p0, uint p1, uint p2, uint p3, uint p4, uint p5, IntPtr p6, uint p7);

    public static int EnableImpersonation (object objDCOM) {return CoSetProxyBlanket (Marshal.GetIDispatchForObject (objDCOM), 10, 0, 0, 0, 3, IntPtr.Zero, 0);  }
 }
 "@
 Add-Type -TypeDefinition $ code

 $ Srv = New-Object -ComObject 'klakaut.KlAkProxy'
 [PowershellComSecurity] :: EnableImpersonation ($ Srv) |  Out-null
 $ Srv.Connect ($ Params)

 "ParentPxyId | KLADMSRV_SERVER_HOSTNAME | KLDBCON_HOST | KLDBCON_DB`r`n" + (EnumSrv -Pxy $ Srv);
 Remove-Variable -Name 'Srv';
 Remove-Variable -Name 'Params';


The stand is small, so the result was not very impressive:

Result
 ParentPxyId | KLADMSRV_SERVER_HOSTNAME | KLDBCON_HOST | KLDBCON_DB
 Root | 9d476a75-1e36-4c0e-8145-56e5b888df67 |. | KAV
 9d476a75-1e36-4c0e-8145-56e5b888df67 | ef4fc3be-3abd-4322-ae35-2c50afdce780 |. \ KAV_CS_ADMIN_KIT | KAV


Naturally, to turn the point into the actual server name, you have to conjure with KlAkHosts2.GetHostInfo (), but this is not so scary, just some more code.

Technical support of the LC, naturally, scared me that the structure of SS_SETTINGS in the next releases of KSC could change, so it’s better not to do so. Unfortunately, even my internal perfectionist thinks that the script cannot simply be written and forgotten: when changing the version of the software used, you have to test and debug it anyway. So while we use what we have, and we will solve problems as they become available, since the technology has already been worked out.

Source: https://habr.com/ru/post/278209/


All Articles