Closed BenPru closed 1 year ago
As far as I can tell from my reverse engeneering they only poll data, the heatpump never sends data on its own. The only case where that maybe happens is the data thet gets sent to heatpump24.com but thats useless to us.
I never used the Websockets API (only in my node red integration https://github.com/Bouni/node-red-contrib-luxtronik2-ws) because I never figured out how to work with the IDs properly as the change on every request.
And the socket api works very well for me ...
Yes, the websocket seems to be very stable but slower as the sockets. I'm currently brute forcing it. Perhaps I find another login as 999999 which provides more informations.
I'm still trying to understand what the issue is that you're trying to solve with the websockets. Why would we need to match the information from the websocket to the information of the old TCP socket API? Isn't it an "either or", so either we're going to use the reverse engineered TCP socket, or the websocket. Or what am I missing here?
It is possible to crash the heatpump using sockets. Websockets seems to be stable. E.g. firmware revision is only provided by websocket not via socket. --> Need for the update sensor for firmware version check.
I am currently parsing the websocket interface to log some data of my heat pump. I can conform that it is also possible to crash the heat pump via the websocket interface. If I recall correctly, one has to send "GET;$id" with a wrong "$id".
The websocket interface provides some more information if you log in as "Installateur" or as "Kundendienst". As Installateur, you see additionally the (current and desired) "Spreizung" of the heat circuit and of the heat source. As "Kundendienst", you also get more temperatures: "Vorlauf Soll", "Verdampfungstemp. d" and "Verflüssigungstemp. b"; and "Freq. min." ,"Freq. max." under "Ausgänge". It would be interesting to locate these temperatures in the calculations of the socket interface.
As "Kundendienst", you also see some Logs: An "Info Log" (which for me only contains timestamps with the message "Eltwin Log" and the id 32) and an "EventLog" in which changes of parameters are logged (but not if the parameter was changed via the socket interface).
I doubt that there is another password than "999999" (which is configurable) to log into the websocket interface. I can try to check whether I can confirm this by looking into the firmware.
It would be interesting to locate these temperatures in the calculations of the socket interface.
Yes. I think the socket interfaces provides the same informations but the websocket has for each value the name of the value.
The websocket interface provides some more information if you log in as "Installateur" or as "Kundendienst"
Do you mean heatpump24.com or the local web interface (which uses the websocket)? For now I have tried 0-999999 and were was no other login as the customer (999999). Every unknown login gets the default readonly data. I check every login and check which gets more data like 999999. Now I try > 999999 but the websocket is slow....
I doubt that there is another password than "999999" (which is configurable) to log into the websocket interface.
Do you know how an "Installateur"/"Kundendienst" logins? There is only one password input without a user name.
I can try to check whether I can confirm this by looking into the firmware.
That would be awesome.
I mean the local web interface (websocket on my heat pump). You first have to log in with 999999 (or your custom password) and then under "Zugang: Benutzer" you can enter the Installateur- or Kundendienst-Passwort.
In the firmware, I have found the location at which the login request (on the websocket) is evaluated, by I did not understand the assembler, yet.
In the firmware, I have found the location at which the login request (on the websocket) is evaluated, by I did not understand the assembler, yet.
Which tool are you using? ghidra is super powerful and able to de-compile most of the assembly listing into readable C code.
I was able to find / verify some interesting aspects in the code (passwords for login on heat pump itself). Haven't looked at the Websocket aspect yet, though. Do you have a location where the password is evaluated?
I was able to find / verify some interesting aspects in the code (passwords for login on heat pump itself). Haven't looked at the Websocket aspect yet, though. Do you have a location where the password is evaluated?
Do you have the ssh login?
Had a (quick) look. Could find the following passages related to password handling and the webserver:
Somewhere at around 00098d18
:
void Init_Webserver_Password(void)
{
if ((999999 < WebserverPassword) || (G_werte_neu != '\0')) {
storeParameter(0x2f3,9,(int *)0x0);
storeParameter(0x2f4,9,(int *)0x0);
storeParameter(0x2f5,9,(int *)0x0);
storeParameter(0x2f6,9,(int *)0x0);
storeParameter(0x2f7,9,(int *)0x0);
storeParameter(0x2f8,9,(int *)0x0);
}
return;
}
Somewhere around 001e740c
:
/* WARNING: Could not reconcile some variable overlaps */
/* WSS_Client::processTraffic(char*, unsigned int) */
undefined4 WSS_Client::processTraffic(char *param_1,uint param_2)
{
int iVar1;
undefined4 uVar2;
char cVar3;
undefined uVar4;
bool bVar5;
void *local_10;
int local_c;
iVar1 = sscanf((char *)param_2,"LOGIN;%d",&local_c);
if (iVar1 != 0) {
iVar1 = WebserverPassword;
if (local_c != WebserverPassword) {
iVar1 = 0;
}
cVar3 = (char)iVar1;
if (local_c == WebserverPassword) {
cVar3 = '\x01';
}
param_1[0x14] = cVar3;
uVar2 = sendPage((WSS_Client *)param_1,(void *)0x0,4);
return uVar2;
}
iVar1 = sscanf((char *)param_2,"GET;0x%p",&local_10);
if (iVar1 != 0) {
uVar2 = sendPage((WSS_Client *)param_1,local_10,4);
return uVar2;
}
iVar1 = strcmp((char *)param_2,"REFRESH");
if (iVar1 == 0) {
uVar2 = sendRefresh((WSS_Client *)param_1);
return uVar2;
}
if (param_1[0x14] == '\0') {
return 0;
}
iVar1 = sscanf((char *)param_2,"SET;set_0x%p;%d",&local_10,&local_c);
if (iVar1 == 2) {
uVar2 = setParam((WSS_Client *)param_1,local_10,local_c);
return uVar2;
}
iVar1 = sscanf((char *)param_2,"SAVE;%d",&local_c);
if (iVar1 == 1) {
bVar5 = local_c != 1;
if (bVar5) {
local_c = 0;
}
uVar4 = (undefined)local_c;
if (!bVar5) {
uVar4 = true;
}
uVar2 = saveParams((WSS_Client *)param_1,(bool)uVar4);
return uVar2;
}
if (Einst_RemoteControl != 0) {
iVar1 = sscanf((char *)param_2,"MOVE;%d",&local_c);
if (iVar1 == 1) {
bVar5 = true;
goto LAB_001e7674;
}
}
bVar5 = false;
LAB_001e7674:
if (!bVar5) {
return 0;
}
uVar2 = performRemoteMove((WSS_Client *)param_1,(uchar)local_c);
return uVar2;
}
This is basically the main function that deals with processing the websocket commands. Essentially there is only a few commands:
LOGIN;%d
GET;0x%p
SET;set_0x%p;%d
SAVE;%d
MOVE;%d
REFRESH
The format for this command relates to format strings that are used by sscanf.
Based on this, it seems to be that there is only one password, which is initialized to 999999
. Every digit of this password is saved parameter (0x2f3
- 0x2f8
, e.g. 755
- 760
).
When I login with 999999
to the websocket interface, it looks like this:
As you can see, I'm logged in as Benutzer
.
I can than log in as Installateur
by using 9445
as password in the Zugang
tab (9445
is the "secret" password to become Installateur
that can also be used locally on the Luxtronik device. It's hard-coded into the firmware):
Afterwards the main page looks like this:
There are some additional data points when using Installateur
(e.g. Abtaubedarf
), but overall it looks quite similar.
Do you have the ssh login?
Yes, although I haven't originally discovered it. Details can be found here: https://github.com/Bouni/luxtronik-firmware-analysis
To be honest: The SSH login wasn't too helpful so far. The application itself can be extracted from the downloadable firmware package. Being root on the heat pump is cool, of course, but essentially its a minimalistic Linux environment running - more or less - one binary that exposes all of the services to the network.
To be honest: The SSH login wasn't too helpful so far. The application itself can be extracted from the downloadable firmware package. Being root on the heat pump is cool, of course, but essentially its a minimalistic Linux environment running - more or less - one binary that exposes all of the services to the network.
The firmware can be even fetched from the heat pump itself: it is served by the webserver under http://my_heatpump/appl
...
The firmware can be even fetched from the heat pump itself: it is served by the webserver under http://my_heatpump/appl...
Nice finding, haven't even tried that. Essentially you can download all files from within /home
, including the passwd
and shadow
:
http://my_heatpump/share/shadow
and http://my_heatpump/share/passwd
.
ls dump:
# pwd
/home
# ls -R
.:
10Min_1 LWD.lin ParamArchive_1673222400 SWPH291.lin index.html lang_it lang_slo
10Min_2 LWD45.lin ParamArchive_1673308800 Webserver lang_CR lang_lt lang_suo
ASB.bin LWD90.lin ParamArchive_1673395200 appl lang_cz lang_lv lang_sve
ASB_BL_Switch.bin LWDRev.lin ParamArchive_1673481600 appl.cfg lang_dan lang_mag lang_tr
ASB_bootloader.bin LuxConst.sqlite ParamArchive_1673568000 appl_param1 lang_de lang_ned share
Defines.txt MSW_15.lin ParamArchive_1673654400 appl_param2 lang_ee lang_nor timezone
GLT.conf MSW_Inverter.lin ParamArchive_1673740800 bootloader.lin lang_en lang_p udhcpc.script
HZIO.lin NewProc SEC.bin default.sqlite lang_es lang_pol
Info.dti ParamArchive_1672617600 SWP.lin default.sqlite-wal lang_fr lang_ro
LD2AG.lin ParamArchive_1673136000 SWPH.lin firmware lang_hr lang_sk
./Webserver:
Lux.js LuxSim.jpg base.css index.html jquery.js saveIcon.png
./share:
localtime passwd shadow
All of this are interesting findings, I'm currently documenting them. Probably not too relevant for this topic, though.
Yes, I also found the passwd
and the shadow
file... It is scary that the heat pump exposes its own root password...
Yes, I also found the
passwd
and theshadow
file... It is scary that the heat pump exposes its own root password...
Well, security-wise this thing is a good demonstration on how to not to it. Basically they are doing every mistake you can make. Feels like its the 90's again in terms of IT security.
On the other hand: For our purpose this is very good, as the official API (GLT Lizenz) does cost money and is not really useful/powerful.
By the way: Coming back to password and access codes:
This is the passage (after some de-compiling) that deals with access codes and contains the secrets:
void CheckPassword(ushort password)
{
int access_level;
if (password == 7311) {
access_level = 1;
}
else if (password == 9445) {
access_level = 3;
}
else {
access_level = 0;
}
storeParameter(107, access_level, (int *)0x0);
return;
}
At least in terms of entering codes there is only those: 9445
and 7311
.
There is another way by using USB sticks. That way you can get Kundendienst
and Werksdienst
access levels, but that's not too helpful here.
Following up on those access codes:
9445
represents Installateur
(see above)7311
represents Kundendienst
.Here you have additional options:
As you can see there are Kurzprogramme
. That way you can heat up the water or activate Abtauen.
Also there are is way more information in the web interface:
@BenPru Maybe this is helpful to you?
I've also tried this with access level manufacturer
(i.e. Werk
):
There is some additional data compared to after sales service
(= Kundendienst
), e.g. Target flow
or Defrost End
.
Also, since I figured out how the access level is managed internally, I've prepared a pull request to set this remotely very easily without the need to enter any codes and/or inserting specially crafted USB sticks. You'll find the details in #42.
@BenPru Maybe this is helpful to you?
Thanks a lot. Very interesting. Unfortunately, this doesn't make a big difference with my Novelan LAD 7. Only the values Verdampfungstemp.
, Verflüssigungstemp.
and Abtauwunsch
have been added. I will include this in my integration. Then I covered (at least for my LAD 7) all readable and the most important writable values of the Luxtronik web interface in the integration.
The categories BMS, Smart and Info Log doesn't exist in my case.
Should the integration have a toggle for param 107?
The download http://my_heatpump/appl
is the raw firmware and not the same as the download package from the ait download page? I can create a link in the integration to this and allow a backup. But a raw file is not useful for a normal user.
I will include this in my integration. Then I covered (at least for my LAD 7) all readable and the most important writable values of the Luxtronik web interface in the integration.
Are you already using information from the web socket interface in your integration? Thought you're still using the old API and are only experimenting with the new websocket stuff.
The categories BMS, Smart and Info Log doesn't exist in my case.
Interesting, no idea, I didn't do anything special to get them activated.
Should the integration have a toggle for param 107?
Well, I'm not sure about this. At least the highest level (manufacturer
= Werk
) gives you a lot of options (locally). Apparently you can even change some (serial) numbers, etc. Probably you can seriously break something, if you don't know what you're doing.
For the sake of security and robustness I would leave it out to be honest for now. You could mention it in the documentation and/or wait for people to find out and ask for it. But giving them full privileges without them asking for it, might go wrong.
The download http://my_heatpump/appl is the raw firmware and not the same as the download package from the ait download page?
The download package contains many files, including the appl
binary. The appl
is just the binary that is being run. You can easily extract the firmware yourself. This is well described here: https://github.com/Bouni/luxtronik-firmware-analysis
I don't think that a download / backup is needed for normal operation. Nothing to gain from it, so I would not put it into your integration. There are some other (configuration) file within /home
that might be more relevant, but to be honest, I don't see a benefit for the HA integration to add links to those, etc.
Are you already using information from the web socket interface in your integration? Thought you're still using the old API and are only experimenting with the new websocket stuff.
No, I don't use the websocket in the integration. Just playing and looking into it.
Sockets and websockets can push messages / data from server to client. I looked at the luxtronik web interface in the firmware and recreated it as a python test. Unfortunately they poll the data every second instead a websocket event
new data
or something else.Do you know if the socket api (8889) can server events?
Btw.: Have you an idea how to match socket api and websocket api values? For example the
flow in
andout temperatures
are calculations(3004) 10 and 11
in the socket. In the websocket the flow in and out temperatures are ingroup Temperaturen (@id=0x0x594240)
with@id 0x0x598308
and0x0x58d5e0
. Do you know how to match them?3004.10
<-->0x0x598308