Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
#!/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')
@espetoet

This comment has been minimized.

Copy link

@espetoet espetoet commented Jun 6, 2020

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
invalid magic

@thedroidgeek

This comment has been minimized.

Copy link
Owner Author

@thedroidgeek thedroidgeek commented Jun 7, 2020

@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.
Now that I did just that, please recheck if it works for you and let me know.
Regards.

@espetoet

This comment has been minimized.

Copy link

@espetoet espetoet commented Jun 7, 2020

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

I made the necessary changes, but when I logged into Telnet. he logs in as a normal user.

ok
1
2

@thedroidgeek

This comment has been minimized.

Copy link
Owner Author

@thedroidgeek thedroidgeek commented Jun 7, 2020

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.

@espetoet

This comment has been minimized.

Copy link

@espetoet espetoet commented Jun 9, 2020

hello it worked. set it to false LimitAccount_ONTUSER and signed in as ONTUSER

@mikegleasonjr

This comment has been minimized.

Copy link

@mikegleasonjr mikegleasonjr commented Jul 3, 2020

Salam!

I was able to unpack/pack successfully but when uploading the firmware I get this:

Checking upgrade partition...
Everything is OK.
swdl_parse_image: fail! image file invalid.
Web: swdl_write_image faild! ret=1

One thing odd is when I re-pack, the size of the firmware is quite different:

$ ls -lh
-rwxrwxrwx 1 root root  54K Jul  3 23:54 config-03072020-235406.cfg
-rwxrwxrwx 1 root root  60K Jul  3 12:52 default-bridged.cfg

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!

@thedroidgeek

This comment has been minimized.

Copy link
Owner Author

@thedroidgeek thedroidgeek commented Jul 4, 2020

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.

@mikegleasonjr

This comment has been minimized.

Copy link

@mikegleasonjr mikegleasonjr commented Jul 5, 2020

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.

@thedroidgeek

This comment has been minimized.

Copy link
Owner Author

@thedroidgeek thedroidgeek commented Jul 5, 2020

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 ¯\_(ツ)_/¯

@sayushrestha

This comment has been minimized.

Copy link

@sayushrestha sayushrestha commented Jul 5, 2020

Is it possible to convert the function from GPON TO EPON via the configuration file?

@mikegleasonjr

This comment has been minimized.

Copy link

@mikegleasonjr mikegleasonjr commented Jul 6, 2020

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!

@0xrabin

This comment has been minimized.

Copy link

@0xrabin 0xrabin commented Aug 17, 2020

In the blog you did not mention how did you actually manage to find the hash mechanism?

@thedroidgeek

This comment has been minimized.

Copy link
Owner Author

@thedroidgeek thedroidgeek commented Aug 17, 2020

@rabindra1337 Blame my laziness, a part 2 was in plans but shit happened. ¯\_(ツ)_/¯ Maybe soon™ though. ;)

@0xrabin

This comment has been minimized.

Copy link

@0xrabin 0xrabin commented Aug 17, 2020

Real excited for part 2.
Any sneak peek of part2?
Part 1 was epic btw.

@shailparmar

This comment has been minimized.

Copy link

@shailparmar shailparmar commented Oct 22, 2020

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
below are the available cmds.
cmd1
cmd2
cmd3

@dcetrulo

This comment has been minimized.

Copy link

@dcetrulo dcetrulo commented Oct 24, 2020

@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
problema nokia
i change name of py for easy write.
and it is the same as the g240 include the access password but it is all locked and i am trying to put it in bridge mode i had the same problem as the espetoet so that with two errors besides the invalid magic i will send you the email with the file.

@mukhilanpari

This comment has been minimized.

Copy link

@mukhilanpari mukhilanpari commented Nov 5, 2020

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 ?

@sh4k4

This comment has been minimized.

Copy link

@sh4k4 sh4k4 commented Nov 11, 2020

My router (G-140w-C) doesn't have Backup and Restore page.
Maybe it's hidden. What is the url of Backup and Restore page (http://ip/something.cgi)?

@MrAnssaien

This comment has been minimized.

Copy link

@MrAnssaien MrAnssaien commented Nov 11, 2020

My router (G-140w-C) doesn't have Backup and Restore page.
Maybe it's hidden. What is the url of Backup and Restore page (http://ip/something.cgi)?

ip/usb.cgi?backup

@sh4k4

This comment has been minimized.

Copy link

@sh4k4 sh4k4 commented Nov 11, 2020

@MrAnssaien Thanks. Unfortunately, blank page. :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.