17 мая 2016 Исправляем вход в адимский интерфейс TP-LINK'а

Перевод: en

В TP-LINK'е сломали импорт настроек после обновления прошивки. На самом деле, его сломали уже довольно давно (как минимум, в 2014 году, судя по сообщениям с некоторых форумов), но я столкнулся с этой проблемой только недавно, обновив свой WDR3600. Я редко меняю прошивку роутера. Источником проблемы стало изменение способа хранения паролей: теперь они не хранятся в окрытом виде, вместо этого записывается некая хэш-сумма (что, само по себе, хорошо). В результате чего, после восстановления сбэкапленных настроек, пользователи потеряли возможность залогиниться в интерфейс роутера.

Одно из возможных решений — сбросить роутер на заводские настройки и повторить кофигурирование по памяти, или списывая с заблаговременно сделанных скриншотов. Подходящих скриншотов у меня не оказалось, а перспектива перенастраивать форвардинг портов и привязку айпишников к MAC-адресам (для выдачи по DHCP) меня не обрадовала.

Немного погуглив, я выяснил, что конфиг экспортируется в виде обычного текста, зашифрованного с помощью симметричного шифра (DES-ECB). К счастью, некие добрые люди уже провели надлежащие исследования, позволяющие его расшифровать. Раскодированный конфиг от старой прошивки состоит из ~1300 пар вида ключ-значение и выглядит примерно так:

lan_ip 192.168.8.200
lan_msk 255.255.255.0
...
lgn_ousr admin
lgn_opswd admin
lgn_usr **********
lgn_pwd **********
...

Чтобы сконвертировать его обратно, в форму, пригодную для восстановления на роутере, нужно, перед шифрования с помощью того же самого шифра, записать в начало файла его MD5-сумму, а с конца дополнить нулевыми байтами до ближайшей восьмибайтовой границы. Я сделал удобный скрипт для автоматизации процесса кодирования/декодирования.

tlrecode.sh

#!/usr/bin/env bash

# tlrecode.sh
# Decode and encode TP-LINK router config files.
#
# Creative Commons CC0 License:
# http://creativecommons.org/publicdomain/zero/1.0/
#
# To the extent possible under law, the person who associated CC0 with this
# work has waived all copyright and related or neighboring rights to this work.

in=""
out=""
mode=""

# See http://teknoraver.net/software/hacks/tplink/
key="478DA50BF9E3D2CF"

tmp_template="tlrecode.XXXXXXXXXX"
tmp=""
tmp2=""

usage() {
    cat <<EOF
tlrecode.sh
Decode and encode TP-LINK router config files.

Usage: tlrecode.sh (-e|-d) [-i] INPUT [-o] OUTPUT

    -i, --input    Input file name.
    -o, --output   Output file name.
    -d, --decode   Decoding mode (default).
    -e, --encode   Encoding mode.
    -h, --help     Print this message.

EOF
}

error() {
    echo "Error: $1" >&2
    exit 1
}

decode() {
    openssl enc -d -des-ecb -K "${key}" -nopad -in "${in}" -out "${tmp}" &&
        tail -c +17 "${tmp}" > "${tmp2}" &&
        tr -d "\000" < "${tmp2}" > "${out}"
}

encode() {
    openssl md5 -binary "${in}" > "${tmp}" &&
        cat "${tmp}" "${in}" > "${tmp2}" &&
        truncate -s %8 "${tmp2}" &&
        openssl enc -e -des-ecb -K "${key}" -nopad -in "${tmp2}" -out "${out}"
}

while [ $# -gt 0 ]; do
    case "$1" in
        -i|--input)
            [ -z "${in}" ] || error "input file '${in}' is already set."
            [ $# -gt 1 ] || error "option '$1' needs an argument."
            in="$2"
            shift 2
            ;;
        -o|--output)
            [ -z "${out}" ] || error "output file '${out}' is already set."
            [ $# -gt 1 ] || error "option '$1' needs an argument."
            out="$2"
            shift 2
            ;;
        -d|--decode)
            [ -z "${mode}" ] || error "mode '${mode}' is already set."
            mode="decode"
            shift 1
            ;;
        -e|--encode)
            [ -z "${mode}" ] || error "mode '${mode}' is already set."
            mode="encode"
            shift 1
            ;;
        -h|--help)
            usage
            exit 0
            ;;
        *)
            if [ -z "${in}" ]; then
                in="$1"
            elif [ -z "${out}" ]; then
                out="$1"
            else
                error "unexpected argument '$1'"
            fi
            shift 1
            ;;
    esac
done

[ -z "${in}" ] && error "no input file given."
[ -f "${in}" ] || error "input file '${in}' does not exist."
[ -z "${out}" ] && error "no output file given."
[ -z "${mode}" ] && mode="decode"

tmp="$(mktemp ${tmp_template})"
tmp2="$(mktemp ${tmp_template})"

if [ "${mode}" == "decode" ]; then
    decode
else
    encode
fi

result=$?
rm "${tmp}" "${tmp2}"
exit ${result}

Для восстановления входа на роутер нужно:

  • сохранить настройки перед обновлением прошивки;
  • сбросить роутер до настроек по умолчанию (если оказалось, что после восстановления сохранённых настроек вход больше невозможен);
  • изменить логин/пароль на желаемые и сохранить новый конфиг;
  • декодировать оба конфига с помощью tlrecode.sh config.bin config.txt && tlrecode.sh config-new.bin config-new.txt;
  • исправить старый конфиг, заменив все строчки, начинающиеся с lgn_, на их вариант из нового конфига;
  • сконвертировать исправленный конфиг с помощью tlrecode.sh -e config.txt config-updated.bin;
  • восстановить настройки роутера, загрузив config-updated.bin.

После завершения процесса обновления, вход с использованием выбранных логина и пароля не должен вызвать проблем.