Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interesting finds #2

Open
KiralyCraft opened this issue Apr 20, 2024 · 36 comments
Open

Interesting finds #2

KiralyCraft opened this issue Apr 20, 2024 · 36 comments

Comments

@KiralyCraft
Copy link
Contributor

KiralyCraft commented Apr 20, 2024

I ran a strings on the U-WB05RT13V1.21-4307516678339185323.bin file, and I came across this:

../../../component/common/drivers/wlan/realtek/src/osdep/lwip_intf.c

Which is actually this file:

https://github.com/ambiot/ambd_sdk/blob/dev/component/common/drivers/wlan/realtek/src/osdep/lwip_intf.h

Might help with reverse engineering some of the code.

Found this as well: ../../../component/os/freertos/freertos_v10.0.1/Source/portable/GCC/ARM_RTL8710C/port.c
As well as [I]: create_DeviceKey :%s - Which may indicate where the encryption key is generated (and how).

It looks like the device was (is) based on an AmebaZ2 RTL8710C, although the FCC pictures show an RTL8720CF: https://device.report/m/68a82c07c0a456cd60cb23c4e70f1e84d20fe8af49c3f36a73e89fd74cd5af95

That device has a Cortex M4 MCU, named KM4 MCU which is 32 bit, and likely little endian.

From here, Ghidra can help with ARM Aggresive Instruction finding, according to: https://blog.feabhas.com/2022/12/disassembling-a-cortex-m-raw-binary-file-with-ghidra/

@maxim-smirnov
Copy link
Owner

As I can see from the .bin file, the firmware itself developed using Ameba-ZII SDK (you can find AmebaZII by offset 0x290). So I think it can be RTL8720CM, RTL8720CF, RTL8720CN or RTL8710CX (got from Realtek docs).

@KiralyCraft
Copy link
Contributor Author

Indeed, it looks like the SDK they use is a bit older, though. The file structure/path shown for the port.c resembles the structure of the vanilla FreeRTOS 10.0.1; I found a link somewhere with screenshots, and the SDK paths used to indeed look like that.

However, that was in a period when you needed an NDA with Realtek to have access to it. They've since noticed interest in the RTL87[XX] and released the SDK openly in that GitHub repo. I'm not sure if things might've also changed during this release, so what we have now may not be 1:1 with what was used to develop it. Nevertheless, useful info

@maxim-smirnov
Copy link
Owner

By offset 0x8140 we see AmebaZIIRTL8710C, so yep, it's RTL8710C.

@maxim-smirnov
Copy link
Owner

Got really interesting fw for some fw_code, it's an android boot img 250M in size, gonna upload it today.

@maxim-smirnov
Copy link
Owner

File is too large, I'll try to figure out how to upload it, the firmwareCode is 362001063066.

@KiralyCraft
Copy link
Contributor Author

Have you looked into Git LFS? It's a Large File Storage extension which is designed for this situation specifically

@maxim-smirnov
Copy link
Owner

Yep, but I just never used it, so I decided to play around with fw first :)

@KiralyCraft
Copy link
Contributor Author

KiralyCraft commented Apr 23, 2024

I'll handle the git then - Do you happen to know if this fw also doesn't respond to bing queries?

It looks like you'll have to do this, since apparently GitHub doesn't support LFS on public forks according this this link. I get an error saying that @KiralyCraft can not upload new objects to public fork KiralyCraft/gree-wifimodule-firmware
For this, you need to:

  1. Actually install git-lfs. On my system, I had to install the git-fs package
  2. Clone the repo, do git lfs install from within the repo
  3. Set up your everything (place the files, etc etc) and then do a git lfs track <name_of_the_img>. Make sure to actually be in the directory where the image is
  4. Run a git add . from the root of the cloned repo
  5. Commit & push

@maxim-smirnov
Copy link
Owner

File is too large, I'll try to figure out how to upload it, the firmwareCode is 362001063066.

Looks like it's for something like Smart Voice Control for AC. Can you give some strings from the packets are used in bind requests/responses? Like json keys, etc.

@KiralyCraft
Copy link
Contributor Author

KiralyCraft commented Apr 23, 2024

I documented some strings and protocols here:

cmroche/greeclimate#70

This is just the scan, to which my device responds, but is then unable to bind. I disconnected my ACs from WiFi, in the hope that they don't update (and ruin our research). When binding, you have the bind keyword somewhere in there, from what I recall.

EDIT: Looks like my attempt was a bind attempt, so it looks about like that. The generic key is a3K8Bx%2r8Y7#xDh

@maxim-smirnov
Copy link
Owner

Here is the firmware I talked about

@KiralyCraft
Copy link
Contributor Author

KiralyCraft commented Apr 23, 2024

Tadaaa! The file is in the squashfs, at /etc/gree

Looks like the binary is not stripped, what a nice find!

> file gree
gree: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 4.4.0, not stripped
> grep "a3K8Bx%2r8Y7#xDh" . -iR                                                                                                                                                                                                       
grep: ./gree: binary file matches

@maxim-smirnov
Copy link
Owner

local_handle_recvdata looks interesting

@KiralyCraft
Copy link
Contributor Author

KiralyCraft commented Apr 23, 2024

Looks like it may be vulnerable to an SQL injection?

select * from device_data where MAC = \"%s\""

EDIT: Do you happen to know if this particular firmware works locally with available local control tools? Is this a jackpot?

@maxim-smirnov
Copy link
Owner

Looks like 👍 I'm a little confused for what kind of device this fw for...

@maxim-smirnov
Copy link
Owner

From local_reqJSON_udp found that key "i" in the json means does the device use locally generated AES key or default string "a3K8Bx%2r8Y7#xDh".

if (LOCAL_AESKEY_FLG == 0) {
  puVar4 = aes_device_key;
}
else {
  puVar4 = ecb_unify_key;
}
uVar7 = aes_ecb_encryption_t(puVar4,auStack_818);
memset(auStack_418,0,0x400);
base64_encode(auStack_418,0x400,auStack_818,uVar7);
uVar2 = cJSON_CreateObject();
uVar5 = cJSON_CreateString("pack");
cJSON_AddItemToObject(uVar2,"t",uVar5);
uVar5 = cJSON_CreateNumber(SUB84((double)(ulonglong)LOCAL_AESKEY_FLG,0));
cJSON_AddItemToObject(uVar2,"i",uVar5);
uVar5 = cJSON_CreateNumber(SUB84((double)(longlong)loginUid,0));
cJSON_AddItemToObject(uVar2,"uid",uVar5);
uVar5 = cJSON_CreateString(LOCAL_MAC);
cJSON_AddItemToObject(uVar2,"cid",uVar5);
uVar5 = cJSON_CreateString("");
cJSON_AddItemToObject(uVar2,"tcid",uVar5);
uVar5 = cJSON_CreateString(auStack_418);
cJSON_AddItemToObject(uVar2,"pack",uVar5);
local_reqJSON_out = (char *)cJSON_PrintUnformatted(uVar2);

@KiralyCraft
Copy link
Contributor Author

I wonder, did you upload the wrong MD file for this new firmware? It seems that the version it gives me is 1.38, whereas the one you uploaded is 1.55

@maxim-smirnov
Copy link
Owner

maxim-smirnov commented Apr 23, 2024

Check the domains

http://test.grih.gree.com/wifiModule/Lastversion?firmwareCode=362001063066

{"CreateDate":"2022-12-06 01:00:21","commProtVer":"","desc":"","forcedUpgrade":0,"r":200,"url":"http://test.grih.gree.com/wifiModule/image/16988/254130648","ver":"1.55"}

http://grih.gree.com/wifiModule/Lastversion?firmwareCode=362001063066

{"CreateDate":"2022-05-31 08:23:21","commProtVer":"","desc":"优化已知功能","forcedUpgrade":0,"r":200,"url":"http://grih.gree.com/wifiModule/image/10463/193714648","ver":"1.38"}

@KiralyCraft
Copy link
Contributor Author

Well, well, looks like I need glasses after all. I was looking at V1.38, and some things weren't lining up with your findings. Haha, they had it with debugging symbols since 1.38!

@maxim-smirnov
Copy link
Owner

Hey! Got ESP32 firmware

@KiralyCraft
Copy link
Contributor Author

Really nice! Didn't get to looking into it just yet, but it's on the TODO list, as soon as possible. Did you find anything interesting in that one yet?

@maxim-smirnov
Copy link
Owner

Still investigating

@KiralyCraft
Copy link
Contributor Author

I convinced the automatic LLM friend to generate a python script for us which checks the links you suggested. I've tested and debugged this, seems to work nicely:

import os
import sys
import json
import requests

def fetch_and_save_data(firmware_code, server):
    # Define the URL
    url = f'http://{server}/wifiModule/Lastversion?firmwareCode={firmware_code}'

    try:
        # Fetch JSON data using requests
        response = requests.get(url,verify=False)
        response.raise_for_status()  # Raise an exception for 4xx and 5xx status codes
        data = response.json()

        # Check if the response status is 405
        if data.get('r') == 405:
            print(f"Ignore firmware code {firmware_code} from {server} due to response status 405")
            return

        # Prepare filename
        version = data.get('ver')
        filename = f"downloaded/{firmware_code}_v{version}_{server}.md"

        # Write data to MD file
        with open(filename, 'w') as file:
            file.write(f"`{url}`\n\n")
            file.write(f"```json\n")
            json.dump(data, file, indent=2)
            file.write(f"```")

        print(f"Data saved for firmware code {firmware_code} from {server}")

    except requests.RequestException as e:
        print(f"Error fetching data for firmware code {firmware_code} from {server}: {str(e)}")
    except json.JSONDecodeError as e:
        print(f"Error decoding JSON response for firmware code {firmware_code} from {server}: {str(e)}")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python script.py <firmware_code>")
        sys.exit(1)

    firmware_code = sys.argv[1]
    servers = [
        "grih.gree.com",
        "test.grih.gree.com",
        "ru.grih.gree.com",
        "na.grih.gree.com",
        "hk.grih.gree.com",
        "eu.grih.gree.com",
        "in.grih.gree.com",
        "sa.grih.gree.com"
    ]

    # Create the "downloaded" directory if it doesn't exist
    os.makedirs("downloaded", exist_ok=True)

    for server in servers:
        fetch_and_save_data(firmware_code, server)

If you find this useful, would you mind adding it? Also, we have a new firmware code contribution for 62001065280+U-WB05RT11V1.21.bin from home-assistant/core#109230 (comment)

Would you mind adding that as well? I'm currently away from my broadband connection, and cloning the repo for a PR would eat my data. Still, that one seems to be yet again, 750 KB with the codename AmebaZIIRTL8710C. I wonder, the submission states that one of the devices is running firmware V1.16; I wonder, is there a link for downloading a specific version? Could we fetch V1.16 somehow, since we know it exists?

@KiralyCraft
Copy link
Contributor Author

Managed to query the DNS requetss of my app. Seems it contacts:

eu12.as.gree.com, eugrih.gree.com

@KiralyCraft
Copy link
Contributor Author

Looks like V1.53 does indeed fix fetching. It's only available on test.grih.gree.com, but it fixes these issues.

@maxim-smirnov
Copy link
Owner

Just to clarify XXgrih.gree.com and XX.grih.gree.com are always resolves to same IP. So eugrih.gree.com and eu.grih.gree.com are same servers. Kinda wondering is commProtVer means something like "communication protocol version"?

@maxim-smirnov
Copy link
Owner

maxim-smirnov commented May 14, 2024

Maybe someone can try to downgrade the firmware with DNS spoofing? I don't have any ACs with WiFi modules :)

@wangeris
Copy link

Maybe someone can try to downgrade the firmware with DNS spoofing? I don't have any ACs with WiFi modules :)

Hey, I could try it (have a unit), but not sure where to begin.

@maxim-smirnov
Copy link
Owner

@wangeris do you know your firmwareCode for your module?

@wangeris
Copy link

@wangeris do you know your firmwareCode for your module?

sadly I do not, tried to find out by intercepting dns queries, but no luck with that due to SSL i believe

@maxim-smirnov
Copy link
Owner

@wangeris is there any labels/stickers on your wifi module?

@wangeris
Copy link

I'll have to open up my AC unit to look when I'm home

@KiralyCraft
Copy link
Contributor Author

KiralyCraft commented May 14, 2024

2024-04-20-20-58-08-108

Here's a picture of mine if it helps. I attempted to upgrade my AC using DNS spoofing. You have to have the EWPE Smart / GREE+ app launched with a debugger attached, and then all regions map to the test server, and you can perform the upgrade (thanks to Urusus2 for this discovery) . I'm now running 1.53, which works with Home Assistant and existing tools.

If you simply change the default domain it's looking for to the IP of the testing server, you get the popup for a firmware upgrade but it never completes. There's no "upgrade firmware" button, it just shows it's available.

The app may have trouble with SSL for actually downloading the image (who knows?). Still, there is a way to make it ignore SSL certificates, and perform a MITM attack on it. If you run Windows, there's this web debugger called "Telerik Fiddler". It can decrypt HTTPs, but it requires that you install a CA certificate which simply trusts everything (which is also generates). Using this certificate, install it on the mobile device, and then connect the phone to a hotspot you control, where you can then play with routing (such as, with iptables) and with DNS queries as well. It seems that the installation of this all-trusting certificate spreads it's effects even in apps.

I haven't done this in a long while, but theory says it should still work. If anything, you can set a proxy on your device's wifi connection to point to Fiddler, and then you'll see all HTTPs traffic intercepted in there, including GREE traffic.

The device itself seems to have an SSL certificate embedded, for the "gree.com" domain, which expires in about 10 years. It was visible in the firmware I uploaded. If firmware update is done through the cloud, then I doubt downgrade would work with manually provided firmware, but it could work if the AC's DNS queries are poisoned to report a custom (locally-hosted) "image meta server", while still downloading the files from China cloud. The prompts for firmware data seem to go over HTTP (since the app worked with poisoned DNS).

@Urusus2
Copy link
Contributor

Urusus2 commented May 14, 2024

Maybe someone can try to downgrade the firmware with DNS spoofing? I don't have any ACs with WiFi modules :)

it doesn't work, it doesn't downgrade...
I update from 1.20 to 1.21, and from 1.21 to 1.22....
I tried with charles proxy to change response: changed url to version 1.21, version to 1.30(example, need to be greater) and sent successfully to wifi module, but it not downgrade......when change response to update (1.21 to 1.22) it successfully updated....

@maxim-smirnov
Copy link
Owner

As I saw from different firmware files, looks like the app provides an fw link to the module, and module proceeds with the update by itself. May be try to change the link on that stage?

@Urusus2
Copy link
Contributor

Urusus2 commented May 15, 2024

I change link, if version is greater it update successfully, but if version is smaller it not downgrade...
Yesterday I try to send request to module directly to update firmware from 1.53 to 1.21, module response with 200, but module not downgrade firmware

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants