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

Encrypted data in Renpho Health app #25

Open
StashOfCode opened this issue Mar 26, 2024 · 11 comments
Open

Encrypted data in Renpho Health app #25

StashOfCode opened this issue Mar 26, 2024 · 11 comments
Assignees
Labels
documentation Improvements or additions to documentation enhancement New feature or request help wanted Extra attention is needed question Further information is requested

Comments

@StashOfCode
Copy link

I was sniffing iOS app's requests to pull my data out of it since renpho doesn't provide a public api. However, it appears to be fucking encrypted now - both request and response payloads. I decompiled an .apk file and looked through some Java code. There is a ton of files and folders in there for such an unspectacular app. Unfortunately, some parts failed to decompile, but the main action appears to be going in an AESUtil.java file. I couldn't figure out what the encyption key was since there are a whole lot of files that show up on a "decrypt" search.

I wish I was an expert in encyption and Java. Is there anyone who managed to decrypt this shit?

@neilzilla
Copy link
Owner

I haven't had a look yet but you make this sound interesting. When I initially looked into this the main issues were using a mitm attack on ssl traffic and decompilation - the decompiled source was not easy to read or find anything. If you haven't already, I wrote a blog on this a while ago here

@antoinebou12
Copy link
Collaborator

You can look at my fork. I saw the data is encrypted for every request. I look at the apk and the decompilation code. One way doing it could be to add debug mode to the signed apk to print the data before request and after find the correct encryption. @StashOfCode if you want to talk or email we can find a way to make it works

antoinebou12#7

@StashOfCode
Copy link
Author

@neilzilla, yeah, that's basically how I found your repo :) Nice write up.

I used Proxyman for request sniffing and Jadx for decompiling. The code produced is very readable except for a few files.

Unfortunatelty, I can't use the older app since it doesn't support new devices

@StashOfCode
Copy link
Author

StashOfCode commented Mar 27, 2024

@antoinebou12, So far I've tried the folllowing things:

  1. I traced the decompiled .apk code to find a place where encyption key is loaded or created. I found a few hardcoded AES-128 keys (check out a DAUL_ENCRYPTION variable in RetrofitUtils.java), but they failed to decrypt traffic. Also, I found this line of code AESUtil.setcKey(AlgorithmJni.getRenphoPassword()); which is one of the places where the encyption key is set. Searching for getRenphoPassword leads to a class where this method is not really defined - public static native String getRenphoPassword();. Perhaps, that's because jadx failed to decompile some code in other files. I wanted to test that an encyption key was indeed a derivative of the account password. I then changed the password, but most request payloads still stayed the same. I'm still eyeballing code to understand what's going on - It's quite convoluted for a non-Java dev. My main problem is that I'm not sure which of the many encryption-related functions is used for cloud.renpho.com traffic.

  2. I dumped iOS data and looked through Renpho .sqlite dbs. I didn't find encryption keys there. It does store token and userid, however, used in request headers. Also, according to createAllTables in AppDataBase_Impl.java, there should've been an encryptedPassword column in a User table, but it doesn't exist in my iOS dump of the db.

  3. I'm looking into dynamic analysis using Frida and Waydroid. I found this brilliant article https://frdmtoplay.com/freeing-glucose-data-from-the-freestyle-libre-3/ that briefly explains how to do it.
    I'm currently stuck at installing a VNC server on my linux VPS 🥲

What do you think about the Frida + Waidroid approach?

@antoinebou12
Copy link
Collaborator

I have a rooted device emulator with http with https traffic. I didn't found the .sqlite db with the encryption code. I have multiple server if you want to play with it your approach. My found thati can set the apk into debug mode and resign the apk to make sure so i can debug. I saw the RetrofitUtils.java and i don't understand the code. I tried Frida with Waydroid in the future. Thanks @StashOfCode !

https://samsclass.info/128/proj/M142.htm

@neilzilla
Copy link
Owner

@StashOfCode Frida and Waydroid look super interesting, there's a lot to think about there - very interesting post!

Correct me if I'm wrong but that post mainly talks about decrypting the local database? This is something I'd not considered but in developing this plugin I'm not sure how useful it is.

I definitely want to have a look at picking apart this new app however, I'll see if I can make some time this weekend.

@antoinebou12 if I can pull apart the new api could you incorporate this into the addon?

@StashOfCode
Copy link
Author

StashOfCode commented Mar 29, 2024

@antoinebou12, do you have an arm64 server with ubuntu 20-22 on it? I managed to configure a rented vps and install Waydroid, but I failed at the apk installation step - turns out the vps was running on x86 while the app requires arm lol

@StashOfCode
Copy link
Author

@neilzilla, right! The goal in that post was to decrypt the db. I believe we can use the same general approach & tools to figure out how Renpho encrypts requests

@antoinebou12
Copy link
Collaborator

@antoinebou12, do you have an arm64 server with ubuntu 20-22 on it? I managed to configure a rented vps and install Waydroid, but I failed at the apk installation step - turns out the vps was running on x86 while the app requires arm lol

Email me at antoine@antoineboucher.info. I can give you a free vm

@antoinebou12 antoinebou12 added documentation Improvements or additions to documentation enhancement New feature or request help wanted Extra attention is needed question Further information is requested labels Apr 25, 2024
@neilzilla
Copy link
Owner

I've been looking into this this afternoon, I wish I had read this thread earlier though.

It appears the class that is not properly defined actually loads native code, and the native code generates the AES key in memory and returns it in a really convoluted way.
For whatever reason they don't want us accessing this.

I've managed to decompile the native arm code and find where it is generating the code in parts, I'll paste it here so let me know if it makes sense.

This is dumped from Ghidra

/* WARNING: Unknown calling convention -- yet parameter storage is locked */
/* getProdServerEncryptKey() */

undefined8 getProdServerEncryptKey(void)

{
  long lVar1;
  long lVar2;
  undefined2 local_68;
  undefined local_66;
  undefined2 local_64 [2];
  undefined2 local_60;
  undefined local_5e;
  undefined2 local_5c [2];
  undefined2 local_58 [2];
  undefined2 local_54 [2];
  undefined4 local_50;
  undefined2 local_4c;
  undefined2 local_48 [2];
  undefined2 local_44;
  undefined local_42;
  undefined8 local_40;
  undefined8 uStack_38;
  undefined local_30;
  long local_28;
  
  lVar1 = tpidr_el0;
  local_28 = *(long *)(lVar1 + 0x28);
  local_42 = 0;
  local_44 = 0x6465;
  local_48[0] = 0x2a;
  local_4c = 0x69;
  local_50 = 0x646a6977;
  local_54[0] = 0x24;
  local_58[0] = 0x68;
  local_5c[0] = 0x36;
  local_5e = 0;
  local_60 = 0x6566;
  local_64[0] = 0x33;
  local_66 = 0;
  local_68 = 0x7765;
  local_30 = 0;
  uStack_38 = 0;
  local_40 = 0x3231;
  __strcpy_chk(&local_40,&local_44,0x11);
  __strcat_chk(&local_40,local_48,0x11);
  __strcat_chk(&local_40,&local_50,0x11);
  __strcat_chk(&local_40,local_54,0x11);
  __strcat_chk(&local_40,local_58,0x11);
  __strcat_chk(&local_40,local_5c,0x11);
  __strcat_chk(&local_40,&local_60,0x11);
  __strcat_chk(&local_40,local_64,0x11);
  __strcat_chk(&local_40,&local_68,0x11);
  lVar2 = cJSON_CreateString(&local_40);
  if (*(long *)(lVar1 + 0x28) == local_28) {
    return *(undefined8 *)(lVar2 + 0x20);
  }
                    /* WARNING: Subroutine does not return */
  __stack_chk_fail();
}

I've parsed it through chatgpt but it returns a 17 character string. I'm not as clued up as I once was in assembly, so please let me know if anyone wishes to help with this and I'll point you in the right direction.
From my research, it appears to be ecnrypting and decrypting using AES/ECB/PKCS5Padding

@neilzilla
Copy link
Owner

Once we crack this it will be similar to the password encryption, it just seems to run all incoming and outgoing requests through an encryption function

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation enhancement New feature or request help wanted Extra attention is needed question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants