EM-129: различия между версиями

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску
(Новая страница: «=EM-129=»)
 
Строка 1: Строка 1:
 
=EM-129=
 
=EM-129=
  +
В связи с нестабильностью питания решил наконец поставить хоть какое-то защитное реле что б не спалить технику <BR>
  +
(в последний раз броски напряжения не пережил свитч Catalyst 3550 и я остался без PoE для все своих железок чем был сильно расстроен)
  +
  +
<BR>
  +
По EM-129 есть практически исчерпывающий обзор от Андрея, которому нет причин не доверять:
  +
* https://www.kirich.blog/obzory/tehnicheskie-obzory/892-wifi-schetchik-elektroenergii-s-funkciey-zaschity-i-upravleniya-em-129-ot-novatek-elektro.html
  +
  +
Однако в обзоре не упоминается ничего про программную часть устройства
  +
  +
=Зачем?=
  +
Я принципиально не хочу отправлять свои данные в любой клауд, если это не мой клауд и привязывать устройство к чему-ьто в интернете мне кажется очень странной идеей
  +
  +
=Пару слов об устройстве=
  +
Я не могу сказать ничего хорошего про реализацию безопастности EM-129
  +
* Поддержка HTTPS отсутвует
  +
* Кабельного подключения нет
  +
Этих 2 факторов вполне достаточно что бы при желании можно было взломать сеть и отснифить пароль - в качестве "защиты" могу скаазть только что надо подойти достаточно близко что бы сниффить траффик.
  +
  +
<BR>
  +
Сигнал достаточно слабый хотя расстяние от места установки до точки доступа - примерно 5 метров и одна бетонная стена
  +
<PRE>
  +
/interface/wireless/registration-table/print
  +
Columns: INTERFACE, MAC-ADDRESS, AP, SIGNAL-STRENGTH, TX-RATE, UPTIME
  +
2 wlan-2.4Ghz-ssid-infra-1 CC:50:E3:FA:83:55 no -81dBm@1Mbps 18Mbps 1d1h13m32s
  +
</PRE>
  +
  +
  +
=Получение данных=
  +
О программной реализации интерфейса тоже можо сказать мало хорошего
  +
<BR>
  +
Из плюсов могу отметить только то что инерфейс работает относительно быстро и не слишком уродлив, впрочем что и не удивительно - под капотом там JavaScript который только отсылает на устройство запросы данных, вся обработка и отрисовка происходит на стороне браузера
  +
  +
<BR>
  +
  +
Из минусов - авторизация сделана максимально плохо
  +
* Используется только пароль, без логина
  +
* При авторизации создается Session ID (далее SID) который может быть только один и который по сути представляет собой префикс в URL для получения данных
  +
* Прямое следствие этого - на устройство можно зайходить и смотреть только одному пользователю одновременно. При подключении второго SID меняется и первого "отлогинивает"
  +
* BasicAuth был бы лучше в разы
  +
  +
  +
Для того что бы понять как происходит авторизация пришлось немного покопаться в коде JS (что замечу говорит о "удачности" решения)
  +
  +
Авторизация происходит следующим образом
  +
* Пользователь вводит пароль
  +
* Браузер отправляет на устройство запрос что бы получить "соль" (случайное число) и тип устройства (похоже что аналогичный код используется не только в EM-129 но и других реле)
  +
* На оснвани полученой соли, имени устройства и пользовательского пароля формируется "секретная строка" и отправляется на сервер
  +
* Если строка верна то сервер возвращает SID
  +
* ВСЕ!
  +
  +
=Код скрипта=
  +
27 строк на bash
  +
  +
* IP - адрес реле
  +
* SALT_URL - адрес куда посылать запрос на "соль"
  +
* TOKEN_URL - адрес куда послылать запрос на SID
  +
* ALL_DATA_URI - суффикс запроса данных
  +
  +
Секретная строка формируется следующим образом:
  +
  +
* sha1 от строки состоящей из 3 частей
  +
- имя устройства
  +
- Пользовательский пароль закодированный в base64
  +
- "соль"
  +
  +
По шагам
  +
* A__EM_129_SALT="$(curl ${SALT_URL} | jq -r '.SALT')" - послать запрос на соль и взять поле с именем "SALT" из полученного json
  +
* S=$(printf ${EM_129_PASSWORD} | base64) - закодировать пароль
  +
* SUM="${E__EM_129_DEVNAME}${S}${A__EM_129_SALT}" - склеять строки
  +
* LOGIN="$(printf "${SUM}" | sha1sum | awk '{ print $1}')" - взять sha1 от склейки строк
  +
* SID="$(curl "${TOKEN_URL}${LOGIN}"| jq -r '.SID')" - отправить запрос на SID и взять из ответа значение поля SID
  +
  +
Получение данных дальше
  +
* ALL_DATA_URL="http://${IP}/${SID}/${ALL_DATA_URI}" - сформировать адрес куда слать запрос с учетом SID
  +
* D=$(curl ${ALL_DATA_URL} | jq -r .) получить данные
  +
  +
Данные получаются в виде json
  +
<PRE>
  +
{
  +
"volt_msr": 2302,
  +
"freq_msr": 5000,
  +
"cur_msr": 321,
  +
"pows_msr": 740,
  +
"enrga_msr": 32,.
  +
"enrga_d_msr": 0,
  +
"enrga_w_msr": 0,
  +
"enrga_m_msr": 0,
  +
"enrgs_msr": 39,
  +
"sys_flag": 1409482896,
  +
"faul_flag": 0,
  +
"ar_time": 0,
  +
"cost_energy": 1700,
  +
"cost_unit": 16,
  +
"STATUS": "OK"
  +
}
  +
</PRE>
  +
  +
Код скрипта
  +
<PRE>
  +
#!/bin/bash
  +
  +
set -eu${DEBUG:+x}
  +
  +
IP="192.168.31.250"
  +
SALT_URL="http://${IP}/api/login?salt"
  +
TOKEN_URL="http://${IP}/api/login?login="
  +
ALL_DATA_URI="api/all/get?volt_msr&freq_msr&cur_msr&pows_msr&enrga_msr&enrga_d_msr&enrga_w_msr&enrga_m_msr&enrgs_msr&sys_flag&faul_flag&ar_time&cost_energy&cost_unit"
  +
  +
A__EM_129_SALT="$(curl ${SALT_URL} | jq -r '.SALT')"
  +
E__EM_129_DEVNAME="EM-129"
  +
EM_129_PASSWORD="12345678"
  +
  +
S=$(printf ${EM_129_PASSWORD} | base64)
  +
SUM="${E__EM_129_DEVNAME}${S}${A__EM_129_SALT}"
  +
LOGIN="$(printf "${SUM}" | sha1sum | awk '{ print $1}')"
  +
SID="$(curl "${TOKEN_URL}${LOGIN}"| jq -r '.SID')"
  +
  +
  +
ALL_DATA_URL="http://${IP}/${SID}/${ALL_DATA_URI}"
  +
D=$(curl ${ALL_DATA_URL} | jq -r .)
  +
if [ "${D}X" != "X" ];
  +
then
  +
echo "${D}"
  +
else
  +
echo "{}"
  +
exit 1
  +
fi
  +
exit 0
  +
</PRE>

Версия 14:18, 14 августа 2022

EM-129

В связи с нестабильностью питания решил наконец поставить хоть какое-то защитное реле что б не спалить технику
(в последний раз броски напряжения не пережил свитч Catalyst 3550 и я остался без PoE для все своих железок чем был сильно расстроен)


По EM-129 есть практически исчерпывающий обзор от Андрея, которому нет причин не доверять:

Однако в обзоре не упоминается ничего про программную часть устройства

Зачем?

Я принципиально не хочу отправлять свои данные в любой клауд, если это не мой клауд и привязывать устройство к чему-ьто в интернете мне кажется очень странной идеей

Пару слов об устройстве

Я не могу сказать ничего хорошего про реализацию безопастности EM-129

  • Поддержка HTTPS отсутвует
  • Кабельного подключения нет

Этих 2 факторов вполне достаточно что бы при желании можно было взломать сеть и отснифить пароль - в качестве "защиты" могу скаазть только что надо подойти достаточно близко что бы сниффить траффик.


Сигнал достаточно слабый хотя расстяние от места установки до точки доступа - примерно 5 метров и одна бетонная стена

/interface/wireless/registration-table/print
Columns: INTERFACE, MAC-ADDRESS, AP, SIGNAL-STRENGTH, TX-RATE, UPTIME
2  wlan-2.4Ghz-ssid-infra-1  CC:50:E3:FA:83:55  no  -81dBm@1Mbps     18Mbps                  1d1h13m32s


Получение данных

О программной реализации интерфейса тоже можо сказать мало хорошего
Из плюсов могу отметить только то что инерфейс работает относительно быстро и не слишком уродлив, впрочем что и не удивительно - под капотом там JavaScript который только отсылает на устройство запросы данных, вся обработка и отрисовка происходит на стороне браузера


Из минусов - авторизация сделана максимально плохо

  • Используется только пароль, без логина
  • При авторизации создается Session ID (далее SID) который может быть только один и который по сути представляет собой префикс в URL для получения данных
  • Прямое следствие этого - на устройство можно зайходить и смотреть только одному пользователю одновременно. При подключении второго SID меняется и первого "отлогинивает"
  • BasicAuth был бы лучше в разы


Для того что бы понять как происходит авторизация пришлось немного покопаться в коде JS (что замечу говорит о "удачности" решения)

Авторизация происходит следующим образом

  • Пользователь вводит пароль
  • Браузер отправляет на устройство запрос что бы получить "соль" (случайное число) и тип устройства (похоже что аналогичный код используется не только в EM-129 но и других реле)
  • На оснвани полученой соли, имени устройства и пользовательского пароля формируется "секретная строка" и отправляется на сервер
  • Если строка верна то сервер возвращает SID
  • ВСЕ!

Код скрипта

27 строк на bash

  • IP - адрес реле
  • SALT_URL - адрес куда посылать запрос на "соль"
  • TOKEN_URL - адрес куда послылать запрос на SID
  • ALL_DATA_URI - суффикс запроса данных

Секретная строка формируется следующим образом:

  • sha1 от строки состоящей из 3 частей
- имя устройства
- Пользовательский пароль закодированный в base64
- "соль"

По шагам

  • A__EM_129_SALT="$(curl ${SALT_URL} | jq -r '.SALT')" - послать запрос на соль и взять поле с именем "SALT" из полученного json
  • S=$(printf ${EM_129_PASSWORD} | base64) - закодировать пароль
  • SUM="${E__EM_129_DEVNAME}${S}${A__EM_129_SALT}" - склеять строки
  • LOGIN="$(printf "${SUM}" | sha1sum | awk '{ print $1}')" - взять sha1 от склейки строк
  • SID="$(curl "${TOKEN_URL}${LOGIN}"| jq -r '.SID')" - отправить запрос на SID и взять из ответа значение поля SID

Получение данных дальше

  • ALL_DATA_URL="http://${IP}/${SID}/${ALL_DATA_URI}" - сформировать адрес куда слать запрос с учетом SID
  • D=$(curl ${ALL_DATA_URL} | jq -r .) получить данные

Данные получаются в виде json

{
  "volt_msr": 2302,
  "freq_msr": 5000,
  "cur_msr": 321,
  "pows_msr": 740,
  "enrga_msr": 32,.
  "enrga_d_msr": 0,
  "enrga_w_msr": 0,
  "enrga_m_msr": 0,
  "enrgs_msr": 39,
  "sys_flag": 1409482896,
  "faul_flag": 0,
  "ar_time": 0,
  "cost_energy": 1700,
  "cost_unit": 16,
  "STATUS": "OK"
}

Код скрипта

#!/bin/bash

set -eu${DEBUG:+x}

IP="192.168.31.250"
SALT_URL="http://${IP}/api/login?salt"
TOKEN_URL="http://${IP}/api/login?login="
ALL_DATA_URI="api/all/get?volt_msr&freq_msr&cur_msr&pows_msr&enrga_msr&enrga_d_msr&enrga_w_msr&enrga_m_msr&enrgs_msr&sys_flag&faul_flag&ar_time&cost_energy&cost_unit"

A__EM_129_SALT="$(curl ${SALT_URL} | jq -r '.SALT')"
E__EM_129_DEVNAME="EM-129"
EM_129_PASSWORD="12345678"

S=$(printf ${EM_129_PASSWORD} | base64)
SUM="${E__EM_129_DEVNAME}${S}${A__EM_129_SALT}"
LOGIN="$(printf "${SUM}" |  sha1sum | awk '{ print $1}')"
SID="$(curl "${TOKEN_URL}${LOGIN}"| jq -r '.SID')"


ALL_DATA_URL="http://${IP}/${SID}/${ALL_DATA_URI}"
D=$(curl ${ALL_DATA_URL} | jq -r .)
if [ "${D}X" != "X" ];
then
    echo "${D}"
else
    echo "{}"
    exit 1
fi
exit 0