-
-
Save Lokotito/5ab7b8627d43d583fd888a0af39d6b12 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python2 | |
# | |
# Nokia/Alcatel-Lucent router backup configuration tool | |
# | |
# Features: | |
# - Unpack/repack .cfg files generated from the backup and restore functionnality | |
# in order to modify the full router configuration | |
# - Decrypt/encrypt the passwords/secret values present in the configuration | |
# | |
# Released under the MIT License (http://opensource.org/licenses/MIT) | |
# Copyright (c) Sami Alaoui Kendil (thedroidgeek) | |
# | |
import sys | |
import zlib | |
import struct | |
import base64 | |
import binascii | |
import datetime | |
big_endian = True | |
def u32(val): | |
return struct.unpack('>I' if big_endian else '<I', val)[0] | |
def p32(val): | |
return struct.pack('>I' if big_endian else '<I', val) | |
# | |
# unpack xml from cfg | |
# | |
if (len(sys.argv) == 3 and sys.argv[1] == '-u'): | |
cf = open(sys.argv[2], 'rb') | |
# read the header | |
header = cf.read(0x14) | |
# check cfg file magic (0x123123) and determine endianness | |
if (header[0:4] == b'\x00\x12\x31\x23'): | |
print('big endian CPU detected') | |
elif (header[0:4] == b'\x23\x31\x12\x00'): | |
print('little endian CPU detected') | |
big_endian = False | |
else: | |
print('invalid cfg file/magic') | |
exit() | |
# get fw_magic (unknown, could be fw version/compile time, hw serial number, etc.) | |
fw_magic = u32(header[0x10:0x14]) | |
print('fw_magic = ' + hex(fw_magic)) | |
# read the size of the compressed data | |
data_size = u32(header[4:8]) | |
# read the compressed data | |
compressed = cf.read(data_size) | |
# read the checksum of the compressed data | |
checksum = u32(header[8:12]) | |
# verify the checksum | |
if (binascii.crc32(compressed) & 0xFFFFFFFF != checksum): | |
print('CRC32 checksum failed') | |
exit() | |
# unpack the config | |
xml_data = zlib.decompress(compressed) | |
# output the xml file | |
out_filename = 'config-%s.xml' % datetime.datetime.now().strftime('%d%m%Y-%H%M%S') | |
of = open(out_filename, 'wb') | |
of.write(xml_data) | |
print('unpacked as: ' + out_filename) | |
print('\n# repack with:') | |
print('%s %s %s %s' % (sys.argv[0], '-pb' if big_endian else '-pl', out_filename, hex(fw_magic))) | |
cf.close() | |
of.close() | |
# | |
# generate cfg from xml | |
# | |
elif (len(sys.argv) == 4 and (sys.argv[1] == '-pb' or sys.argv[1] == '-pl')): | |
fw_magic = 0 | |
try: | |
# parse hex string | |
fw_magic = int(sys.argv[3], 16) | |
# 32-bit check | |
p32(fw_magic) | |
except: | |
print('invalid magic value specified (32-bit hex)') | |
exit() | |
big_endian = sys.argv[1] == '-pb' | |
out_filename = 'config-%s.cfg' % datetime.datetime.now().strftime('%d%m%Y-%H%M%S') | |
# read the xml file | |
xf = open(sys.argv[2], 'rb') | |
xml_data = xf.read() | |
xf.close() | |
# compress using default zlib compression | |
compressed = zlib.compress(xml_data) | |
# create the cfg file | |
of = open(out_filename, 'wb') | |
## write the header ## | |
# magic | |
of.write(p32(0x123123)) | |
# size of compressed data | |
of.write(p32(len(compressed))) | |
# crc32 checksum | |
of.write(p32(binascii.crc32(compressed) & 0xFFFFFFFF)) | |
# size of xml file | |
of.write(p32(len(xml_data) + 1)) | |
# fw_magic | |
of.write(p32(fw_magic)) | |
# write the compressed data | |
of.write(compressed) | |
of.close() | |
print('packed as: ' + out_filename) | |
# | |
# decrypt/encrypt secret value | |
# | |
elif (len(sys.argv) == 3 and (sys.argv[1] == '-d' or sys.argv[1] == '-e')): | |
decrypt_mode = sys.argv[1] == '-d' | |
from Crypto.Cipher import AES | |
# key and IV for AES | |
key = '3D A3 73 D7 DC 82 2E 2A 47 0D EC 37 89 6E 80 D7 2C 49 B3 16 29 DD C9 97 35 4B 84 03 91 77 9E A4' | |
iv = 'D0 E6 DC CD A7 4A 00 DF 76 0F C0 85 11 CB 05 EA' | |
# create AES-128-CBC cipher | |
cipher = AES.new(bytes(bytearray.fromhex(key)), AES.MODE_CBC, bytes(bytearray.fromhex(iv))) | |
if decrypt_mode: | |
# base64 decode + AES decrypt | |
output = cipher.decrypt(base64.b64decode(sys.argv[2])).decode('UTF-8') | |
# remove PKCS#7 padding | |
output = output[:-ord(output[-1])] | |
print('\ndecrypted: ' + output + '\n') | |
else: | |
# add PKCS#7 padding for 128-bit AES | |
input_str = sys.argv[2] | |
padding_num = (16 - (len(input_str) % 16)) | |
input_str += chr(padding_num) * padding_num | |
# AES encrypt + base64 encode | |
output = base64.b64encode(cipher.encrypt(input_str)).decode('UTF-8') | |
print('\nencrypted: ' + output + '\n') | |
else: | |
print('\n#\n# Nokia/Alcatel-Lucent router backup configuration tool\n#\n') | |
print('# cfg to xml\n') | |
print(sys.argv[0] + ' -u config.cfg\n') | |
print('# xml to cfg for big/little endian w/ fw_magic = 0x13377331\n') | |
print(sys.argv[0] + ' -pb config.xml 0x13377331') | |
print(sys.argv[0] + ' -pl config.xml 0x13377331\n') | |
print('# decrypt/encrypt secret values within xml (ealgo="ab")\n') | |
print(sys.argv[0] + ' -d OYdLWUVDdKQTPaCIeTqniA==') | |
print(sys.argv[0] + ' -e admin\n') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The issue is not related to patching but I'm facing an issue. I tried to enable port forwarding on Nokia G-2425G-A after that I'm facing internet connectivity issue. Can someone please help? If I hard reset the router then it works for few minutes(2-3 minutes) then again internet goes down. On router page it says Authentication failure.