Circumvent new tuya sdk protection

This commit is contained in:
Madmartigan
2019-09-18 21:38:11 +02:00
parent 9b0e36d3f5
commit 7d588cda4e
5 changed files with 165 additions and 20 deletions

View File

@@ -9,6 +9,8 @@ Copyright (c) 2018 VTRUST. All rights reserved.
import tornado.web
import os
import hashlib
import hmac
import binascii
def file_as_bytes(file):
with file:
return file.read()
@@ -32,7 +34,8 @@ class JSONHandler(tornado.web.RequestHandler):
def get(self):
print('\n')
print('URI:'+str(self.request.uri))
self.write('Hello Human, Do you have IOT?')
#self.write('Hello Human, Do you have IOT?')
self.post()
def post(self):
print('\n')
uri = str(self.request.uri)
@@ -42,7 +45,7 @@ class JSONHandler(tornado.web.RequestHandler):
if(a == "s.gw.token.get"):
print("Answer s.gw.token.get")
answer =(b'{"result":{"gwApiUrl":"http://10.42.42.1/gw.json","stdTimeZone":"-05:00","mqttRanges":"","timeZone":"-05:00",'
b'"httpsPSKUrl":"https://10.42.42.1/gw.json","mediaMqttUrl":"10.42.42.1","gwMqttUrl":"10.42.42.1","dstIntervals":[]},"t":7,"e":false,"success":true}\n'
b'"httpsPSKUrl":"https://10.42.42.1/gw.json","mediaMqttUrl":"10.42.42.1","mqttsUrl":"10.42.42.1","gwMqttUrl":"10.42.42.1","dstIntervals":[]},"t":7,"e":false,"success":true}\n'
)
self.set_header("Content-Type", "application/json;charset=UTF-8")
@@ -71,22 +74,47 @@ class JSONHandler(tornado.web.RequestHandler):
self.set_header('Content-Length', str(len(answer)))
self.set_header('Content-Language', 'zh-CN')
self.write(answer)
print("TRIGGER UPGRADE IN 10 SECONDS")
os.system("./trigger_upgrade.sh %s &" % str(gwId))
elif(".dynamic.config.get" in a):
print("Answer tuya.device.dynamic.config.get")
index = uri.find("gwId=")+5
gwId = uri[index:index+20]
print("READ GW ID",gwId)
answer = (b'{"result":'
b'{'
b'"ackId":"1234567", "time":"1", "validTime":"1",'
b'"config":{"stdTimeZone":"UTC", "dstIntervals":"0"}'
b'},'
b'"t":9, "e":false,"success":true}')
self.set_header("Content-Type", "application/json;charset=UTF-8")
self.set_header('Content-Length', str(len(answer)))
self.set_header('Content-Language', 'zh-CN')
self.write(answer)
elif(".upgrade" in a):
print("Answer s.gw.upgrade")
elif(".upgrade.get" in a) or ('.upgrade.silent.get' in a):
print("Answer s.gw.upgrade.get")
#Fixme
#Calculate MD5 and Filesize
file_md5 = hashlib.md5(file_as_bytes(open('../files/upgrade.bin', 'rb'))).hexdigest()
file_len = os.path.getsize('../files/upgrade.bin')
answer = b'{"result":{"auto":3,"fileSize":"%d","etag":"0000000000","version":"9.0.0","url":"http://10.42.42.1/files/upgrade.bin","md5":"%s"},"t":100,"e":false,"success":true}' % (file_len,file_md5.encode('utf-8'))
file_sha256 = hashlib.sha256(file_as_bytes(open('../files/upgrade.bin', 'rb'))).hexdigest().upper()
file_hmac = hmac.HMAC(b'0000000000000000', file_sha256.encode(), 'sha256').hexdigest().upper()
answer = b'{"result":{"auto":3,"size":"%d","type":9,"pskUrl":"https://10.42.42.1/files/upgrade.bin","hmac":"%s","version":"9.0.0"},"t":10,"e":false,"success":true}'%(file_len, file_hmac.encode())
print(answer)
self.set_header("Content-Type", "application/json;charset=UTF-8")
self.set_header('Content-Length', str(len(answer)))
self.set_header('Content-Language', 'zh-CN')
self.write(answer)
elif(".dynamic.config.ack" in a):
print("Answer tuya.device.dynamic.config.ack")
answer =b'{"result":true,"t":7,"e":false,"success":true}'
self.set_header("Content-Type", "application/json;charset=UTF-8")
self.set_header('Content-Length', str(len(answer)))
self.set_header('Content-Language', 'zh-CN')
self.write(answer)
print("TRIGGER UPGRADE IN 10 SECONDS")
os.system("./trigger_upgrade.sh %s &" % str(gwId))
elif(".debug.log" in a):
print("Answer atop.online.debug.log")
answer =b'{"result":true,"t":7,"e":false,"success":true}'

View File

@@ -8,6 +8,7 @@ Copyright (c) 2018 VTRUST. All rights reserved.
import sys, getopt, time, pyaes, base64
import paho.mqtt.client as mqtt #pip install paho-mqtt
from hashlib import md5
import binascii
help_message = '''USAGE:
"-i"/"--deviceID"
@@ -25,8 +26,7 @@ class iotAES(object):
cipher = pyaes.blockfeeder.Encrypter(pyaes.AESModeOfOperationECB(self.key.encode()))
crypted_text = cipher.feed(raw)
crypted_text += cipher.feed()
crypted_text_b64 = base64.b64encode(crypted_text)
return crypted_text_b64
return crypted_text
def decrypt(self, enc):
enc = base64.b64decode(enc)
cipher = pyaes.blockfeeder.Decrypter(pyaes.AESModeOfOperationECB(self.key))
@@ -47,15 +47,11 @@ def iot_dec(message, local_key):
def iot_enc(message, local_key):
iot_aes = iotAES(local_key)
messge_enc = iot_aes.encrypt(message)
m = md5()
PROTOCOL_VERSION_BYTES = b'2.1'
# preMd5String = b'data=' + messge_enc + b'||lpv=' + PROTOCOL_VERSION_BYTES + b'||' + local_key
preMd5String = b'data=' + messge_enc + b'||pv=' + PROTOCOL_VERSION_BYTES + b'||' + local_key.encode()
# print (preMd5String)
m.update(preMd5String)
md5sum = m.hexdigest()
print (md5sum) #ca2b66d33d3f50a1 #ca2b66d33d3f50a1
messge_enc = PROTOCOL_VERSION_BYTES + md5sum[8:][:16].encode('latin1') + messge_enc
message = b'%08d'%((int(time.time()*100)%100000000)) + messge_enc
c = binascii.crc32(message)
PROTOCOL_VERSION_BYTES = b'2.2'
messge_enc = PROTOCOL_VERSION_BYTES + (c).to_bytes(4, byteorder='big') +message
print (messge_enc)
return messge_enc
@@ -98,7 +94,8 @@ def main(argv=None):
print (help_message)
return 2
message = '{"data":{"gwId":"%s"},"protocol":15,"s":%d,"t":%d}' %(deviceID, 1523715, time.time())
message = '{"data":{"gwId":"%s"},"protocol":15,"s":"%d","t":"%d"}' %(deviceID, 1523715, time.time())
m1 = iot_enc(message, localKey)
client = mqtt.Client("P1")

117
scripts/psk-frontend.py Executable file
View File

@@ -0,0 +1,117 @@
#!/usr/bin/env python3
import socket
import select
import ssl
import sslpsk
from Crypto.Cipher import AES
import hashlib
from binascii import hexlify, unhexlify
server_hint_hex = "316448527363324e6a62486c74624778336557683530303030303030303030303030303030"
server_hint = unhexlify(server_hint_hex)
def listener(host, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((host, port))
sock.listen(1)
return sock
def client(host, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
return sock
def get_psk(identity):
id = identity
server_hint = unhexlify(server_hint_hex)
md5_uuid = id[17:(17+16)]
source = id[1:50]
rand = server_hint[21:21+16]
key = hashlib.md5(rand).digest()
to_encode = id[1:33]
iv = hashlib.md5(source).digest()
cipher = AES.new(key ,AES.MODE_CBC, iv)
c = cipher.encrypt(to_encode)
print("PSK: %r"%(hexlify(c)))
return c
class PskFrontend():
def __init__(self, listening_host, listening_port, host, port):
self.listening_port = listening_port
self.listening_host = listening_host
self.host = host
self.port = port
self.server_sock = listener(listening_host, listening_port)
self.sessions = []
self.hint = '1dHRsc2NjbHltbGx3eWh50000000000000000'
def readables(self):
readables = [self.server_sock]
for (s1, s2) in self.sessions:
readables.append(s1)
readables.append(s2)
return readables
def new_client(self, s1):
try:
ssl_sock = sslpsk.wrap_socket(s1,
server_side = True,
ssl_version=ssl.PROTOCOL_TLSv1_2,
ciphers='PSK-AES128-CBC-SHA256',
psk=get_psk,
hint=self.hint)
s2 = client(self.host, self.port)
self.sessions.append((ssl_sock, s2))
except:
pass
def data_ready_cb(self, s):
if s == self.server_sock:
_s, frm = s.accept()
print("new client on port %d from %r"%(self.listening_port, frm))
self.new_client(_s)
for (s1, s2) in self.sessions:
if s == s1 or s == s2:
c = s1 if s == s2 else s2
try:
buf = s.recv(4096)
if len(buf) > 0:
c.send(buf)
else:
s1.shutdown(socket.SHUT_RDWR)
s2.shutdown(socket.SHUT_RDWR)
self.sessions.remove((s1,s2))
except:
self.sessions.remove((s1,s2))
def main():
proxies = [PskFrontend('', 443, '127.0.0.1', 80), PskFrontend('', 8886, '127.0.0.1', 1883)]
while True:
readables = []
for p in proxies:
readables = readables + p.readables()
r,_,_ = select.select(readables, [], [])
for s in r:
for p in proxies:
p.data_ready_cb(s)
if __name__ == '__main__':
main()

View File

@@ -44,6 +44,8 @@ $screen_with_log smarthack-web.log -S smarthack-web -m -d ./fake-registration-se
echo " Starting Mosquitto in a screen"
sudo service mosquitto stop >/dev/null 2>&1
$screen_with_log smarthack-mqtt.log -S smarthack-mqtt -m -d mosquitto -v
echo " Starting PSK frontend in a screen"
$screen_with_log smarthack-psk.log -S smarthack-psk -m -d ./psk-frontend.py -v
echo
echo "======================================================"
echo

View File

@@ -5,3 +5,4 @@ sudo screen -S smarthack-wifi -X stuff '^C'
sudo screen -S smarthack-web -X stuff '^C'
sudo screen -S smarthack-smartconfig -X stuff '^C'
sudo screen -S smarthack-mqtt -X stuff '^C'
sudo screen -S smarthack-psk -X stuff '^C'