zaLinux.ru

Как расшифровать NS3 пароли из конфигурационного файла ZyXEL (NDMS V2)


Роутеры ZyXEL, например, модель Keenetic Lite II, имеют вкладку System → Configuration на которой можно скачать файл running-config (running configuration). Этот файл содержит текущие настройки, в том числе пароль для подключению к Интернет-провайдеру и пароль для Wi-Fi сети.

Пароли хранятся в закодированном виде, например:

authentication wpa-psk ns3 HfNV/Uq8ubal+UXhXERgHRdO

authentication password ns3 9IpS3eYkkEN3Vld3CXRZtnBz

Строка с wpa-psk — это закодированный пароль от точки доступа Wi-Fi, а строка с password это пароль для Интернет-подключения к провайдеру.

Этот метод кодирования называют по-разному: NS3 / NDMS V2 / ZyXEL config.

Пользователь Felis-Sapiens с помощью обратного инженеринга раскрыл метод кодирования и даже написал скрипт на Python 3 для кодирования и декодирования.

А пользователь VasiliyP сделал ещё одну реализацию декодирования на JavaScript, благодаря чему пользователи могут декодировать NS3 (NDMS V2) прямо в окне веб-браузера.

Декодирование NS3 (NDMS V2) в веб-браузере

Создайте файл zyxel_scramble.htm:

gedit zyxel_scramble.htm

И скопируйте в него

<!DOCTYPE html>

<html>
  
  <head>
    <meta charset="utf-8">

<meta name="robots" content="noindex">
    <title>ns3 decoder</title>
    <script>

var Base64 = {
    _keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
    decode: function (f_input) {
        var result = '';
        var v1, v2, v3;
        var v4, v5, v6, v7;
        var v8 = 0;
        f_input = f_input.replace(/[^A-Za-z0-9+/=]/g, '');
        while (v8 < f_input.length) {
            v4 = this._keyStr.indexOf(f_input.charAt(v8++));
            v5 = this._keyStr.indexOf(f_input.charAt(v8++));
            v6 = this._keyStr.indexOf(f_input.charAt(v8++));
            v7 = this._keyStr.indexOf(f_input.charAt(v8++));
            v1 = v4 << 2 | v5 >> 4;
            v2 = (v5 & 15) << 4 | v6 >> 2;
            v3 = (v6 & 3) << 6 | v7;
            result = result + String.fromCharCode(v1);
            if (v6 != 64) {
                result = result + String.fromCharCode(v2)
            };
            if (v7 != 64) {
                result = result + String.fromCharCode(v3)
            }
        };
        return result
    }
}
     
      function xor1(a0, buffer){
        var a1 = 0;
        var a3 = 0;

        var v1 = 1;
        for (;;) {
          v1++;
          if (v1 == a0) break;
          a3 ^= buffer[a1 + v1 - 2];
        }

        var a2 = 1;
        var t0 = 8;
        for (;;) {
          var v0 = 0xFF ^ a3;
          v0 = v0 << a2;
          var v1 = a3 >> a2;
          v1 ^= v0;
          v1 &= 0xFF;
          v0 = 0xFF ^ v1;
          v0 ^= a3;
          v1 = v1 << a2;
          v1 ^= v0;
          a2++;
          a3 = v1 & 0xFF;
          if (a2 == t0) break;
        }

        var v1 = 1;
        for (;;) {
          v1++;
          a1++;
          if (v1 == a0) return;
          buffer[a1 - 1] ^= a3;
        }
      }

      function xor2(a0, buffer, a2, a3){
        var a1 = 0;
        a2 &= 0xFF;
        a3 &= 0xFF;
        var v1 = 1;
        for (;;) {
          v1 += 1;
          a1++;
          if (v1 == a0) return;

          var v0 = buffer[a1 - 1];
          v0 ^= a3;
          a3 += a2;
          buffer[a1 - 1] = v0 & 0xFF;
          a2 = a3 - a2;
        }
      }

      function ns3decode(ns3){
        //var buffer = Base64.decode(ns3).split('').map(v => v.charCodeAt(0));
        var buffer = Base64.decode(ns3).split('');
        for (var i = 0; i < buffer.length; i++) buffer[i] = buffer[i].charCodeAt(0);

        var s4_size = buffer.length;
        var s2_size = s4_size - 2;
        var size24924925 = s4_size * 0x24924925;

        var hi_size24924925 = size24924925 / 0x100000000;
        var tmp = s4_size - hi_size24924925;

        var addr_move_to = (hi_size24924925 + (tmp / 2 )) / 4;
        var s0 = buffer.splice(addr_move_to, 1); 
        buffer.push(buffer[buffer.length - 1]);

        var mod = s0 % (s4_size - 1);

        var addr_move_to = mod;

        var s2 = buffer.splice(addr_move_to, 1); 
        buffer.push(buffer[buffer.length - 1]);

        xor1(s4_size, buffer);
        xor2(s4_size, buffer, s2, s0);
        //var str = buffer.map(v => String.fromCharCode(v)).join('');
        var arr = [];
        for (var i = 0; i < buffer.length; i++) arr[i] = String.fromCharCode(buffer[i]);
        var str = arr.join('');

        for(var i = 0; i < buffer.length; i++){
          if (!buffer[i]) {
            str = str.substr(0, i);
            break;
          }
        }

        return str;
      }
        
      function calculate(){
        var ns3 = document.getElementById("input").value;

        if(ns3.length == 0){
          document.getElementById("output").hidden = true;
          return;
        }

        var decoded = ns3decode(ns3);
        var box = document.getElementById("output");
        box.value = decoded;
        box.hidden = false;
        box.select();
      }

      function init() {
        var box = document.getElementById("input");

        box.ondragenter = function() {
          this.value = '';
          document.getElementById("output").value = '';
        };

        box.ondrop = function() {
          calculate();
        };


        box.onclick = function() {
          this.select();
        };

        box.select();

        var box = document.getElementById("output");
        box.onclick = function() {
          this.select();
        };
      }

    </script>


  </head>
  
  <body onload="init()" >
    
    <h1>ns3 decoder</h1>
    <input type="text" id="input" style="border: solid 1px #EEEEEE" value="BiEjZE6GOPmOmTtDIO0Gtcw+"/>
    <input type="submit" id="button" onClick="calculate()" value="decode"/>
    <br>
    <input type="text" id="output" hidden="true" style="border: solid 1px #EEEEEE" />


</body>
</html>

Теперь просто откройте файл в любом веб-браузере.


Введите в окно данные для декодирования и нажмите кнопку «decode».

Кодирование и декодирование NS3 (NDMS V2) в командной строке

Создайте файл zyxel_scramble.py:

gedit zyxel_scramble.py

И скопируйте в него:

#!/usr/bin/env python3
#
# zyxel_scramble.py
#
# author: Felis-Sapiens
#
# Decode password from ZyXEL config (NDMS V2)

import sys
from base64 import b64decode, b64encode
from hashlib import md5

def first_step(password, x1, x2):
    x1 &= 0xff
    x2 &= 0xff
    for i in range(len(password)):
        password[i] = (password[i] ^ x2) & 0xff
        x2, x1 = x1 + x2, x2
    return password

def second_step(password):
    x = 0
    for b in password:
        x ^= b
    for i in range(1,8):
        a = ((x >> i) ^ (~x << i)) & 0xff
        x = ((a << i) ^ (~a ^ x)) & 0xff
    for i in range(len(password)):
        password[i] ^= x
    return password


def scramble_decode(password):
    if len(password) % 4 != 0:
        password += '=' * (4 - len(password) % 4)
 
    password = list(b64decode(password))
    length = len(password)
    if length not in [0x12, 0x24, 0x48]:
        print('ERROR: invalid input length')
        return
 
    a2 = length // 7
    x2 = password[a2]
    del password[a2]
 
    a1 = x2 % (length - 1)
    x1 = password[a1]
    del password[a1]
 
    password = second_step(password)
    password = first_step(password, x1, x2)
 
    zero_pos = password.index(0)
    if zero_pos != -1:
        length = zero_pos
    return bytes(password[:length]).decode()

def scramble_encode(password):
    old_length = len(password)
    length = len(password) + 3
    if length < 0x13:
        length = 0x12
    elif length < 0x25:
        length = 0x24
    elif length < 0x49:
        length = 0x48
    else:
        print('ERROR: password is too long')
        return
 
    password = password.encode()
    md5_digest = md5(password).digest()
 
    password = list(password)
    if length != old_length:
        password.append(0)
        for i in range(old_length+1, length-2):
            password.append((password[i-old_length-1] * 2 + md5_digest[2 + i%14]) & 0xff)
 
    x1 = md5_digest[0]
    x2 = md5_digest[1]
    password = first_step(password, x1, x2)
    password = second_step(password)
    password.insert(x2 % (length - 1), x1)
    password.insert(length // 7, x2)
    return b64encode(bytes(password))

def main():
    if len(sys.argv) < 3:
        print('Usage: zyxel_scramble.py decode|encode password')
        return
 
    if sys.argv[1] == 'decode':
        password = scramble_decode(sys.argv[2])
    elif sys.argv[1] == 'encode':
        password = scramble_encode(sys.argv[2])
    else:
        print('ERROR: unknown command', sys.argv[1])
        return
    if password is not None:
        print(password)

if __name__ == '__main__':
    main()

Для декодирования используйте команду вида:

python3 zyxel_scramble.py decode 'СТРОКА'

Например:

python3 zyxel_scramble.py decode '9IpS3eYkkEN3Vld3CXRZtnBz'

Для кодирования в NS3 (NDMS V2) используйте команду вида:

python3 zyxel_scramble.py encode 'СТРОКА'

Например:

python3 zyxel_scramble.py encode 'HackWare'

Будет выведена строка вида «b'HfNV/Uq8ubal+UXhXERgHRdO'» - вам нужно взять из неё то, что помещено в одинарные кавычки.


Заключение

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


Рекомендуемые статьи:

Оставить комментарий

Ваш адрес email не будет опубликован.