Skip to content

Instantly share code, notes, and snippets.

@Lokotito
Forked from thedroidgeek/nokia-router-cfg-tool.py
Created December 2, 2020 07:52
Show Gist options
  • Save Lokotito/5ab7b8627d43d583fd888a0af39d6b12 to your computer and use it in GitHub Desktop.
Save Lokotito/5ab7b8627d43d583fd888a0af39d6b12 to your computer and use it in GitHub Desktop.
#!/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')
@mriamnobody
Copy link

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.

[alert] <129>1 1970-01-01T00:03:40.542628+00:00 AONT syslog 4001 - -  cfgDal_getParamVal(InternetGatewayDevice.UserInterface.ISPLogo) stl=0 update=0 failed 
[alert] <129>1 1970-01-01T00:03:55.038055+00:00 AONT syslog 4001 - -  Session is closed now, now reset the WAN 
[alert] <129>1 1970-01-01T00:03:55.055777+00:00 AONT syslog 4001 - -  wan_reset done 
[err] <131>1 1970-01-01T00:04:13.287854+00:00 AONT pppd 7059 - -  PPP-Nego:upap_rauthnak() PAP authentication failed 
[alert] <129>1 1970-01-01T00:04:14.581323+00:00 AONT syslog 4001 - -  [tr069] signal 15 received, terminate now ```

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment