Subscriber Discussion

Password Brute-Forcing Protection

UI
Undisclosed Integrator #1
Feb 11, 2019

What, if anything, are you doing to block people from brute-forcing passwords to the admin accounts of your VMS? Users that log in through a domain controller can be protected by controls on the domain controller itself. Users that use "Basic Authentication" are at the mercy of the VMS.

I know that Ocularis has nothing to stop somebody from brute-forcing the password over the course of a few months. In fact, I discovered this issue after stumbling across 272 failed sign-in attempts (over the course of 30 seconds!) that happened the previous month when a customer's IT department ran a vulnerability test. If the installation is connected to the Internet and you aren't watching the logs, a hacker could take all the time they needed to brute force a password and you'd never know about it.

From what I can tell Milestone doesn't have anything built in either, but somebody else may have better information.

For Ocularis, my initial thought was to set up something like fail2ban to read the logs and temporarily block IP addresses. Only problem is that the logs for Ocularis Base go straight into SQL Server, specifically the VSAudits database. That makes it real easy to query in Ocularis Administrator, but there's no good way to monitor them without setting up a potentially costly insert trigger or giving the bad guys a head start by polling on a schedule.

What is everybody else doing? Are you using fail2ban or some other IPS? Does your VMS have built in protections? Do you just hope all your users are using strong passwords?

(2)
Avatar
Josh Hendricks
Feb 11, 2019
Milestone Systems

Hi UI1, you're right that there is currently no protection against brute forcing of basic user credentials and in fact there's no enabled/disabled/locked property for a basic user today - a user exists or it doesn't exist.

This is something we call out in our hardening guide on page 18 where we recommend the use of Active Directory or at least local Windows user accounts - here's a snippet:

Use Windows users with Active Directory
There are two types of users in XProtect VMS:
• Basic user: a dedicated VMS user account authenticated by a combination of username and
password using a password policy. Basic users connect to the VMS using a secure socket
layer (SSL) with current Transport Layer (TLS) security protocol session
(https://datatracker.ietf.org/wg/tls/charter/) for login, encrypting the traffic contents and
username and password.
• Windows user: the user account is specific to a machine or a domain, and it is
authenticated based on the Windows login. Windows users connecting to the VMS can use
Microsoft Windows Challenge/Response (NTML) for login, Kerberos (see "About Kerberos
authentication" on page 19), or other SSP options from Microsoft
(https://msdn.microsoft.com/en-us/library/windows/desktop/aa380502(v=vs.85).aspx).

Milestone recommends that, whenever possible, you use Windows users in combination with Active
Directory (AD) to authorize access to the VMS. This allows you to enforce:
• A password policy that requires users to change their password regularly
• Brute force protection, so that the Windows AD account is blocked after a number of failed
authentication attempts, again in line with the organization password policy
• Multi-factor authentication in the VMS, particularly for administrators
• Role-based permissions, so you can apply access controls across your domain

 

On the upside, there is no pre-configured basic user account with a common username, and passwords for basic users must meet the password complexity requirements of the OS where the software is installed so you usually have to go out of your way to use an easily guessable credential. But without brute force protection and with some prior knowledge or social engineering, a brute force campaign could be successful.

Thanks for highlighting this, I'll definitely bring it to the attention of the product owner. Even though we recommend customers use Windows/Active Directory users, basic users exist and IMO they should offer strong protection against brute force attacks.

(1)
U
Undisclosed #3
Feb 12, 2019

If the admin application is the 'root' user of the milestone system why would you just let it set there listening for clients? If possible just firewall those ports and use a local login directly on the server/vm server.

What a shame some of these VMS provides have not provide 2FA for their root applications. Basing it off of another MS application is not cool in an enterprise environment. What if the system has fifteen thousand cameras...you want that ability to just sit there underneath some lazy IT guy? 

Own your applications or get owned, it is so simple to offer a higher security implementation and if you don't you really deserver to get hacked.

Here is how we progress. We need security manufacturers to participate in some or all of the major hacker-cons, public display your server to the masses and lets watch what happens.

2FA or GTFO, IMHO. #E.evolve

UI
Undisclosed Integrator #1
Feb 12, 2019

Joshua, thanks for the explanation and for bringing this issue up internally. Adding more security to the login is a win for everybody, IMO.

U
Undisclosed #2
Feb 11, 2019
IPVMU Certified

...but there's no good way to monitor them without setting up a potentially costly insert trigger...

If you know how to do an insert trigger, do it.  I doubt it would affect performance in any measurable way during normal operation, because the flat i/o is cheap and relatively infrequent.

While you’re at it, maybe you could setup an insert trigger on the password table itself, and bounce any inserts that don’t meet your custom complexity formula.  (Though this may not be possible if the passwords are already encrypted before the INSERT statement).

 

UI
Undisclosed Integrator #1
Feb 12, 2019

My concern with the insert trigger is that the Audits table tracks way more than authentication. Just about everything that happens in the desktop client gets logged in the Audit table (view selection, camera selection, circular control opening, PTZ, browse mode, etc.). When you get 20 or 30 security guards doing their stuff, I would expect a lot of inserts. Even if you check the action and ignore everything that isn't authentication, it just seems like you would risk locking the table too often and slowing everybody down.

But I obviously don't know what's going on under the hood and have never added an insert trigger before. The code looks simple enough, but a lot of sources say it's a bad idea to export a text file from an insert trigger.

> Though this may not be possible if the passwords are already encrypted before the INSERT statement

They are indeed already encrypted. But that would be a pretty cool idea!

Also, it might cause a few errors if Ocularis tried to insert something into the database and the insert failed/got rolled back immediately.

UI
Undisclosed Integrator #4
Feb 12, 2019

Not sure what your level of access to the code is, but would it be possible to trigger on concurrent use cases?

IE-Someone tries doing the same action multiple times would cause the export from the trigger. 

U
Undisclosed #2
Feb 12, 2019
IPVMU Certified

So looking at it a bit, the cleanest way may be by creating your own SQL Server audit object:

Above you define the action to take on audit, in our case writing to a file.

Then you define the what causes the audit to be triggered, in our case specific DML statements:

There is no explicit TRIGGER to code, and the write to the log is handled by (presumably) a thread-safe section.

Then have fail2ban tail that file etc.  more info here

two other ideas just to throwout,

1) have the TRIGGER itself issue net commands to block an ip etc, when your condition is met with a background call to xp_cmdshell.  Then there is no overhead with a flat file.

2) Use SQL Object Broker to implement a messaging queue, and create a client process to consume the messages and take action when necessary.  This may the “right” way, but it’s a PITA if your not familiar with message queues.  more info here

(2)
UI
Undisclosed Integrator #1
Feb 12, 2019

Thanks for your help, U2. Since Ocularis uses SQL Server 2014 Express, auditing options might be a little limited, but I'm going to look into that some more tomorrow. (This is my way of saying that I couldn't find the Audits folder inside any Security folder.)

Whenever I think I have a technology figured out (such as SQL and databases), Microsoft never ceases to astound me with how much more capability and complexity it can have. Kind of like looking in your tool chest one day and realizing there's a nuclear reactor in there - but it only works if your chest is painted blue or was made after 2012.

U
Undisclosed #2
Feb 12, 2019
IPVMU Certified

Thanks for your help, U2. Since Ocularis uses SQL Server 2014 Express, auditing options might be a little limited...

True, apparently SQL Express only has server-level audit capability, you would need database level capability, so...

Thinking more about this option:

1) have the TRIGGER itself issue net commands to block an ip etc, when your condition is met with a background call to xp_cmdshell. Then there is no overhead with a flat file.

This method has the advantage of no external polling/monitoring process and no flat file writing.  It only exits the SQL environment in the rare case of an actual attack.

The TRIGGER would supply the data values of the audit row that is being inserted, and only in the case that it is a login failure would you run a query to determine if you are being flooded with attempts:

select count(*) from audit_table where event=failed_login and event_datetime in(last_minute)

and then only if that query returns a number indicating an attack would you run an 

xp_cmdshell(“netsh <block ip cmd>“ + @ip)

For normal, non-login events the added processing would amount to the invocation overhead, plus the compare, which is about as low as you can get.

*Note, any code examples shown are merely approximations pulled from a faulty memory and should not be expected to work verbatim :)

(1)
UI
Undisclosed Integrator #1
Feb 15, 2019

I've been fiddling with this the last few days. There are a few gotchas:

But on the plus side, I'm learning a lot about SQL Server :D

Here's the code I'm using for the trigger (grumble code formatting grumble):

ALTER TRIGGER [dbo].[throttle_login_attempts]
ON [VSAudits].[dbo].[AuditRecords]
AFTER INSERT
AS

DECLARE @ip CHAR(16), @action INT, @count INT;
SELECT @ip = [loc].[Location] ,@action = [ins].[FK_ActionTypes_ID] FROM INSERTED ins INNER JOIN [VSAudits].[dbo].[SessionIDs] AS [ses] ON [ins].[SessionID] = [ses].[ID] INNER JOIN [VSAudits].[dbo].[Locations] AS [loc] ON [ses].[LocationID] = [loc].[ID];

IF @action = 1 BEGIN

SELECT @count = (SELECT COUNT(*) FROM [VSAudits].[dbo].[AuditRecords] AS [Audits] INNER JOIN [VSAudits].[dbo].[SessionIDs] AS [Sessions] ON [Audits].[SessionID] = [Sessions].[ID] INNER JOIN [VSAudits].[dbo].[Locations] AS [Locations] ON [Sessions].[LocationID] = [Locations].[ID] WHERE [Audits].[FK_ActionTypes_ID] = 1 AND [Locations].[Location] = @ip AND [Audits].[Occurred] > DATEADD(MINUTE, -1, GETDATE()) AND [Audits].[Description] LIKE '%attempted%')

IF @count >= 3 BEGIN

EXEC block_ip @ip

END

END

The stored procedure block_ip isn't doing much yet. I'm thinking of spawning a Python process or something like that, to give me greater control over what's blocked and what isn't.

CREATE PROC block_ip @ip CHAR(16)
AS

DECLARE @command VARCHAR(64), @cleanedIP CHAR(16);

SELECT @cleanedIP = LEFT(SUBSTRING(@ip, PATINDEX('%[0-9.]%', @ip), 8000), PATINDEX('%[^0-9.]%', SUBSTRING(@ip, PATINDEX('%[0-9.]%', @ip), 8000) + 'X') -1)

SELECT @command = FORMATMESSAGE('type NUL > C:\ocularis-audits\%s', @cleanedIP);

EXEC xp_cmdshell @command;

GO

U
Undisclosed #2
Feb 16, 2019
IPVMU Certified

Sounds like you got it!  Now you see why I only gave pseudo code ;)

xp_cmdshell runs synchronously...

Though it should only be called in the rare case of attack.  

You can use the windows utility START (or AT) to run the process in the background.

Hows the performance on the select count(*) out of the audit table?

I’m not sure how it’s keyed and how big it gets; it could be something that seems ok when your testing but then slowly strangled you.

Another, more predictive method would be to insert your own row into a temp table on every access and then query that every time.  You could also dbcc “pin” the table in memory to speed performance.

then just drop and recreate the table after there is a new login right after a lull in attempts.

good luck.

(1)
U
Undisclosed #5
Feb 16, 2019

i made it about halfway through the comments above (that are almost all well above my personal nerdery threshold) before my eyes started to lose focus...

here are two thoughts:

1.  Why do you (collective you) think that VMS manufacturers haven't implemented brute force protection schemes? If it aint hard to do (based on the comments above [I think]), then the only explanation is operational efficiency - no?

2.  How come nobody ever complains about the default ability to use a PW that is the same as the user name?  Even though the attacker doesn't know that the PW is the same as the user name, when they click on the desktop icon and launch the login screen to begin their brute force 'hack' attack, they are given the PW because the last logged-in user name is generally displayed.

New discussion

Ask questions and get answers to your physical security questions from IPVM team members and fellow subscribers.

Newest discussions