In order for things to work for the ULYSSIS CTF, we had to configure a bunch of routers (in this case, a D-Link GO-RT-N150). However, the web UI config was very limited, but we suspected the actual config format underneath was much more flexible.
In the web UI, there’s an option to import and export a config file. But on first sight, it looks like nothing useful at all:
1 2 3 4 5 6 7 8 9 10 |
00000000 5e a3 a4 17 00 00 00 40 00 00 07 a0 6b 2f f4 9e |^......@....k/..| 00000010 bc de 1b a0 46 1d 90 3c b0 0e e1 98 73 69 67 6e |....F..<....sign| 00000020 61 74 75 72 65 3d 47 4f 2d 52 54 2d 4e 31 35 30 |ature=GO-RT-N150| 00000030 5f 77 72 67 6e 36 32 00 6e 6f 68 65 61 64 65 72 |_wrgn62.noheader| 00000040 3d 31 00 74 79 70 65 3d 64 65 76 63 6f 6e 66 00 |=1.type=devconf.| 00000050 64 65 76 3d 75 70 67 72 61 64 65 00 1f 8b 08 00 |dev=upgrade.....| 00000060 00 00 00 00 00 03 c5 19 5d 53 db 38 f0 99 fc 8a |........]S.8....| 00000070 7b ef 94 c4 26 64 68 c7 e3 19 0a b9 1e 33 5c 60 |{...&dh......3\`| 00000080 20 bd de 5b 47 d8 4a a2 69 22 bb b6 4c 48 7f fd | ..[G.J.i"..LH..| 00000090 ed 87 64 cb 26 09 d0 a3 6d a7 83 57 ab d5 6a b5 |..d.&...m..W..j.| |
Searching on the Internet doesn’t yield much either. However, on further inspection, one can see the following:
5ea3a417
is 4 bytes long and looks rather random, so it’s probably magic.00000040
and000007a0
Look like big-endian ints, probably the length of something.- Then there are 16 bytes of random data:
6b2ff49e bcde1ba0 461d903c b00ee198
- Following that, a bunch of null-terminated strings are found.
- Random data for the rest of the file.
Let’s try making sense of those integers first. The string starts at offset 1C
and end at 5C
. In other words, that’s where the 00000040
comes from!
The file is 2044 bytes long. In hexadecimal, that is 07fc
. Subtract 5C
(start of garbled data) from that, and you get 7a0
. This probably means that blob is one whole instead of multiple things concatenated.
Now, if you look closer at the random data, it starts with the following bytes: 1f 8b
. That’s the magic header for gzip.
Decompressing that data reveals an XML file with a plethora of options not available in the web UI. \o/ This isn’t of much use unless we can create these files by ourself, though. However, the only thing we still need to figure out is the 16 random bytes. I suspect this is a hash of some sort.
So, let’s try a bunch of hash functions with an 128-bit output on the data: (The output we want is 6b2ff49ebcde1ba0461d903cb00ee198
)
1 2 |
$ tail -c +93 cfg.bin|zcat|md5sum 6207de154ebdc3c03ec836630831c059 - |
Nope. What if we try this instead?
1 2 |
$ tail -c +93 cfg.bin|md5sum 6b2ff49ebcde1ba0461d903cb00ee198 - |
Bingo!
So, here’s the file format:
1 2 3 4 5 6 7 8 |
cfg { u8 magic[4] = {0x5E, 0xA3, 0xA4, 0x17}; u32_be descrlen; u32_be bloblen; u8 md5sum[0x10]; // MD5 of `data` char descr[descrlen]; u8 data[bloblen]; // gzipped XML }; |
The implementation is left as an exercise for the reader 🙂