4

so I have backup from my router its zte zxv10h201l and its linux based but I can not identify type of compression of this file. Here is couple of first "lines" of it


00000000  99 99 99 99 44 44 44 44  55 55 55 55 aa aa aa aa  |....DDDDUUUU....|
00000010  00 00 00 00 00 00 00 00  00 00 00 04 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 40  |...............@|
00000040  00 01 00 00 00 00 00 80  00 00 23 90 00 00 00 00  |..........#.....|
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000080  04 03 02 01 00 00 00 00  00 00 00 0b 5a 58 56 31  |............ZXV1|
00000090  30 20 48 32 30 31 4c 01  02 03 04 00 00 00 00 00  |0 H201L.........|
000000a0  01 4c 54 00 00 23 78 00  00 20 00 40 34 b7 80 e9  |.LT..#x.. .@4...|
000000b0  80 47 c0 00 00 00 00 00  00 00 00 00 00 00 00 00  |.G..............|
000000c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000d0  00 00 00 00 00 20 00 00  00 03 d0 00 00 04 18 78  |..... .........x|
000000e0  da ed 58 61 53 da 30 18  fe be 5f c1 f1 03 b0 29  |..XaS.0..._....)|
000000f0  88 db 4e 77 07 6d d1 de  00 3b e8 64 b7 2f 5e 6c  |..Nw.m...;.d./^l|
00000100  23 e6 2c 49 2f 4d 11 f6  eb 97 da 56 0b da 34 45  |#.,I/M.....V..4E|
00000110  77 d3 13 94 2b 94 27 6f  9e be 79 f2 bc 6f 7b 6c  |w...+.'o..y..o{l|
00000120  f6 bf 7d 6a 88 d7 b1 7b  15 34 08 5c a0 93 a6 d9  |..}j...{.4.\....|
00000130  ef c3 08 35 1b 13 7a 67  d0 98 f0 93 26 68 a6 a0  |...5..zg....&h..|
00000140  7b a0 38 dd 18 d3 93 a6  56 38 79 ff 83 39 ca 02  |{.8.....V8y..9..|
00000150  d8 03 9b 5c d3 66 63 09  03 01 03 e2 4f 17 ef 8e  |...\.fc.....O...|
00000160  96 be 80 d6 d5 40 27 fd  a6 03 fd 30 3b 7d 98 fc  |.....@'....0;}..|
00000170  92 1e f5 ec d8 4e 8e cd  83 c2 dc 07 62 f2 8c ef  |.....N......b...|

Afer that I connected ttl-rs232 to router and when backup button is pressed on my router web UI this show up in log


=~=~=~=~=~=~=~=~=~=~=~= PuTTY log 2014.01.31 22:58:29 =~=~=~=~=~=~=~=~=~=~=~=
04:15:12 [webd][Info] [upload.c(1138)my_upload_file] Enter my_upload_file.
04:15:12 [webd][Info] [upload.c(1343)my_upload_file] Begin download file.(filetype : config)
04:15:12 [DB][Info] [dbc_mgr_file.c(1644)dbGetBinFile] DB get cfg start
04:15:12 [FLASHRW][Info] [proc_file_mod.c(1204)file_open] open file: /proc/cfg/db_user_cfg.xml
04:15:12 [FLASHRW][Info] [proc_file_mod.c(1334)file_close] close file: /proc/cfg/db_user_cfg.xml
04:15:12 [DB][Info] [dbc_mgr_file_en(570)dbcCfgFileIsEnc] FileIsEncry return 0
04:15:12 [FLASHRW][Info] [proc_file_mod.c(1204)file_open] open file: /proc/cfg/db_user_cfg.xml
04:15:12 [FLASHRW][Info] [proc_file_mod.c(1334)file_close] close file: /proc/cfg/db_user_cfg.xml
04:15:12 [DB][Info] [dbc_mgr_file_si(198)dbcCfgFileSign] SignFile return 0
04:15:12 [DB][Info] [dbc_mgr_file_ve(277)dbcCfgFileVersi] add FileVersion return 0
04:15:12 [DB][Warn] [dbc_mgr_file.c(1708)dbGetBinFile] DB download cfg(iRet:0)
04:15:12 [webd][Info] [upload.c(644)create_config_f] user cfg path:/var/tmp/version-cfg

So I searched router firmware for srings of text like above and found this line

deflate 1.1.4 jean loup gailly

nearby some of strings, after quick google it seams that this is zlib and its used for compression of "something", after that with my little knowlage I tried to decompress it with comands like this

printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" |cat - zlib.raw |gzip -dc

cat /tmp/data | openssl zlib -d

but with no luck, later on I found similar file on web with no compression on it, so I take a look and it seams that header of file and couple more "byts" are the same as my compressed file and Im not sure how I can skip these first "byts" and try to decompress rest of "data", also from log u can see some type of "Sign" which are also need to be skiped, here is how similar file which is not compressed look like


00000000  99 99 99 99 44 44 44 44  55 55 55 55 aa aa aa aa  |....DDDDUUUU....|
00000010  00 00 00 00 00 00 00 00  00 00 00 04 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 40  |...............@|
00000040  00 02 00 00 00 00 00 80  00 04 5e 85 00 00 00 00  |..........^.....|
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000080  3c 44 42 3e 0a 3c 54 62  6c 20 6e 61 6d 65 3d 22  |<DB>.<Tbl name="|
00000090  44 42 42 61 73 65 22 20  52 6f 77 43 6f 75 6e 74  |DBBase" RowCount|
000000a0  3d 22 31 22 3e 0a 3c 52  6f 77 20 4e 6f 3d 22 30  |="1">.<Row No="0|
000000b0  22 3e 0a 3c 44 4d 20 6e  61 6d 65 3d 22 49 46 49  |">.<DM name="IFI|
000000c0  6e 66 6f 22 20 76 61 6c  3d 22 30 31 30 31 30 32  |nfo" val="010102|
000000d0  30 31 30 34 30 30 30 30  30 30 30 31 30 36 30 31  |0104000000010601|
000000e0  30 34 30 30 30 30 30 32  31 32 35 30 30 30 30 30  |0400000212500000|
000000f0  30 30 35 30 30 31 30 30  30 30 35 30 30 32 30 30  |0050010000500200|
00000100  30 30 35 30 30 33 30 30  30 30 22 2f 3e 0a 3c 2f  |0050030000"/>.</|
00000110  52 6f 77 3e 0a 3c 2f 54  62 6c 3e 0a 3c 54 62 6c  |Row>.</Tbl>.<Tbl|
00000120  20 6e 61 6d 65 3d 22 45  54 48 22 20 52 6f 77 43  | name="ETH" RowC|
00000130  6f 75 6e 74 3d 22 34 22  3e 0a 3c 52 6f 77 20 4e  |ount="4">.<Row N|
00000140  6f 3d 22 30 22 3e 0a 3c  44 4d 20 6e 61 6d 65 3d  |o="0">.<DM name=|
00000150  22 56 69 65 77 4e 61 6d  65 22 20 76 61 6c 3d 22  |"ViewName" val="|
00000160  49 47 44 2e 4c 44 31 2e  45 54 48 31 22 2f 3e 0a  |IGD.LD1.ETH1"/>.|
00000170  3c 44 4d 20 6e 61 6d 65  3d 22 4c 44 57 44 56 69  |<DM name="LDWDVi|

Here u can find compressed backup.

Edit: On picture u can see comparasion of two files db_user_cfg.xml (file from log) on (left side) and that "same file" but when is "backedup" on right side

Zte compare

10

If you look at offset 0xDF of your backup file you'll see the two bytes:

0x78 0xDA

These commonly delimit the beginning of a zlib compressed file.

In fact, the original XML config file has been split up into multiple zlib compressed blocks:

$ binwalk default-config.bin

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------------------
223           0xDF            Zlib header, best compression, uncompressed size >= 8192
1211          0x4BB           Zlib header, best compression, uncompressed size >= 8192
2260          0x8D4           Zlib header, best compression, uncompressed size >= 8192
2901          0xB55           Zlib header, best compression, uncompressed size >= 8192
3796          0xED4           Zlib header, best compression, uncompressed size >= 8192
4306          0x10D2          Zlib header, best compression, uncompressed size >= 8192
5224          0x1468          Zlib header, best compression, uncompressed size >= 8192
6066          0x17B2          Zlib header, best compression, uncompressed size >= 8192
7084          0x1BAC          Zlib header, best compression, uncompressed size >= 8192
8058          0x1F7A          Zlib header, best compression, uncompressed size >= 8192
8981          0x2315          Zlib header, best compression, uncompressed size >= 3156

If you decompress each of those blocks and concatenate the decompressed data together, you'll get the original XML config file.

  • Thank u devttys0 its great to have u here, Im amazed for what u just say, I run biwalk on this file but did not get anything from him, strange :) $ binwalk Binwalk v1.2.2-1 Thank u once more time and cheers ! – Vido Feb 2 '14 at 18:25
  • zlib scans were implemented as an optional plugin in v1.2.2. zlib is now included in the default scan in the latest code (github.com/devttys0/binwalk). – devttys0 Feb 2 '14 at 20:00
  • Great I must have that new version :) – Vido Feb 2 '14 at 21:58
5

Ok here is little python script that works :)


import zlib

magic_numbers = ['\x78\xDA'] filename = 'config-marina.bin'

infile = open(filename, 'r') data = infile.read()

pos = 0 found = False

while pos < len(data): window = data[pos:pos+2] for marker in magic_numbers: if window == marker: found = True start = pos print "Start of zlib %s" % pos rest_of_data = data[start:] decomp_obj = zlib.decompressobj() uncompressed_msg = decomp_obj.decompress(rest_of_data) print "Content: %s" % uncompressed_msg break if pos == len(data): break pos += 1

if found: header = data[:start] footer = decomp_obj.unused_data

if not found: print "Sorry, no zlib found."

  • To make it working for me with Python 2.7.7 (that I found on my computer), I had to change the line: infile = open(filename, 'r') To: infile = open(filename, 'rb') – Attila Kovács Sep 29 '14 at 19:11
  • This script also works for the newest ZTE F609 ONT firmware (v5). Thanks! – EDP Jan 21 '16 at 17:19
  • @Vido some idiot took your decompression script and claimed on on exploit-db.com that it exploits a zero-day vulnerability – julian Mar 3 '17 at 1:31
  • Tnx for reporting @SYS_V ... lol :) – Vido Mar 3 '17 at 16:10
2

Every compressed chunk in the config.bin file is prepended by a small 3-DWORDs header containing the following information:

  1. the length of the uncompressed xml chunk. This value is 0x10000 for all but the last chunk
  2. the length of the compressed zlib chunk
  3. the cumulative length of the file after the chunk is appended. This value is 0x0 for the last chunk.

These headers can be used to avoid false positives during the detection of the chunks: valid chunks will have either a 0x10000 on the first field or a 0x0 on the third field. The headers can also be used to verify the uncompressed data size.

import re
import zlib
import struct


def extract_config_xml(config_bin):
    config_xml = b''
    for zlib_chunk in re.finditer('\x78\xda', config_bin):
        zlib_chunk_start = zlib_chunk.start()
        zlib_chunk_header = config_bin[zlib_chunk_start - 12: zlib_chunk_start]
        xml_chunk_length, zlib_chunk_length, config_bin_length = \
            struct.unpack('>LLL', zlib_chunk_header)
        if xml_chunk_length == 0x10000 or config_bin_length == 0:
            zlib_chunk_end = zlib_chunk_start + zlib_chunk_length
            zlib_chunk = config_bin[zlib_chunk_start: zlib_chunk_end]
            xml_chunk = zlib.decompress(zlib_chunk)
            assert xml_chunk_length == len(xml_chunk)
            config_xml += xml_chunk
    return config_xml


with open('config.bin', 'rb') as f:
    print extract_config_xml(f.read())
  • tnx for realy nice explanation, to me its more clear whats going on here :) – Vido Jun 30 '15 at 6:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.