Descomprimir archivos de configuración lzw

Descomprimir lzw

Algunos routers usan archivos de configuración comprimidos por lzw.

No existe demasiada información en la web para poder descomprimirlos, pero algo hay, en particular:

https://www.ip-phone-forum.de/threads/o2-homebox-6641-daten-auslesen.273298/page-4

Se usa la librería lzw en python, y con unos sencillos pasos se descomprime.

El comienzo de este tipo de archivos es del tipo:

<compresed alg=lzw len=xxxxx> ... <crc=0xXXXXXX>

En la siguiente imagen puede verse:

Hay que recortar todo el comienzo del archivo hasta el byte que comienza con 80 (cualquier editor hex nos valdrá)

Se guarda el archivo y se descomprime con python (instalamos primero el módulo lzw)

y ejecutamos el código para descomprimir, sencillo, indicamos un archivo de salida. El error hay que obviarlo, todo se genera bien.

Y el archivo descomprimido:

Volver a comprimir lzw

Ahora lo ideal sería cambiar cualquier parámetro del archivo descomprimido, recomprimirlo y subirlo al router, sin embargo he encontrado alguna dificultad (no lo he conseguido). Tenemos que calcular el crc y la longitud del archivo. La longitud del archivo indicada en ‘len=’ es justo la del archivo recortado, pero el crc es calculado de alguna manera que desconozco por ahora.

Comprobación de que el valor «len» del archivo original del router, coincide con el calculado por el comando «cksum» con el archivo original del router al quitarle los bytes iniciales hasta el byte «80», el CRC no coincide

 

Para volver a comprimir hay que hacer algo parecido a la descompresión [morebytes=lzw.compres(mybytes) ]

Nos crea un archivo, donde puede inferirse unos bytes de cabecera comunes (comprimiendo distintos archivos se repiten) antes del byte «80». Recortando y añadiendo los bytes «<compressed….  >» podría valer, pero el crc hay que calcularlo como lo hace el router (ver en el siguiente apartado).

Sin embargo, este algoritmo de compresión produce un resultado distinto al original del router (en binario), es decir, la misma configuración (xml) es resultado de dos compresiones distintas, la del router y la de la librería lzw de python.

Profundizando en buscar el por qué, imprimiendo los «codepoint» del algoritmo lzw, vemos que la diferencia es producida por un orden distinto en un único codepoint del diccionario creado (más o menos, al descomprimir se va creando un diccionario con unos codepoints y unos clearbytes, los diccionarios son los mismos en ambos casos)

Archivo original del router (recortando la cabecera), vemos los codepoints al usar el lzw.decompress, donde el primero es el byte 256 (parámetro tamaño del algoritmo lzw)

Sin, embargo, al usar como fuente de lzw.decompress el mismo archivo xml, pero comprimido con python lzw.compress , vemos que los codepoints coinciden uno a uno, con la excepción que el 256 está ahora el último.

Por eso los binarios son distintos.

Buscando en internet sobre firmware de routers zyxel, uno puede encontrar alguno, donde existe una carpeta con utilidades (hostTools), y entre ellas una utilidad (32 bits) compressConfig, que resulta que genera exactamente el mismo archivo de configuración (binario) que el router (eso sí, desde el byte 80).

Adjunto la utilidad en zip: CompressConfig

Por tanto ya tenemos todo.

Calcular el CRC

Más investigaciones y búsquedas por internet, permiten saber cuál es el algoritmo usado para calcular el CRC del archivo binario con la configuración (ojo, desde el byte 80 )

En https://nada-labs.net/2018/crc-algorithm-finder/ tenemos una pequeña utilidad en python que usa la librería crcmod  ( https://pypi.org/project/crcmod/ ), y hace un recorrido por todos los algoritmos que tiene disponibles para poder mostrar el algortimo crc usado:

Nota: pip install me falló, por lo que tuve que compilar los fuentes para poder usar crcmod:

Usando este script con el archivo de configuración sin la cabecera, obtenemos por fin el algoritmo crc usado, que es jamcrc.

The «JAMCRC» is simply the bitwise-not of the standard CRC-32. A quick search turned up this, and I am sure you can find many implementations of CRC-32. Then you just take the not (~) of the result to get the JAMCRC.

Por tanto, ya podemos componer nuestro archivo de configuración modificado.

Una pequeña modificación del script en python nos permite calcular el crc de nuestra configuración (siempre desde el byte 80)

#!/usr/bin/python2
# Finds a CRC algorithm based on data and known CRC
# Requires crcmod
import crcmod
def find_crc(data, expected_crc):
    crc = crcmod.predefined.mkCrcFun('jamcrc')
    return crc(data)
if __name__ == '__main__':
    import argparse
    parser = argparse.ArgumentParser(description='Find CRC algorithm')
    parser.add_argument('infile', help='File containing the data (in binary) to CRC. ')
    args = parser.parse_args()
    data = None
    with open(args.infile, 'rb') as f:
       data = f.read()
    #excrc = int(args.crc, 0)
    crc = find_crc(data, 1)
    if crc:
        print('crcmod predefined algorithm produced %X from the provided data' % crc)
    else:
        print('crcmod predefined algorithm not found')

Bastará copiar la cabecera inicial de nuestro archivo descargado desde el router, pegarla al inicio del nuestro archivo de configuración modificado y comprimido con lzw, y modificar los correspondientes valores de len (obtenido con el comando cksum) y de crc (obtenido con el algoritmo jamcrc)

 

Consideraciones y Notas adicionales

Por desgracia, los routers de los operadores tienen un firmware muy capado y limitado, y lo que uno puede pensar que se puede cambiar al modificar el archivo de configuración, resulta que los cambios no se trasladan al comportamiento del router, es decir, no vale para nada, por ejemplo, he tratado de activar telnet, pero no funciona…(otro sí, por supuesto)

 

También, es posible que el router admita el archivo en xml para subírselo como configuración, sin necesidad de comprimirlo ni calcular longitud ni crc.

 

Algunos routers muestran con páginas web ocultas la configuración directamente en el navegador (en xml)

Algunos enlaces con páginas ocultas del router (accesibles, una vez hecho el login usual)

https://adrenaline.uol.com.br/forum/threads/banda-larga-vivo-xdsl-vdsl-fibra-optica-hfc.594503/page-141

https://www.cristianoronan.com.br/alteracao-das-configuracoes-bloqueadas-pelo-firmware-da-vivo/

http://community.plus.net/aptgm87544/attachments/aptgm87544/TechHelp/64716/1/2704n-plusnet-hack-DIY.pdf

https://pastebin.com/YwweWuna

Pero, como ya he visto, si el router está muy capado, muchas de las cosas que cambiemos no van a tener efecto ninguno… (incluso el interface web del router casca y hay que reinicialo).

Por ejemplo, modificando los valores de Telnet (estaba en DENY_ALL) no se consigue nada, y al reiniciar el router vuelve a cargar el valor DENY_ALL

 

 

10 Comments

  1. Fran · miércoles, 24 junio, 2020 Reply

    Buenas tardes, excelente post, tengo un inconveniente a la hora de hacer el compress, la cabecera varia mucho y el primer byte 80 que encuentro no tiene sentido con el del anterior archivo y el router no lo levanta por este mismo motivo, quisiera saber a qué se puede deber? el resto me funciona perfectamente

    • abrazalaweb · jueves, 25 junio, 2020 Reply

      No sé, lo mejor sería probar con un archivo de configuración (sin modificar) que funcione en el router, descomprimir y comprimir, y ver si funciona al comprimirlo, y cómo son las cabeceras. Podrías dar más detalles de esa cabecera nueva?

      • Fran · jueves, 25 junio, 2020 Reply

        Muchas gracias por tu pronta respuesta, realice la prueba que indicas sin modificar nada el otro dia y sucede lo mismo, te adjunto la cabecera nueva que me devuelve el archivo re-comprimido:

        1E 0F CF 06 D3 60 80 EC 65 39 1C CD 26 F3 70 F4 44 31 17 0C 04 43 F1 F0 28 78 44 39 9B 08 67 03 29 0E 1A 66 34 99 E0 F0 98 5C 36 1E 33 89 08 A2 C2 01 00 F0 92 6E 3A 42 4D C6 53 A1 1C C3 32 3B 98 4F 24 43 29 D8 D2 63 32 CB 25 B2 E2 61 04 9D 3D 9F D0 49 C7 53 69 8A 12 4F 33 11 66 27 23 49 94 E6 3E 18 8F 05 F4 6A 44 FA 80 65 A6 53 AA 15 2A A5 5A B0 0A A2 4B 8A F4 7A 4D 82 C5 4F 39 54

        • abrazalaweb · viernes, 26 junio, 2020 Reply

          ¿Y el archivo descomprimido? ¿cómo es la cabecera? ¿tiene los tags y ? Quizá el crc no sea el mismo que he puesto en el blog, o quizá haya algún pequeño error en el cálculo de la longitud.
          Si te descargas un archivo de configuración del router correcto, y lo descomprimes con esta manera ¿el archivo es un xml legible? Si es así, entonces, el comprimirlo tendría que ir bien. ¿puedes comparar los archivos comprimidos original del router y el que sale con el algoritmo de compresión una vez descomprimido? Ahí tendrá que verse qué es lo que cambia (yo tuve que hacer muchas pruebas así)

          • Fran · sábado, 27 junio, 2020

            El archivo descomprimido es totalmente legible y tiene formato xml, puedo ver las configuraciones y demás, la longitud varía en 5 caracteres aprox cuando lo vuelvo a comprimir pero me da bien, ambos archivos me figura que usan jamcrc, y si intento descomprimir el archivo recomprimido sigue siendo un archivo legible. pero si comparo el hexadecimal de ambos es totalmente distinto, y pierde la cabecera 80 0F 07, tampoco aparecen etiquetas de compress o simil en el archivo comprimido.
            (tienes mi mail por si prefieres una comunicación más fluida por ese medio)

          • Fran · sábado, 27 junio, 2020

            (cabecera del arhivo descomprimido)

  2. Fran · sábado, 27 junio, 2020 Reply

    xml version=»1.0″?
    DslCpeConfig version=»3.0″
    InternetGatewayDevice

    • abrazalaweb · domingo, 28 junio, 2020 Reply

      Vale, perdona, tenía esto un poco «oxidado», ya que al final abandoné y puse el router del ISP en modo «bridge» y me compré un router Asus, más configurable.

      He estado mirando y revisando todas las cosas que tenía de mis pruebas y el propio post, el error también se me producía a mí, y lo explico cuando hablo de los «codepoint», lo que tiene que estar pasando es que el orden no es correcto, en particular el del bit 256, que en el archivo del router aparece al principio, y en el archivo comprimido con lzw aparece al final, habría entonces que modificar un poco el algoritmo para ello. Creo que no lo hice porque encontré una utilidad que está puesta en el post (para descargar) CompressConfig (https://abrazalaweb.net/myBlog/wp-content/uploads/2018/11/CompressConfig.zip)
      La encontré durante toda la investigación que estuve haciendo en algún firmware de routers (Zyxel).

      Usa es herramienta para la re-compresión del archivo modificado, y luego sigue con el tema del crc, la longitud y luego pegar la cabecera original sustituyendo los valores crc y len, tal como se indica en el post.

      Espero que ahora puedas conseguirlo,

      • Fran · domingo, 28 junio, 2020 Reply

        Ahhh, genial, sospechaba que podría ser eso, el tema es que no me queda muy claro cómo ver los codepoints, o como utilizar la herramienta que indicas, tipo en el post dicen que lo usas, pero no me quedo muy claro como, si me puedes explicar un poco mas en detalle como es que lo utilizas tanto al codepoint como a la herramienta estaria muy agradecido.
        Saludos

        • abrazalaweb · lunes, 29 junio, 2020 Reply

          Lo de los codepoints sale de analizar el código fuente de la función lzw en python que se instala, poniendo que muestre algunas cosas por pantalla para ver lo que va haciendo (está en /usr/local/lib/python2.7/dist-packages/)

          La herramienta es simplemente un ejecutable (linux) a la que se le pasan dos argumentos: CompressConfig input file (descomprimido) output file (comprimido)

Leave a Reply

Tu dirección de correo electrónico no será publicada.

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.