#!/usr/bin/env python3 | |
# | |
# 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 | |
# | |
# Blog post: https://0x41.cf/reversing/2019/10/08/unlocking-nokia-g240wa.html | |
# | |
# 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 | |
encrypted_cfg = False | |
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) | |
def checkendian(cfg): | |
if (cfg[0:4] == b'\x00\x12\x31\x23'): | |
return True | |
elif (cfg[0:4] == b'\x23\x31\x12\x00'): | |
return False | |
else: | |
return None | |
class RouterCrypto: | |
def __init__(self): | |
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 | |
self.cipher = AES.new(bytes(bytearray.fromhex(key)), AES.MODE_CBC, bytes(bytearray.fromhex(iv))) | |
def decrypt(self, data): | |
output = self.cipher.decrypt(data) | |
# remove PKCS#7 padding | |
return output[:-ord(output[-1:])] | |
def encrypt(self, data): | |
# add PKCS#7 padding for 128-bit AES | |
pad_num = (16 - (len(data) % 16)) | |
data += chr(pad_num).encode() * pad_num | |
return self.cipher.encrypt(data) | |
# | |
# unpack xml from cfg | |
# | |
if (len(sys.argv) == 3 and sys.argv[1] == '-u'): | |
# line feed | |
print('') | |
# read the cfg file | |
cf = open(sys.argv[2], 'rb') | |
cfg_data = cf.read() | |
# check cfg file magic (0x123123) and determine endianness | |
big_endian = checkendian(cfg_data) | |
if big_endian == None: | |
# check if config is encrypted | |
decrypted = None | |
try: | |
# decrypt and check validity | |
decrypted = RouterCrypto().decrypt(cfg_data) | |
big_endian = checkendian(decrypted) | |
except ValueError: | |
pass | |
# if decryption failed, or still invalid, bail out | |
if big_endian == None: | |
print('invalid cfg file/magic :(\n') | |
exit() | |
# set decrypted cfg buffer and encryption flag | |
print('-> encrypted cfg detected') | |
cfg_data = decrypted | |
encrypted_cfg = True | |
# log endianness | |
if big_endian: | |
print('-> big endian CPU detected') | |
else: | |
print('-> little endian CPU detected') | |
# get fw_magic (unknown, could be fw version/compile time, hw serial number, etc.) | |
fw_magic = u32(cfg_data[0x10:0x14]) | |
print('-> fw_magic = ' + hex(fw_magic)) | |
# get the size of the compressed data | |
data_size = u32(cfg_data[4:8]) | |
# get the compressed data | |
compressed = cfg_data[0x14 : 0x14 + data_size] | |
# get the checksum of the compressed data | |
checksum = u32(cfg_data[8:12]) | |
# verify the checksum | |
if (binascii.crc32(compressed) & 0xFFFFFFFF != checksum): | |
print('\nCRC32 checksum failed :(\n') | |
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('\nunpacked as: ' + out_filename) | |
print('\n# repack with:') | |
print('%s %s %s %s\n' % (sys.argv[0], ('-pb' if big_endian else '-pl') + ('e' if encrypted_cfg else ''), out_filename, hex(fw_magic))) | |
cf.close() | |
of.close() | |
# | |
# generate cfg from xml | |
# | |
elif (len(sys.argv) == 4 and (sys.argv[1][:3] == '-pb' or sys.argv[1][:3] == '-pl')): | |
fw_magic = 0 | |
try: | |
# parse hex string | |
fw_magic = int(sys.argv[3], 16) | |
# 32-bit check | |
p32(fw_magic) | |
except: | |
print('\ninvalid magic value specified (32-bit hex)\n') | |
exit() | |
big_endian = sys.argv[1][:3] == '-pb' | |
encrypted_cfg = sys.argv[1][3:] == 'e' | |
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) | |
## construct the header ## | |
# magic | |
cfg_data = p32(0x123123) | |
# size of compressed data | |
cfg_data += p32(len(compressed)) | |
# crc32 checksum | |
cfg_data += p32(binascii.crc32(compressed) & 0xFFFFFFFF) | |
# size of xml file | |
cfg_data += p32(len(xml_data) + 1) | |
# fw_magic | |
cfg_data += p32(fw_magic) | |
# add the compressed xml | |
cfg_data += compressed | |
# encrypt if necessary | |
if encrypted_cfg: | |
cfg_data = RouterCrypto().encrypt(cfg_data) | |
# write the cfg file | |
of = open(out_filename, 'wb') | |
of.write(cfg_data) | |
of.close() | |
print('\npacked as: ' + out_filename + '\n') | |
# | |
# 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' | |
if decrypt_mode: | |
# base64 decode + AES decrypt | |
print('\ndecrypted: ' + RouterCrypto().decrypt(base64.b64decode(sys.argv[2])).decode('UTF-8') + '\n') | |
else: | |
# AES encrypt + base64 encode | |
print('\nencrypted: ' + base64.b64encode(RouterCrypto().encrypt(sys.argv[2].encode())).decode('UTF-8') + '\n') | |
else: | |
print('\n#\n# Nokia/Alcatel-Lucent router backup configuration tool\n#\n') | |
print('# unpack (cfg to xml)\n') | |
print(sys.argv[0] + ' -u config.cfg\n') | |
print('# pack (xml to cfg)\n') | |
print(sys.argv[0] + ' -pb config.xml 0x13377331 # big endian, no encryption, fw_magic = 0x13377331') | |
print(sys.argv[0] + ' -pl config.xml 0x13377331 # little endian, ...') | |
print(sys.argv[0] + ' -pbe config.xml 0x13377331 # big endian, with encryption, ...') | |
print(sys.argv[0] + ' -ple 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') |
This comment has been minimized.
This comment has been minimized.
@espetoet - Hello, I've been contacted last year by someone who had a Nokia router with an ARM (little endian) CPU and a different value for 'magic2', and I've since fixed the script for him in private, but never got around to rewriting this one and making it universal. |
This comment has been minimized.
This comment has been minimized.
Thank you very much the extraction was successful. Now I have another problem, I followed the tutorial as a reference https://0x41.cf/reversing/2019/10/08/unlocking-nokia-g240wa.html |
This comment has been minimized.
This comment has been minimized.
It seems the behavior is different across devices/fw versions - perhaps try setting LimitAccount_ONTUSER to false and then login with ONTUSER, if that doesn't work, I'd suggest you look for other settings that might look interesting in the xml. |
This comment has been minimized.
This comment has been minimized.
hello it worked. set it to false LimitAccount_ONTUSER and signed in as ONTUSER |
This comment has been minimized.
This comment has been minimized.
Salam! I was able to unpack/pack successfully but when uploading the firmware I get this:
One thing odd is when I re-pack, the size of the firmware is quite different:
I want to have a root access to try to put the device (Nokia G-240W-A) into wan bridge (do the vlan and media conversion on it, and only have to do the pppoe on a second router, a Mikrotik. Right now I'm on a full bridge mode and my Mikrotik struggles in terms of speed to do the vlan and pppoe on the cpu). I don't know if I will be able to do that :P Shoukrane! |
This comment has been minimized.
This comment has been minimized.
Salam, I'm pretty confused as to why you're referring to the cfg file as firmware - I think you were meant to upload it via the same page you got it from. For the size, it's normal, there's garbage bytes that are included when generating the cfg from the router (I think, didn't bother to check). For your 'WAN bridge' setup, I'm not sure if you'll be able to achieve it - I'd advise you just get a decent router that can handle VLAN and PPPoE and leave the Nokia as a simple ONT modem - I personally got an Archer C60 v2 3 months ago (~500MAD) that I've flashed with OpenWrt (can easily NAT 100mbps even without software flow offloading, and has decent 5GHz range) and I never had to power cycle anything ever again. |
This comment has been minimized.
This comment has been minimized.
If you knew what I meant then it's ok. I already have a Mikrotik and using the Nokia in bridge mode and handling the VLAN and pppoe on the Mikrotik. Just playing with it to see if I can do a wan bridge. I saw in the HTML than the drop down has been hidden to put in in "pppoe bridge". I was able to save the wan in bridge mode by enabling the previously hidden HTML element but I don't know if the hardware behind is supporting it. It does save correctly and says it's connected to the ISP in status but it doesn't seem to work, I will have to test again. Still, the script don't work for me. And yes I was referring to a backup/restore of the config. A lot of companies are calling the bin a firmware. |
This comment has been minimized.
This comment has been minimized.
Feel free to send me an example cfg file via email (address is on my profile) I guess, even though it doesn't seem like the script failed ¯\_(ツ)_/¯ |
This comment has been minimized.
This comment has been minimized.
Is it possible to convert the function from GPON TO EPON via the configuration file? |
This comment has been minimized.
This comment has been minimized.
Oh man I feel dumb :P I was not re-uploading the config at the right place, it works and I have root, my bad! |
This comment has been minimized.
This comment has been minimized.
In the blog you did not mention how did you actually manage to find the hash mechanism? |
This comment has been minimized.
This comment has been minimized.
@rabindra1337 Blame my laziness, a part 2 was in plans but shit happened. ¯\_(ツ)_/¯ Maybe soon™ though. ;) |
This comment has been minimized.
This comment has been minimized.
Real excited for part 2. |
This comment has been minimized.
This comment has been minimized.
Hello @thedroidgeek Thankyou for the detailed instruction , although this is the first time ive used python and still able get to root user succesfully on G-140w-F & G-140w-C . now what i want is to Modify the default configuration of the ONT ( that means if we hard reset the ONT it will restore our modified configuration). Thanks Again for the Guide |
This comment has been minimized.
This comment has been minimized.
@thedroidgeek your script is awesome I have a Nokia G-140W-h ont and that looks similar. but when I use your script it returns me a message (Invalid magic) Would you help me |
This comment has been minimized.
This comment has been minimized.
Got the root shell. Thank you so much. But my router is configured for airtel and hard-coded in tr-069 page. I want to use it for bsnl, but I think I can change in .XML if needed. And I don't know whether some other settings will mitigate usage. Can you help, is there any way to reset the router without vendor detail ? |
This comment has been minimized.
This comment has been minimized.
My router (G-140w-C) doesn't have Backup and Restore page. |
This comment has been minimized.
This comment has been minimized.
ip/usb.cgi?backup |
This comment has been minimized.
This comment has been minimized.
@MrAnssaien Thanks. Unfortunately, blank page. :( |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Hello @shailparmar, Did you able to root the Nokia - G-140W-F? |
This comment has been minimized.
This comment has been minimized.
Aw man, looks like it's overwriting the |
This comment has been minimized.
This comment has been minimized.
Yes
At first I got same
Than I tried This. It seems the behavior is different across devices/fw versions - perhaps try setting LimitAccount_ONTUSER to false and then login with ONTUSER, if that doesn't work, I'd suggest you look for other settings that might look interesting in the xml. |
This comment has been minimized.
This comment has been minimized.
@dcetrulo - I've now added support for encrypted cfg files, as it turned out (from the files I was sent by email), that they generally use the same encryption used on credentials, on some routers' cfg files. |
This comment has been minimized.
This comment has been minimized.
Hi! Thanks for your work, it's awesome!! I've got two devices: an I-240W-A, and a G-240W-B. I got ssh access on the G-one! But it logs me out immediately: `[tulio@TulainasV5 G-240W-B]$ ssh -vvv admin@192.168.1.253 debug3: receive packet: type 52 debug3: send packet: type 1 Do you have an idea how to get around it? I'm still working on the I-240 one, which has a firewall blocking ssh input traffic. I'm stilll working on it. |
This comment has been minimized.
This comment has been minimized.
Hello @shailparmar, Yes, LimitAccount_ONTUSER has been set to false. Still root access is not permitted. |
This comment has been minimized.
This comment has been minimized.
I got a G-140W-H here, hardware version 3FE48054BDAA, software version 3FE48077CGCB30, boot version U-Boot Mar-31-2020--23:07:20. This is for a brazilian ISP called "Oi". They block A LOT of ports, and don't give the option to bridge the router. They provide a very limited "userAdmin" user, and they have changed the AdminGPON user default password. No one has it. I was trying an easier way to get AdminGPON access, other than dumping the firmware with JTAG cable, wich I don't have. One way would be backing up the firmware from web interface, but this userAdmin user does not have access to firmware page. Does anyone here know of a hardcoded password for this model, or knows a way to dump the firmware from web interface with this "userAdmin" unprivilleged user? BTW, changing html at runtime vi browser debug console does not work to change configurations at this model. Web interface complains about user privilleges for any changes at the "WAN" tab. |
This comment has been minimized.
This comment has been minimized.
@espetoet Hello how did you login ONTUSER? I have password of ADMINGPON and the telnetssh but I don't have password of ONT USer? |
This comment has been minimized.
This comment has been minimized.
disregard previous comment. the password is SUGAR2A041 |
This comment has been minimized.
This comment has been minimized.
I have a Nokia GPON with Model Number: "G-2425G-A" and Hardware Version "3FE48299DBAA". Most of the settings have been disabled by Airtel when I login using "admin" user id. Is it possible to somehow enable the greyed out setting options? |
This comment has been minimized.
This comment has been minimized.
i have G-140W-B from telmex, not telnet/ssh enable, download config using your excellent tool to unpack and only modify Telnet Enable from False to True, then pack with magic, when upload via page Import Config, it upload OK and then restart router, but when it restart no any changes, again download config and check and no changes appear done, do you have similar problem?, share some device daa
|
This comment has been minimized.
This comment has been minimized.
@thedroidgeek Thank you for the script. I was able to login to telnet and try to access shell which is asking for password that I try to provide same password as telnet but it says invalid. can you guys help to identify in the xml where is the shell password @shailparmar me having G-140w-F & G-140w-C both able to login to telnet but not getting shell prompt like you shared screenshot in this thread. Help to identify where is the configuration in the xml. I tried my best last 2 weeks. Thank you again |
This comment has been minimized.
Hello!

very good your script,
I have a Nokia G-120W-F modem that looks similar. but when I use your script it returns me a message (Invalid magic) and generates a config.xml file but with 0 bytes. Would you help me. can i send you my cfg file for you to analyze